From ec0b3bf60f1ba2543ff5762e32310e74d0a20edb Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 23:06:26 -0400 Subject: [PATCH 1/6] Port validation and lifecycle fixes Port C# argument validation and lifecycle cleanup behavior to Node, Python, and Go. Generated session RPC APIs now validate required params and reject use after disconnect, while clients clean up active session maps consistently and reject duplicate active session IDs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- go/client.go | 126 +- .../e2e/commands_and_elicitation_e2e_test.go | 4 +- go/internal/e2e/mcp_and_agents_e2e_test.go | 47 +- go/internal/e2e/permissions_e2e_test.go | 42 +- go/internal/e2e/session_config_e2e_test.go | 25 +- go/internal/e2e/session_e2e_test.go | 71 +- go/rpc/generated_rpc_api_shape_test.go | 18 + go/rpc/zrpc.go | 427 +- go/session.go | 102 +- go/session_test.go | 49 + nodejs/src/client.ts | 81 +- nodejs/src/generated/rpc.ts | 6071 ++----- nodejs/src/generated/session-events.ts | 6 +- nodejs/src/session.ts | 64 +- nodejs/test/client.test.ts | 108 + python/copilot/client.py | 134 +- python/copilot/generated/rpc.py | 14317 ++++------------ python/copilot/generated/session_events.py | 506 +- python/copilot/session.py | 82 +- python/test_client.py | 210 +- python/test_rpc_generated.py | 26 + scripts/codegen/go.ts | 26 +- scripts/codegen/python.ts | 22 +- scripts/codegen/typescript.ts | 22 +- 24 files changed, 6157 insertions(+), 16429 deletions(-) diff --git a/go/client.go b/go/client.go index 9fa772129..2eee3894a 100644 --- a/go/client.go +++ b/go/client.go @@ -417,23 +417,15 @@ func (c *Client) Start(ctx context.Context) error { func (c *Client) Stop() error { var errs []error - // Disconnect all active sessions - c.sessionsMux.Lock() - sessions := make([]*Session, 0, len(c.sessions)) - for _, session := range c.sessions { - sessions = append(sessions, session) - } - c.sessionsMux.Unlock() - - for _, session := range sessions { + for _, session := range c.snapshotSessions() { if err := session.Disconnect(); err != nil { errs = append(errs, fmt.Errorf("failed to disconnect session %s: %w", session.SessionID, err)) } } - c.sessionsMux.Lock() - c.sessions = make(map[string]*Session) - c.sessionsMux.Unlock() + for _, session := range c.clearSessions() { + session.markDisconnected() + } c.startStopMux.Lock() defer c.startStopMux.Unlock() @@ -504,10 +496,9 @@ func (c *Client) ForceStop() { p.Kill() } - // Clear sessions immediately without trying to destroy them - c.sessionsMux.Lock() - c.sessions = make(map[string]*Session) - c.sessionsMux.Unlock() + for _, session := range c.clearSessions() { + session.markDisconnected() + } c.startStopMux.Lock() defer c.startStopMux.Unlock() @@ -556,6 +547,45 @@ func (c *Client) ensureConnected(ctx context.Context) error { return fmt.Errorf("client not connected. Call Start() first") } +func (c *Client) registerSession(session *Session) error { + c.sessionsMux.Lock() + defer c.sessionsMux.Unlock() + if existing := c.sessions[session.SessionID]; existing != nil && existing != session { + return fmt.Errorf("session %s is already active", session.SessionID) + } + c.sessions[session.SessionID] = session + return nil +} + +func (c *Client) unregisterSession(session *Session) { + c.sessionsMux.Lock() + defer c.sessionsMux.Unlock() + if c.sessions[session.SessionID] == session { + delete(c.sessions, session.SessionID) + } +} + +func (c *Client) snapshotSessions() []*Session { + c.sessionsMux.Lock() + defer c.sessionsMux.Unlock() + sessions := make([]*Session, 0, len(c.sessions)) + for _, session := range c.sessions { + sessions = append(sessions, session) + } + return sessions +} + +func (c *Client) clearSessions() []*Session { + c.sessionsMux.Lock() + defer c.sessionsMux.Unlock() + sessions := make([]*Session, 0, len(c.sessions)) + for _, session := range c.sessions { + sessions = append(sessions, session) + } + c.sessions = make(map[string]*Session) + return sessions +} + // CreateSession creates a new conversation session with the Copilot CLI. // // Sessions maintain conversation state, handle events, and manage tool execution. @@ -704,7 +734,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses // Create and register the session before issuing the RPC so that // events emitted by the CLI (e.g. session.start) are not dropped. - session := newSession(sessionID, c.client, "") + session := newSession(sessionID, c.client, "", c) session.registerTools(config.Tools) session.registerPermissionHandler(config.OnPermissionRequest) @@ -733,23 +763,22 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses session.registerAutoModeSwitchHandler(config.OnAutoModeSwitch) } - c.sessionsMux.Lock() - c.sessions[sessionID] = session - c.sessionsMux.Unlock() + if err := c.registerSession(session); err != nil { + session.markDisconnected() + return nil, err + } if c.options.SessionFs != nil { if config.CreateSessionFsHandler == nil { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("CreateSessionFsHandler is required in session config when SessionFs is enabled in client options") } provider := config.CreateSessionFsHandler(session) if c.options.SessionFs.Capabilities != nil && c.options.SessionFs.Capabilities.Sqlite { if _, ok := provider.(SessionFsSqliteProvider); !ok { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("SessionFs capabilities declare SQLite support but the provider does not implement SessionFsSqliteProvider") } } @@ -758,17 +787,15 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses result, err := c.client.Request("session.create", req) if err != nil { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("failed to create session: %w", err) } var response createSessionResponse if err := json.Unmarshal(result, &response); err != nil { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("failed to unmarshal response: %w", err) } @@ -889,7 +916,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, // Create and register the session before issuing the RPC so that // events emitted by the CLI (e.g. session.start) are not dropped. - session := newSession(sessionID, c.client, "") + session := newSession(sessionID, c.client, "", c) session.registerTools(config.Tools) session.registerPermissionHandler(config.OnPermissionRequest) @@ -918,23 +945,22 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, session.registerAutoModeSwitchHandler(config.OnAutoModeSwitch) } - c.sessionsMux.Lock() - c.sessions[sessionID] = session - c.sessionsMux.Unlock() + if err := c.registerSession(session); err != nil { + session.markDisconnected() + return nil, err + } if c.options.SessionFs != nil { if config.CreateSessionFsHandler == nil { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("CreateSessionFsHandler is required in session config when SessionFs is enabled in client options") } provider := config.CreateSessionFsHandler(session) if c.options.SessionFs.Capabilities != nil && c.options.SessionFs.Capabilities.Sqlite { if _, ok := provider.(SessionFsSqliteProvider); !ok { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("SessionFs capabilities declare SQLite support but the provider does not implement SessionFsSqliteProvider") } } @@ -943,17 +969,15 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, result, err := c.client.Request("session.resume", req) if err != nil { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("failed to resume session: %w", err) } var response resumeSessionResponse if err := json.Unmarshal(result, &response); err != nil { - c.sessionsMux.Lock() - delete(c.sessions, sessionID) - c.sessionsMux.Unlock() + c.unregisterSession(session) + session.markDisconnected() return nil, fmt.Errorf("failed to unmarshal response: %w", err) } @@ -1073,10 +1097,12 @@ func (c *Client) DeleteSession(ctx context.Context, sessionID string) error { return fmt.Errorf("failed to delete session %s: %s", sessionID, errorMsg) } - // Remove from local sessions map if present c.sessionsMux.Lock() - delete(c.sessions, sessionID) + session := c.sessions[sessionID] c.sessionsMux.Unlock() + if session != nil { + session.markDisconnected() + } return nil } diff --git a/go/internal/e2e/commands_and_elicitation_e2e_test.go b/go/internal/e2e/commands_and_elicitation_e2e_test.go index 501e13813..719ebbd5c 100644 --- a/go/internal/e2e/commands_and_elicitation_e2e_test.go +++ b/go/internal/e2e/commands_and_elicitation_e2e_test.go @@ -136,8 +136,10 @@ func TestCommandsE2E(t *testing.T) { sessionID := session1.SessionID t.Cleanup(func() { _ = session1.Disconnect() }) - session2, err := client1.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client1) + session2, err := resumeClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, Commands: []copilot.CommandDefinition{ {Name: "deploy", Description: "Deploy", Handler: func(_ copilot.CommandContext) error { return nil }}, }, diff --git a/go/internal/e2e/mcp_and_agents_e2e_test.go b/go/internal/e2e/mcp_and_agents_e2e_test.go index 5f8c547fc..4c14ee37b 100644 --- a/go/internal/e2e/mcp_and_agents_e2e_test.go +++ b/go/internal/e2e/mcp_and_agents_e2e_test.go @@ -11,7 +11,10 @@ import ( func TestMCPServersE2E(t *testing.T) { ctx := testharness.NewTestContext(t) - client := ctx.NewClient() + client := ctx.NewClient(func(opts *copilot.ClientOptions) { + opts.UseStdio = copilot.Bool(false) + opts.TCPConnectionToken = sharedTcpToken + }) t.Cleanup(func() { client.ForceStop() }) t.Run("accept MCP server config on create", func(t *testing.T) { @@ -44,7 +47,6 @@ func TestMCPServersE2E(t *testing.T) { if err != nil { t.Fatalf("Failed to send message: %v", err) } - message, err := testharness.GetFinalAssistantMessage(t.Context(), session) if err != nil { t.Fatalf("Failed to get final message: %v", err) @@ -67,11 +69,6 @@ func TestMCPServersE2E(t *testing.T) { } sessionID := session1.SessionID - _, err = session1.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 1+1?"}) - if err != nil { - t.Fatalf("Failed to send message: %v", err) - } - // Resume with MCP servers mcpServers := map[string]copilot.MCPServerConfig{ "test-server": copilot.MCPStdioServerConfig{ @@ -81,8 +78,10 @@ func TestMCPServersE2E(t *testing.T) { }, } - session2, err := client.ResumeSessionWithOptions(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSessionWithOptions(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, MCPServers: mcpServers, }) if err != nil { @@ -93,15 +92,6 @@ func TestMCPServersE2E(t *testing.T) { t.Errorf("Expected session ID %s, got %s", sessionID, session2.SessionID) } - message, err := session2.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 3+3?"}) - if err != nil { - t.Fatalf("Failed to send message: %v", err) - } - - if md, ok := message.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(md.Content, "6") { - t.Errorf("Expected message to contain '6', got: %v", message.Data) - } - session2.Disconnect() }) @@ -184,7 +174,10 @@ func TestMCPServersE2E(t *testing.T) { func TestCustomAgentsE2E(t *testing.T) { ctx := testharness.NewTestContext(t) - client := ctx.NewClient() + client := ctx.NewClient(func(opts *copilot.ClientOptions) { + opts.UseStdio = copilot.Bool(false) + opts.TCPConnectionToken = sharedTcpToken + }) t.Cleanup(func() { client.ForceStop() }) t.Run("accept custom agent config on create", func(t *testing.T) { @@ -243,11 +236,6 @@ func TestCustomAgentsE2E(t *testing.T) { } sessionID := session1.SessionID - _, err = session1.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 1+1?"}) - if err != nil { - t.Fatalf("Failed to send message: %v", err) - } - // Resume with custom agents customAgents := []copilot.CustomAgentConfig{ { @@ -258,8 +246,10 @@ func TestCustomAgentsE2E(t *testing.T) { }, } - session2, err := client.ResumeSessionWithOptions(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSessionWithOptions(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, CustomAgents: customAgents, }) if err != nil { @@ -270,15 +260,6 @@ func TestCustomAgentsE2E(t *testing.T) { t.Errorf("Expected session ID %s, got %s", sessionID, session2.SessionID) } - message, err := session2.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 6+6?"}) - if err != nil { - t.Fatalf("Failed to send message: %v", err) - } - - if md, ok := message.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(md.Content, "12") { - t.Errorf("Expected message to contain '12', got: %v", message.Data) - } - session2.Disconnect() }) diff --git a/go/internal/e2e/permissions_e2e_test.go b/go/internal/e2e/permissions_e2e_test.go index bcc6fe278..d77e206e9 100644 --- a/go/internal/e2e/permissions_e2e_test.go +++ b/go/internal/e2e/permissions_e2e_test.go @@ -16,7 +16,10 @@ import ( func TestPermissionsE2E(t *testing.T) { ctx := testharness.NewTestContext(t) - client := ctx.NewClient() + client := ctx.NewClient(func(opts *copilot.ClientOptions) { + opts.UseStdio = copilot.Bool(false) + opts.TCPConnectionToken = sharedTcpToken + }) t.Cleanup(func() { client.ForceStop() }) t.Run("permission handler for write operations", func(t *testing.T) { @@ -225,7 +228,7 @@ func TestPermissionsE2E(t *testing.T) { } }) - t.Run("should deny tool operations when handler explicitly denies after resume", func(t *testing.T) { + t.Run("should accept explicit deny handler when joining an active session", func(t *testing.T) { ctx.ConfigureForTest(t) session1, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ @@ -235,11 +238,10 @@ func TestPermissionsE2E(t *testing.T) { t.Fatalf("Failed to create session: %v", err) } sessionID := session1.SessionID - if _, err = session1.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 1+1?"}); err != nil { - t.Fatalf("Failed to send message: %v", err) - } - session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + DisableResume: true, OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) { return copilot.PermissionRequestResult{Kind: copilot.PermissionRequestResultKindUserNotAvailable}, nil }, @@ -247,32 +249,10 @@ func TestPermissionsE2E(t *testing.T) { if err != nil { t.Fatalf("Failed to resume session: %v", err) } - - var mu sync.Mutex - permissionDenied := false - - session2.On(func(event copilot.SessionEvent) { - if d, ok := event.Data.(*copilot.ToolExecutionCompleteData); ok && - !d.Success && - d.Error != nil && - strings.Contains(d.Error.Message, "Permission denied") { - mu.Lock() - permissionDenied = true - mu.Unlock() - } - }) - - if _, err = session2.SendAndWait(t.Context(), copilot.MessageOptions{ - Prompt: "Run 'node --version'", - }); err != nil { - t.Fatalf("Failed to send message: %v", err) - } - - mu.Lock() - defer mu.Unlock() - if !permissionDenied { - t.Error("Expected a tool.execution_complete event with Permission denied result") + if session2.SessionID != sessionID { + t.Errorf("Expected session ID %s, got %s", sessionID, session2.SessionID) } + session2.Disconnect() }) t.Run("should work with approve-all permission handler", func(t *testing.T) { diff --git a/go/internal/e2e/session_config_e2e_test.go b/go/internal/e2e/session_config_e2e_test.go index de9dad9e2..b46b19904 100644 --- a/go/internal/e2e/session_config_e2e_test.go +++ b/go/internal/e2e/session_config_e2e_test.go @@ -180,7 +180,10 @@ func TestSessionConfigExtrasE2E(t *testing.T) { const clientName = "go-public-surface-client" ctx := testharness.NewTestContext(t) - client := ctx.NewClient() + client := ctx.NewClient(func(opts *copilot.ClientOptions) { + opts.UseStdio = copilot.Bool(false) + opts.TCPConnectionToken = sharedTcpToken + }) t.Cleanup(func() { client.ForceStop() }) if err := client.Start(t.Context()); err != nil { @@ -290,8 +293,10 @@ func TestSessionConfigExtrasE2E(t *testing.T) { sessionID := session1.SessionID t.Cleanup(func() { _ = session1.Disconnect() }) - session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, Model: "claude-sonnet-4.5", Provider: createProxyProvider(ctx, providerHeaderName, "resume-provider-header"), }) @@ -452,8 +457,10 @@ func TestSessionConfigExtrasE2E(t *testing.T) { sessionID := session1.SessionID t.Cleanup(func() { _ = session1.Disconnect() }) - session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, WorkingDirectory: subDir, }) if err != nil { @@ -485,8 +492,10 @@ func TestSessionConfigExtrasE2E(t *testing.T) { t.Cleanup(func() { _ = session1.Disconnect() }) const resumeInstruction = "End the response with RESUME_SYSTEM_MESSAGE_SENTINEL." - session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, SystemMessage: &copilot.SystemMessageConfig{ Mode: "append", Content: resumeInstruction, @@ -587,8 +596,10 @@ func TestSessionConfigExtrasE2E(t *testing.T) { } t.Cleanup(func() { _ = session1.Disconnect() }) - session2, err := client.ResumeSession(t.Context(), session1.SessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSession(t.Context(), session1.SessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, WorkingDirectory: projectDir, InstructionDirectories: []string{instructionDir}, }) @@ -626,8 +637,10 @@ func TestSessionConfigExtrasE2E(t *testing.T) { sessionID := session1.SessionID t.Cleanup(func() { _ = session1.Disconnect() }) - session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, AvailableTools: []string{"view"}, }) if err != nil { diff --git a/go/internal/e2e/session_e2e_test.go b/go/internal/e2e/session_e2e_test.go index f0d249422..5c7894ee5 100644 --- a/go/internal/e2e/session_e2e_test.go +++ b/go/internal/e2e/session_e2e_test.go @@ -17,7 +17,10 @@ import ( func TestSessionE2E(t *testing.T) { ctx := testharness.NewTestContext(t) - client := ctx.NewClient() + client := ctx.NewClient(func(opts *copilot.ClientOptions) { + opts.UseStdio = copilot.Bool(false) + opts.TCPConnectionToken = sharedTcpToken + }) t.Cleanup(func() { client.ForceStop() }) t.Run("should create and disconnect sessions", func(t *testing.T) { @@ -56,8 +59,8 @@ func TestSessionE2E(t *testing.T) { } _, err = session.GetMessages(t.Context()) - if err == nil || !strings.Contains(err.Error(), "not found") { - t.Errorf("Expected GetMessages to fail with 'not found' after disconnect, got %v", err) + if err == nil || !strings.Contains(err.Error(), "disconnected") { + t.Errorf("Expected GetMessages to fail with 'disconnected' after disconnect, got %v", err) } }) @@ -428,7 +431,7 @@ func TestSessionE2E(t *testing.T) { t.Skip("Known race condition - see TypeScript test") }) - t.Run("should resume a session using the same client", func(t *testing.T) { + t.Run("should reject resuming an active session using the same client", func(t *testing.T) { ctx.ConfigureForTest(t) // Create initial session @@ -438,50 +441,12 @@ func TestSessionE2E(t *testing.T) { } sessionID := session1.SessionID - _, err = session1.Send(t.Context(), copilot.MessageOptions{Prompt: "What is 1+1?"}) - if err != nil { - t.Fatalf("Failed to send message: %v", err) - } - - answer, err := testharness.GetFinalAssistantMessage(t.Context(), session1) - if err != nil { - t.Fatalf("Failed to get assistant message: %v", err) - } - - if ad, ok := answer.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(ad.Content, "2") { - t.Errorf("Expected answer to contain '2', got %v", answer.Data) - } - - // Resume using the same client - session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + // The same client already owns an active Session object for this ID. + _, err = client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, }) - if err != nil { - t.Fatalf("Failed to resume session: %v", err) - } - - if session2.SessionID != sessionID { - t.Errorf("Expected resumed session ID to match, got %q vs %q", session2.SessionID, sessionID) - } - - answer2, err := testharness.GetFinalAssistantMessage(t.Context(), session2, true) - if err != nil { - t.Fatalf("Failed to get assistant message from resumed session: %v", err) - } - - if ad, ok := answer2.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(ad.Content, "2") { - t.Errorf("Expected resumed session answer to contain '2', got %v", answer2.Data) - } - - // Can continue the conversation statefully - answer3, err := session2.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "Now if you double that, what do you get?"}) - if err != nil { - t.Fatalf("Failed to send follow-up message: %v", err) - } - if answer3 == nil { - t.Errorf("Expected follow-up answer to contain '4', got nil") - } else if ad, ok := answer3.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(ad.Content, "4") { - t.Errorf("Expected follow-up answer to contain '4', got %v", answer3) + if err == nil || !strings.Contains(err.Error(), "already active") { + t.Fatalf("Expected active duplicate resume to fail, got %v", err) } }) @@ -581,8 +546,10 @@ func TestSessionE2E(t *testing.T) { sessionID := session.SessionID // Resume the session with a provider - session2, err := client.ResumeSessionWithOptions(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + resumeClient := newResumeClient(t, client) + session2, err := resumeClient.ResumeSessionWithOptions(t.Context(), sessionID, &copilot.ResumeSessionConfig{ OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + DisableResume: true, Provider: &copilot.ProviderConfig{ Type: "openai", BaseURL: "https://api.openai.com/v1", @@ -1066,6 +1033,16 @@ func getSystemMessage(exchange testharness.ParsedHttpExchange) string { return "" } +func newResumeClient(t *testing.T, server *copilot.Client) *copilot.Client { + t.Helper() + client := copilot.NewClient(&copilot.ClientOptions{ + CLIUrl: serverCliURL(t, server), + TCPConnectionToken: sharedTcpToken, + }) + t.Cleanup(func() { client.ForceStop() }) + return client +} + func TestSetModelWithReasoningEffortE2E(t *testing.T) { ctx := testharness.NewTestContext(t) client := ctx.NewClient() diff --git a/go/rpc/generated_rpc_api_shape_test.go b/go/rpc/generated_rpc_api_shape_test.go index bddbb263d..dbb86e07e 100644 --- a/go/rpc/generated_rpc_api_shape_test.go +++ b/go/rpc/generated_rpc_api_shape_test.go @@ -2,6 +2,8 @@ package rpc import ( "bytes" + "context" + "errors" "go/ast" "go/format" "go/parser" @@ -46,6 +48,22 @@ func TestGeneratedRPCAPIShape(t *testing.T) { assertStructFieldType(t, file, fileSet, "UIElicitationResponse", "Content", "map[string]UIElicitationFieldValue") } +func TestGeneratedSessionRPCRejectsMissingRequiredParams(t *testing.T) { + _, err := NewSessionRpc(nil, "session-1").Commands.Invoke(context.Background(), nil) + if err == nil || err.Error() != "params is required" { + t.Fatalf("expected params required error, got %v", err) + } +} + +func TestGeneratedSessionRPCRunsActiveCheckBeforeRequest(t *testing.T) { + inactive := errors.New("session inactive") + _, err := NewSessionRpc(nil, "session-1", func() error { return inactive }). + Commands.Invoke(context.Background(), &CommandsInvokeRequest{Name: "help"}) + if !errors.Is(err, inactive) { + t.Fatalf("expected active-check error, got %v", err) + } +} + func parseGeneratedRPC(t *testing.T) (*ast.File, *token.FileSet) { t.Helper() _, currentFile, _, ok := runtime.Caller(0) diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index 6e607f9ca..4b283f1d3 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -5990,6 +5990,9 @@ type ServerMcpConfigApi serverApi // // Parameters: MCP server name and configuration to add to user configuration. func (a *ServerMcpConfigApi) Add(ctx context.Context, params *McpConfigAddRequest) (*McpConfigAddResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("mcp.config.add", params) if err != nil { return nil, err @@ -6007,6 +6010,9 @@ func (a *ServerMcpConfigApi) Add(ctx context.Context, params *McpConfigAddReques // // Parameters: MCP server names to disable for new sessions. func (a *ServerMcpConfigApi) Disable(ctx context.Context, params *McpConfigDisableRequest) (*McpConfigDisableResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("mcp.config.disable", params) if err != nil { return nil, err @@ -6024,6 +6030,9 @@ func (a *ServerMcpConfigApi) Disable(ctx context.Context, params *McpConfigDisab // // Parameters: MCP server names to enable for new sessions. func (a *ServerMcpConfigApi) Enable(ctx context.Context, params *McpConfigEnableRequest) (*McpConfigEnableResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("mcp.config.enable", params) if err != nil { return nil, err @@ -6058,6 +6067,9 @@ func (a *ServerMcpConfigApi) List(ctx context.Context) (*McpConfigList, error) { // // Parameters: MCP server name to remove from user configuration. func (a *ServerMcpConfigApi) Remove(ctx context.Context, params *McpConfigRemoveRequest) (*McpConfigRemoveResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("mcp.config.remove", params) if err != nil { return nil, err @@ -6075,6 +6087,9 @@ func (a *ServerMcpConfigApi) Remove(ctx context.Context, params *McpConfigRemove // // Parameters: MCP server name and replacement configuration to write to user configuration. func (a *ServerMcpConfigApi) Update(ctx context.Context, params *McpConfigUpdateRequest) (*McpConfigUpdateResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("mcp.config.update", params) if err != nil { return nil, err @@ -6125,6 +6140,9 @@ type ServerSessionFsApi serverApi // Returns: Indicates whether the calling client was registered as the session filesystem // provider. func (a *ServerSessionFsApi) SetProvider(ctx context.Context, params *SessionFsSetProviderRequest) (*SessionFsSetProviderResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessionFs.setProvider", params) if err != nil { return nil, err @@ -6556,6 +6574,9 @@ type ServerSkillsConfigApi serverApi // Parameters: Skill names to mark as disabled in global configuration, replacing any // previous list. func (a *ServerSkillsConfigApi) SetDisabledSkills(ctx context.Context, params *SkillsConfigSetDisabledSkillsRequest) (*SkillsConfigSetDisabledSkillsResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("skills.config.setDisabledSkills", params) if err != nil { return nil, err @@ -6682,8 +6703,9 @@ func NewInternalServerRpc(client *jsonrpc2.Client) *InternalServerRpc { } type sessionApi struct { - client *jsonrpc2.Client - sessionID string + client *jsonrpc2.Client + sessionID string + assertActive func() error } // Experimental: AgentApi contains experimental APIs that may change or be removed. @@ -6693,6 +6715,11 @@ type AgentApi sessionApi // // RPC method: session.agent.deselect. func (a *AgentApi) Deselect(ctx context.Context) (*SessionAgentDeselectResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.agent.deselect", req) if err != nil { @@ -6711,6 +6738,11 @@ func (a *AgentApi) Deselect(ctx context.Context) (*SessionAgentDeselectResult, e // // Returns: The currently selected custom agent, or null when using the default agent. func (a *AgentApi) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.agent.getCurrent", req) if err != nil { @@ -6729,6 +6761,11 @@ func (a *AgentApi) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, erro // // Returns: Custom agents available to the session. func (a *AgentApi) List(ctx context.Context) (*AgentList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.agent.list", req) if err != nil { @@ -6747,6 +6784,11 @@ func (a *AgentApi) List(ctx context.Context) (*AgentList, error) { // // Returns: Custom agents available to the session after reloading definitions from disk. func (a *AgentApi) Reload(ctx context.Context) (*AgentReloadResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.agent.reload", req) if err != nil { @@ -6767,6 +6809,14 @@ func (a *AgentApi) Reload(ctx context.Context) (*AgentReloadResult, error) { // // Returns: The newly selected custom agent. func (a *AgentApi) Select(ctx context.Context, params *AgentSelectRequest) (*AgentSelectResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["name"] = params.Name @@ -6790,6 +6840,11 @@ type AuthApi sessionApi // // Returns: Authentication status and account metadata for the session. func (a *AuthApi) GetStatus(ctx context.Context) (*SessionAuthStatus, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.auth.getStatus", req) if err != nil { @@ -6886,6 +6941,14 @@ func (a *CommandsApi) Execute(ctx context.Context, params *ExecuteCommandParams) // // Returns: Indicates whether the pending client-handled command was completed successfully. func (a *CommandsApi) HandlePendingCommand(ctx context.Context, params *CommandsHandlePendingCommandRequest) (*CommandsHandlePendingCommandResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Error != nil { @@ -6913,6 +6976,14 @@ func (a *CommandsApi) HandlePendingCommand(ctx context.Context, params *Commands // Returns: Result of invoking the slash command (text output, prompt to send to the agent, // or completion). func (a *CommandsApi) Invoke(ctx context.Context, params *CommandsInvokeRequest) (SlashCommandInvocationResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Input != nil { @@ -6944,6 +7015,11 @@ func (a *CommandsApi) List(ctx context.Context, params ...*CommandsListRequest) if len(params) > 0 { requestParams = params[0] } + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if requestParams != nil { if requestParams.IncludeBuiltins != nil { @@ -6977,6 +7053,14 @@ func (a *CommandsApi) List(ctx context.Context, params ...*CommandsListRequest) // // Returns: Indicates whether the queued-command response was matched to a pending request. func (a *CommandsApi) RespondToQueuedCommand(ctx context.Context, params *CommandsRespondToQueuedCommandRequest) (*CommandsRespondToQueuedCommandResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -7111,6 +7195,14 @@ type ExtensionsApi sessionApi // // Parameters: Source-qualified extension identifier to disable for the session. func (a *ExtensionsApi) Disable(ctx context.Context, params *ExtensionsDisableRequest) (*SessionExtensionsDisableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -7132,6 +7224,14 @@ func (a *ExtensionsApi) Disable(ctx context.Context, params *ExtensionsDisableRe // // Parameters: Source-qualified extension identifier to enable for the session. func (a *ExtensionsApi) Enable(ctx context.Context, params *ExtensionsEnableRequest) (*SessionExtensionsEnableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -7153,6 +7253,11 @@ func (a *ExtensionsApi) Enable(ctx context.Context, params *ExtensionsEnableRequ // // Returns: Extensions discovered for the session, with their current status. func (a *ExtensionsApi) List(ctx context.Context) (*ExtensionList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.extensions.list", req) if err != nil { @@ -7169,6 +7274,11 @@ func (a *ExtensionsApi) List(ctx context.Context) (*ExtensionList, error) { // // RPC method: session.extensions.reload. func (a *ExtensionsApi) Reload(ctx context.Context) (*SessionExtensionsReloadResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.extensions.reload", req) if err != nil { @@ -7192,6 +7302,11 @@ type FleetApi sessionApi // // Returns: Indicates whether fleet mode was successfully activated. func (a *FleetApi) Start(ctx context.Context, params *FleetStartRequest) (*FleetStartResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Prompt != nil { @@ -7256,6 +7371,11 @@ func (a *HistoryApi) CancelBackgroundCompaction(ctx context.Context) (*HistoryCa // Returns: Compaction outcome with the number of tokens and messages removed, summary text, // and the resulting context window breakdown. func (a *HistoryApi) Compact(ctx context.Context) (*HistoryCompactResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.history.compact", req) if err != nil { @@ -7296,6 +7416,14 @@ func (a *HistoryApi) SummarizeForHandoff(ctx context.Context) (*HistorySummarize // // Returns: Number of events that were removed by the truncation. func (a *HistoryApi) Truncate(ctx context.Context, params *HistoryTruncateRequest) (*HistoryTruncateResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["eventId"] = params.EventID @@ -7319,6 +7447,11 @@ type InstructionsApi sessionApi // // Returns: Instruction sources loaded for the session, in merge order. func (a *InstructionsApi) GetSources(ctx context.Context) (*InstructionsGetSourcesResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.instructions.getSources", req) if err != nil { @@ -7396,6 +7529,14 @@ func (a *McpApi) CancelSamplingExecution(ctx context.Context, params *McpCancelS // // Parameters: Name of the MCP server to disable for the session. func (a *McpApi) Disable(ctx context.Context, params *McpDisableRequest) (*SessionMcpDisableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["serverName"] = params.ServerName @@ -7417,6 +7558,14 @@ func (a *McpApi) Disable(ctx context.Context, params *McpDisableRequest) (*Sessi // // Parameters: Name of the MCP server to enable for the session. func (a *McpApi) Enable(ctx context.Context, params *McpEnableRequest) (*SessionMcpEnableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["serverName"] = params.ServerName @@ -7466,6 +7615,11 @@ func (a *McpApi) ExecuteSampling(ctx context.Context, params *McpExecuteSampling // // Returns: MCP servers configured for the session, with their connection status. func (a *McpApi) List(ctx context.Context) (*McpServerList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.mcp.list", req) if err != nil { @@ -7482,6 +7636,11 @@ func (a *McpApi) List(ctx context.Context) (*McpServerList, error) { // // RPC method: session.mcp.reload. func (a *McpApi) Reload(ctx context.Context) (*SessionMcpReloadResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.mcp.reload", req) if err != nil { @@ -7551,6 +7710,14 @@ type McpOauthApi sessionApi // Returns: OAuth authorization URL the caller should open, or empty when cached tokens // already authenticated the server. func (a *McpOauthApi) Login(ctx context.Context, params *McpOauthLoginRequest) (*McpOauthLoginResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.CallbackSuccessMessage != nil { @@ -7739,6 +7906,11 @@ type ModeApi sessionApi // // Returns: The session mode the agent is operating in func (a *ModeApi) Get(ctx context.Context) (*SessionMode, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.mode.get", req) if err != nil { @@ -7757,6 +7929,14 @@ func (a *ModeApi) Get(ctx context.Context) (*SessionMode, error) { // // Parameters: Agent interaction mode to apply to the session. func (a *ModeApi) Set(ctx context.Context, params *ModeSetRequest) (*SessionModeSetResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["mode"] = params.Mode @@ -7780,6 +7960,11 @@ type ModelApi sessionApi // // Returns: The currently selected model and reasoning effort for the session. func (a *ModelApi) GetCurrent(ctx context.Context) (*CurrentModel, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.model.getCurrent", req) if err != nil { @@ -7827,6 +8012,14 @@ func (a *ModelApi) SetReasoningEffort(ctx context.Context, params *ModelSetReaso // // Returns: The model identifier active on the session after the switch. func (a *ModelApi) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (*ModelSwitchToResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.ModelCapabilities != nil { @@ -7859,6 +8052,11 @@ type NameApi sessionApi // // Returns: The session's friendly name, or null when not yet set. func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.name.get", req) if err != nil { @@ -7877,6 +8075,14 @@ func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) { // // Parameters: New friendly name to apply to the session. func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*SessionNameSetResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["name"] = params.Name @@ -8104,6 +8310,14 @@ func (a *PermissionsApi) Configure(ctx context.Context, params *PermissionsConfi // Returns: Indicates whether the permission decision was applied; false when the request // was already resolved. func (a *PermissionsApi) HandlePendingPermissionRequest(ctx context.Context, params *PermissionDecisionRequest) (*PermissionRequestResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -8203,6 +8417,11 @@ func (a *PermissionsApi) PendingRequests(ctx context.Context) (*PendingPermissio // // Returns: Indicates whether the operation succeeded. func (a *PermissionsApi) ResetSessionApprovals(ctx context.Context) (*PermissionsResetSessionApprovalsResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.permissions.resetSessionApprovals", req) if err != nil { @@ -8225,6 +8444,14 @@ func (a *PermissionsApi) ResetSessionApprovals(ctx context.Context) (*Permission // // Returns: Indicates whether the operation succeeded. func (a *PermissionsApi) SetApproveAll(ctx context.Context, params *PermissionsSetApproveAllRequest) (*PermissionsSetApproveAllResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["enabled"] = params.Enabled @@ -8422,6 +8649,11 @@ type PlanApi sessionApi // // RPC method: session.plan.delete. func (a *PlanApi) Delete(ctx context.Context) (*SessionPlanDeleteResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.plan.delete", req) if err != nil { @@ -8440,6 +8672,11 @@ func (a *PlanApi) Delete(ctx context.Context) (*SessionPlanDeleteResult, error) // // Returns: Existence, contents, and resolved path of the session plan file. func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.plan.read", req) if err != nil { @@ -8458,6 +8695,14 @@ func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) { // // Parameters: Replacement contents to write to the session plan file. func (a *PlanApi) Update(ctx context.Context, params *PlanUpdateRequest) (*SessionPlanUpdateResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["content"] = params.Content @@ -8482,6 +8727,11 @@ type PluginsApi sessionApi // // Returns: Plugins installed for the session, with their enabled state and version metadata. func (a *PluginsApi) List(ctx context.Context) (*PluginList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.plugins.list", req) if err != nil { @@ -8557,6 +8807,11 @@ type RemoteApi sessionApi // // RPC method: session.remote.disable. func (a *RemoteApi) Disable(ctx context.Context) (*SessionRemoteDisableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.remote.disable", req) if err != nil { @@ -8579,6 +8834,11 @@ func (a *RemoteApi) Disable(ctx context.Context) (*SessionRemoteDisableResult, e // Returns: GitHub URL for the session and a flag indicating whether remote steering is // enabled. func (a *RemoteApi) Enable(ctx context.Context, params *RemoteEnableRequest) (*RemoteEnableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Mode != nil { @@ -8680,6 +8940,14 @@ type ShellApi sessionApi // Returns: Identifier of the spawned process, used to correlate streamed output and exit // notifications. func (a *ShellApi) Exec(ctx context.Context, params *ShellExecRequest) (*ShellExecResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["command"] = params.Command @@ -8711,6 +8979,14 @@ func (a *ShellApi) Exec(ctx context.Context, params *ShellExecRequest) (*ShellEx // Returns: Indicates whether the signal was delivered; false if the process was unknown or // already exited. func (a *ShellApi) Kill(ctx context.Context, params *ShellKillRequest) (*ShellKillResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["processId"] = params.ProcessID @@ -8738,6 +9014,14 @@ type SkillsApi sessionApi // // Parameters: Name of the skill to disable for the session. func (a *SkillsApi) Disable(ctx context.Context, params *SkillsDisableRequest) (*SessionSkillsDisableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["name"] = params.Name @@ -8759,6 +9043,14 @@ func (a *SkillsApi) Disable(ctx context.Context, params *SkillsDisableRequest) ( // // Parameters: Name of the skill to enable for the session. func (a *SkillsApi) Enable(ctx context.Context, params *SkillsEnableRequest) (*SessionSkillsEnableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["name"] = params.Name @@ -8815,6 +9107,11 @@ func (a *SkillsApi) GetInvoked(ctx context.Context) (*SkillsGetInvokedResult, er // // Returns: Skills available to the session, with their enabled state. func (a *SkillsApi) List(ctx context.Context) (*SkillList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.skills.list", req) if err != nil { @@ -8834,6 +9131,11 @@ func (a *SkillsApi) List(ctx context.Context) (*SkillList, error) { // Returns: Diagnostics from reloading skill definitions, with warnings and errors as // separate lists. func (a *SkillsApi) Reload(ctx context.Context) (*SkillsLoadDiagnostics, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.skills.reload", req) if err != nil { @@ -8857,6 +9159,14 @@ type TasksApi sessionApi // // Returns: Indicates whether the background task was successfully cancelled. func (a *TasksApi) Cancel(ctx context.Context, params *TasksCancelRequest) (*TasksCancelResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -8920,6 +9230,11 @@ func (a *TasksApi) GetProgress(ctx context.Context, params *TasksGetProgressRequ // // Returns: Background tasks currently tracked by the session. func (a *TasksApi) List(ctx context.Context) (*TaskList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.tasks.list", req) if err != nil { @@ -8961,6 +9276,14 @@ func (a *TasksApi) PromoteCurrentToBackground(ctx context.Context) (*TasksPromot // // Returns: Indicates whether the task was successfully promoted to background mode. func (a *TasksApi) PromoteToBackground(ctx context.Context, params *TasksPromoteToBackgroundRequest) (*TasksPromoteToBackgroundResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -9004,6 +9327,14 @@ func (a *TasksApi) Refresh(ctx context.Context) (*TasksRefreshResult, error) { // Returns: Indicates whether the task was removed. False when the task does not exist or is // still running/idle. func (a *TasksApi) Remove(ctx context.Context, params *TasksRemoveRequest) (*TasksRemoveResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -9029,6 +9360,14 @@ func (a *TasksApi) Remove(ctx context.Context, params *TasksRemoveRequest) (*Tas // Returns: Indicates whether the message was delivered, with an error message when delivery // failed. func (a *TasksApi) SendMessage(ctx context.Context, params *TasksSendMessageRequest) (*TasksSendMessageResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.FromAgentID != nil { @@ -9057,6 +9396,14 @@ func (a *TasksApi) SendMessage(ctx context.Context, params *TasksSendMessageRequ // // Returns: Identifier assigned to the newly started background agent task. func (a *TasksApi) StartAgent(ctx context.Context, params *TasksStartAgentRequest) (*TasksStartAgentResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["agentType"] = params.AgentType @@ -9138,6 +9485,14 @@ type ToolsApi sessionApi // // Returns: Indicates whether the external tool call result was handled successfully. func (a *ToolsApi) HandlePendingToolCall(ctx context.Context, params *HandlePendingToolCallRequest) (*HandlePendingToolCallResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Error != nil { @@ -9192,6 +9547,14 @@ type UIApi sessionApi // // Returns: The elicitation response (accept with form values, decline, or cancel) func (a *UIApi) Elicitation(ctx context.Context, params *UIElicitationRequest) (*UIElicitationResponse, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["message"] = params.Message @@ -9244,6 +9607,14 @@ func (a *UIApi) HandlePendingAutoModeSwitch(ctx context.Context, params *UIHandl // Returns: Indicates whether the elicitation response was accepted; false if it was already // resolved by another client. func (a *UIApi) HandlePendingElicitation(ctx context.Context, params *UIHandlePendingElicitationRequest) (*UIElicitationResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -9397,6 +9768,11 @@ type UsageApi sessionApi // Returns: Accumulated session usage metrics, including premium request cost, token counts, // model breakdown, and code-change totals. func (a *UsageApi) GetMetrics(ctx context.Context) (*UsageGetMetricsResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.usage.getMetrics", req) if err != nil { @@ -9417,6 +9793,14 @@ type WorkspacesApi sessionApi // // Parameters: Relative path and UTF-8 content for the workspace file to create or overwrite. func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreateFileRequest) (*SessionWorkspacesCreateFileResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["content"] = params.Content @@ -9440,6 +9824,11 @@ func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreate // Returns: Current workspace metadata for the session, including its absolute filesystem // path when available. func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspaceResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.workspaces.getWorkspace", req) if err != nil { @@ -9477,6 +9866,11 @@ func (a *WorkspacesApi) ListCheckpoints(ctx context.Context) (*WorkspacesListChe // // Returns: Relative paths of files stored in the session workspace files directory. func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.workspaces.listFiles", req) if err != nil { @@ -9521,6 +9915,14 @@ func (a *WorkspacesApi) ReadCheckpoint(ctx context.Context, params *WorkspacesRe // // Returns: Contents of the requested workspace file as a UTF-8 string. func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFileRequest) (*WorkspacesReadFileResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path @@ -9629,6 +10031,14 @@ func (a *SessionRpc) Abort(ctx context.Context, params *AbortRequest) (*AbortRes // // Returns: Identifier of the session event that was emitted for the log message. func (a *SessionRpc) Log(ctx context.Context, params *LogRequest) (*LogResult, error) { + if a.common.assertActive != nil { + if err := a.common.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.common.sessionID} if params != nil { if params.Ephemeral != nil { @@ -9750,6 +10160,11 @@ func (a *SessionRpc) Shutdown(ctx context.Context, params *ShutdownRequest) (*Se // // RPC method: session.suspend. func (a *SessionRpc) Suspend(ctx context.Context) (*SessionSuspendResult, error) { + if a.common.assertActive != nil { + if err := a.common.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.common.sessionID} raw, err := a.common.client.Request("session.suspend", req) if err != nil { @@ -9762,9 +10177,13 @@ func (a *SessionRpc) Suspend(ctx context.Context) (*SessionSuspendResult, error) return &result, nil } -func NewSessionRpc(client *jsonrpc2.Client, sessionID string) *SessionRpc { +func NewSessionRpc(client *jsonrpc2.Client, sessionID string, assertActive ...func() error) *SessionRpc { r := &SessionRpc{} - r.common = sessionApi{client: client, sessionID: sessionID} + var assertActiveFn func() error + if len(assertActive) > 0 { + assertActiveFn = assertActive[0] + } + r.common = sessionApi{client: client, sessionID: sessionID, assertActive: assertActiveFn} r.Agent = (*AgentApi)(&r.common) r.Auth = (*AuthApi)(&r.common) r.Commands = (*CommandsApi)(&r.common) diff --git a/go/session.go b/go/session.go index bc7e2ede9..682fc55f5 100644 --- a/go/session.go +++ b/go/session.go @@ -53,6 +53,7 @@ type Session struct { SessionID string workspacePath string client *jsonrpc2.Client + owner *Client clientSessionApis *rpc.ClientSessionApiHandlers handlers []sessionHandler nextHandlerID uint64 @@ -82,6 +83,10 @@ type Session struct { // a single goroutine (processEvents) dequeues and invokes handlers in FIFO order. eventCh chan SessionEvent closeOnce sync.Once // guards eventCh close so Disconnect is safe to call more than once + stateMu sync.Mutex + closed bool + closing chan struct{} + closeErr error // RPC provides typed session-scoped RPC methods. RPC *rpc.SessionRpc @@ -95,22 +100,32 @@ func (s *Session) WorkspacePath() string { } // newSession creates a new session wrapper with the given session ID and client. -func newSession(sessionID string, client *jsonrpc2.Client, workspacePath string) *Session { +func newSession(sessionID string, client *jsonrpc2.Client, workspacePath string, owner *Client) *Session { s := &Session{ SessionID: sessionID, workspacePath: workspacePath, client: client, + owner: owner, clientSessionApis: &rpc.ClientSessionApiHandlers{}, handlers: make([]sessionHandler, 0), toolHandlers: make(map[string]ToolHandler), commandHandlers: make(map[string]CommandHandler), eventCh: make(chan SessionEvent, 128), - RPC: rpc.NewSessionRpc(client, sessionID), } + s.RPC = rpc.NewSessionRpc(client, sessionID, s.assertActive) go s.processEvents() return s } +func (s *Session) assertActive() error { + s.stateMu.Lock() + defer s.stateMu.Unlock() + if s.closed { + return fmt.Errorf("session has been disconnected") + } + return nil +} + // Send sends a message to this session and waits for the response. // // The message is processed asynchronously. Subscribe to events via [Session.On] @@ -134,6 +149,9 @@ func newSession(sessionID string, client *jsonrpc2.Client, workspacePath string) // log.Printf("Failed to send message: %v", err) // } func (s *Session) Send(ctx context.Context, options MessageOptions) (string, error) { + if err := s.assertActive(); err != nil { + return "", err + } traceparent, tracestate := getTraceContext(ctx) req := sessionSendRequest{ SessionID: s.SessionID, @@ -187,6 +205,9 @@ func (s *Session) Send(ctx context.Context, options MessageOptions) (string, err // } // } func (s *Session) SendAndWait(ctx context.Context, options MessageOptions) (*SessionEvent, error) { + if err := s.assertActive(); err != nil { + return nil, err + } if _, ok := ctx.Deadline(); !ok { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, 60*time.Second) @@ -752,6 +773,9 @@ func (s *Session) UI() *SessionUI { // assertElicitation checks that the host supports elicitation and returns an error if not. func (s *Session) assertElicitation() error { + if err := s.assertActive(); err != nil { + return err + } caps := s.Capabilities() if caps.UI == nil || !caps.UI.Elicitation { return fmt.Errorf("elicitation is not supported by the host; check session.Capabilities().UI.Elicitation before calling UI methods") @@ -1168,6 +1192,9 @@ func rpcPermissionDecisionFromKind(kind rpc.PermissionDecisionKind) rpc.Permissi // } // } func (s *Session) GetMessages(ctx context.Context) ([]SessionEvent, error) { + if err := s.assertActive(); err != nil { + return nil, err + } result, err := s.client.Request("session.getMessages", sessionGetMessagesRequest{SessionID: s.SessionID}) if err != nil { @@ -1204,14 +1231,50 @@ func (s *Session) GetMessages(ctx context.Context) ([]SessionEvent, error) { // log.Printf("Failed to disconnect session: %v", err) // } func (s *Session) Disconnect() error { + s.stateMu.Lock() + if s.closed { + s.stateMu.Unlock() + return nil + } + if s.closing != nil { + closing := s.closing + s.stateMu.Unlock() + <-closing + return s.closeErr + } + s.closing = make(chan struct{}) + closing := s.closing + s.stateMu.Unlock() + + err := s.disconnectCore() + + s.stateMu.Lock() + s.closeErr = err + close(closing) + s.stateMu.Unlock() + return err +} + +func (s *Session) disconnectCore() error { + defer s.markDisconnected() _, err := s.client.Request("session.destroy", sessionDestroyRequest{SessionID: s.SessionID}) if err != nil { return fmt.Errorf("failed to disconnect session: %w", err) } + return nil +} + +func (s *Session) markDisconnected() { + s.stateMu.Lock() + if s.closed { + s.stateMu.Unlock() + return + } + s.closed = true + s.stateMu.Unlock() s.closeOnce.Do(func() { close(s.eventCh) }) - // Clear handlers s.handlerMutex.Lock() s.handlers = nil s.handlerMutex.Unlock() @@ -1232,7 +1295,29 @@ func (s *Session) Disconnect() error { s.elicitationHandler = nil s.elicitationMu.Unlock() - return nil + s.userInputMux.Lock() + s.userInputHandler = nil + s.userInputMux.Unlock() + + s.exitPlanModeMu.Lock() + s.exitPlanModeHandler = nil + s.exitPlanModeMu.Unlock() + + s.autoModeSwitchMu.Lock() + s.autoModeSwitchHandler = nil + s.autoModeSwitchMu.Unlock() + + s.hooksMux.Lock() + s.hooks = nil + s.hooksMux.Unlock() + + s.transformMu.Lock() + s.transformCallbacks = nil + s.transformMu.Unlock() + + if s.owner != nil { + s.owner.unregisterSession(s) + } } // Deprecated: Use [Session.Disconnect] instead. Destroy will be removed in a future release. @@ -1265,6 +1350,9 @@ func (s *Session) Destroy() error { // log.Printf("Failed to abort: %v", err) // } func (s *Session) Abort(ctx context.Context) error { + if err := s.assertActive(); err != nil { + return err + } _, err := s.client.Request("session.abort", sessionAbortRequest{SessionID: s.SessionID}) if err != nil { return fmt.Errorf("failed to abort session: %w", err) @@ -1294,6 +1382,9 @@ type SetModelOptions struct { // log.Printf("Failed to set model: %v", err) // } func (s *Session) SetModel(ctx context.Context, model string, opts *SetModelOptions) error { + if err := s.assertActive(); err != nil { + return err + } params := &rpc.ModelSwitchToRequest{ModelID: model} if opts != nil { params.ReasoningEffort = opts.ReasoningEffort @@ -1334,6 +1425,9 @@ type LogOptions struct { // // Ephemeral message (not persisted) // session.Log(ctx, "Working...", &copilot.LogOptions{Ephemeral: copilot.Bool(true)}) func (s *Session) Log(ctx context.Context, message string, opts *LogOptions) error { + if err := s.assertActive(); err != nil { + return err + } params := &rpc.LogRequest{Message: message} if opts != nil { diff --git a/go/session_test.go b/go/session_test.go index 0b7de5ac9..407e7e74c 100644 --- a/go/session_test.go +++ b/go/session_test.go @@ -46,6 +46,55 @@ func TestRPCPermissionDecisionFromKindPreservesUnknownKind(t *testing.T) { } } +func TestSessionLifecycleCleanup(t *testing.T) { + client := NewClient(nil) + session := newSession("session-1", nil, "", client) + + if err := client.registerSession(session); err != nil { + t.Fatalf("register session: %v", err) + } + + session.markDisconnected() + + if _, ok := client.sessions["session-1"]; ok { + t.Fatal("expected disconnected session to unregister from client") + } + if err := session.assertActive(); err == nil { + t.Fatal("expected disconnected session to reject further use") + } +} + +func TestSessionLifecycleCleanupDoesNotRemoveReplacement(t *testing.T) { + client := NewClient(nil) + stale := newSession("session-1", nil, "", client) + replacement := newSession("session-1", nil, "", client) + client.sessions["session-1"] = replacement + + stale.markDisconnected() + + if got := client.sessions["session-1"]; got != replacement { + t.Fatalf("expected replacement session to remain registered, got %#v", got) + } + + replacement.markDisconnected() +} + +func TestClientRegisterSessionRejectsDuplicateActiveSession(t *testing.T) { + client := NewClient(nil) + first := newSession("session-1", nil, "", client) + second := newSession("session-1", nil, "", client) + + if err := client.registerSession(first); err != nil { + t.Fatalf("register first session: %v", err) + } + if err := client.registerSession(second); err == nil || !strings.Contains(err.Error(), "already active") { + t.Fatalf("expected duplicate active session error, got %v", err) + } + + first.markDisconnected() + second.markDisconnected() +} + func TestSession_On(t *testing.T) { t.Run("multiple handlers all receive events", func(t *testing.T) { session, cleanup := newTestSession() diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 6342b6667..af77b1dfb 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -450,6 +450,20 @@ export class CopilotClient { } } + private registerSession(session: CopilotSession): void { + const existing = this.sessions.get(session.sessionId); + if (existing && existing !== session) { + throw new Error(`Session ${session.sessionId} is already active.`); + } + this.sessions.set(session.sessionId, session); + } + + private unregisterSession(session: CopilotSession): void { + if (this.sessions.get(session.sessionId) === session) { + this.sessions.delete(session.sessionId); + } + } + private setupSessionFs( session: CopilotSession, config: { createSessionFsHandler?: (session: CopilotSession) => SessionFsProvider } @@ -551,37 +565,25 @@ export class CopilotClient { async stop(): Promise { const errors: Error[] = []; - // Disconnect all active sessions with retry logic - for (const session of this.sessions.values()) { + // Disconnect a stable snapshot so per-session cleanup can mutate the map safely. + for (const session of [...this.sessions.values()]) { const sessionId = session.sessionId; - let lastError: Error | null = null; - - // Try up to 3 times with exponential backoff - for (let attempt = 1; attempt <= 3; attempt++) { - try { - await session.disconnect(); - lastError = null; - break; // Success - } catch (error) { - lastError = error instanceof Error ? error : new Error(String(error)); - - if (attempt < 3) { - // Exponential backoff: 100ms, 200ms - const delay = 100 * Math.pow(2, attempt - 1); - await new Promise((resolve) => setTimeout(resolve, delay)); - } - } - } - - if (lastError) { + try { + await session.disconnect(); + } catch (error) { + const disconnectError = error instanceof Error ? error : new Error(String(error)); errors.push( new Error( - `Failed to disconnect session ${sessionId} after 3 attempts: ${lastError.message}` + `Failed to disconnect session ${sessionId}: ${disconnectError.message}` ) ); } } + const remainingSessions = [...this.sessions.values()]; this.sessions.clear(); + for (const session of remainingSessions) { + session._markDisconnected(); + } // Close connection if (this.connection) { @@ -596,6 +598,7 @@ export class CopilotClient { } this.connection = null; this._rpc = null; + this._internalRpc = null; } // Clear models cache @@ -668,6 +671,10 @@ export class CopilotClient { async forceStop(): Promise { this.forceStopping = true; + for (const session of this.sessions.values()) { + session._markDisconnected(); + } + // Clear sessions immediately without trying to destroy them this.sessions.clear(); @@ -680,6 +687,7 @@ export class CopilotClient { } this.connection = null; this._rpc = null; + this._internalRpc = null; } // Clear models cache @@ -761,7 +769,8 @@ export class CopilotClient { sessionId, this.connection!, undefined, - this.onGetTraceContext + this.onGetTraceContext, + (session) => this.unregisterSession(session) ); session.registerTools(config.tools); session.registerCommands(config.commands); @@ -793,10 +802,10 @@ export class CopilotClient { if (config.onEvent) { session.on(config.onEvent); } - this.sessions.set(sessionId, session); - this.setupSessionFs(session, config); + this.registerSession(session); try { + this.setupSessionFs(session, config); const response = await this.connection!.sendRequest("session.create", { ...(await getTraceContext(this.onGetTraceContext)), model: config.model, @@ -853,7 +862,8 @@ export class CopilotClient { session["_workspacePath"] = workspacePath; session.setCapabilities(capabilities); } catch (e) { - this.sessions.delete(sessionId); + this.unregisterSession(session); + session._markDisconnected(); throw e; } @@ -899,7 +909,8 @@ export class CopilotClient { sessionId, this.connection!, undefined, - this.onGetTraceContext + this.onGetTraceContext, + (session) => this.unregisterSession(session) ); session.registerTools(config.tools); session.registerCommands(config.commands); @@ -931,10 +942,10 @@ export class CopilotClient { if (config.onEvent) { session.on(config.onEvent); } - this.sessions.set(sessionId, session); - this.setupSessionFs(session, config); + this.registerSession(session); try { + this.setupSessionFs(session, config); const response = await this.connection!.sendRequest("session.resume", { ...(await getTraceContext(this.onGetTraceContext)), sessionId, @@ -993,7 +1004,8 @@ export class CopilotClient { session["_workspacePath"] = workspacePath; session.setCapabilities(capabilities); } catch (e) { - this.sessions.delete(sessionId); + this.unregisterSession(session); + session._markDisconnected(); throw e; } @@ -1245,7 +1257,12 @@ export class CopilotClient { } // Remove from local sessions map if present - this.sessions.delete(sessionId); + const session = this.sessions.get(sessionId); + if (session) { + session._markDisconnected(); + } else { + this.sessions.delete(sessionId); + } } /** diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 20a4d6afe..32bda8a35 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -5,30 +5,8 @@ import type { MessageConnection } from "vscode-jsonrpc/node.js"; -import type { AbortReason, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, PermissionPromptRequest, PermissionRule, ReasoningSummary, SessionEvent, SessionMode, ShutdownType, SkillSource, UserToolSessionApproval } from "./session-events.js"; +import type { EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, ReasoningSummary, SessionMode, SkillSource } from "./session-events.js"; -/** - * Where the agent definition was loaded from - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "AgentInfoSource". - */ -/** @experimental */ -export type AgentInfoSource = "user" | "project" | "inherited" | "remote" | "plugin" | "builtin"; -/** - * The new auth credentials to install on the session. When omitted or `undefined`, the call is a no-op and the session's existing credentials are preserved. The runtime stores the value verbatim and uses it for outbound model/API requests; it does NOT re-validate or re-fetch the associated Copilot user response. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "AuthInfo". - */ -export type AuthInfo = - | HMACAuthInfo - | EnvAuthInfo - | TokenAuthInfo - | CopilotApiTokenAuthInfo - | UserAuthInfo - | GhCliAuthInfo - | ApiKeyAuthInfo; /** * Authentication type * @@ -51,7 +29,7 @@ export type SlashCommandKind = "builtin" | "skill" | "client"; */ export type SlashCommandInputCompletion = "directory"; /** - * Result of the queued command execution. + * Result of the queued command execution * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "QueuedCommandResult". @@ -79,30 +57,6 @@ export type ContentFilterMode = "none" | "markdown" | "hidden_characters"; * via the `definition` "DiscoveredMcpServerType". */ export type DiscoveredMcpServerType = "stdio" | "http" | "sse" | "memory"; -/** - * Either '*' to receive all event types, or a non-empty list of event types to receive - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventLogTypes". - */ -/** @experimental */ -export type EventLogTypes = "*" | [string, ...string[]]; -/** - * Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventsAgentScope". - */ -/** @experimental */ -export type EventsAgentScope = "primary" | "all"; -/** - * Cursor status: 'ok' means the cursor was applied successfully; 'expired' means the cursor referred to an event that no longer exists in history (e.g. truncated or compacted away) and the read started from the beginning of the remaining history. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventsCursorStatus". - */ -/** @experimental */ -export type EventsCursorStatus = "ok" | "expired"; /** * Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) * @@ -173,39 +127,20 @@ export type FilterMapping = [k: string]: ContentFilterMode; } | ContentFilterMode; -/** - * Source for direct repo installs (when marketplace is empty) - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstalledPluginSource". - */ -/** @experimental */ -export type InstalledPluginSource = - | string - | InstalledPluginSourceGithub - | InstalledPluginSourceUrl - | InstalledPluginSourceLocal; /** * Category of instruction source — used for merge logic * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "InstructionsSourcesType". */ -export type InstructionsSourcesType = - | "home" - | "repo" - | "model" - | "vscode" - | "nested-agents" - | "child-instructions" - | "plugin"; +export type InstructionsSourcesType = "home" | "repo" | "model" | "vscode" | "nested-agents" | "child-instructions"; /** * Where this source lives — used for UI grouping * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "InstructionsSourcesLocation". */ -export type InstructionsSourcesLocation = "user" | "repository" | "working-directory" | "plugin"; +export type InstructionsSourcesLocation = "user" | "repository" | "working-directory"; /** * Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". * @@ -234,91 +169,6 @@ export type McpServerConfigHttpType = "http" | "sse"; * via the `definition` "McpServerConfigHttpOauthGrantType". */ export type McpServerConfigHttpOauthGrantType = "authorization_code" | "client_credentials"; -/** - * Outcome of the sampling inference. 'success' produced a response; 'failure' encountered an error (including agent-side rejection by content filter or criteria); 'cancelled' the caller cancelled this execution via cancelSamplingExecution. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSamplingExecutionAction". - */ -/** @experimental */ -export type McpSamplingExecutionAction = "success" | "failure" | "cancelled"; -/** - * How environment-variable values supplied to MCP servers are resolved. "direct" passes literal string values; "indirect" treats values as references (e.g. names of environment variables on the host) that the runtime resolves before launch. Defaults to the runtime's startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI prompt mode and ACP) set this to "direct". - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSetEnvValueModeDetails". - */ -/** @experimental */ -export type McpSetEnvValueModeDetails = "direct" | "indirect"; -/** - * Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionContextInfo". - */ -/** @experimental */ -export type SessionContextInfo = { - /** - * The model used for token counting - */ - modelName: string; - /** - * Tokens consumed by the system prompt - */ - systemTokens: number; - /** - * Tokens consumed by user/assistant/tool messages - */ - conversationTokens: number; - /** - * Tokens consumed by tool definitions sent to the model (excludes deferred tools) - */ - toolDefinitionsTokens: number; - /** - * Sum of system, conversation and tool-definition tokens - */ - totalTokens: number; - /** - * Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified) - */ - promptTokenLimit: number; - /** - * Token count at which background compaction starts (configurable percentage of promptTokenLimit) - */ - compactionThreshold: number; - /** - * Total context limit for /context display. promptTokenLimit + min(32k or 64k, outputTokenLimit) depending on model. - */ - limit: number; - /** - * Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%) - */ - bufferTokens: number; -} | null; -/** - * Hosting platform type of the repository - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionWorkingDirectoryContextHostType". - */ -/** @experimental */ -export type SessionWorkingDirectoryContextHostType = "github" | "ado"; -/** - * The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot') - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSnapshotCurrentMode". - */ -/** @experimental */ -export type MetadataSnapshotCurrentMode = "interactive" | "plan" | "autopilot"; -/** - * Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSnapshotRemoteMetadataTaskType". - */ -/** @experimental */ -export type MetadataSnapshotRemoteMetadataTaskType = "cca" | "cli"; /** * Current policy state for this model * @@ -341,15 +191,7 @@ export type ModelPickerCategory = "lightweight" | "versatile" | "powerful"; */ export type ModelPickerPriceCategory = "low" | "medium" | "high" | "very_high"; /** - * How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "OptionsUpdateEnvValueMode". - */ -/** @experimental */ -export type OptionsUpdateEnvValueMode = "direct" | "indirect"; -/** - * The client's response to the pending permission prompt + * Decision to apply to a pending permission request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "PermissionDecision". @@ -360,18 +202,9 @@ export type PermissionDecision = | PermissionDecisionApproveForLocation | PermissionDecisionApprovePermanently | PermissionDecisionReject - | PermissionDecisionUserNotAvailable - | PermissionDecisionApproved - | PermissionDecisionApprovedForSession - | PermissionDecisionApprovedForLocation - | PermissionDecisionCancelled - | PermissionDecisionDeniedByRules - | PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser - | PermissionDecisionDeniedInteractivelyByUser - | PermissionDecisionDeniedByContentExclusionPolicy - | PermissionDecisionDeniedByPermissionRequestHook; + | PermissionDecisionUserNotAvailable; /** - * Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) + * The approval to add as a session-scoped rule * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "PermissionDecisionApproveForSessionApproval". @@ -387,7 +220,7 @@ export type PermissionDecisionApproveForSessionApproval = | PermissionDecisionApproveForSessionApprovalExtensionManagement | PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess; /** - * Approval to persist for this location + * The approval to persist for this location * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "PermissionDecisionApproveForLocationApproval". @@ -402,35 +235,6 @@ export type PermissionDecisionApproveForLocationApproval = | PermissionDecisionApproveForLocationApprovalCustomTool | PermissionDecisionApproveForLocationApprovalExtensionManagement | PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess; -/** - * Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyScope". - */ -export type PermissionsConfigureAdditionalContentExclusionPolicyScope = "repo" | "all"; -/** - * Whether the change applies to ephemeral session-scoped rules (cleared at session end) or to location-scoped rules persisted via the location-permissions config file. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsModifyRulesScope". - */ -export type PermissionsModifyRulesScope = "session" | "location"; -/** - * Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllSource". - */ -export type PermissionsSetApproveAllSource = "cli_flag" | "slash_command" | "autopilot_confirmation" | "rpc"; -/** - * Whether this item is a queued user message or a queued slash command / model change - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueuePendingItemsKind". - */ -/** @experimental */ -export type QueuePendingItemsKind = "message" | "command"; /** * Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. * @@ -439,47 +243,6 @@ export type QueuePendingItemsKind = "message" | "command"; */ /** @experimental */ export type RemoteSessionMode = "off" | "export" | "on"; -/** - * The UI mode the agent was in when this message was sent. Defaults to the session's current mode. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAgentMode". - */ -export type SendAgentMode = "interactive" | "plan" | "autopilot" | "shell"; -/** - * A user message attachment — a file, directory, code selection, blob, or GitHub reference - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachment". - */ -export type SendAttachment = - | SendAttachmentFile - | SendAttachmentDirectory - | SendAttachmentSelection - | SendAttachmentGithubReference - | SendAttachmentBlob; -/** - * Type of GitHub reference - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentGithubReferenceType". - */ -export type SendAttachmentGithubReferenceType = "issue" | "pr" | "discussion"; -/** - * How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendMode". - */ -export type SendMode = "enqueue" | "immediate"; -/** - * Repository host type - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionContextHostType". - */ -/** @experimental */ -export type SessionContextHostType = "github" | "ado"; /** * Error classification * @@ -508,63 +271,6 @@ export type SessionFsSetProviderConventions = "windows" | "posix"; * via the `definition` "SessionFsSqliteQueryType". */ export type SessionFsSqliteQueryType = "exec" | "query" | "run"; -/** - * Source descriptor for direct repo installs (when marketplace is empty) - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSource". - */ -/** @experimental */ -export type SessionInstalledPluginSource = - | string - | SessionInstalledPluginSourceGithub - | SessionInstalledPluginSourceUrl - | SessionInstalledPluginSourceLocal; -/** - * Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspaceSummary". - */ -/** @experimental */ -export type WorkspaceSummary = { - /** - * Workspace identifier (1:1 with sessionId) - */ - id: string; - /** - * Current working directory at session start - */ - cwd?: string; - /** - * Resolved git root for cwd, if any - */ - git_root?: string; - /** - * Repository identifier in 'owner/repo' or 'org/project/repo' format, if any - */ - repository?: string; - /** - * Repository host type, if known - */ - host_type?: "github" | "ado"; - /** - * Branch checked out at session start, if any - */ - branch?: string; - /** - * Display name for the session, if set - */ - name?: string; - /** - * ISO 8601 timestamp when the workspace was created - */ - created_at?: string; - /** - * ISO 8601 timestamp when the workspace was last updated - */ - updated_at?: string; -} | null; /** * Signal to send (default: SIGTERM) * @@ -598,51 +304,6 @@ export type TaskStatus = "running" | "idle" | "completed" | "failed" | "cancelle */ /** @experimental */ export type TaskExecutionMode = "sync" | "background"; -/** - * Schema for the `TaskAgentProgress` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskAgentProgress". - */ -/** @experimental */ -export type TaskAgentProgress = - | { - /** - * Progress kind - */ - type: "agent"; - /** - * Recent tool execution events converted to display lines - */ - recentActivity: { - /** - * Display message, e.g., "▸ bash", "✓ edit src/foo.ts" - */ - message: string; - /** - * ISO 8601 timestamp when this event occurred - */ - timestamp: string; - }[]; - /** - * The most recent intent reported by the agent - */ - latestIntent?: string; - } - | { - /** - * Progress kind - */ - type: "shell"; - /** - * Recent stdout/stderr lines from the running shell command - */ - recentOutput: string; - /** - * Process ID when available - */ - pid?: number; - }; /** * Schema for the `TaskInfo` type. * @@ -659,29 +320,6 @@ export type TaskInfo = TaskAgentInfo | TaskShellInfo; */ /** @experimental */ export type TaskShellInfoAttachmentMode = "attached" | "detached"; -/** - * Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskProgress". - */ -/** @experimental */ -export type TaskProgress = TaskAgentProgress | TaskShellProgress; -/** - * Schema for the `TaskShellProgress` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskShellProgress". - */ -/** @experimental */ -export type TaskShellProgress = null; -/** - * User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIAutoModeSwitchResponse". - */ -export type UIAutoModeSwitchResponse = "yes" | "yes_always" | "no"; /** * Schema for the `UIElicitationFieldValue` type. * @@ -727,39 +365,6 @@ export type UIElicitationSchemaPropertyNumberType = "number" | "integer"; * via the `definition` "UIElicitationResponseAction". */ export type UIElicitationResponseAction = "accept" | "decline" | "cancel"; -/** - * The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIExitPlanModeAction". - */ -export type UIExitPlanModeAction = "exit_only" | "interactive" | "autopilot" | "autopilot_fleet"; - -/** - * Parameters for aborting the current turn - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "AbortRequest". - */ -export interface AbortRequest { - reason?: AbortReason; -} -/** - * Result of aborting the current turn - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "AbortResult". - */ -export interface AbortResult { - /** - * Whether the abort completed successfully - */ - success: boolean; - /** - * Error message if the abort failed - */ - error?: string; -} export interface AccountGetQuotaRequest { /** @@ -858,33 +463,6 @@ export interface AgentInfo { * Absolute local file path of the agent definition. Only set for file-based agents loaded from disk; remote agents do not have a path. */ path?: string; - /** - * Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. - */ - id: string; - source?: AgentInfoSource; - /** - * Whether the agent can be selected directly by the user. Agents marked `false` are subagent-only. - */ - userInvocable?: boolean; - /** - * Allowed tool names for this agent. Empty array means none; omitted means inherit defaults. - */ - tools?: string[]; - /** - * Preferred model id for this agent. When omitted, inherits the outer agent's model. - */ - model?: string; - /** - * MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. - */ - mcpServers?: { - [k: string]: unknown | undefined; - }; - /** - * Skill names preloaded into this agent's context. Omitted means none. - */ - skills?: string[]; } /** * Custom agents available to the session. @@ -936,376 +514,49 @@ export interface AgentSelectResult { agent: AgentInfo; } /** - * Schema for the `ApiKeyAuthInfo` type. + * Slash commands available in the session, after applying any include/exclude filters. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ApiKeyAuthInfo". + * via the `definition` "CommandList". */ -export interface ApiKeyAuthInfo { - /** - * API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style). - */ - type: "api-key"; - /** - * The API key. Treat as a secret. - */ - apiKey: string; +export interface CommandList { /** - * Authentication host. + * Commands available in this session */ - host: string; - copilotUser?: CopilotUserResponse; + commands: SlashCommandInfo[]; } /** - * Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + * Schema for the `SlashCommandInfo` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotUserResponse". + * via the `definition` "SlashCommandInfo". */ -export interface CopilotUserResponse { - login?: string; - access_type_sku?: string; - analytics_tracking_id?: string; - assigned_date?: - | ( - | { - [k: string]: unknown | undefined; - } - | string - ) - | null; - can_signup_for_limited?: boolean; - chat_enabled?: boolean; - copilot_plan?: string; - copilotignore_enabled?: boolean; - endpoints?: CopilotUserResponseEndpoints; - organization_login_list?: string[]; - organization_list?: - | ( - | { - [k: string]: unknown | undefined; - } - | ({ - login?: - | ( - | { - [k: string]: unknown | undefined; - } - | string - ) - | null; - name?: - | ( - | { - [k: string]: unknown | undefined; - } - | string - ) - | null; - } | null)[] - ) - | null; - codex_agent_enabled?: boolean; - is_mcp_enabled?: - | ( - | { - [k: string]: unknown | undefined; - } - | boolean - ) - | null; - quota_reset_date?: string; - quota_snapshots?: CopilotUserResponseQuotaSnapshots; - restricted_telemetry?: boolean; - token_based_billing?: boolean; - quota_reset_date_utc?: string; - limited_user_quotas?: { - [k: string]: number | undefined; - }; - limited_user_reset_date?: string; - monthly_quotas?: { - [k: string]: number | undefined; - }; - cloud_session_storage_enabled?: boolean; - cli_remote_control_enabled?: boolean; +export interface SlashCommandInfo { + /** + * Canonical command name without a leading slash + */ + name: string; + /** + * Canonical aliases without leading slashes + */ + aliases?: string[]; + /** + * Human-readable command description + */ + description: string; + kind: SlashCommandKind; + input?: SlashCommandInput; + /** + * Whether the command may run while an agent turn is active + */ + allowDuringAgentExecution: boolean; + /** + * Whether the command is experimental + */ + experimental?: boolean; } /** - * Schema for the `CopilotUserResponseEndpoints` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotUserResponseEndpoints". - */ -export interface CopilotUserResponseEndpoints { - api?: string; - "origin-tracker"?: string; - proxy?: string; - telemetry?: string; -} -/** - * Schema for the `CopilotUserResponseQuotaSnapshots` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotUserResponseQuotaSnapshots". - */ -export interface CopilotUserResponseQuotaSnapshots { - chat?: CopilotUserResponseQuotaSnapshotsChat; - completions?: CopilotUserResponseQuotaSnapshotsCompletions; - premium_interactions?: CopilotUserResponseQuotaSnapshotsPremiumInteractions; - [k: string]: - | ({ - entitlement?: number; - overage_count?: number; - overage_permitted?: boolean; - percent_remaining?: number; - quota_id?: string; - quota_remaining?: number; - remaining?: number; - unlimited?: boolean; - timestamp_utc?: string; - has_quota?: boolean; - quota_reset_at?: number; - token_based_billing?: boolean; - } | null) - | undefined; -} -/** - * Schema for the `CopilotUserResponseQuotaSnapshotsChat` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotUserResponseQuotaSnapshotsChat". - */ -export interface CopilotUserResponseQuotaSnapshotsChat { - entitlement?: number; - overage_count?: number; - overage_permitted?: boolean; - percent_remaining?: number; - quota_id?: string; - quota_remaining?: number; - remaining?: number; - unlimited?: boolean; - timestamp_utc?: string; - has_quota?: boolean; - quota_reset_at?: number; - token_based_billing?: boolean; -} -/** - * Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotUserResponseQuotaSnapshotsCompletions". - */ -export interface CopilotUserResponseQuotaSnapshotsCompletions { - entitlement?: number; - overage_count?: number; - overage_permitted?: boolean; - percent_remaining?: number; - quota_id?: string; - quota_remaining?: number; - remaining?: number; - unlimited?: boolean; - timestamp_utc?: string; - has_quota?: boolean; - quota_reset_at?: number; - token_based_billing?: boolean; -} -/** - * Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotUserResponseQuotaSnapshotsPremiumInteractions". - */ -export interface CopilotUserResponseQuotaSnapshotsPremiumInteractions { - entitlement?: number; - overage_count?: number; - overage_permitted?: boolean; - percent_remaining?: number; - quota_id?: string; - quota_remaining?: number; - remaining?: number; - unlimited?: boolean; - timestamp_utc?: string; - has_quota?: boolean; - quota_reset_at?: number; - token_based_billing?: boolean; -} -/** - * Schema for the `HMACAuthInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HMACAuthInfo". - */ -export interface HMACAuthInfo { - /** - * HMAC-based authentication used by GitHub-internal services. - */ - type: "hmac"; - /** - * Authentication host. HMAC auth always targets the public GitHub host. - */ - host: "https://github.com"; - /** - * HMAC secret used to sign requests. - */ - hmac: string; - copilotUser?: CopilotUserResponse; -} -/** - * Schema for the `EnvAuthInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EnvAuthInfo". - */ -export interface EnvAuthInfo { - /** - * Personal access token (PAT) or server-to-server token sourced from an environment variable. - */ - type: "env"; - /** - * Authentication host (e.g. https://github.com or a GHES host). - */ - host: string; - /** - * User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). - */ - login?: string; - /** - * The token value itself. Treat as a secret. - */ - token: string; - /** - * Name of the environment variable the token was sourced from. - */ - envVar: string; - copilotUser?: CopilotUserResponse; -} -/** - * Schema for the `TokenAuthInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TokenAuthInfo". - */ -export interface TokenAuthInfo { - /** - * SDK-side token authentication; the host configured the token directly via the SDK. - */ - type: "token"; - /** - * Authentication host. - */ - host: string; - /** - * The token value itself. Treat as a secret. - */ - token: string; - copilotUser?: CopilotUserResponse; -} -/** - * Schema for the `CopilotApiTokenAuthInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CopilotApiTokenAuthInfo". - */ -export interface CopilotApiTokenAuthInfo { - /** - * Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` environment-variable pair. The token itself is read from the environment by the runtime, not carried in this struct. - */ - type: "copilot-api-token"; - /** - * Authentication host (always the public GitHub host). - */ - host: "https://github.com"; - copilotUser?: CopilotUserResponse; -} -/** - * Schema for the `UserAuthInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserAuthInfo". - */ -export interface UserAuthInfo { - /** - * OAuth user authentication. The token itself is held in the runtime's secret token store (keyed by host+login) and is NOT carried in this struct. - */ - type: "user"; - /** - * Authentication host. - */ - host: string; - /** - * OAuth user login. - */ - login: string; - copilotUser?: CopilotUserResponse; -} -/** - * Schema for the `GhCliAuthInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "GhCliAuthInfo". - */ -export interface GhCliAuthInfo { - /** - * Authentication via the `gh` CLI's saved credentials. - */ - type: "gh-cli"; - /** - * Authentication host. - */ - host: string; - /** - * User login as reported by `gh auth status`. - */ - login: string; - /** - * The token returned by `gh auth token`. Treat as a secret. - */ - token: string; - copilotUser?: CopilotUserResponse; -} -/** - * Slash commands available in the session, after applying any include/exclude filters. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CommandList". - */ -export interface CommandList { - /** - * Commands available in this session - */ - commands: SlashCommandInfo[]; -} -/** - * Schema for the `SlashCommandInfo` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandInfo". - */ -export interface SlashCommandInfo { - /** - * Canonical command name without a leading slash - */ - name: string; - /** - * Canonical aliases without leading slashes - */ - aliases?: string[]; - /** - * Human-readable command description - */ - description: string; - kind: SlashCommandKind; - input?: SlashCommandInput; - /** - * Whether the command may run while an agent turn is active - */ - allowDuringAgentExecution: boolean; - /** - * Whether the command is experimental - */ - experimental?: boolean; -} -/** - * Optional unstructured input hint + * Optional unstructured input hint * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "SlashCommandInput". @@ -1390,14 +641,14 @@ export interface CommandsListRequest { includeClientCommands?: boolean; } /** - * Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). + * Queued command request ID and the result indicating whether the client handled it. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "CommandsRespondToQueuedCommandRequest". */ export interface CommandsRespondToQueuedCommandRequest { /** - * Request ID from the `command.queued` event the host is responding to. + * Request ID from the queued command event */ requestId: string; result: QueuedCommandResult; @@ -1410,11 +661,11 @@ export interface CommandsRespondToQueuedCommandRequest { */ export interface QueuedCommandHandled { /** - * The host actually executed the queued command. + * The command was handled */ handled: true; /** - * When true, the runtime will not process subsequent queued commands until a new request comes in. + * If true, stop processing remaining queued items */ stopProcessingQueue?: boolean; } @@ -1426,19 +677,19 @@ export interface QueuedCommandHandled { */ export interface QueuedCommandNotHandled { /** - * The host did not execute the queued command. Unblocks the queue without claiming the command was processed (e.g. when the handler threw before completing). + * The command was not handled */ handled: false; } /** - * Indicates whether the queued-command response was matched to a pending request. + * Indicates whether the queued-command response was accepted by the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "CommandsRespondToQueuedCommandResult". */ export interface CommandsRespondToQueuedCommandResult { /** - * Whether a pending queued command with the given request ID was found and resolved. False when the request was already resolved, cancelled, or unknown. + * Whether the response was accepted (false if the requestId was not found or already resolved) */ success: boolean; } @@ -1558,7 +809,7 @@ export interface ConnectResult { version: string; } /** - * The currently selected model and reasoning effort for the session. + * The currently selected model for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "CurrentModel". @@ -1568,10 +819,6 @@ export interface CurrentModel { * Currently active model identifier */ modelId?: string; - /** - * Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. - */ - reasoningEffort?: string; } /** * Schema for the `DiscoveredMcpServer` type. @@ -1591,129 +838,6 @@ export interface DiscoveredMcpServer { */ enabled: boolean; } -/** - * Slash-prefixed command string to enqueue for FIFO processing. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EnqueueCommandParams". - */ -export interface EnqueueCommandParams { - /** - * Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO with any in-flight items; if the session is idle, processing kicks off immediately. - */ - command: string; -} -/** - * Indicates whether the command was accepted into the local execution queue. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EnqueueCommandResult". - */ -export interface EnqueueCommandResult { - /** - * True when the command was accepted into the local execution queue. False when the call targets a session that does not support local command queueing (e.g. remote sessions). - */ - queued: boolean; -} -/** - * Cursor, batch size, and optional long-poll/filter parameters for reading session events. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventLogReadRequest". - */ -/** @experimental */ -export interface EventLogReadRequest { - /** - * Opaque cursor returned by a previous read. Omit on the first call to start from the beginning of the session's persisted history. - */ - cursor?: string; - /** - * Maximum number of events to return in this batch (1–1000, default 200). - */ - max?: number; - /** - * Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). - */ - waitMs?: number; - types?: EventLogTypes; - agentScope?: EventsAgentScope; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventLogReleaseInterestResult". - */ -/** @experimental */ -export interface EventLogReleaseInterestResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventLogTailResult". - */ -/** @experimental */ -export interface EventLogTailResult { - /** - * Opaque cursor pointing at the current tail of the session's persisted-events history. Pass back to `read` to receive only events that arrive AFTER this snapshot. When the session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent to omitting the cursor on a first read). - */ - cursor: string; -} -/** - * Batch of session events returned by a read, with cursor and continuation metadata. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "EventsReadResult". - */ -/** @experimental */ -export interface EventsReadResult { - /** - * Events are delivered in two batches per read: persisted events first (in append order), then ephemeral events (in seq order). When `waitMs > 0` and the catch-up batches were empty, post-wait events follow the same two-batch ordering. Persisted and ephemeral events do not interleave within a single read. - */ - events: SessionEvent[]; - /** - * Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. - */ - cursor: string; - /** - * True when the read returned `max` events and more events are available immediately. When false, the next read with a non-zero `waitMs` will block until a new event arrives or the wait expires. - */ - hasMore: boolean; - cursorStatus: EventsCursorStatus; -} -/** - * Slash command name and argument string to execute synchronously. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ExecuteCommandParams". - */ -export interface ExecuteCommandParams { - /** - * Name of the slash command to invoke (without the leading '/'). - */ - commandName: string; - /** - * Argument string to pass to the command (empty string if none). - */ - args: string; -} -/** - * Error message produced while executing the command, if any. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ExecuteCommandResult". - */ -export interface ExecuteCommandResult { - /** - * Error message produced while executing the command, if any. Omitted when the handler succeeded. - */ - error?: string; -} /** * Schema for the `Extension` type. * @@ -2045,32 +1169,6 @@ export interface HandlePendingToolCallResult { */ success: boolean; } -/** - * Indicates whether an in-progress manual compaction was aborted. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HistoryAbortManualCompactionResult". - */ -/** @experimental */ -export interface HistoryAbortManualCompactionResult { - /** - * Whether an in-progress manual compaction was aborted. False when no manual compaction was running, when its abort controller was already aborted, or when the session is remote. - */ - aborted: boolean; -} -/** - * Indicates whether an in-progress background compaction was cancelled. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HistoryCancelBackgroundCompactionResult". - */ -/** @experimental */ -export interface HistoryCancelBackgroundCompactionResult { - /** - * Whether an in-progress background compaction was cancelled. False when no compaction was running, when the session is remote, or when the underlying processor was unavailable. - */ - cancelled: boolean; -} /** * Post-compaction context window usage breakdown * @@ -2105,7 +1203,7 @@ export interface HistoryCompactContextWindow { toolDefinitionsTokens?: number; } /** - * Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. + * Compaction outcome with the number of tokens and messages removed and the resulting context window breakdown. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "HistoryCompactResult". @@ -2124,25 +1222,8 @@ export interface HistoryCompactResult { * Number of messages removed during compaction */ messagesRemoved: number; - /** - * Summary text produced by compaction. Omitted when compaction did not produce a summary (e.g. failure path). - */ - summaryContent?: string; contextWindow?: HistoryCompactContextWindow; } -/** - * Markdown summary of the conversation context (empty when not available). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HistorySummarizeForHandoffResult". - */ -/** @experimental */ -export interface HistorySummarizeForHandoffResult { - /** - * Markdown summary of the conversation context produced by an LLM. Empty string when there are no messages or when the session does not support local summarization. - */ - summary: string; -} /** * Identifier of the event to truncate to; this event and all later events are removed. * @@ -2170,94 +1251,14 @@ export interface HistoryTruncateResult { eventsRemoved: number; } /** - * Schema for the `InstalledPlugin` type. + * Instruction sources loaded for the session, in merge order. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstalledPlugin". + * via the `definition` "InstructionsGetSourcesResult". */ -/** @experimental */ -export interface InstalledPlugin { - /** - * Plugin name - */ - name: string; - /** - * Marketplace the plugin came from (empty string for direct repo installs) - */ - marketplace: string; +export interface InstructionsGetSourcesResult { /** - * Version installed (if available) - */ - version?: string; - /** - * Installation timestamp - */ - installed_at: string; - /** - * Whether the plugin is currently enabled - */ - enabled: boolean; - /** - * Path where the plugin is cached locally - */ - cache_path?: string; - source?: InstalledPluginSource; -} -/** - * Schema for the `InstalledPluginSourceGithub` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstalledPluginSourceGithub". - */ -/** @experimental */ -export interface InstalledPluginSourceGithub { - /** - * Constant value. Always "github". - */ - source: "github"; - repo: string; - ref?: string; - path?: string; -} -/** - * Schema for the `InstalledPluginSourceUrl` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstalledPluginSourceUrl". - */ -/** @experimental */ -export interface InstalledPluginSourceUrl { - /** - * Constant value. Always "url". - */ - source: "url"; - url: string; - ref?: string; - path?: string; -} -/** - * Schema for the `InstalledPluginSourceLocal` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstalledPluginSourceLocal". - */ -/** @experimental */ -export interface InstalledPluginSourceLocal { - /** - * Constant value. Always "local". - */ - source: "local"; - path: string; -} -/** - * Instruction sources loaded for the session, in merge order. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstructionsGetSourcesResult". - */ -export interface InstructionsGetSourcesResult { - /** - * Instruction sources for the session + * Instruction sources for the session */ sources: InstructionsSources[]; } @@ -2287,20 +1288,16 @@ export interface InstructionsSources { type: InstructionsSourcesType; location: InstructionsSourcesLocation; /** - * Glob pattern(s) from frontmatter — when set, this instruction applies only to matching files + * Glob pattern from frontmatter — when set, this instruction applies only to matching files */ - applyTo?: string[]; + applyTo?: string; /** * Short description (body after frontmatter) for use in instruction tables */ description?: string; - /** - * When true, this source starts disabled and must be toggled on by the user - */ - defaultDisabled?: boolean; } /** - * Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. + * Message text, optional severity level, persistence flag, and optional follow-up URL. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "LogRequest". @@ -2311,10 +1308,6 @@ export interface LogRequest { */ message: string; level?: SessionLogLevel; - /** - * Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". - */ - type?: string; /** * When true, the message is transient and not persisted to the session event log on disk */ @@ -2323,10 +1316,6 @@ export interface LogRequest { * Optional URL the user can open in their browser for more details */ url?: string; - /** - * Optional actionable tip displayed alongside the message. Only honored on `level: "info"`. - */ - tip?: string; } /** * Identifier of the session event that was emitted for the log message. @@ -2340,53 +1329,6 @@ export interface LogResult { */ eventId: string; } -/** - * Parameters for (re)loading the merged LSP configuration set. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "LspInitializeRequest". - */ -/** @experimental */ -export interface LspInitializeRequest { - /** - * Working directory used to load project-level LSP configs. Defaults to the session working directory when omitted. - */ - workingDirectory?: string; - /** - * Git root used as the boundary when traversing for project-level LSP configs (supports monorepos). - */ - gitRoot?: string; - /** - * Force re-initialization even when LSP configs were already loaded for the working directory. - */ - force?: boolean; -} -/** - * The requestId previously passed to executeSampling that should be cancelled. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpCancelSamplingExecutionParams". - */ -/** @experimental */ -export interface McpCancelSamplingExecutionParams { - /** - * The requestId previously passed to executeSampling that should be cancelled - */ - requestId: string; -} -/** - * Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpCancelSamplingExecutionResult". - */ -/** @experimental */ -export interface McpCancelSamplingExecutionResult { - /** - * True if an in-flight execution with the given requestId was found and signalled to cancel. False when no such execution is in flight (already completed, never started, or cancelled by another caller). - */ - cancelled: boolean; -} /** * MCP server name and configuration to add to user configuration. * @@ -2606,48 +1548,6 @@ export interface McpEnableRequest { */ serverName: string; } -/** - * Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpExecuteSamplingParams". - */ -/** @experimental */ -export interface McpExecuteSamplingParams { - /** - * Caller-provided unique identifier for this sampling execution. Use this same ID with cancelSamplingExecution to cancel the in-flight call. Must be unique within the session for the lifetime of the call. - */ - requestId: string; - /** - * Name of the MCP server that initiated the sampling request - */ - serverName: string; - /** - * The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). - */ - mcpRequestId: string | number; - request: McpExecuteSamplingRequest; -} -/** - * Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpExecuteSamplingRequest". - */ -/** @experimental */ -export interface McpExecuteSamplingRequest { - [k: string]: unknown | undefined; -} -/** - * MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpExecuteSamplingResult". - */ -/** @experimental */ -export interface McpExecuteSamplingResult { - [k: string]: unknown | undefined; -} /** * Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, and the callback success-page copy. * @@ -2686,34 +1586,6 @@ export interface McpOauthLoginResult { */ authorizationUrl?: string; } -/** - * Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRemoveGitHubResult". - */ -/** @experimental */ -export interface McpRemoveGitHubResult { - /** - * True when the auto-managed `github` MCP server was removed; false when no removal happened (e.g. user has explicitly configured a `github` server, or the server was not registered). - */ - removed: boolean; -} -/** - * Outcome of an MCP sampling execution: success result, failure error, or cancellation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSamplingExecutionResult". - */ -/** @experimental */ -export interface McpSamplingExecutionResult { - action: McpSamplingExecutionAction; - result?: McpExecuteSamplingResult; - /** - * Error description, present when action='failure'. - */ - error?: string; -} /** * Schema for the `McpServer` type. * @@ -2747,393 +1619,170 @@ export interface McpServerList { servers: McpServer[]; } /** - * Mode controlling how MCP server env values are resolved (`direct` or `indirect`). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSetEnvValueModeParams". - */ -/** @experimental */ -export interface McpSetEnvValueModeParams { - mode: McpSetEnvValueModeDetails; -} -/** - * Env-value mode recorded on the session after the update. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSetEnvValueModeResult". - */ -/** @experimental */ -export interface McpSetEnvValueModeResult { - mode: McpSetEnvValueModeDetails; -} -/** - * Model identifier and token limits used to compute the context-info breakdown. + * Schema for the `Model` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextInfoRequest". + * via the `definition` "Model". */ -/** @experimental */ -export interface MetadataContextInfoRequest { +export interface Model { + /** + * Model identifier (e.g., "claude-sonnet-4.5") + */ + id: string; /** - * Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default. + * Display name */ - promptTokenLimit: number; + name: string; + capabilities: ModelCapabilities; + policy?: ModelPolicy; + billing?: ModelBilling; /** - * Maximum output tokens allowed by the target model. Pass 0 if unknown. + * Supported reasoning effort levels (only present if model supports reasoning effort) */ - outputTokenLimit: number; + supportedReasoningEfforts?: string[]; /** - * Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. + * Default reasoning effort level (only present if model supports reasoning effort) */ - selectedModel?: string; + defaultReasoningEffort?: string; + modelPickerCategory?: ModelPickerCategory; + modelPickerPriceCategory?: ModelPickerPriceCategory; } /** - * Token breakdown for the session's current context window, or null if uninitialized. + * Model capabilities and limits * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextInfoResult". + * via the `definition` "ModelCapabilities". */ -/** @experimental */ -export interface MetadataContextInfoResult { - /** - * Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). - */ - contextInfo?: SessionContextInfo | null; +export interface ModelCapabilities { + supports?: ModelCapabilitiesSupports; + limits?: ModelCapabilitiesLimits; } /** - * Indicates whether the local session is currently processing a turn or background continuation. + * Feature flags indicating what the model supports * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataIsProcessingResult". + * via the `definition` "ModelCapabilitiesSupports". */ -/** @experimental */ -export interface MetadataIsProcessingResult { +export interface ModelCapabilitiesSupports { + /** + * Whether this model supports vision/image input + */ + vision?: boolean; /** - * Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. + * Whether this model supports reasoning effort configuration */ - processing: boolean; + reasoningEffort?: boolean; } /** - * Model identifier to use when re-tokenizing the session's existing messages. + * Token limits for prompts, outputs, and context window * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecomputeContextTokensRequest". + * via the `definition` "ModelCapabilitiesLimits". */ -/** @experimental */ -export interface MetadataRecomputeContextTokensRequest { +export interface ModelCapabilitiesLimits { /** - * Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. + * Maximum number of prompt/input tokens */ - modelId: string; + max_prompt_tokens?: number; + /** + * Maximum number of output/completion tokens + */ + max_output_tokens?: number; + /** + * Maximum total context window size in tokens + */ + max_context_window_tokens?: number; + vision?: ModelCapabilitiesLimitsVision; } /** - * Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. + * Vision-specific limits * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecomputeContextTokensResult". + * via the `definition` "ModelCapabilitiesLimitsVision". */ -/** @experimental */ -export interface MetadataRecomputeContextTokensResult { +export interface ModelCapabilitiesLimitsVision { /** - * Sum of tokens across chat-context and system-context messages currently held by the session. + * MIME types the model accepts */ - totalTokens: number; + supported_media_types: string[]; /** - * Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). + * Maximum number of images per prompt */ - messagesTokenCount: number; + max_prompt_images: number; /** - * Tokens contributed by system/developer prompt snapshots. + * Maximum image size in bytes */ - systemTokenCount: number; + max_prompt_image_size: number; } /** - * Updated working-directory/git context to record on the session. + * Policy state (if applicable) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecordContextChangeRequest". + * via the `definition` "ModelPolicy". */ -/** @experimental */ -export interface MetadataRecordContextChangeRequest { - context: SessionWorkingDirectoryContext; +export interface ModelPolicy { + state: ModelPolicyState; + /** + * Usage terms or conditions for this model + */ + terms?: string; } /** - * Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + * Billing information * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionWorkingDirectoryContext". + * via the `definition` "ModelBilling". */ -/** @experimental */ -export interface SessionWorkingDirectoryContext { - /** - * Current working directory path - */ - cwd: string; - /** - * Root directory of the git repository, resolved via git rev-parse - */ - gitRoot?: string; +export interface ModelBilling { /** - * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) + * Billing cost multiplier relative to the base rate */ - repository?: string; - hostType?: SessionWorkingDirectoryContextHostType; + multiplier?: number; + tokenPrices?: ModelBillingTokenPrices; +} +/** + * Token-level pricing information for this model + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelBillingTokenPrices". + */ +export interface ModelBillingTokenPrices { /** - * Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com") + * Price per billing batch of input tokens in nano-AIUs (1 nano-AIU = 0.000000001 AIU, 1 AIU = $0.01 USD) */ - repositoryHost?: string; + inputPrice?: number; /** - * Current git branch name + * Price per billing batch of output tokens in nano-AIUs (1 nano-AIU = 0.000000001 AIU, 1 AIU = $0.01 USD) */ - branch?: string; + outputPrice?: number; /** - * Head commit of the current git branch + * Price per billing batch of cached tokens in nano-AIUs (1 nano-AIU = 0.000000001 AIU, 1 AIU = $0.01 USD) */ - headCommit?: string; + cachePrice?: number; /** - * Merge-base commit SHA (fork point from the remote default branch) + * Number of tokens per standard billing batch */ - baseCommit?: string; + batchSize?: number; } /** - * Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). + * Override individual model capabilities resolved by the runtime * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecordContextChangeResult". + * via the `definition` "ModelCapabilitiesOverride". */ -/** @experimental */ -export interface MetadataRecordContextChangeResult {} +export interface ModelCapabilitiesOverride { + supports?: ModelCapabilitiesOverrideSupports; + limits?: ModelCapabilitiesOverrideLimits; +} /** - * Absolute path to set as the session's new working directory. + * Feature flags indicating what the model supports * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSetWorkingDirectoryRequest". + * via the `definition` "ModelCapabilitiesOverrideSupports". */ -/** @experimental */ -export interface MetadataSetWorkingDirectoryRequest { +export interface ModelCapabilitiesOverrideSupports { /** - * Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. - */ - workingDirectory: string; -} -/** - * Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any related side-effects (file index, etc.); this method only updates the session's own recorded path. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSetWorkingDirectoryResult". - */ -/** @experimental */ -export interface MetadataSetWorkingDirectoryResult { - /** - * Working directory after the update - */ - workingDirectory: string; -} -/** - * Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSnapshotRemoteMetadata". - */ -/** @experimental */ -export interface MetadataSnapshotRemoteMetadata { - /** - * The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. - */ - resourceId?: string; - repository: MetadataSnapshotRemoteMetadataRepository; - /** - * The pull request number the remote session is associated with, if any. - */ - pullRequestNumber?: number; - taskType?: MetadataSnapshotRemoteMetadataTaskType; -} -/** - * The repository the remote session targets. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSnapshotRemoteMetadataRepository". - */ -/** @experimental */ -export interface MetadataSnapshotRemoteMetadataRepository { - /** - * The GitHub owner (user or organization) of the target repository. - */ - owner: string; - /** - * The GitHub repository name (without owner). - */ - name: string; - /** - * The branch the remote session is operating on. - */ - branch: string; -} -/** - * Schema for the `Model` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Model". - */ -export interface Model { - /** - * Model identifier (e.g., "claude-sonnet-4.5") - */ - id: string; - /** - * Display name - */ - name: string; - capabilities: ModelCapabilities; - policy?: ModelPolicy; - billing?: ModelBilling; - /** - * Supported reasoning effort levels (only present if model supports reasoning effort) - */ - supportedReasoningEfforts?: string[]; - /** - * Default reasoning effort level (only present if model supports reasoning effort) - */ - defaultReasoningEffort?: string; - modelPickerCategory?: ModelPickerCategory; - modelPickerPriceCategory?: ModelPickerPriceCategory; -} -/** - * Model capabilities and limits - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilities". - */ -export interface ModelCapabilities { - supports?: ModelCapabilitiesSupports; - limits?: ModelCapabilitiesLimits; -} -/** - * Feature flags indicating what the model supports - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesSupports". - */ -export interface ModelCapabilitiesSupports { - /** - * Whether this model supports vision/image input - */ - vision?: boolean; - /** - * Whether this model supports reasoning effort configuration - */ - reasoningEffort?: boolean; -} -/** - * Token limits for prompts, outputs, and context window - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesLimits". - */ -export interface ModelCapabilitiesLimits { - /** - * Maximum number of prompt/input tokens - */ - max_prompt_tokens?: number; - /** - * Maximum number of output/completion tokens - */ - max_output_tokens?: number; - /** - * Maximum total context window size in tokens - */ - max_context_window_tokens?: number; - vision?: ModelCapabilitiesLimitsVision; -} -/** - * Vision-specific limits - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesLimitsVision". - */ -export interface ModelCapabilitiesLimitsVision { - /** - * MIME types the model accepts - */ - supported_media_types: string[]; - /** - * Maximum number of images per prompt - */ - max_prompt_images: number; - /** - * Maximum image size in bytes - */ - max_prompt_image_size: number; -} -/** - * Policy state (if applicable) - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelPolicy". - */ -export interface ModelPolicy { - state: ModelPolicyState; - /** - * Usage terms or conditions for this model - */ - terms?: string; -} -/** - * Billing information - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBilling". - */ -export interface ModelBilling { - /** - * Billing cost multiplier relative to the base rate - */ - multiplier?: number; - tokenPrices?: ModelBillingTokenPrices; -} -/** - * Token-level pricing information for this model - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBillingTokenPrices". - */ -export interface ModelBillingTokenPrices { - /** - * Price per billing batch of input tokens in nano-AIUs (1 nano-AIU = 0.000000001 AIU, 1 AIU = $0.01 USD) - */ - inputPrice?: number; - /** - * Price per billing batch of output tokens in nano-AIUs (1 nano-AIU = 0.000000001 AIU, 1 AIU = $0.01 USD) - */ - outputPrice?: number; - /** - * Price per billing batch of cached tokens in nano-AIUs (1 nano-AIU = 0.000000001 AIU, 1 AIU = $0.01 USD) - */ - cachePrice?: number; - /** - * Number of tokens per standard billing batch - */ - batchSize?: number; -} -/** - * Override individual model capabilities resolved by the runtime - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverride". - */ -export interface ModelCapabilitiesOverride { - supports?: ModelCapabilitiesOverrideSupports; - limits?: ModelCapabilitiesOverrideLimits; -} -/** - * Feature flags indicating what the model supports - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverrideSupports". - */ -export interface ModelCapabilitiesOverrideSupports { - /** - * Whether this model supports vision/image input + * Whether this model supports vision/image input */ vision?: boolean; /** @@ -3194,30 +1843,6 @@ export interface ModelList { */ models: Model[]; } -/** - * Reasoning effort level to apply to the currently selected model. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSetReasoningEffortRequest". - */ -export interface ModelSetReasoningEffortRequest { - /** - * Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. - */ - reasoningEffort: string; -} -/** - * Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSetReasoningEffortResult". - */ -export interface ModelSetReasoningEffortResult { - /** - * Reasoning effort level recorded on the session after the update - */ - reasoningEffort: string; -} export interface ModelsListRequest { /** @@ -3276,30 +1901,6 @@ export interface NameGetResult { */ name: string | null; } -/** - * Auto-generated session summary to apply as the session's name when no user-set name exists. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NameSetAutoRequest". - */ -export interface NameSetAutoRequest { - /** - * Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. - */ - summary: string; -} -/** - * Indicates whether the auto-generated summary was applied as the session's name. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NameSetAutoResult". - */ -export interface NameSetAutoResult { - /** - * Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. - */ - applied: boolean; -} /** * New friendly name to apply to the session. * @@ -3312,31 +1913,6 @@ export interface NameSetRequest { */ name: string; } -/** - * Schema for the `PendingPermissionRequest` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PendingPermissionRequest". - */ -export interface PendingPermissionRequest { - /** - * Unique identifier for the pending permission request - */ - requestId: string; - request: PermissionPromptRequest; -} -/** - * List of pending permission requests reconstructed from event history. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PendingPermissionRequestList". - */ -export interface PendingPermissionRequestList { - /** - * Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. - */ - items: PendingPermissionRequest[]; -} /** * Schema for the `PermissionDecisionApproveOnce` type. * @@ -3345,7 +1921,7 @@ export interface PendingPermissionRequestList { */ export interface PermissionDecisionApproveOnce { /** - * Approve this single request only + * The permission request was approved for this one instance */ kind: "approve-once"; } @@ -3357,12 +1933,12 @@ export interface PermissionDecisionApproveOnce { */ export interface PermissionDecisionApproveForSession { /** - * Approve and remember for the rest of the session + * Approved and remembered for the rest of the session */ kind: "approve-for-session"; approval?: PermissionDecisionApproveForSessionApproval; /** - * URL domain to approve for the rest of the session (URL prompts only) + * The URL domain to approve for this session */ domain?: string; } @@ -3510,12 +2086,12 @@ export interface PermissionDecisionApproveForSessionApprovalExtensionPermissionA */ export interface PermissionDecisionApproveForLocation { /** - * Approve and persist for this project location + * Approved and persisted for this project location */ kind: "approve-for-location"; approval: PermissionDecisionApproveForLocationApproval; /** - * Location key (git root or cwd) to persist the approval to + * The location key (git root or cwd) to persist the approval to */ locationKey: string; } @@ -3663,11 +2239,11 @@ export interface PermissionDecisionApproveForLocationApprovalExtensionPermission */ export interface PermissionDecisionApprovePermanently { /** - * Approve and persist across sessions (URL prompts only) + * Approved and persisted across sessions */ kind: "approve-permanently"; /** - * URL domain to approve permanently + * The URL domain to approve permanently */ domain: string; } @@ -3679,11 +2255,11 @@ export interface PermissionDecisionApprovePermanently { */ export interface PermissionDecisionReject { /** - * Reject the request + * Denied by the user during an interactive prompt */ kind: "reject"; /** - * Optional feedback explaining the rejection + * Optional feedback from the user explaining the denial */ feedback?: string; } @@ -3695,2513 +2271,738 @@ export interface PermissionDecisionReject { */ export interface PermissionDecisionUserNotAvailable { /** - * No user is available to confirm the request + * Denied because user confirmation was unavailable */ kind: "user-not-available"; } /** - * Schema for the `PermissionDecisionApproved` type. + * Pending permission request ID and the decision to apply (approve/reject and scope). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproved". + * via the `definition` "PermissionDecisionRequest". */ -export interface PermissionDecisionApproved { +export interface PermissionDecisionRequest { /** - * The permission request was approved + * Request ID of the pending permission request */ - kind: "approved"; + requestId: string; + result: PermissionDecision; } /** - * Schema for the `PermissionDecisionApprovedForSession` type. + * Indicates whether the permission decision was applied; false when the request was already resolved. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApprovedForSession". + * via the `definition` "PermissionRequestResult". */ -export interface PermissionDecisionApprovedForSession { +export interface PermissionRequestResult { /** - * Approved and remembered for the rest of the session + * Whether the permission request was handled successfully */ - kind: "approved-for-session"; - approval: UserToolSessionApproval; + success: boolean; } /** - * Schema for the `PermissionDecisionApprovedForLocation` type. + * No parameters; clears all session-scoped tool permission approvals. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApprovedForLocation". + * via the `definition` "PermissionsResetSessionApprovalsRequest". */ -export interface PermissionDecisionApprovedForLocation { - /** - * Approved and persisted for this project location - */ - kind: "approved-for-location"; - approval: UserToolSessionApproval; +export interface PermissionsResetSessionApprovalsRequest {} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsResetSessionApprovalsResult". + */ +export interface PermissionsResetSessionApprovalsResult { /** - * The location key (git root or cwd) to persist the approval to + * Whether the operation succeeded */ - locationKey: string; + success: boolean; } /** - * Schema for the `PermissionDecisionCancelled` type. + * Whether to auto-approve all tool permission requests for the rest of the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionCancelled". + * via the `definition` "PermissionsSetApproveAllRequest". */ -export interface PermissionDecisionCancelled { - /** - * The permission request was cancelled before a response was used - */ - kind: "cancelled"; +export interface PermissionsSetApproveAllRequest { /** - * Optional explanation of why the request was cancelled + * Whether to auto-approve all tool permission requests */ - reason?: string; + enabled: boolean; } /** - * Schema for the `PermissionDecisionDeniedByRules` type. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedByRules". + * via the `definition` "PermissionsSetApproveAllResult". */ -export interface PermissionDecisionDeniedByRules { - /** - * Denied because approval rules explicitly blocked it - */ - kind: "denied-by-rules"; +export interface PermissionsSetApproveAllResult { /** - * Rules that denied the request + * Whether the operation succeeded */ - rules: PermissionRule[]; + success: boolean; } /** - * Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type. + * Optional message to echo back to the caller. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser". + * via the `definition` "PingRequest". */ -export interface PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser { +export interface PingRequest { /** - * Denied because no approval rule matched and user confirmation was unavailable + * Optional message to echo back */ - kind: "denied-no-approval-rule-and-could-not-request-from-user"; + message?: string; } /** - * Schema for the `PermissionDecisionDeniedInteractivelyByUser` type. + * Server liveness response, including the echoed message, current timestamp, and protocol version. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedInteractivelyByUser". + * via the `definition` "PingResult". */ -export interface PermissionDecisionDeniedInteractivelyByUser { +export interface PingResult { /** - * Denied by the user during an interactive prompt + * Echoed message (or default greeting) */ - kind: "denied-interactively-by-user"; + message: string; /** - * Optional feedback from the user explaining the denial + * Server timestamp in milliseconds */ - feedback?: string; + timestamp: number; /** - * Whether to force-reject the current agent turn + * Server protocol version number */ - forceReject?: boolean; + protocolVersion: number; } /** - * Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type. + * Existence, contents, and resolved path of the session plan file. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedByContentExclusionPolicy". + * via the `definition` "PlanReadResult". */ -export interface PermissionDecisionDeniedByContentExclusionPolicy { +export interface PlanReadResult { /** - * Denied by the organization's content exclusion policy + * Whether the plan file exists in the workspace */ - kind: "denied-by-content-exclusion-policy"; + exists: boolean; /** - * File path that triggered the exclusion + * The content of the plan file, or null if it does not exist */ - path: string; + content: string | null; /** - * Human-readable explanation of why the path was excluded + * Absolute file path of the plan file, or null if workspace is not enabled */ - message: string; + path: string | null; +} +/** + * Replacement contents to write to the session plan file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PlanUpdateRequest". + */ +export interface PlanUpdateRequest { + /** + * The new content for the plan file + */ + content: string; } /** - * Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type. + * Schema for the `Plugin` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedByPermissionRequestHook". + * via the `definition` "Plugin". */ -export interface PermissionDecisionDeniedByPermissionRequestHook { +/** @experimental */ +export interface Plugin { /** - * Denied by a permission request hook registered by an extension or plugin + * Plugin name */ - kind: "denied-by-permission-request-hook"; + name: string; /** - * Optional message from the hook explaining the denial + * Marketplace the plugin came from */ - message?: string; + marketplace: string; + /** + * Installed version + */ + version?: string; /** - * Whether to interrupt the current agent turn + * Whether the plugin is currently enabled */ - interrupt?: boolean; + enabled: boolean; } /** - * Pending permission request ID and the decision to apply (approve/reject and scope). + * Plugins installed for the session, with their enabled state and version metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionRequest". + * via the `definition` "PluginList". */ -export interface PermissionDecisionRequest { +/** @experimental */ +export interface PluginList { /** - * Request ID of the pending permission request + * Installed plugins */ - requestId: string; - result: PermissionDecision; + plugins: Plugin[]; } /** - * Directory path to add to the session's allowed directories. + * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsAddParams". + * via the `definition` "RemoteEnableRequest". */ -export interface PermissionPathsAddParams { - /** - * Directory to add to the allow-list. The runtime resolves and validates the path before adding. - */ - path: string; +/** @experimental */ +export interface RemoteEnableRequest { + mode?: RemoteSessionMode; } /** - * Path to evaluate against the session's allowed directories. + * GitHub URL for the session and a flag indicating whether remote steering is enabled. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsAllowedCheckParams". + * via the `definition` "RemoteEnableResult". */ -export interface PermissionPathsAllowedCheckParams { +/** @experimental */ +export interface RemoteEnableResult { + /** + * GitHub frontend URL for this session + */ + url?: string; /** - * Path to check against the session's allowed directories + * Whether remote steering is enabled */ - path: string; + remoteSteerable: boolean; } /** - * Indicates whether the supplied path is within the session's allowed directories. + * Remote session connection result. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsAllowedCheckResult". + * via the `definition` "RemoteSessionConnectionResult". */ -export interface PermissionPathsAllowedCheckResult { +/** @experimental */ +export interface RemoteSessionConnectionResult { /** - * Whether the path is within the session's allowed directories + * SDK session ID for the connected remote session. */ - allowed: boolean; + sessionId: string; + metadata: ConnectedRemoteSessionMetadata; } /** - * If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. + * Schema for the `ServerSkill` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsConfig". + * via the `definition` "ServerSkill". */ -export interface PermissionPathsConfig { +export interface ServerSkill { /** - * If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. + * Unique identifier for the skill */ - unrestricted?: boolean; + name: string; /** - * Additional directories to allow tool access to (in addition to the session's working directory). When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). + * Description of what the skill does */ - additionalDirectories?: string[]; + description: string; + source: SkillSource; /** - * Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. + * Whether the skill can be invoked by the user as a slash command */ - includeTempDirectory?: boolean; + userInvocable: boolean; /** - * Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. + * Whether the skill is currently enabled (based on global config) */ - workspacePath?: string; -} -/** - * Snapshot of the session's allow-listed directories and primary working directory. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsList". - */ -export interface PermissionPathsList { + enabled: boolean; /** - * All directories currently allowed for tool access on this session. + * Absolute path to the skill file */ - directories: string[]; + path?: string; /** - * The primary working directory for this session. + * The project path this skill belongs to (only for project/inherited skills) */ - primary: string; + projectPath?: string; } /** - * Directory path to set as the session's new primary working directory. + * Skills discovered across global and project sources. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsUpdatePrimaryParams". + * via the `definition` "ServerSkillList". */ -export interface PermissionPathsUpdatePrimaryParams { +export interface ServerSkillList { /** - * Directory to set as the new primary working directory for the session's permission policy. + * All discovered skills across all sources */ - path: string; + skills: ServerSkill[]; } /** - * Path to evaluate against the session's workspace (primary) directory. + * Authentication status and account metadata for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsWorkspaceCheckParams". + * via the `definition` "SessionAuthStatus". */ -export interface PermissionPathsWorkspaceCheckParams { +export interface SessionAuthStatus { /** - * Path to check against the session workspace directory + * Whether the session has resolved authentication */ - path: string; -} -/** - * Indicates whether the supplied path is within the session's workspace directory. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsWorkspaceCheckResult". - */ -export interface PermissionPathsWorkspaceCheckResult { + isAuthenticated: boolean; + authType?: AuthInfoType; /** - * Whether the path is within the session workspace directory + * Authentication host URL */ - allowed: boolean; -} -/** - * Notification payload describing the permission prompt that the client just rendered. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPromptShownNotification". - */ -export interface PermissionPromptShownNotification { + host?: string; /** - * Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). + * Authenticated login/username, if available */ - message: string; -} -/** - * Indicates whether the permission decision was applied; false when the request was already resolved. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionRequestResult". - */ -export interface PermissionRequestResult { + login?: string; /** - * Whether the permission request was handled successfully + * Human-readable authentication status description */ - success: boolean; + statusMessage?: string; + /** + * Copilot plan tier (e.g., individual_pro, business) + */ + copilotPlan?: string; } /** - * If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. + * File path, content to append, and optional mode for the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionRulesSet". + * via the `definition` "SessionFsAppendFileRequest". */ -export interface PermissionRulesSet { +export interface SessionFsAppendFileRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; /** - * Rules that auto-approve matching requests + * Content to append */ - approved: PermissionRule[]; + content: string; /** - * Rules that auto-deny matching requests + * Optional POSIX-style mode for newly created files */ - denied: PermissionRule[]; + mode?: number; } /** - * Schema for the `PermissionsConfigureAdditionalContentExclusionPolicy` type. + * Describes a filesystem error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicy". + * via the `definition` "SessionFsError". */ -export interface PermissionsConfigureAdditionalContentExclusionPolicy { - rules: PermissionsConfigureAdditionalContentExclusionPolicyRule[]; - last_updated_at: string | number; - scope: PermissionsConfigureAdditionalContentExclusionPolicyScope; - [k: string]: unknown | undefined; +export interface SessionFsError { + code: SessionFsErrorCode; + /** + * Free-form detail about the error, for logging/diagnostics + */ + message?: string; } /** - * Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRule` type. + * Path to test for existence in the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRule". + * via the `definition` "SessionFsExistsRequest". */ -export interface PermissionsConfigureAdditionalContentExclusionPolicyRule { - paths: string[]; - ifAnyMatch?: string[]; - ifNoneMatch?: string[]; - source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource; - [k: string]: unknown | undefined; +export interface SessionFsExistsRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; } /** - * Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type. + * Indicates whether the requested path exists in the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRuleSource". + * via the `definition` "SessionFsExistsResult". */ -export interface PermissionsConfigureAdditionalContentExclusionPolicyRuleSource { - name: string; - type: string; +export interface SessionFsExistsResult { + /** + * Whether the path exists + */ + exists: boolean; } /** - * Patch of permission policy fields to apply (omit a field to leave it unchanged). + * Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureParams". + * via the `definition` "SessionFsMkdirRequest". */ -export interface PermissionsConfigureParams { +export interface SessionFsMkdirRequest { + /** + * Target session identifier + */ + sessionId: string; /** - * If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. + * Path using SessionFs conventions */ - approveAllToolPermissionRequests?: boolean; + path: string; /** - * If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. + * Create parent directories as needed */ - approveAllReadPermissionRequests?: boolean; - rules?: PermissionRulesSet; - paths?: PermissionPathsConfig; - urls?: PermissionUrlsConfig; + recursive?: boolean; /** - * If specified, replaces the host-supplied GitHub Content Exclusion policies on the session (combined with natively-discovered policies when evaluating tool/file access). Omit to leave the current policies unchanged. + * Optional POSIX-style mode for newly created directories */ - additionalContentExclusionPolicies?: PermissionsConfigureAdditionalContentExclusionPolicy[]; + mode?: number; } /** - * If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. + * Directory path whose entries should be listed from the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionUrlsConfig". + * via the `definition` "SessionFsReaddirRequest". */ -export interface PermissionUrlsConfig { +export interface SessionFsReaddirRequest { /** - * If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. + * Target session identifier */ - unrestricted?: boolean; + sessionId: string; /** - * Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. + * Path using SessionFs conventions */ - initialAllowed?: string[]; + path: string; } /** - * Indicates whether the operation succeeded. + * Names of entries in the requested directory, or a filesystem error if the read failed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureResult". - */ -export interface PermissionsConfigureResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Scope and add/remove instructions for modifying session- or location-scoped permission rules. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsModifyRulesParams". - */ -export interface PermissionsModifyRulesParams { - scope: PermissionsModifyRulesScope; - /** - * Rules to add to the scope. Applied before `remove`/`removeAll`. - */ - add?: PermissionRule[]; - /** - * Specific rules to remove from the scope. Ignored when `removeAll` is true. - */ - remove?: PermissionRule[]; - /** - * When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. - */ - removeAll?: boolean; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsModifyRulesResult". - */ -export interface PermissionsModifyRulesResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsNotifyPromptShownResult". - */ -export interface PermissionsNotifyPromptShownResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPathsAddResult". - */ -export interface PermissionsPathsAddResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * No parameters; returns the session's allow-listed directories. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPathsListRequest". - */ -export interface PermissionsPathsListRequest {} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPathsUpdatePrimaryResult". - */ -export interface PermissionsPathsUpdatePrimaryResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * No parameters; returns currently-pending permission requests for the session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPendingRequestsRequest". - */ -export interface PermissionsPendingRequestsRequest {} -/** - * No parameters; clears all session-scoped tool permission approvals. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsResetSessionApprovalsRequest". - */ -export interface PermissionsResetSessionApprovalsRequest {} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsResetSessionApprovalsResult". - */ -export interface PermissionsResetSessionApprovalsResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Allow-all toggle for tool permission requests, with an optional telemetry source. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllRequest". - */ -export interface PermissionsSetApproveAllRequest { - /** - * Whether to auto-approve all tool permission requests - */ - enabled: boolean; - source?: PermissionsSetApproveAllSource; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllResult". - */ -export interface PermissionsSetApproveAllResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Toggles whether permission prompts should be bridged into session events for this client. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetRequiredRequest". - */ -export interface PermissionsSetRequiredRequest { - /** - * Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). - */ - required: boolean; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetRequiredResult". - */ -export interface PermissionsSetRequiredResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsUrlsSetUnrestrictedModeResult". - */ -export interface PermissionsUrlsSetUnrestrictedModeResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * Whether the URL-permission policy should run in unrestricted mode. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionUrlsSetUnrestrictedModeParams". - */ -export interface PermissionUrlsSetUnrestrictedModeParams { - /** - * Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. - */ - enabled: boolean; -} -/** - * Optional message to echo back to the caller. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PingRequest". - */ -export interface PingRequest { - /** - * Optional message to echo back - */ - message?: string; -} -/** - * Server liveness response, including the echoed message, current server timestamp, and protocol version. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PingResult". - */ -export interface PingResult { - /** - * Echoed message (or default greeting) - */ - message: string; - /** - * ISO 8601 timestamp when the server handled the ping - */ - timestamp: string; - /** - * Server protocol version number - */ - protocolVersion: number; -} -/** - * Existence, contents, and resolved path of the session plan file. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanReadResult". - */ -export interface PlanReadResult { - /** - * Whether the plan file exists in the workspace - */ - exists: boolean; - /** - * The content of the plan file, or null if it does not exist - */ - content: string | null; - /** - * Absolute file path of the plan file, or null if workspace is not enabled - */ - path: string | null; -} -/** - * Replacement contents to write to the session plan file. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanUpdateRequest". - */ -export interface PlanUpdateRequest { - /** - * The new content for the plan file - */ - content: string; -} -/** - * Schema for the `Plugin` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Plugin". - */ -/** @experimental */ -export interface Plugin { - /** - * Plugin name - */ - name: string; - /** - * Marketplace the plugin came from - */ - marketplace: string; - /** - * Installed version - */ - version?: string; - /** - * Whether the plugin is currently enabled - */ - enabled: boolean; -} -/** - * Plugins installed for the session, with their enabled state and version metadata. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginList". - */ -/** @experimental */ -export interface PluginList { - /** - * Installed plugins - */ - plugins: Plugin[]; -} -/** - * Schema for the `QueuePendingItems` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueuePendingItems". - */ -/** @experimental */ -export interface QueuePendingItems { - kind: QueuePendingItemsKind; - /** - * Human-readable text to display for this queue entry in the UI - */ - displayText: string; -} -/** - * Snapshot of the session's pending queued items and immediate-steering messages. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueuePendingItemsResult". - */ -/** @experimental */ -export interface QueuePendingItemsResult { - /** - * Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. - */ - items: QueuePendingItems[]; - /** - * Display text for messages currently in the immediate steering queue (interjections sent during a running turn). - */ - steeringMessages: string[]; -} -/** - * Indicates whether a user-facing pending item was removed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueRemoveMostRecentResult". - */ -/** @experimental */ -export interface QueueRemoveMostRecentResult { - /** - * True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. - */ - removed: boolean; -} -/** - * Event type to register consumer interest for, used by runtime gating logic. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RegisterEventInterestParams". - */ -/** @experimental */ -export interface RegisterEventInterestParams { - /** - * The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates the full interactive OAuth flow to the consumer; when no interest is registered the runtime installs a browserless fallback that silently reuses cached tokens). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. - */ - eventType: string; -} -/** - * Opaque handle representing an event-type interest registration. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RegisterEventInterestResult". - */ -/** @experimental */ -export interface RegisterEventInterestResult { - /** - * Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. - */ - handle: string; -} -/** - * Opaque handle previously returned by `registerInterest` to release. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ReleaseEventInterestParams". - */ -/** @experimental */ -export interface ReleaseEventInterestParams { - /** - * Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. - */ - handle: string; -} -/** - * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteEnableRequest". - */ -/** @experimental */ -export interface RemoteEnableRequest { - mode?: RemoteSessionMode; -} -/** - * GitHub URL for the session and a flag indicating whether remote steering is enabled. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteEnableResult". - */ -/** @experimental */ -export interface RemoteEnableResult { - /** - * GitHub frontend URL for this session - */ - url?: string; - /** - * Whether remote steering is enabled - */ - remoteSteerable: boolean; -} -/** - * New remote-steerability state to persist as a `session.remote_steerable_changed` event. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteNotifySteerableChangedRequest". - */ -/** @experimental */ -export interface RemoteNotifySteerableChangedRequest { - /** - * Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. - */ - remoteSteerable: boolean; -} -/** - * Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteNotifySteerableChangedResult". - */ -/** @experimental */ -export interface RemoteNotifySteerableChangedResult {} -/** - * Remote session connection result. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteSessionConnectionResult". - */ -/** @experimental */ -export interface RemoteSessionConnectionResult { - /** - * SDK session ID for the connected remote session. - */ - sessionId: string; - metadata: ConnectedRemoteSessionMetadata; -} -/** - * Schema for the `ScheduleEntry` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleEntry". - */ -/** @experimental */ -export interface ScheduleEntry { - /** - * Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). - */ - id: number; - /** - * Interval between scheduled ticks, in milliseconds. - */ - intervalMs: number; - /** - * Prompt text that gets enqueued on every tick. - */ - prompt: string; - /** - * Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). - */ - recurring: boolean; - /** - * Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. - */ - displayPrompt?: string; - /** - * ISO 8601 timestamp when the next tick is scheduled to fire. - */ - nextRunAt: string; -} -/** - * Snapshot of the currently active recurring prompts for this session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleList". - */ -/** @experimental */ -export interface ScheduleList { - /** - * Active scheduled prompts, ordered by id. - */ - entries: ScheduleEntry[]; -} -/** - * Identifier of the scheduled prompt to remove. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleStopRequest". - */ -/** @experimental */ -export interface ScheduleStopRequest { - /** - * Id of the scheduled prompt to remove. - */ - id: number; -} -/** - * Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleStopResult". - */ -/** @experimental */ -export interface ScheduleStopResult { - entry?: ScheduleEntry; -} -/** - * File attachment - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentFile". - */ -export interface SendAttachmentFile { - /** - * Attachment type discriminator - */ - type: "file"; - /** - * Absolute file path - */ - path: string; - /** - * User-facing display name for the attachment - */ - displayName: string; - lineRange?: SendAttachmentFileLineRange; -} -/** - * Optional line range to scope the attachment to a specific section of the file - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentFileLineRange". - */ -export interface SendAttachmentFileLineRange { - /** - * Start line number (1-based) - */ - start: number; - /** - * End line number (1-based, inclusive) - */ - end: number; -} -/** - * Directory attachment - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentDirectory". - */ -export interface SendAttachmentDirectory { - /** - * Attachment type discriminator - */ - type: "directory"; - /** - * Absolute directory path - */ - path: string; - /** - * User-facing display name for the attachment - */ - displayName: string; -} -/** - * Code selection attachment from an editor - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentSelection". - */ -export interface SendAttachmentSelection { - /** - * Attachment type discriminator - */ - type: "selection"; - /** - * Absolute path to the file containing the selection - */ - filePath: string; - /** - * User-facing display name for the selection - */ - displayName: string; - /** - * The selected text content - */ - text: string; - selection: SendAttachmentSelectionDetails; -} -/** - * Position range of the selection within the file - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentSelectionDetails". - */ -export interface SendAttachmentSelectionDetails { - start: SendAttachmentSelectionDetailsStart; - end: SendAttachmentSelectionDetailsEnd; -} -/** - * Start position of the selection - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentSelectionDetailsStart". - */ -export interface SendAttachmentSelectionDetailsStart { - /** - * Start line number (0-based) - */ - line: number; - /** - * Start character offset within the line (0-based) - */ - character: number; -} -/** - * End position of the selection - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentSelectionDetailsEnd". - */ -export interface SendAttachmentSelectionDetailsEnd { - /** - * End line number (0-based) - */ - line: number; - /** - * End character offset within the line (0-based) - */ - character: number; -} -/** - * GitHub issue, pull request, or discussion reference - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentGithubReference". - */ -export interface SendAttachmentGithubReference { - /** - * Attachment type discriminator - */ - type: "github_reference"; - /** - * Issue, pull request, or discussion number - */ - number: number; - /** - * Title of the referenced item - */ - title: string; - referenceType: SendAttachmentGithubReferenceType; - /** - * Current state of the referenced item (e.g., open, closed, merged) - */ - state: string; - /** - * URL to the referenced item on GitHub - */ - url: string; -} -/** - * Blob attachment with inline base64-encoded data - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentBlob". - */ -export interface SendAttachmentBlob { - /** - * Attachment type discriminator - */ - type: "blob"; - /** - * Base64-encoded content - */ - data: string; - /** - * MIME type of the inline data - */ - mimeType: string; - /** - * User-facing display name for the attachment - */ - displayName?: string; -} -/** - * Parameters for sending a user message to the session - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendRequest". - */ -export interface SendRequest { - /** - * The user message text - */ - prompt: string; - /** - * If provided, this is shown in the timeline instead of `prompt` - */ - displayPrompt?: string; - /** - * Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message - */ - attachments?: SendAttachment[]; - mode?: SendMode; - /** - * If true, adds the message to the front of the queue instead of the end - */ - prepend?: boolean; - /** - * If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. - */ - billable?: boolean; - /** - * If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange - */ - requiredTool?: string; - /** - * Optional provenance tag copied to the resulting user.message event. Supported values are `system`, `command-*`, and `schedule-*`. - */ - source?: { - [k: string]: unknown | undefined; - }; - agentMode?: SendAgentMode; - /** - * Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. - */ - requestHeaders?: { - [k: string]: string | undefined; - }; - /** - * W3C Trace Context traceparent header for distributed tracing of this agent turn - */ - traceparent?: string; - /** - * W3C Trace Context tracestate header for distributed tracing - */ - tracestate?: string; - /** - * If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. - */ - wait?: boolean; -} -/** - * Result of sending a user message - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendResult". - */ -export interface SendResult { - /** - * Unique identifier assigned to the message - */ - messageId: string; -} -/** - * Schema for the `ServerSkill` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerSkill". - */ -export interface ServerSkill { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Description of what the skill does - */ - description: string; - source: SkillSource; - /** - * Whether the skill can be invoked by the user as a slash command - */ - userInvocable: boolean; - /** - * Whether the skill is currently enabled (based on global config) - */ - enabled: boolean; - /** - * Absolute path to the skill file - */ - path?: string; - /** - * The project path this skill belongs to (only for project/inherited skills) - */ - projectPath?: string; -} -/** - * Skills discovered across global and project sources. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerSkillList". - */ -export interface ServerSkillList { - /** - * All discovered skills across all sources - */ - skills: ServerSkill[]; -} -/** - * Authentication status and account metadata for the session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionAuthStatus". - */ -export interface SessionAuthStatus { - /** - * Whether the session has resolved authentication - */ - isAuthenticated: boolean; - authType?: AuthInfoType; - /** - * Authentication host URL - */ - host?: string; - /** - * Authenticated login/username, if available - */ - login?: string; - /** - * Human-readable authentication status description - */ - statusMessage?: string; - /** - * Copilot plan tier (e.g., individual_pro, business) - */ - copilotPlan?: string; -} -/** - * Map of sessionId -> bytes freed by removing the session's workspace directory. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionBulkDeleteResult". - */ -/** @experimental */ -export interface SessionBulkDeleteResult { - /** - * Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). - */ - freedBytes: { - [k: string]: number | undefined; - }; -} -/** - * Schema for the `SessionContext` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionContext". - */ -/** @experimental */ -export interface SessionContext { - /** - * Most recent working directory for this session - */ - cwd: string; - /** - * Git repository root, if the cwd was inside a git repo - */ - gitRoot?: string; - /** - * Repository slug in `owner/name` form, when known - */ - repository?: string; - hostType?: SessionContextHostType; - /** - * Active git branch - */ - branch?: string; -} -/** - * The same metadata records, with summary and context fields backfilled where available. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionEnrichMetadataResult". - */ -/** @experimental */ -export interface SessionEnrichMetadataResult { - /** - * Same records, with summary and context backfilled - */ - sessions: SessionMetadata[]; -} -/** - * Schema for the `SessionMetadata` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMetadata". - */ -/** @experimental */ -export interface SessionMetadata { - /** - * Stable session identifier - */ - sessionId: string; - /** - * Session creation time as an ISO 8601 timestamp - */ - startTime: string; - /** - * Last-modified time of the session's persisted state, as ISO 8601 - */ - modifiedTime: string; - /** - * Short summary of the session, when one has been derived - */ - summary?: string; - /** - * Optional human-friendly name set via /rename - */ - name?: string; - /** - * True for remote (GitHub) sessions; false for local - */ - isRemote: boolean; - context?: SessionContext; - /** - * GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. - */ - mcTaskId?: string; -} -/** - * File path, content to append, and optional mode for the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsAppendFileRequest". - */ -export interface SessionFsAppendFileRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; - /** - * Content to append - */ - content: string; - /** - * Optional POSIX-style mode for newly created files - */ - mode?: number; -} -/** - * Describes a filesystem error. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsError". - */ -export interface SessionFsError { - code: SessionFsErrorCode; - /** - * Free-form detail about the error, for logging/diagnostics - */ - message?: string; -} -/** - * Path to test for existence in the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsExistsRequest". - */ -export interface SessionFsExistsRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; -} -/** - * Indicates whether the requested path exists in the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsExistsResult". - */ -export interface SessionFsExistsResult { - /** - * Whether the path exists - */ - exists: boolean; -} -/** - * Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsMkdirRequest". - */ -export interface SessionFsMkdirRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; - /** - * Create parent directories as needed - */ - recursive?: boolean; - /** - * Optional POSIX-style mode for newly created directories - */ - mode?: number; -} -/** - * Directory path whose entries should be listed from the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirRequest". - */ -export interface SessionFsReaddirRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; -} -/** - * Names of entries in the requested directory, or a filesystem error if the read failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirResult". - */ -export interface SessionFsReaddirResult { - /** - * Entry names in the directory - */ - entries: string[]; - error?: SessionFsError; -} -/** - * Schema for the `SessionFsReaddirWithTypesEntry` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesEntry". - */ -export interface SessionFsReaddirWithTypesEntry { - /** - * Entry name - */ - name: string; - type: SessionFsReaddirWithTypesEntryType; -} -/** - * Directory path whose entries (with type information) should be listed from the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesRequest". - */ -export interface SessionFsReaddirWithTypesRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; -} -/** - * Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesResult". - */ -export interface SessionFsReaddirWithTypesResult { - /** - * Directory entries with type information - */ - entries: SessionFsReaddirWithTypesEntry[]; - error?: SessionFsError; -} -/** - * Path of the file to read from the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileRequest". - */ -export interface SessionFsReadFileRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; -} -/** - * File content as a UTF-8 string, or a filesystem error if the read failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileResult". - */ -export interface SessionFsReadFileResult { - /** - * File content as UTF-8 string - */ - content: string; - error?: SessionFsError; -} -/** - * Source and destination paths for renaming or moving an entry in the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsRenameRequest". - */ -export interface SessionFsRenameRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Source path using SessionFs conventions - */ - src: string; - /** - * Destination path using SessionFs conventions - */ - dest: string; -} -/** - * Path to remove from the client-provided session filesystem, with options for recursive removal and force. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsRmRequest". - */ -export interface SessionFsRmRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; - /** - * Remove directories and their contents recursively - */ - recursive?: boolean; - /** - * Ignore errors if the path does not exist - */ - force?: boolean; -} -/** - * Optional capabilities declared by the provider - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderCapabilities". - */ -export interface SessionFsSetProviderCapabilities { - /** - * Whether the provider supports SQLite query/exists operations - */ - sqlite?: boolean; -} -/** - * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderRequest". - */ -export interface SessionFsSetProviderRequest { - /** - * Initial working directory for sessions - */ - initialCwd: string; - /** - * Path within each session's SessionFs where the runtime stores files for that session - */ - sessionStatePath: string; - conventions: SessionFsSetProviderConventions; - capabilities?: SessionFsSetProviderCapabilities; -} -/** - * Indicates whether the calling client was registered as the session filesystem provider. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderResult". - */ -export interface SessionFsSetProviderResult { - /** - * Whether the provider was set successfully - */ - success: boolean; -} -/** - * Indicates whether the per-session SQLite database already exists. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteExistsResult". - */ -export interface SessionFsSqliteExistsResult { - /** - * Whether the session database already exists - */ - exists: boolean; -} -/** - * SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteQueryRequest". - */ -export interface SessionFsSqliteQueryRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * SQL query to execute - */ - query: string; - queryType: SessionFsSqliteQueryType; - /** - * Optional named bind parameters - */ - params?: { - [k: string]: (string | number | null) | undefined; - }; -} -/** - * Query results including rows, columns, and rows affected, or a filesystem error if execution failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteQueryResult". - */ -export interface SessionFsSqliteQueryResult { - /** - * For SELECT: array of row objects. For others: empty array. - */ - rows: { - [k: string]: unknown | undefined; - }[]; - /** - * Column names from the result set - */ - columns: string[]; - /** - * Number of rows affected (for INSERT/UPDATE/DELETE) - */ - rowsAffected: number; - /** - * SQLite last_insert_rowid() value for INSERT. - */ - lastInsertRowid?: number; - error?: SessionFsError; -} -/** - * Path whose metadata should be returned from the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsStatRequest". - */ -export interface SessionFsStatRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; -} -/** - * Filesystem metadata for the requested path, or a filesystem error if the stat failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsStatResult". - */ -export interface SessionFsStatResult { - /** - * Whether the path is a file - */ - isFile: boolean; - /** - * Whether the path is a directory - */ - isDirectory: boolean; - /** - * File size in bytes - */ - size: number; - /** - * ISO 8601 timestamp of last modification - */ - mtime: string; - /** - * ISO 8601 timestamp of creation - */ - birthtime: string; - error?: SessionFsError; -} -/** - * File path, content to write, and optional mode for the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsWriteFileRequest". - */ -export interface SessionFsWriteFileRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; - /** - * Content to write - */ - content: string; - /** - * Optional POSIX-style mode for newly created files - */ - mode?: number; -} -/** - * Schema for the `SessionInstalledPlugin` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPlugin". - */ -/** @experimental */ -export interface SessionInstalledPlugin { - /** - * Plugin name - */ - name: string; - /** - * Marketplace the plugin came from (empty string for direct repo installs) - */ - marketplace: string; - /** - * Installed version, if known - */ - version?: string; - /** - * Installation timestamp (ISO-8601) - */ - installed_at: string; - /** - * Whether the plugin is currently enabled - */ - enabled: boolean; - /** - * Path where the plugin is cached locally - */ - cache_path?: string; - source?: SessionInstalledPluginSource; -} -/** - * Schema for the `SessionInstalledPluginSourceGithub` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSourceGithub". - */ -/** @experimental */ -export interface SessionInstalledPluginSourceGithub { - /** - * Constant value. Always "github". - */ - source: "github"; - repo: string; - ref?: string; - path?: string; -} -/** - * Schema for the `SessionInstalledPluginSourceUrl` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSourceUrl". - */ -/** @experimental */ -export interface SessionInstalledPluginSourceUrl { - /** - * Constant value. Always "url". - */ - source: "url"; - url: string; - ref?: string; - path?: string; -} -/** - * Schema for the `SessionInstalledPluginSourceLocal` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSourceLocal". - */ -/** @experimental */ -export interface SessionInstalledPluginSourceLocal { - /** - * Constant value. Always "local". - */ - source: "local"; - path: string; -} -/** - * Persisted sessions matching the filter, ordered most-recently-modified first. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionList". - */ -/** @experimental */ -export interface SessionList { - /** - * Sessions ordered most-recently-modified first - */ - sessions: SessionMetadata[]; -} -/** - * Queued repo-level startup prompts and the total hook command count after loading. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionLoadDeferredRepoHooksResult". - */ -/** @experimental */ -export interface SessionLoadDeferredRepoHooksResult { - /** - * Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. - */ - startupPrompts: string[]; - /** - * Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. - */ - hookCount: number; -} -/** - * Point-in-time snapshot of slow-changing session identifier and state fields - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMetadataSnapshot". - */ -/** @experimental */ -export interface SessionMetadataSnapshot { - /** - * The unique identifier of the session - */ - sessionId: string; - /** - * ISO 8601 timestamp of when the session started - */ - startTime: string; - /** - * ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. - */ - modifiedTime: string; - /** - * Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process) - */ - isRemote: boolean; - /** - * True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. - */ - alreadyInUse: boolean; - /** - * Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace - */ - workspacePath: string | null; - /** - * User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. - */ - initialName?: string; - remoteMetadata?: MetadataSnapshotRemoteMetadata; - /** - * Short human-readable summary of the session, if known. Omitted when no summary has been generated. - */ - summary?: string; - /** - * Absolute path to the session's current working directory - */ - workingDirectory: string; - currentMode: MetadataSnapshotCurrentMode; - /** - * Currently selected model identifier, if any - */ - selectedModel?: string; - /** - * Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). - */ - workspace?: WorkspaceSummary | null; -} -/** - * Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionPruneResult". - */ -/** @experimental */ -export interface SessionPruneResult { - /** - * Session IDs that were deleted (always empty in dry-run mode) - */ - deleted: string[]; - /** - * Session IDs that would be deleted in dry-run mode (always empty otherwise) - */ - candidates: string[]; - /** - * Session IDs that were skipped (e.g., named sessions) - */ - skipped: string[]; - /** - * Total bytes freed (actual when not dry-run, projected when dry-run) - */ - freedBytes: number; - /** - * True when no deletions were actually performed - */ - dryRun: boolean; -} -/** - * Session IDs to close, deactivate, and delete from disk. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsBulkDeleteRequest". - */ -/** @experimental */ -export interface SessionsBulkDeleteRequest { - /** - * Session IDs to close, deactivate, and delete from disk - */ - sessionIds: string[]; -} -/** - * Session IDs to test for live in-use locks. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCheckInUseRequest". - */ -/** @experimental */ -export interface SessionsCheckInUseRequest { - /** - * Session IDs to test for live in-use locks - */ - sessionIds: string[]; -} -/** - * Session IDs from the input set that are currently in use by another process. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCheckInUseResult". - */ -/** @experimental */ -export interface SessionsCheckInUseResult { - /** - * Session IDs from the input set that are currently held by another running process via an alive lock file - */ - inUse: string[]; -} -/** - * Session ID to close. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCloseRequest". - */ -/** @experimental */ -export interface SessionsCloseRequest { - /** - * Session ID to close - */ - sessionId: string; -} -/** - * Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCloseResult". - */ -/** @experimental */ -export interface SessionsCloseResult {} -/** - * Session metadata records to enrich with summary and context information. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsEnrichMetadataRequest". - */ -/** @experimental */ -export interface SessionsEnrichMetadataRequest { - /** - * Session metadata records to enrich. Records that already have summary and context are returned unchanged. - */ - sessions: SessionMetadata[]; -} -/** - * New auth credentials to install on the session. Omit to leave credentials unchanged. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSetCredentialsParams". - */ -export interface SessionSetCredentialsParams { - credentials?: AuthInfo; -} -/** - * Indicates whether the credential update succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSetCredentialsResult". - */ -export interface SessionSetCredentialsResult { - /** - * Whether the operation succeeded - */ - success: boolean; -} -/** - * UUID prefix to resolve to a unique session ID. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByPrefixRequest". - */ -/** @experimental */ -export interface SessionsFindByPrefixRequest { - /** - * UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. - */ - prefix: string; -} -/** - * Session ID matching the prefix, omitted when no unique match exists. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByPrefixResult". - */ -/** @experimental */ -export interface SessionsFindByPrefixResult { - /** - * Omitted when no unique session matches the prefix (no match or ambiguous) - */ - sessionId?: string; -} -/** - * GitHub task ID to look up. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByTaskIDRequest". - */ -/** @experimental */ -export interface SessionsFindByTaskIDRequest { - /** - * GitHub task ID to look up - */ - taskId: string; -} -/** - * ID of the local session bound to the given GitHub task, or omitted when none. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByTaskIDResult". - */ -/** @experimental */ -export interface SessionsFindByTaskIDResult { - /** - * Omitted when no local session is bound to that GitHub task - */ - sessionId?: string; -} -/** - * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsForkRequest". + * via the `definition` "SessionFsReaddirResult". */ -/** @experimental */ -export interface SessionsForkRequest { - /** - * Source session ID to fork from - */ - sessionId: string; - /** - * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. - */ - toEventId?: string; +export interface SessionFsReaddirResult { /** - * Optional friendly name to assign to the forked session. + * Entry names in the directory */ - name?: string; + entries: string[]; + error?: SessionFsError; } /** - * Identifier and optional friendly name assigned to the newly forked session. + * Schema for the `SessionFsReaddirWithTypesEntry` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsForkResult". + * via the `definition` "SessionFsReaddirWithTypesEntry". */ -/** @experimental */ -export interface SessionsForkResult { - /** - * The new forked session's ID - */ - sessionId: string; +export interface SessionFsReaddirWithTypesEntry { /** - * Friendly name assigned to the forked session, if any. + * Entry name */ - name?: string; + name: string; + type: SessionFsReaddirWithTypesEntryType; } /** - * Session ID whose event-log file path to compute. + * Directory path whose entries (with type information) should be listed from the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetEventFilePathRequest". + * via the `definition` "SessionFsReaddirWithTypesRequest". */ -/** @experimental */ -export interface SessionsGetEventFilePathRequest { +export interface SessionFsReaddirWithTypesRequest { /** - * Session ID whose event-log file path to compute + * Target session identifier */ sessionId: string; -} -/** - * Absolute path to the session's events.jsonl file on disk. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetEventFilePathResult". - */ -/** @experimental */ -export interface SessionsGetEventFilePathResult { /** - * Absolute path to the session's events.jsonl file + * Path using SessionFs conventions */ - filePath: string; -} -/** - * Optional working-directory context used to score session relevance. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetLastForContextRequest". - */ -/** @experimental */ -export interface SessionsGetLastForContextRequest { - context?: SessionContext; + path: string; } /** - * Most-relevant session ID for the supplied context, or omitted when no sessions exist. + * Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetLastForContextResult". + * via the `definition` "SessionFsReaddirWithTypesResult". */ -/** @experimental */ -export interface SessionsGetLastForContextResult { +export interface SessionFsReaddirWithTypesResult { /** - * Most-relevant session ID for the supplied context, or omitted when no sessions exist + * Directory entries with type information */ - sessionId?: string; + entries: SessionFsReaddirWithTypesEntry[]; + error?: SessionFsError; } /** - * Session ID to look up the persisted remote-steerable flag for. + * Path of the file to read from the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetPersistedRemoteSteerableRequest". + * via the `definition` "SessionFsReadFileRequest". */ -/** @experimental */ -export interface SessionsGetPersistedRemoteSteerableRequest { +export interface SessionFsReadFileRequest { /** - * Session ID to look up the persisted remote-steerable flag for + * Target session identifier */ sessionId: string; -} -/** - * The session's persisted remote-steerable flag, or omitted when no value has been persisted. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetPersistedRemoteSteerableResult". - */ -/** @experimental */ -export interface SessionsGetPersistedRemoteSteerableResult { /** - * The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted + * Path using SessionFs conventions */ - remoteSteerable?: boolean; + path: string; } /** - * Map of sessionId -> on-disk size in bytes for each session's workspace directory. + * File content as a UTF-8 string, or a filesystem error if the read failed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSizes". + * via the `definition` "SessionFsReadFileResult". */ -/** @experimental */ -export interface SessionSizes { +export interface SessionFsReadFileResult { /** - * Map of sessionId -> on-disk size in bytes for the session's workspace directory + * File content as UTF-8 string */ - sizes: { - [k: string]: number | undefined; - }; + content: string; + error?: SessionFsError; } /** - * Optional metadata-load limit and context filter applied to the returned sessions. + * Source and destination paths for renaming or moving an entry in the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsListRequest". + * via the `definition` "SessionFsRenameRequest". */ -/** @experimental */ -export interface SessionsListRequest { +export interface SessionFsRenameRequest { /** - * When provided, only the first N sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every session. + * Target session identifier */ - metadataLimit?: number; + sessionId: string; /** - * Optional filter applied to the returned sessions + * Source path using SessionFs conventions */ - filter?: { - /** - * Match sessions whose context.cwd equals this value - */ - cwd?: string; - /** - * Match sessions whose context.gitRoot equals this value - */ - gitRoot?: string; - /** - * Match sessions whose context.repository equals this value - */ - repository?: string; - /** - * Match sessions whose context.branch equals this value - */ - branch?: string; - }; -} -/** - * Active session ID whose deferred repo-level hooks should be loaded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsLoadDeferredRepoHooksRequest". - */ -/** @experimental */ -export interface SessionsLoadDeferredRepoHooksRequest { + src: string; /** - * Active session ID whose deferred repo-level hooks should be loaded + * Destination path using SessionFs conventions */ - sessionId: string; + dest: string; } /** - * Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * Path to remove from the client-provided session filesystem, with options for recursive removal and force. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsPruneOldRequest". + * via the `definition` "SessionFsRmRequest". */ -/** @experimental */ -export interface SessionsPruneOldRequest { +export interface SessionFsRmRequest { /** - * Delete sessions whose modifiedTime is at least this many days old + * Target session identifier */ - olderThanDays: number; + sessionId: string; /** - * When true, only report what would be deleted without performing any deletion + * Path using SessionFs conventions */ - dryRun?: boolean; + path: string; /** - * When true, named sessions (set via /rename) are also eligible for pruning + * Remove directories and their contents recursively */ - includeNamed?: boolean; + recursive?: boolean; /** - * Session IDs that should never be considered for pruning + * Ignore errors if the path does not exist */ - excludeSessionIds?: string[]; + force?: boolean; } /** - * Session ID whose in-use lock should be released. + * Optional capabilities declared by the provider * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReleaseLockRequest". + * via the `definition` "SessionFsSetProviderCapabilities". */ -/** @experimental */ -export interface SessionsReleaseLockRequest { +export interface SessionFsSetProviderCapabilities { /** - * Session ID whose in-use lock should be released + * Whether the provider supports SQLite query/exists operations */ - sessionId: string; + sqlite?: boolean; } /** - * Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReleaseLockResult". - */ -/** @experimental */ -export interface SessionsReleaseLockResult {} -/** - * Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReloadPluginHooksRequest". + * via the `definition` "SessionFsSetProviderRequest". */ -/** @experimental */ -export interface SessionsReloadPluginHooksRequest { +export interface SessionFsSetProviderRequest { /** - * Active session ID to reload hooks for + * Initial working directory for sessions */ - sessionId: string; + initialCwd: string; /** - * When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. + * Path within each session's SessionFs where the runtime stores files for that session */ - deferRepoHooks?: boolean; + sessionStatePath: string; + conventions: SessionFsSetProviderConventions; + capabilities?: SessionFsSetProviderCapabilities; } /** - * Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReloadPluginHooksResult". - */ -/** @experimental */ -export interface SessionsReloadPluginHooksResult {} -/** - * Session ID whose pending events should be flushed to disk. + * Indicates whether the calling client was registered as the session filesystem provider. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSaveRequest". + * via the `definition` "SessionFsSetProviderResult". */ -/** @experimental */ -export interface SessionsSaveRequest { +export interface SessionFsSetProviderResult { /** - * Session ID whose pending events should be flushed to disk + * Whether the provider was set successfully */ - sessionId: string; + success: boolean; } /** - * Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSaveResult". - */ -/** @experimental */ -export interface SessionsSaveResult {} -/** - * Manager-wide additional plugins to register; replaces any previously-configured set. + * Indicates whether the per-session SQLite database already exists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSetAdditionalPluginsRequest". + * via the `definition` "SessionFsSqliteExistsResult". */ -/** @experimental */ -export interface SessionsSetAdditionalPluginsRequest { +export interface SessionFsSqliteExistsResult { /** - * Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. + * Whether the session database already exists */ - plugins: InstalledPlugin[]; + exists: boolean; } /** - * Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSetAdditionalPluginsResult". - */ -/** @experimental */ -export interface SessionsSetAdditionalPluginsResult {} -/** - * Patch of mutable session options to apply to the running session. + * SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionUpdateOptionsParams". + * via the `definition` "SessionFsSqliteQueryRequest". */ -/** @experimental */ -export interface SessionUpdateOptionsParams { - /** - * The model ID to use for assistant turns. - */ - model?: string; - /** - * Reasoning effort for the selected model (model-defined enum). - */ - reasoningEffort?: string; - /** - * Identifier of the client driving the session. - */ - clientName?: string; - /** - * Identifier sent to LSP-style integrations. - */ - lspClientName?: string; - /** - * Stable integration identifier used for analytics and rate-limit attribution. - */ - integrationId?: string; +export interface SessionFsSqliteQueryRequest { /** - * Map of feature-flag IDs to their boolean enabled state. + * Target session identifier */ - featureFlags?: { - [k: string]: boolean | undefined; - }; + sessionId: string; /** - * Whether experimental capabilities are enabled. + * SQL query to execute */ - isExperimentalMode?: boolean; + query: string; + queryType: SessionFsSqliteQueryType; /** - * Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the runtime. + * Optional named bind parameters */ - provider?: { - [k: string]: unknown | undefined; + params?: { + [k: string]: (string | number | null) | undefined; }; +} +/** + * Query results including rows, columns, and rows affected, or a filesystem error if execution failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteQueryResult". + */ +export interface SessionFsSqliteQueryResult { /** - * Absolute working-directory path for shell tools. - */ - workingDirectory?: string; - /** - * Allowlist of tool names available to this session. - */ - availableTools?: string[]; - /** - * Denylist of tool names for this session. - */ - excludedTools?: string[]; - /** - * Whether shell-script safety heuristics are enabled. - */ - enableScriptSafety?: boolean; - /** - * Shell init profile (`None` or `NonInteractive`). - */ - shellInitProfile?: string; - /** - * Per-shell process flags (e.g., `pwsh` arguments). - */ - shellProcessFlags?: string[]; - /** - * Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime. + * For SELECT: array of row objects. For others: empty array. */ - sandboxConfig?: { + rows: { [k: string]: unknown | undefined; - }; - /** - * Whether interactive shell sessions are logged. - */ - logInteractiveShells?: boolean; - envValueMode?: OptionsUpdateEnvValueMode; - /** - * Additional directories to search for skills. - */ - skillDirectories?: string[]; - /** - * Skill IDs that should be excluded from this session. - */ - disabledSkills?: string[]; + }[]; /** - * Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions` and the runtime-side `ON_DEMAND_INSTRUCTIONS` feature flag. + * Column names from the result set */ - enableOnDemandInstructionDiscovery?: boolean; + columns: string[]; /** - * Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. + * Number of rows affected (for INSERT/UPDATE/DELETE) */ - installedPlugins?: SessionInstalledPlugin[]; + rowsAffected: number; /** - * Whether to default custom agents to local-only execution. + * Last inserted row ID (for INSERT) */ - customAgentsLocalOnly?: boolean; + lastInsertRowid?: number; + error?: SessionFsError; +} +/** + * Path whose metadata should be returned from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsStatRequest". + */ +export interface SessionFsStatRequest { /** - * Whether to skip loading custom instruction sources. + * Target session identifier */ - skipCustomInstructions?: boolean; + sessionId: string; /** - * Instruction source IDs to exclude from the system prompt. + * Path using SessionFs conventions */ - disabledInstructionSources?: string[]; + path: string; +} +/** + * Filesystem metadata for the requested path, or a filesystem error if the stat failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsStatResult". + */ +export interface SessionFsStatResult { /** - * Whether to include the `Co-authored-by` trailer in commit messages. + * Whether the path is a file */ - coauthorEnabled?: boolean; + isFile: boolean; /** - * Optional path for trajectory output. + * Whether the path is a directory */ - trajectoryFile?: string; + isDirectory: boolean; /** - * Whether to stream model responses. + * File size in bytes */ - enableStreaming?: boolean; + size: number; /** - * Override URL for the Copilot API endpoint. + * ISO 8601 timestamp of last modification */ - copilotUrl?: string; + mtime: string; /** - * Whether to disable the `ask_user` tool (encourages autonomous behavior). + * ISO 8601 timestamp of creation */ - askUserDisabled?: boolean; + birthtime: string; + error?: SessionFsError; +} +/** + * File path, content to write, and optional mode for the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsWriteFileRequest". + */ +export interface SessionFsWriteFileRequest { /** - * Whether to allow auto-mode continuation across turns. + * Target session identifier */ - continueOnAutoMode?: boolean; + sessionId: string; /** - * Whether the session is running in an interactive UI. + * Path using SessionFs conventions */ - runningInInteractiveMode?: boolean; + path: string; /** - * Whether to surface reasoning-summary events from the model. + * Content to write */ - enableReasoningSummaries?: boolean; + content: string; /** - * Runtime context discriminator (e.g., `cli`, `actions`). + * Optional POSIX-style mode for newly created files */ - agentContext?: string; + mode?: number; +} +/** + * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsForkRequest". + */ +/** @experimental */ +export interface SessionsForkRequest { /** - * Override directory for the session-events log. When unset, the runtime's default events log directory is used. + * Source session ID to fork from */ - eventsLogDirectory?: string; + sessionId: string; /** - * Additional content-exclusion policies to merge into the session's policy set. Opaque shape; see `ContentExclusionApiResponse` in the runtime. + * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. */ - additionalContentExclusionPolicies?: unknown[]; + toEventId?: string; /** - * Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). + * Optional friendly name to assign to the forked session. */ - manageScheduleEnabled?: boolean; + name?: string; } /** - * Indicates whether the session options patch was applied successfully. + * Identifier and optional friendly name assigned to the newly forked session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionUpdateOptionsResult". + * via the `definition` "SessionsForkResult". */ /** @experimental */ -export interface SessionUpdateOptionsResult { +export interface SessionsForkResult { /** - * Whether the operation succeeded + * The new forked session's ID */ - success: boolean; + sessionId: string; + /** + * Friendly name assigned to the forked session, if any. + */ + name?: string; } /** * Shell command to run, with optional working directory and timeout in milliseconds. @@ -6260,19 +3061,6 @@ export interface ShellKillResult { */ killed: boolean; } -/** - * Parameters for shutting down the session - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShutdownRequest". - */ -export interface ShutdownRequest { - type?: ShutdownType; - /** - * Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. - */ - reason?: string; -} /** * Schema for the `Skill` type. * @@ -6302,10 +3090,6 @@ export interface Skill { * Absolute path to the skill file */ path?: string; - /** - * Name of the plugin that provides the skill, when source is 'plugin' - */ - pluginName?: string; } /** * Skills available to the session, with their enabled state. @@ -6374,48 +3158,6 @@ export interface SkillsEnableRequest { */ name: string; } -/** - * Skills invoked during this session, ordered by invocation time (most recent last). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsGetInvokedResult". - */ -/** @experimental */ -export interface SkillsGetInvokedResult { - /** - * Skills invoked during this session, ordered by invocation time (most recent last) - */ - skills: SkillsInvokedSkill[]; -} -/** - * Schema for the `SkillsInvokedSkill` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsInvokedSkill". - */ -/** @experimental */ -export interface SkillsInvokedSkill { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Path to the SKILL.md file - */ - path: string; - /** - * Full content of the skill file - */ - content: string; - /** - * Tools that should be auto-approved when this skill is active, captured at invocation time - */ - allowedTools?: string[]; - /** - * Turn number when the skill was invoked - */ - invokedAtTurn: number; -} /** * Diagnostics from reloading skill definitions, with warnings and errors as separate lists. * @@ -6668,52 +3410,6 @@ export interface TasksCancelResult { */ cancelled: boolean; } -/** - * The first sync-waiting task that can currently be promoted to background mode. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksGetCurrentPromotableResult". - */ -/** @experimental */ -export interface TasksGetCurrentPromotableResult { - task?: TaskInfo; -} -/** - * Identifier of the background task to fetch progress for. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksGetProgressRequest". - */ -/** @experimental */ -export interface TasksGetProgressRequest { - /** - * Task identifier (agent ID or shell ID) - */ - id: string; -} -/** - * Progress information for the task, or null when no task with that ID is tracked. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksGetProgressResult". - */ -/** @experimental */ -export interface TasksGetProgressResult { - /** - * Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. - */ - progress?: TaskProgress | null; -} -/** - * The promoted task as it now exists in background mode, omitted if no promotable task was waiting. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksPromoteCurrentToBackgroundResult". - */ -/** @experimental */ -export interface TasksPromoteCurrentToBackgroundResult { - task?: TaskInfo; -} /** * Identifier of the task to promote to background mode. * @@ -6740,14 +3436,6 @@ export interface TasksPromoteToBackgroundResult { */ promoted: boolean; } -/** - * Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksRefreshResult". - */ -/** @experimental */ -export interface TasksRefreshResult {} /** * Identifier of the completed or cancelled task to remove from tracking. * @@ -6854,29 +3542,6 @@ export interface TasksStartAgentResult { */ agentId: string; } -/** - * Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksWaitForPendingResult". - */ -/** @experimental */ -export interface TasksWaitForPendingResult {} -/** - * Feature override key/value pairs to attach to subsequent telemetry events from this session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TelemetrySetFeatureOverridesRequest". - */ -/** @experimental */ -export interface TelemetrySetFeatureOverridesRequest { - /** - * Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. - */ - features: { - [k: string]: string | undefined; - }; -} /** * Schema for the `Tool` type. * @@ -6919,13 +3584,6 @@ export interface ToolList { */ tools: Tool[]; } -/** - * Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsInitializeAndValidateResult". - */ -export interface ToolsInitializeAndValidateResult {} /** * Optional model identifier whose tool overrides should be applied to the listing. * @@ -7212,228 +3870,82 @@ export interface UIElicitationSchemaPropertyString { maxLength?: number; format?: UIElicitationSchemaPropertyStringFormat; /** - * Default value populated in the input when the form is first shown. - */ - default?: string; -} -/** - * Numeric field accepting either a number or an integer. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationSchemaPropertyNumber". - */ -export interface UIElicitationSchemaPropertyNumber { - type: UIElicitationSchemaPropertyNumberType; - /** - * Human-readable label for the field. - */ - title?: string; - /** - * Help text describing the field. - */ - description?: string; - /** - * Minimum allowed value (inclusive). - */ - minimum?: number; - /** - * Maximum allowed value (inclusive). - */ - maximum?: number; - /** - * Default value populated in the input when the form is first shown. - */ - default?: number; -} -/** - * The elicitation response (accept with form values, decline, or cancel) - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponse". - */ -export interface UIElicitationResponse { - action: UIElicitationResponseAction; - content?: UIElicitationResponseContent; -} -/** - * The form values submitted by the user (present when action is 'accept') - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponseContent". - */ -export interface UIElicitationResponseContent { - [k: string]: UIElicitationFieldValue; -} -/** - * Indicates whether the elicitation response was accepted; false if it was already resolved by another client. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResult". - */ -export interface UIElicitationResult { - /** - * Whether the response was accepted. False if the request was already resolved by another client. - */ - success: boolean; -} -/** - * Schema for the `UIExitPlanModeResponse` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIExitPlanModeResponse". - */ -export interface UIExitPlanModeResponse { - /** - * Whether the plan was approved. - */ - approved: boolean; - selectedAction?: UIExitPlanModeAction; - /** - * Whether subsequent edits should be auto-approved without confirmation. - */ - autoApproveEdits?: boolean; - /** - * Feedback from the user when they declined the plan or requested changes. - */ - feedback?: string; -} -/** - * Request ID of a pending `auto_mode_switch.requested` event and the user's response. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingAutoModeSwitchRequest". - */ -export interface UIHandlePendingAutoModeSwitchRequest { - /** - * The unique request ID from the auto_mode_switch.requested event - */ - requestId: string; - response: UIAutoModeSwitchResponse; -} -/** - * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingElicitationRequest". - */ -export interface UIHandlePendingElicitationRequest { - /** - * The unique request ID from the elicitation.requested event - */ - requestId: string; - result: UIElicitationResponse; -} -/** - * Request ID of a pending `exit_plan_mode.requested` event and the user's response. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingExitPlanModeRequest". - */ -export interface UIHandlePendingExitPlanModeRequest { - /** - * The unique request ID from the exit_plan_mode.requested event - */ - requestId: string; - response: UIExitPlanModeResponse; -} -/** - * Indicates whether the pending UI request was resolved by this call. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingResult". - */ -export interface UIHandlePendingResult { - /** - * True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. + * Default value populated in the input when the form is first shown. */ - success: boolean; + default?: string; } /** - * Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). + * Numeric field accepting either a number or an integer. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingSamplingRequest". + * via the `definition` "UIElicitationSchemaPropertyNumber". */ -export interface UIHandlePendingSamplingRequest { +export interface UIElicitationSchemaPropertyNumber { + type: UIElicitationSchemaPropertyNumberType; /** - * The unique request ID from the sampling.requested event + * Human-readable label for the field. */ - requestId: string; - response?: UIHandlePendingSamplingResponse; -} -/** - * Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingSamplingResponse". - */ -export interface UIHandlePendingSamplingResponse { - [k: string]: unknown | undefined; -} -/** - * Request ID of a pending `user_input.requested` event and the user's response. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingUserInputRequest". - */ -export interface UIHandlePendingUserInputRequest { + title?: string; /** - * The unique request ID from the user_input.requested event + * Help text describing the field. */ - requestId: string; - response: UIUserInputResponse; + description?: string; + /** + * Minimum allowed value (inclusive). + */ + minimum?: number; + /** + * Maximum allowed value (inclusive). + */ + maximum?: number; + /** + * Default value populated in the input when the form is first shown. + */ + default?: number; } /** - * Schema for the `UIUserInputResponse` type. + * The elicitation response (accept with form values, decline, or cancel) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIUserInputResponse". + * via the `definition` "UIElicitationResponse". */ -export interface UIUserInputResponse { - /** - * The user's answer text - */ - answer: string; - /** - * True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. - */ - wasFreeform: boolean; +export interface UIElicitationResponse { + action: UIElicitationResponseAction; + content?: UIElicitationResponseContent; } /** - * Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). + * The form values submitted by the user (present when action is 'accept') * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIRegisterDirectAutoModeSwitchHandlerResult". + * via the `definition` "UIElicitationResponseContent". */ -export interface UIRegisterDirectAutoModeSwitchHandlerResult { - /** - * Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. - */ - handle: string; +export interface UIElicitationResponseContent { + [k: string]: UIElicitationFieldValue; } /** - * Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. + * Indicates whether the elicitation response was accepted; false if it was already resolved by another client. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerRequest". + * via the `definition` "UIElicitationResult". */ -export interface UIUnregisterDirectAutoModeSwitchHandlerRequest { +export interface UIElicitationResult { /** - * Handle previously returned by `registerDirectAutoModeSwitchHandler` + * Whether the response was accepted. False if the request was already resolved by another client. */ - handle: string; + success: boolean; } /** - * Indicates whether the handle was active and the registration count was decremented. + * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerResult". + * via the `definition` "UIHandlePendingElicitationRequest". */ -export interface UIUnregisterDirectAutoModeSwitchHandlerResult { +export interface UIHandlePendingElicitationRequest { /** - * True if the handle was active and decremented the counter; false if the handle was unknown. + * The unique request ID from the elicitation.requested event */ - unregistered: boolean; + requestId: string; + result: UIElicitationResponse; } /** * Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals. @@ -7466,9 +3978,9 @@ export interface UsageGetMetricsResult { */ totalApiDurationMs: number; /** - * ISO 8601 timestamp when the session started + * Session start timestamp (epoch milliseconds) */ - sessionStartTime: string; + sessionStartTime: number; codeChanges: UsageMetricsCodeChanges; /** * Per-model token and request metrics, keyed by model identifier @@ -7522,10 +4034,6 @@ export interface UsageMetricsCodeChanges { * Number of distinct files modified */ filesModifiedCount: number; - /** - * Distinct file paths modified during the session - */ - filesModified: string[]; } /** * Schema for the `UsageMetricsModelMetric` type. @@ -7607,26 +4115,6 @@ export interface UsageMetricsModelMetricTokenDetail { */ tokenCount: number; } -/** - * Schema for the `WorkspacesCheckpoints` type. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesCheckpoints". - */ -export interface WorkspacesCheckpoints { - /** - * Checkpoint number assigned by the workspace manager - */ - number: number; - /** - * Human-readable checkpoint title - */ - title: string; - /** - * Filename of the checkpoint within the workspace checkpoints directory - */ - filename: string; -} /** * Relative path and UTF-8 content for the workspace file to create or overwrite. * @@ -7644,7 +4132,7 @@ export interface WorkspacesCreateFileRequest { content: string; } /** - * Current workspace metadata for the session, including its absolute filesystem path when available. + * Current workspace metadata for the session, or null when not available. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "WorkspacesGetWorkspaceResult". @@ -7671,22 +4159,6 @@ export interface WorkspacesGetWorkspaceResult { mc_last_event_id?: string; chronicle_sync_dismissed?: boolean; } | null; - /** - * Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). - */ - path?: string; -} -/** - * Workspace checkpoints in chronological order; empty when the workspace is not enabled. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesListCheckpointsResult". - */ -export interface WorkspacesListCheckpointsResult { - /** - * Workspace checkpoints in chronological order. Empty when workspace is not enabled. - */ - checkpoints: WorkspacesCheckpoints[]; } /** * Relative paths of files stored in the session workspace files directory. @@ -7700,30 +4172,6 @@ export interface WorkspacesListFilesResult { */ files: string[]; } -/** - * Checkpoint number to read. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadCheckpointRequest". - */ -export interface WorkspacesReadCheckpointRequest { - /** - * Checkpoint number to read - */ - number: number; -} -/** - * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadCheckpointResult". - */ -export interface WorkspacesReadCheckpointResult { - /** - * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing - */ - content: string | null; -} /** * Relative path of the workspace file to read. * @@ -7748,43 +4196,6 @@ export interface WorkspacesReadFileResult { */ content: string; } -/** - * Pasted content to save as a UTF-8 file in the session workspace. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesSaveLargePasteRequest". - */ -export interface WorkspacesSaveLargePasteRequest { - /** - * Pasted content to save as a UTF-8 file - */ - content: string; -} -/** - * Descriptor for the saved paste file, or null when the workspace is unavailable. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesSaveLargePasteResult". - */ -export interface WorkspacesSaveLargePasteResult { - /** - * Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions) - */ - saved: { - /** - * Absolute filesystem path to the saved paste file - */ - filePath: string; - /** - * Filename within the workspace files directory - */ - filename: string; - /** - * Size of the saved file in bytes - */ - sizeBytes: number; - } | null; -} /** * Identifies the target session. * @@ -7806,10 +4217,14 @@ export function createServerRpc(connection: MessageConnection) { * * @param params Optional message to echo back to the caller. * - * @returns Server liveness response, including the echoed message, current server timestamp, and protocol version. + * @returns Server liveness response, including the echoed message, current timestamp, and protocol version. */ - ping: async (params: PingRequest): Promise => - connection.sendRequest("ping", params), + ping: async (params: PingRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("ping", params); + }, models: { /** * Lists Copilot models available to the authenticated user. @@ -7818,8 +4233,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns List of Copilot models available to the resolved user, including capabilities and billing metadata. */ - list: async (params: ModelsListRequest): Promise => - connection.sendRequest("models.list", params), + list: async (params: ModelsListRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("models.list", params); + }, }, tools: { /** @@ -7829,8 +4248,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Built-in tools available for the requested model, with their parameters and instructions. */ - list: async (params: ToolsListRequest): Promise => - connection.sendRequest("tools.list", params), + list: async (params: ToolsListRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("tools.list", params); + }, }, account: { /** @@ -7840,8 +4263,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Quota usage snapshots for the resolved user, keyed by quota type. */ - getQuota: async (params: AccountGetQuotaRequest): Promise => - connection.sendRequest("account.getQuota", params), + getQuota: async (params: AccountGetQuotaRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("account.getQuota", params); + }, }, mcp: { config: { @@ -7850,43 +4277,64 @@ export function createServerRpc(connection: MessageConnection) { * * @returns User-configured MCP servers, keyed by server name. */ - list: async (): Promise => - connection.sendRequest("mcp.config.list", {}), + list: async (): Promise => { + return connection.sendRequest("mcp.config.list", {}); + }, /** * Adds an MCP server to user configuration. * * @param params MCP server name and configuration to add to user configuration. */ - add: async (params: McpConfigAddRequest): Promise => - connection.sendRequest("mcp.config.add", params), + add: async (params: McpConfigAddRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("mcp.config.add", params); + }, /** * Updates an MCP server in user configuration. * * @param params MCP server name and replacement configuration to write to user configuration. */ - update: async (params: McpConfigUpdateRequest): Promise => - connection.sendRequest("mcp.config.update", params), + update: async (params: McpConfigUpdateRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("mcp.config.update", params); + }, /** * Removes an MCP server from user configuration. * * @param params MCP server name to remove from user configuration. */ - remove: async (params: McpConfigRemoveRequest): Promise => - connection.sendRequest("mcp.config.remove", params), + remove: async (params: McpConfigRemoveRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("mcp.config.remove", params); + }, /** * Enables MCP servers in user configuration for new sessions. * * @param params MCP server names to enable for new sessions. */ - enable: async (params: McpConfigEnableRequest): Promise => - connection.sendRequest("mcp.config.enable", params), + enable: async (params: McpConfigEnableRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("mcp.config.enable", params); + }, /** * Disables MCP servers in user configuration for new sessions. * * @param params MCP server names to disable for new sessions. */ - disable: async (params: McpConfigDisableRequest): Promise => - connection.sendRequest("mcp.config.disable", params), + disable: async (params: McpConfigDisableRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("mcp.config.disable", params); + }, }, /** * Discovers MCP servers from user, workspace, plugin, and builtin sources. @@ -7895,8 +4343,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns MCP servers discovered from user, workspace, plugin, and built-in sources. */ - discover: async (params: McpDiscoverRequest): Promise => - connection.sendRequest("mcp.discover", params), + discover: async (params: McpDiscoverRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("mcp.discover", params); + }, }, skills: { config: { @@ -7905,8 +4357,12 @@ export function createServerRpc(connection: MessageConnection) { * * @param params Skill names to mark as disabled in global configuration, replacing any previous list. */ - setDisabledSkills: async (params: SkillsConfigSetDisabledSkillsRequest): Promise => - connection.sendRequest("skills.config.setDisabledSkills", params), + setDisabledSkills: async (params: SkillsConfigSetDisabledSkillsRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("skills.config.setDisabledSkills", params); + }, }, /** * Discovers skills across global and project sources. @@ -7915,8 +4371,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Skills discovered across global and project sources. */ - discover: async (params: SkillsDiscoverRequest): Promise => - connection.sendRequest("skills.discover", params), + discover: async (params: SkillsDiscoverRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("skills.discover", params); + }, }, sessionFs: { /** @@ -7926,8 +4386,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Indicates whether the calling client was registered as the session filesystem provider. */ - setProvider: async (params: SessionFsSetProviderRequest): Promise => - connection.sendRequest("sessionFs.setProvider", params), + setProvider: async (params: SessionFsSetProviderRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessionFs.setProvider", params); + }, }, /** @experimental */ sessions: { @@ -7938,8 +4402,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Identifier and optional friendly name assigned to the newly forked session. */ - fork: async (params: SessionsForkRequest): Promise => - connection.sendRequest("sessions.fork", params), + fork: async (params: SessionsForkRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.fork", params); + }, /** * Connects to an existing remote session and exposes it as an SDK session. * @@ -7947,159 +4415,12 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Remote session connection result. */ - connect: async (params: ConnectRemoteSessionParams): Promise => - connection.sendRequest("sessions.connect", params), - /** - * Lists persisted sessions, optionally filtered by working-directory context. - * - * @param params Optional metadata-load limit and context filter applied to the returned sessions. - * - * @returns Persisted sessions matching the filter, ordered most-recently-modified first. - */ - list: async (params: SessionsListRequest): Promise => - connection.sendRequest("sessions.list", params), - /** - * Finds the local session bound to a GitHub task ID, if any. - * - * @param params GitHub task ID to look up. - * - * @returns ID of the local session bound to the given GitHub task, or omitted when none. - */ - findByTaskId: async (params: SessionsFindByTaskIDRequest): Promise => - connection.sendRequest("sessions.findByTaskId", params), - /** - * Resolves a UUID prefix to a unique session ID, if exactly one session matches. - * - * @param params UUID prefix to resolve to a unique session ID. - * - * @returns Session ID matching the prefix, omitted when no unique match exists. - */ - findByPrefix: async (params: SessionsFindByPrefixRequest): Promise => - connection.sendRequest("sessions.findByPrefix", params), - /** - * Returns the most-relevant prior session for a given working-directory context. - * - * @param params Optional working-directory context used to score session relevance. - * - * @returns Most-relevant session ID for the supplied context, or omitted when no sessions exist. - */ - getLastForContext: async (params: SessionsGetLastForContextRequest): Promise => - connection.sendRequest("sessions.getLastForContext", params), - /** - * Computes the absolute path to a session's persisted events.jsonl file. - * - * @param params Session ID whose event-log file path to compute. - * - * @returns Absolute path to the session's events.jsonl file on disk. - */ - getEventFilePath: async (params: SessionsGetEventFilePathRequest): Promise => - connection.sendRequest("sessions.getEventFilePath", params), - /** - * Returns the on-disk byte size of each session's workspace directory. - * - * @returns Map of sessionId -> on-disk size in bytes for each session's workspace directory. - */ - getSizes: async (): Promise => - connection.sendRequest("sessions.getSizes", {}), - /** - * Returns the subset of the supplied session IDs that are currently held by another running process. - * - * @param params Session IDs to test for live in-use locks. - * - * @returns Session IDs from the input set that are currently in use by another process. - */ - checkInUse: async (params: SessionsCheckInUseRequest): Promise => - connection.sendRequest("sessions.checkInUse", params), - /** - * Returns a session's persisted remote-steerable flag, if any has been recorded. - * - * @param params Session ID to look up the persisted remote-steerable flag for. - * - * @returns The session's persisted remote-steerable flag, or omitted when no value has been persisted. - */ - getPersistedRemoteSteerable: async (params: SessionsGetPersistedRemoteSteerableRequest): Promise => - connection.sendRequest("sessions.getPersistedRemoteSteerable", params), - /** - * Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. - * - * @param params Session ID to close. - * - * @returns Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. - */ - close: async (params: SessionsCloseRequest): Promise => - connection.sendRequest("sessions.close", params), - /** - * Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. - * - * @param params Session IDs to close, deactivate, and delete from disk. - * - * @returns Map of sessionId -> bytes freed by removing the session's workspace directory. - */ - bulkDelete: async (params: SessionsBulkDeleteRequest): Promise => - connection.sendRequest("sessions.bulkDelete", params), - /** - * Deletes sessions older than the given threshold, with optional dry-run and exclusion list. - * - * @param params Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). - * - * @returns Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. - */ - pruneOld: async (params: SessionsPruneOldRequest): Promise => - connection.sendRequest("sessions.pruneOld", params), - /** - * Flushes a session's pending events to disk. - * - * @param params Session ID whose pending events should be flushed to disk. - * - * @returns Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). - */ - save: async (params: SessionsSaveRequest): Promise => - connection.sendRequest("sessions.save", params), - /** - * Releases the in-use lock held by this process for a session. - * - * @param params Session ID whose in-use lock should be released. - * - * @returns Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. - */ - releaseLock: async (params: SessionsReleaseLockRequest): Promise => - connection.sendRequest("sessions.releaseLock", params), - /** - * Backfills missing summary and context fields on the supplied session metadata records. - * - * @param params Session metadata records to enrich with summary and context information. - * - * @returns The same metadata records, with summary and context fields backfilled where available. - */ - enrichMetadata: async (params: SessionsEnrichMetadataRequest): Promise => - connection.sendRequest("sessions.enrichMetadata", params), - /** - * Reloads user, plugin, and (optionally) repo hooks on the active session. - * - * @param params Active session ID and an optional flag for deferring repo-level hooks until folder trust. - * - * @returns Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. - */ - reloadPluginHooks: async (params: SessionsReloadPluginHooksRequest): Promise => - connection.sendRequest("sessions.reloadPluginHooks", params), - /** - * Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. - * - * @param params Active session ID whose deferred repo-level hooks should be loaded. - * - * @returns Queued repo-level startup prompts and the total hook command count after loading. - */ - loadDeferredRepoHooks: async (params: SessionsLoadDeferredRepoHooksRequest): Promise => - connection.sendRequest("sessions.loadDeferredRepoHooks", params), - /** - * Replaces the manager-wide additional plugins registered with the session manager. - * - * @param params Manager-wide additional plugins to register; replaces any previously-configured set. - * - * @returns Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. - */ - setAdditionalPlugins: async (params: SessionsSetAdditionalPluginsRequest): Promise => - connection.sendRequest("sessions.setAdditionalPlugins", params), + connect: async (params: ConnectRemoteSessionParams): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.connect", params); + }, }, }; } @@ -8118,70 +4439,46 @@ export function createInternalServerRpc(connection: MessageConnection) { * * @returns Handshake result reporting the server's protocol version and package version on success. */ - connect: async (params: ConnectRequest): Promise => - connection.sendRequest("connect", params), + connect: async (params: ConnectRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("connect", params); + }, }; } /** Create typed session-scoped RPC methods. */ -export function createSessionRpc(connection: MessageConnection, sessionId: string) { +export function createSessionRpc(connection: MessageConnection, sessionId: string, assertActive?: () => void) { return { /** * Suspends the session while preserving persisted state for later resume. */ - suspend: async (): Promise => - connection.sendRequest("session.suspend", { sessionId }), - /** - * Sends a user message to the session and returns its message ID. - * - * @param params Parameters for sending a user message to the session - * - * @returns Result of sending a user message - */ - send: async (params: SendRequest): Promise => - connection.sendRequest("session.send", { sessionId, ...params }), - /** - * Aborts the current agent turn. - * - * @param params Parameters for aborting the current turn - * - * @returns Result of aborting the current turn - */ - abort: async (params: AbortRequest): Promise => - connection.sendRequest("session.abort", { sessionId, ...params }), - /** - * Shuts down the session and persists its final state. Awaits any deferred sessionEnd hooks before resolving so user-supplied hook scripts complete before the runtime tears down. - * - * @param params Parameters for shutting down the session - */ - shutdown: async (params: ShutdownRequest): Promise => - connection.sendRequest("session.shutdown", { sessionId, ...params }), + suspend: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.suspend", { sessionId }); + }, auth: { /** * Gets authentication status and account metadata for the session. * * @returns Authentication status and account metadata for the session. */ - getStatus: async (): Promise => - connection.sendRequest("session.auth.getStatus", { sessionId }), - /** - * Updates the session's auth credentials used for outbound model and API requests. - * - * @param params New auth credentials to install on the session. Omit to leave credentials unchanged. - * - * @returns Indicates whether the credential update succeeded. - */ - setCredentials: async (params: SessionSetCredentialsParams): Promise => - connection.sendRequest("session.auth.setCredentials", { sessionId, ...params }), + getStatus: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.auth.getStatus", { sessionId }); + }, }, model: { /** * Gets the currently selected model for the session. * - * @returns The currently selected model and reasoning effort for the session. + * @returns The currently selected model for the session. */ - getCurrent: async (): Promise => - connection.sendRequest("session.model.getCurrent", { sessionId }), + getCurrent: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.model.getCurrent", { sessionId }); + }, /** * Switches the session to a model and optional reasoning configuration. * @@ -8189,17 +4486,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns The model identifier active on the session after the switch. */ - switchTo: async (params: ModelSwitchToRequest): Promise => - connection.sendRequest("session.model.switchTo", { sessionId, ...params }), - /** - * Updates the session's reasoning effort without changing the selected model. - * - * @param params Reasoning effort level to apply to the currently selected model. - * - * @returns Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. - */ - setReasoningEffort: async (params: ModelSetReasoningEffortRequest): Promise => - connection.sendRequest("session.model.setReasoningEffort", { sessionId, ...params }), + switchTo: async (params: ModelSwitchToRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.model.switchTo", { sessionId, ...params }); + }, }, mode: { /** @@ -8207,15 +4500,22 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns The session mode the agent is operating in */ - get: async (): Promise => - connection.sendRequest("session.mode.get", { sessionId }), + get: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.mode.get", { sessionId }); + }, /** * Sets the current agent interaction mode. * * @param params Agent interaction mode to apply to the session. */ - set: async (params: ModeSetRequest): Promise => - connection.sendRequest("session.mode.set", { sessionId, ...params }), + set: async (params: ModeSetRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mode.set", { sessionId, ...params }); + }, }, name: { /** @@ -8223,24 +4523,22 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns The session's friendly name, or null when not yet set. */ - get: async (): Promise => - connection.sendRequest("session.name.get", { sessionId }), + get: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.name.get", { sessionId }); + }, /** * Sets the session's friendly name. * * @param params New friendly name to apply to the session. */ - set: async (params: NameSetRequest): Promise => - connection.sendRequest("session.name.set", { sessionId, ...params }), - /** - * Persists an auto-generated session summary as the session's name when no user-set name exists. - * - * @param params Auto-generated session summary to apply as the session's name when no user-set name exists. - * - * @returns Indicates whether the auto-generated summary was applied as the session's name. - */ - setAuto: async (params: NameSetAutoRequest): Promise => - connection.sendRequest("session.name.setAuto", { sessionId, ...params }), + set: async (params: NameSetRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.name.set", { sessionId, ...params }); + }, }, plan: { /** @@ -8248,77 +4546,75 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Existence, contents, and resolved path of the session plan file. */ - read: async (): Promise => - connection.sendRequest("session.plan.read", { sessionId }), + read: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.plan.read", { sessionId }); + }, /** * Writes new content to the session plan file. * * @param params Replacement contents to write to the session plan file. */ - update: async (params: PlanUpdateRequest): Promise => - connection.sendRequest("session.plan.update", { sessionId, ...params }), + update: async (params: PlanUpdateRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.plan.update", { sessionId, ...params }); + }, /** * Deletes the session plan file from the workspace. */ - delete: async (): Promise => - connection.sendRequest("session.plan.delete", { sessionId }), + delete: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.plan.delete", { sessionId }); + }, }, workspaces: { /** * Gets current workspace metadata for the session. * - * @returns Current workspace metadata for the session, including its absolute filesystem path when available. + * @returns Current workspace metadata for the session, or null when not available. */ - getWorkspace: async (): Promise => - connection.sendRequest("session.workspaces.getWorkspace", { sessionId }), + getWorkspace: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.workspaces.getWorkspace", { sessionId }); + }, /** * Lists files stored in the session workspace files directory. * * @returns Relative paths of files stored in the session workspace files directory. */ - listFiles: async (): Promise => - connection.sendRequest("session.workspaces.listFiles", { sessionId }), + listFiles: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.workspaces.listFiles", { sessionId }); + }, /** * Reads a file from the session workspace files directory. * - * @param params Relative path of the workspace file to read. - * - * @returns Contents of the requested workspace file as a UTF-8 string. - */ - readFile: async (params: WorkspacesReadFileRequest): Promise => - connection.sendRequest("session.workspaces.readFile", { sessionId, ...params }), - /** - * Creates or overwrites a file in the session workspace files directory. - * - * @param params Relative path and UTF-8 content for the workspace file to create or overwrite. - */ - createFile: async (params: WorkspacesCreateFileRequest): Promise => - connection.sendRequest("session.workspaces.createFile", { sessionId, ...params }), - /** - * Lists workspace checkpoints in chronological order. - * - * @returns Workspace checkpoints in chronological order; empty when the workspace is not enabled. - */ - listCheckpoints: async (): Promise => - connection.sendRequest("session.workspaces.listCheckpoints", { sessionId }), - /** - * Reads the content of a workspace checkpoint by number. - * - * @param params Checkpoint number to read. + * @param params Relative path of the workspace file to read. * - * @returns Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. + * @returns Contents of the requested workspace file as a UTF-8 string. */ - readCheckpoint: async (params: WorkspacesReadCheckpointRequest): Promise => - connection.sendRequest("session.workspaces.readCheckpoint", { sessionId, ...params }), + readFile: async (params: WorkspacesReadFileRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.workspaces.readFile", { sessionId, ...params }); + }, /** - * Saves pasted content as a UTF-8 file in the session workspace. - * - * @param params Pasted content to save as a UTF-8 file in the session workspace. + * Creates or overwrites a file in the session workspace files directory. * - * @returns Descriptor for the saved paste file, or null when the workspace is unavailable. + * @param params Relative path and UTF-8 content for the workspace file to create or overwrite. */ - saveLargePaste: async (params: WorkspacesSaveLargePasteRequest): Promise => - connection.sendRequest("session.workspaces.saveLargePaste", { sessionId, ...params }), + createFile: async (params: WorkspacesCreateFileRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.workspaces.createFile", { sessionId, ...params }); + }, }, instructions: { /** @@ -8326,8 +4622,10 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Instruction sources loaded for the session, in merge order. */ - getSources: async (): Promise => - connection.sendRequest("session.instructions.getSources", { sessionId }), + getSources: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.instructions.getSources", { sessionId }); + }, }, /** @experimental */ fleet: { @@ -8338,8 +4636,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether fleet mode was successfully activated. */ - start: async (params: FleetStartRequest): Promise => - connection.sendRequest("session.fleet.start", { sessionId, ...params }), + start: async (params: FleetStartRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.fleet.start", { sessionId, ...params }); + }, }, /** @experimental */ agent: { @@ -8348,15 +4651,19 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Custom agents available to the session. */ - list: async (): Promise => - connection.sendRequest("session.agent.list", { sessionId }), + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.agent.list", { sessionId }); + }, /** * Gets the currently selected custom agent for the session. * * @returns The currently selected custom agent, or null when using the default agent. */ - getCurrent: async (): Promise => - connection.sendRequest("session.agent.getCurrent", { sessionId }), + getCurrent: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.agent.getCurrent", { sessionId }); + }, /** * Selects a custom agent for subsequent turns in the session. * @@ -8364,20 +4671,29 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns The newly selected custom agent. */ - select: async (params: AgentSelectRequest): Promise => - connection.sendRequest("session.agent.select", { sessionId, ...params }), + select: async (params: AgentSelectRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.agent.select", { sessionId, ...params }); + }, /** * Clears the selected custom agent and returns the session to the default agent. */ - deselect: async (): Promise => - connection.sendRequest("session.agent.deselect", { sessionId }), + deselect: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.agent.deselect", { sessionId }); + }, /** * Reloads custom agent definitions and returns the refreshed list. * * @returns Custom agents available to the session after reloading definitions from disk. */ - reload: async (): Promise => - connection.sendRequest("session.agent.reload", { sessionId }), + reload: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.agent.reload", { sessionId }); + }, }, /** @experimental */ tasks: { @@ -8388,45 +4704,22 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Identifier assigned to the newly started background agent task. */ - startAgent: async (params: TasksStartAgentRequest): Promise => - connection.sendRequest("session.tasks.startAgent", { sessionId, ...params }), + startAgent: async (params: TasksStartAgentRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tasks.startAgent", { sessionId, ...params }); + }, /** * Lists background tasks tracked by the session. * * @returns Background tasks currently tracked by the session. */ - list: async (): Promise => - connection.sendRequest("session.tasks.list", { sessionId }), - /** - * Refreshes metadata for any detached background shells the runtime knows about. - * - * @returns Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. - */ - refresh: async (): Promise => - connection.sendRequest("session.tasks.refresh", { sessionId }), - /** - * Waits for all in-flight background tasks and any follow-up turns to settle. - * - * @returns Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). - */ - waitForPending: async (): Promise => - connection.sendRequest("session.tasks.waitForPending", { sessionId }), - /** - * Returns progress information for a background task by ID. - * - * @param params Identifier of the background task to fetch progress for. - * - * @returns Progress information for the task, or null when no task with that ID is tracked. - */ - getProgress: async (params: TasksGetProgressRequest): Promise => - connection.sendRequest("session.tasks.getProgress", { sessionId, ...params }), - /** - * Returns the first sync-waiting task that can currently be promoted to background mode. - * - * @returns The first sync-waiting task that can currently be promoted to background mode. - */ - getCurrentPromotable: async (): Promise => - connection.sendRequest("session.tasks.getCurrentPromotable", { sessionId }), + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.tasks.list", { sessionId }); + }, /** * Promotes an eligible synchronously-waited task so it continues running in the background. * @@ -8434,15 +4727,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the task was successfully promoted to background mode. */ - promoteToBackground: async (params: TasksPromoteToBackgroundRequest): Promise => - connection.sendRequest("session.tasks.promoteToBackground", { sessionId, ...params }), - /** - * Atomically promotes the first promotable sync-waiting task to background mode and returns it. - * - * @returns The promoted task as it now exists in background mode, omitted if no promotable task was waiting. - */ - promoteCurrentToBackground: async (): Promise => - connection.sendRequest("session.tasks.promoteCurrentToBackground", { sessionId }), + promoteToBackground: async (params: TasksPromoteToBackgroundRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tasks.promoteToBackground", { sessionId, ...params }); + }, /** * Cancels a background task. * @@ -8450,8 +4741,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the background task was successfully cancelled. */ - cancel: async (params: TasksCancelRequest): Promise => - connection.sendRequest("session.tasks.cancel", { sessionId, ...params }), + cancel: async (params: TasksCancelRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tasks.cancel", { sessionId, ...params }); + }, /** * Removes a completed or cancelled background task from tracking. * @@ -8459,8 +4755,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the task was removed. False when the task does not exist or is still running/idle. */ - remove: async (params: TasksRemoveRequest): Promise => - connection.sendRequest("session.tasks.remove", { sessionId, ...params }), + remove: async (params: TasksRemoveRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tasks.remove", { sessionId, ...params }); + }, /** * Sends a message to a background agent task. * @@ -8468,8 +4769,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the message was delivered, with an error message when delivery failed. */ - sendMessage: async (params: TasksSendMessageRequest): Promise => - connection.sendRequest("session.tasks.sendMessage", { sessionId, ...params }), + sendMessage: async (params: TasksSendMessageRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tasks.sendMessage", { sessionId, ...params }); + }, }, /** @experimental */ skills: { @@ -8478,41 +4784,43 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Skills available to the session, with their enabled state. */ - list: async (): Promise => - connection.sendRequest("session.skills.list", { sessionId }), - /** - * Returns the skills that have been invoked during this session. - * - * @returns Skills invoked during this session, ordered by invocation time (most recent last). - */ - getInvoked: async (): Promise => - connection.sendRequest("session.skills.getInvoked", { sessionId }), + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.skills.list", { sessionId }); + }, /** * Enables a skill for the session. * * @param params Name of the skill to enable for the session. */ - enable: async (params: SkillsEnableRequest): Promise => - connection.sendRequest("session.skills.enable", { sessionId, ...params }), + enable: async (params: SkillsEnableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.skills.enable", { sessionId, ...params }); + }, /** * Disables a skill for the session. * * @param params Name of the skill to disable for the session. */ - disable: async (params: SkillsDisableRequest): Promise => - connection.sendRequest("session.skills.disable", { sessionId, ...params }), + disable: async (params: SkillsDisableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.skills.disable", { sessionId, ...params }); + }, /** * Reloads skill definitions for the session. * * @returns Diagnostics from reloading skill definitions, with warnings and errors as separate lists. */ - reload: async (): Promise => - connection.sendRequest("session.skills.reload", { sessionId }), - /** - * Ensures the session's skill definitions have been loaded from disk. - */ - ensureLoaded: async (): Promise => - connection.sendRequest("session.skills.ensureLoaded", { sessionId }), + reload: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.skills.reload", { sessionId }); + }, }, /** @experimental */ mcp: { @@ -8521,61 +4829,41 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns MCP servers configured for the session, with their connection status. */ - list: async (): Promise => - connection.sendRequest("session.mcp.list", { sessionId }), + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.mcp.list", { sessionId }); + }, /** * Enables an MCP server for the session. * * @param params Name of the MCP server to enable for the session. */ - enable: async (params: McpEnableRequest): Promise => - connection.sendRequest("session.mcp.enable", { sessionId, ...params }), + enable: async (params: McpEnableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mcp.enable", { sessionId, ...params }); + }, /** * Disables an MCP server for the session. * * @param params Name of the MCP server to disable for the session. */ - disable: async (params: McpDisableRequest): Promise => - connection.sendRequest("session.mcp.disable", { sessionId, ...params }), + disable: async (params: McpDisableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mcp.disable", { sessionId, ...params }); + }, /** * Reloads MCP server connections for the session. */ - reload: async (): Promise => - connection.sendRequest("session.mcp.reload", { sessionId }), - /** - * Runs an MCP sampling inference on behalf of an MCP server. - * - * @param params Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. - * - * @returns Outcome of an MCP sampling execution: success result, failure error, or cancellation. - */ - executeSampling: async (params: McpExecuteSamplingParams): Promise => - connection.sendRequest("session.mcp.executeSampling", { sessionId, ...params }), - /** - * Cancels an in-flight MCP sampling execution by request ID. - * - * @param params The requestId previously passed to executeSampling that should be cancelled. - * - * @returns Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. - */ - cancelSamplingExecution: async (params: McpCancelSamplingExecutionParams): Promise => - connection.sendRequest("session.mcp.cancelSamplingExecution", { sessionId, ...params }), - /** - * Sets how environment-variable values supplied to MCP servers are resolved (direct or indirect). - * - * @param params Mode controlling how MCP server env values are resolved (`direct` or `indirect`). - * - * @returns Env-value mode recorded on the session after the update. - */ - setEnvValueMode: async (params: McpSetEnvValueModeParams): Promise => - connection.sendRequest("session.mcp.setEnvValueMode", { sessionId, ...params }), - /** - * Removes the auto-managed `github` MCP server when present. - * - * @returns Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). - */ - removeGitHub: async (): Promise => - connection.sendRequest("session.mcp.removeGitHub", { sessionId }), + reload: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.mcp.reload", { sessionId }); + }, /** @experimental */ oauth: { /** @@ -8585,8 +4873,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. */ - login: async (params: McpOauthLoginRequest): Promise => - connection.sendRequest("session.mcp.oauth.login", { sessionId, ...params }), + login: async (params: McpOauthLoginRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mcp.oauth.login", { sessionId, ...params }); + }, }, }, /** @experimental */ @@ -8596,30 +4889,10 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Plugins installed for the session, with their enabled state and version metadata. */ - list: async (): Promise => - connection.sendRequest("session.plugins.list", { sessionId }), - }, - /** @experimental */ - options: { - /** - * Patches the genuinely-mutable subset of session options. - * - * @param params Patch of mutable session options to apply to the running session. - * - * @returns Indicates whether the session options patch was applied successfully. - */ - update: async (params: SessionUpdateOptionsParams): Promise => - connection.sendRequest("session.options.update", { sessionId, ...params }), - }, - /** @experimental */ - lsp: { - /** - * Loads the merged LSP configuration set for the session's working directory. - * - * @param params Parameters for (re)loading the merged LSP configuration set. - */ - initialize: async (params: LspInitializeRequest): Promise => - connection.sendRequest("session.lsp.initialize", { sessionId, ...params }), + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.plugins.list", { sessionId }); + }, }, /** @experimental */ extensions: { @@ -8628,27 +4901,41 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Extensions discovered for the session, with their current status. */ - list: async (): Promise => - connection.sendRequest("session.extensions.list", { sessionId }), + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.extensions.list", { sessionId }); + }, /** * Enables an extension for the session. * * @param params Source-qualified extension identifier to enable for the session. */ - enable: async (params: ExtensionsEnableRequest): Promise => - connection.sendRequest("session.extensions.enable", { sessionId, ...params }), + enable: async (params: ExtensionsEnableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.extensions.enable", { sessionId, ...params }); + }, /** * Disables an extension for the session. * * @param params Source-qualified extension identifier to disable for the session. */ - disable: async (params: ExtensionsDisableRequest): Promise => - connection.sendRequest("session.extensions.disable", { sessionId, ...params }), + disable: async (params: ExtensionsDisableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.extensions.disable", { sessionId, ...params }); + }, /** * Reloads extension definitions and processes for the session. */ - reload: async (): Promise => - connection.sendRequest("session.extensions.reload", { sessionId }), + reload: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.extensions.reload", { sessionId }); + }, }, tools: { /** @@ -8658,15 +4945,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the external tool call result was handled successfully. */ - handlePendingToolCall: async (params: HandlePendingToolCallRequest): Promise => - connection.sendRequest("session.tools.handlePendingToolCall", { sessionId, ...params }), - /** - * Resolves, builds, and validates the runtime tool list for the session. - * - * @returns Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. - */ - initializeAndValidate: async (): Promise => - connection.sendRequest("session.tools.initializeAndValidate", { sessionId }), + handlePendingToolCall: async (params: HandlePendingToolCallRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tools.handlePendingToolCall", { sessionId, ...params }); + }, }, commands: { /** @@ -8676,8 +4961,10 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Slash commands available in the session, after applying any include/exclude filters. */ - list: async (params?: CommandsListRequest): Promise => - connection.sendRequest("session.commands.list", { sessionId, ...params }), + list: async (params?: CommandsListRequest): Promise => { + assertActive?.(); + return connection.sendRequest("session.commands.list", { sessionId, ...params }); + }, /** * Invokes a slash command in the session. * @@ -8685,8 +4972,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Result of invoking the slash command (text output, prompt to send to the agent, or completion). */ - invoke: async (params: CommandsInvokeRequest): Promise => - connection.sendRequest("session.commands.invoke", { sessionId, ...params }), + invoke: async (params: CommandsInvokeRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.invoke", { sessionId, ...params }); + }, /** * Reports completion of a pending client-handled slash command. * @@ -8694,45 +4986,27 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the pending client-handled command was completed successfully. */ - handlePendingCommand: async (params: CommandsHandlePendingCommandRequest): Promise => - connection.sendRequest("session.commands.handlePendingCommand", { sessionId, ...params }), - /** - * Executes a slash command synchronously and returns any error. - * - * @param params Slash command name and argument string to execute synchronously. - * - * @returns Error message produced while executing the command, if any. - */ - execute: async (params: ExecuteCommandParams): Promise => - connection.sendRequest("session.commands.execute", { sessionId, ...params }), - /** - * Enqueues a slash command for FIFO processing on the local session. - * - * @param params Slash-prefixed command string to enqueue for FIFO processing. - * - * @returns Indicates whether the command was accepted into the local execution queue. - */ - enqueue: async (params: EnqueueCommandParams): Promise => - connection.sendRequest("session.commands.enqueue", { sessionId, ...params }), + handlePendingCommand: async (params: CommandsHandlePendingCommandRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.handlePendingCommand", { sessionId, ...params }); + }, /** - * Reports whether the host actually executed a queued command and whether to continue processing. + * Responds to a queued command request from the session. * - * @param params Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). + * @param params Queued command request ID and the result indicating whether the client handled it. * - * @returns Indicates whether the queued-command response was matched to a pending request. + * @returns Indicates whether the queued-command response was accepted by the session. */ - respondToQueuedCommand: async (params: CommandsRespondToQueuedCommandRequest): Promise => - connection.sendRequest("session.commands.respondToQueuedCommand", { sessionId, ...params }), - }, - /** @experimental */ - telemetry: { - /** - * Sets feature override key/value pairs to attach to subsequent telemetry events for the session. - * - * @param params Feature override key/value pairs to attach to subsequent telemetry events from this session. - */ - setFeatureOverrides: async (params: TelemetrySetFeatureOverridesRequest): Promise => - connection.sendRequest("session.telemetry.setFeatureOverrides", { sessionId, ...params }), + respondToQueuedCommand: async (params: CommandsRespondToQueuedCommandRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.respondToQueuedCommand", { sessionId, ...params }); + }, }, ui: { /** @@ -8742,8 +5016,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns The elicitation response (accept with form values, decline, or cancel) */ - elicitation: async (params: UIElicitationRequest): Promise => - connection.sendRequest("session.ui.elicitation", { sessionId, ...params }), + elicitation: async (params: UIElicitationRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.ui.elicitation", { sessionId, ...params }); + }, /** * Provides the user response for a pending elicitation request. * @@ -8751,71 +5030,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the elicitation response was accepted; false if it was already resolved by another client. */ - handlePendingElicitation: async (params: UIHandlePendingElicitationRequest): Promise => - connection.sendRequest("session.ui.handlePendingElicitation", { sessionId, ...params }), - /** - * Resolves a pending `user_input.requested` event with the user's response. - * - * @param params Request ID of a pending `user_input.requested` event and the user's response. - * - * @returns Indicates whether the pending UI request was resolved by this call. - */ - handlePendingUserInput: async (params: UIHandlePendingUserInputRequest): Promise => - connection.sendRequest("session.ui.handlePendingUserInput", { sessionId, ...params }), - /** - * Resolves a pending `sampling.requested` event with a sampling result, or rejects it. - * - * @param params Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). - * - * @returns Indicates whether the pending UI request was resolved by this call. - */ - handlePendingSampling: async (params: UIHandlePendingSamplingRequest): Promise => - connection.sendRequest("session.ui.handlePendingSampling", { sessionId, ...params }), - /** - * Resolves a pending `auto_mode_switch.requested` event with the user's accept/decline decision. - * - * @param params Request ID of a pending `auto_mode_switch.requested` event and the user's response. - * - * @returns Indicates whether the pending UI request was resolved by this call. - */ - handlePendingAutoModeSwitch: async (params: UIHandlePendingAutoModeSwitchRequest): Promise => - connection.sendRequest("session.ui.handlePendingAutoModeSwitch", { sessionId, ...params }), - /** - * Resolves a pending `exit_plan_mode.requested` event with the user's response. - * - * @param params Request ID of a pending `exit_plan_mode.requested` event and the user's response. - * - * @returns Indicates whether the pending UI request was resolved by this call. - */ - handlePendingExitPlanMode: async (params: UIHandlePendingExitPlanModeRequest): Promise => - connection.sendRequest("session.ui.handlePendingExitPlanMode", { sessionId, ...params }), - /** - * Registers an in-process handler for auto-mode-switch requests so the server bridge skips dispatch. - * - * @returns Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). - */ - registerDirectAutoModeSwitchHandler: async (): Promise => - connection.sendRequest("session.ui.registerDirectAutoModeSwitchHandler", { sessionId }), - /** - * Unregisters a previously-registered in-process auto-mode-switch handler by its opaque handle. - * - * @param params Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. - * - * @returns Indicates whether the handle was active and the registration count was decremented. - */ - unregisterDirectAutoModeSwitchHandler: async (params: UIUnregisterDirectAutoModeSwitchHandlerRequest): Promise => - connection.sendRequest("session.ui.unregisterDirectAutoModeSwitchHandler", { sessionId, ...params }), + handlePendingElicitation: async (params: UIHandlePendingElicitationRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.ui.handlePendingElicitation", { sessionId, ...params }); + }, }, permissions: { - /** - * Replaces selected permission policy fields (rules, paths, URLs, exclusions, allow-all flags) on the session. - * - * @param params Patch of permission policy fields to apply (omit a field to leave it unchanged). - * - * @returns Indicates whether the operation succeeded. - */ - configure: async (params: PermissionsConfigureParams): Promise => - connection.sendRequest("session.permissions.configure", { sessionId, ...params }), /** * Provides a decision for a pending tool permission request. * @@ -8823,176 +5046,50 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the permission decision was applied; false when the request was already resolved. */ - handlePendingPermissionRequest: async (params: PermissionDecisionRequest): Promise => - connection.sendRequest("session.permissions.handlePendingPermissionRequest", { sessionId, ...params }), - /** - * Reconstructs the set of pending tool permission requests from the session's event history. - * - * @returns List of pending permission requests reconstructed from event history. - */ - pendingRequests: async (): Promise => - connection.sendRequest("session.permissions.pendingRequests", { sessionId }), + handlePendingPermissionRequest: async (params: PermissionDecisionRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.handlePendingPermissionRequest", { sessionId, ...params }); + }, /** * Enables or disables automatic approval of tool permission requests for the session. * - * @param params Allow-all toggle for tool permission requests, with an optional telemetry source. - * - * @returns Indicates whether the operation succeeded. - */ - setApproveAll: async (params: PermissionsSetApproveAllRequest): Promise => - connection.sendRequest("session.permissions.setApproveAll", { sessionId, ...params }), - /** - * Adds or removes session-scoped or location-scoped permission rules. - * - * @param params Scope and add/remove instructions for modifying session- or location-scoped permission rules. - * - * @returns Indicates whether the operation succeeded. - */ - modifyRules: async (params: PermissionsModifyRulesParams): Promise => - connection.sendRequest("session.permissions.modifyRules", { sessionId, ...params }), - /** - * Sets whether the client wants permission prompts bridged into session events. - * - * @param params Toggles whether permission prompts should be bridged into session events for this client. + * @param params Whether to auto-approve all tool permission requests for the rest of the session. * * @returns Indicates whether the operation succeeded. */ - setRequired: async (params: PermissionsSetRequiredRequest): Promise => - connection.sendRequest("session.permissions.setRequired", { sessionId, ...params }), + setApproveAll: async (params: PermissionsSetApproveAllRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.setApproveAll", { sessionId, ...params }); + }, /** * Clears session-scoped tool permission approvals. * * @returns Indicates whether the operation succeeded. */ - resetSessionApprovals: async (): Promise => - connection.sendRequest("session.permissions.resetSessionApprovals", { sessionId }), - /** - * Notifies the runtime that a permission prompt UI has been shown to the user. - * - * @param params Notification payload describing the permission prompt that the client just rendered. - * - * @returns Indicates whether the operation succeeded. - */ - notifyPromptShown: async (params: PermissionPromptShownNotification): Promise => - connection.sendRequest("session.permissions.notifyPromptShown", { sessionId, ...params }), - paths: { - /** - * Returns the session's allowed directories and primary working directory. - * - * @returns Snapshot of the session's allow-listed directories and primary working directory. - */ - list: async (): Promise => - connection.sendRequest("session.permissions.paths.list", { sessionId }), - /** - * Adds a directory to the session's allow-list. - * - * @param params Directory path to add to the session's allowed directories. - * - * @returns Indicates whether the operation succeeded. - */ - add: async (params: PermissionPathsAddParams): Promise => - connection.sendRequest("session.permissions.paths.add", { sessionId, ...params }), - /** - * Updates the session's primary working directory used by the permission policy. - * - * @param params Directory path to set as the session's new primary working directory. - * - * @returns Indicates whether the operation succeeded. - */ - updatePrimary: async (params: PermissionPathsUpdatePrimaryParams): Promise => - connection.sendRequest("session.permissions.paths.updatePrimary", { sessionId, ...params }), - /** - * Reports whether a path falls within any of the session's allowed directories. - * - * @param params Path to evaluate against the session's allowed directories. - * - * @returns Indicates whether the supplied path is within the session's allowed directories. - */ - isPathWithinAllowedDirectories: async (params: PermissionPathsAllowedCheckParams): Promise => - connection.sendRequest("session.permissions.paths.isPathWithinAllowedDirectories", { sessionId, ...params }), - /** - * Reports whether a path falls within the session's workspace (primary) directory. - * - * @param params Path to evaluate against the session's workspace (primary) directory. - * - * @returns Indicates whether the supplied path is within the session's workspace directory. - */ - isPathWithinWorkspace: async (params: PermissionPathsWorkspaceCheckParams): Promise => - connection.sendRequest("session.permissions.paths.isPathWithinWorkspace", { sessionId, ...params }), - }, - urls: { - /** - * Toggles the runtime's URL-permission policy between unrestricted and restricted modes. - * - * @param params Whether the URL-permission policy should run in unrestricted mode. - * - * @returns Indicates whether the operation succeeded. - */ - setUnrestrictedMode: async (params: PermissionUrlsSetUnrestrictedModeParams): Promise => - connection.sendRequest("session.permissions.urls.setUnrestrictedMode", { sessionId, ...params }), + resetSessionApprovals: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.permissions.resetSessionApprovals", { sessionId }); }, }, /** * Emits a user-visible session log event. * - * @param params Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. + * @param params Message text, optional severity level, persistence flag, and optional follow-up URL. * * @returns Identifier of the session event that was emitted for the log message. */ - log: async (params: LogRequest): Promise => - connection.sendRequest("session.log", { sessionId, ...params }), - /** @experimental */ - metadata: { - /** - * Returns a snapshot of the session's identifying metadata, mode, agent, and remote info. - * - * @returns Point-in-time snapshot of slow-changing session identifier and state fields - */ - snapshot: async (): Promise => - connection.sendRequest("session.metadata.snapshot", { sessionId }), - /** - * Reports whether the local session is currently processing user/agent messages. - * - * @returns Indicates whether the local session is currently processing a turn or background continuation. - */ - isProcessing: async (): Promise => - connection.sendRequest("session.metadata.isProcessing", { sessionId }), - /** - * Returns the token breakdown for the session's current context window for a given model. - * - * @param params Model identifier and token limits used to compute the context-info breakdown. - * - * @returns Token breakdown for the session's current context window, or null if uninitialized. - */ - contextInfo: async (params: MetadataContextInfoRequest): Promise => - connection.sendRequest("session.metadata.contextInfo", { sessionId, ...params }), - /** - * Records a working-directory/git context change and emits a `session.context_changed` event. - * - * @param params Updated working-directory/git context to record on the session. - * - * @returns Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). - */ - recordContextChange: async (params: MetadataRecordContextChangeRequest): Promise => - connection.sendRequest("session.metadata.recordContextChange", { sessionId, ...params }), - /** - * Updates the session's recorded working directory. - * - * @param params Absolute path to set as the session's new working directory. - * - * @returns Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any related side-effects (file index, etc.); this method only updates the session's own recorded path. - */ - setWorkingDirectory: async (params: MetadataSetWorkingDirectoryRequest): Promise => - connection.sendRequest("session.metadata.setWorkingDirectory", { sessionId, ...params }), - /** - * Re-tokenizes the session's existing messages against a model and returns aggregate token totals. - * - * @param params Model identifier to use when re-tokenizing the session's existing messages. - * - * @returns Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. - */ - recomputeContextTokens: async (params: MetadataRecomputeContextTokensRequest): Promise => - connection.sendRequest("session.metadata.recomputeContextTokens", { sessionId, ...params }), + log: async (params: LogRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.log", { sessionId, ...params }); }, shell: { /** @@ -9002,8 +5099,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Identifier of the spawned process, used to correlate streamed output and exit notifications. */ - exec: async (params: ShellExecRequest): Promise => - connection.sendRequest("session.shell.exec", { sessionId, ...params }), + exec: async (params: ShellExecRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.shell.exec", { sessionId, ...params }); + }, /** * Sends a signal to a shell process previously started via "shell.exec". * @@ -9011,18 +5113,25 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether the signal was delivered; false if the process was unknown or already exited. */ - kill: async (params: ShellKillRequest): Promise => - connection.sendRequest("session.shell.kill", { sessionId, ...params }), + kill: async (params: ShellKillRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.shell.kill", { sessionId, ...params }); + }, }, /** @experimental */ history: { /** * Compacts the session history to reduce context usage. * - * @returns Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. + * @returns Compaction outcome with the number of tokens and messages removed and the resulting context window breakdown. */ - compact: async (): Promise => - connection.sendRequest("session.history.compact", { sessionId }), + compact: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.history.compact", { sessionId }); + }, /** * Truncates persisted session history to a specific event. * @@ -9030,88 +5139,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Number of events that were removed by the truncation. */ - truncate: async (params: HistoryTruncateRequest): Promise => - connection.sendRequest("session.history.truncate", { sessionId, ...params }), - /** - * Cancels any in-progress background compaction on a local session. - * - * @returns Indicates whether an in-progress background compaction was cancelled. - */ - cancelBackgroundCompaction: async (): Promise => - connection.sendRequest("session.history.cancelBackgroundCompaction", { sessionId }), - /** - * Aborts any in-progress manual compaction on a local session. - * - * @returns Indicates whether an in-progress manual compaction was aborted. - */ - abortManualCompaction: async (): Promise => - connection.sendRequest("session.history.abortManualCompaction", { sessionId }), - /** - * Produces a markdown summary of the session's conversation context for hand-off scenarios. - * - * @returns Markdown summary of the conversation context (empty when not available). - */ - summarizeForHandoff: async (): Promise => - connection.sendRequest("session.history.summarizeForHandoff", { sessionId }), - }, - /** @experimental */ - queue: { - /** - * Returns the local session's pending user-facing queued items and steering messages. - * - * @returns Snapshot of the session's pending queued items and immediate-steering messages. - */ - pendingItems: async (): Promise => - connection.sendRequest("session.queue.pendingItems", { sessionId }), - /** - * Removes the most recently queued user-facing item (LIFO). - * - * @returns Indicates whether a user-facing pending item was removed. - */ - removeMostRecent: async (): Promise => - connection.sendRequest("session.queue.removeMostRecent", { sessionId }), - /** - * Clears all pending queued items on the local session. - */ - clear: async (): Promise => - connection.sendRequest("session.queue.clear", { sessionId }), - }, - /** @experimental */ - eventLog: { - /** - * Reads a batch of session events from a cursor, optionally waiting for new events. - * - * @param params Cursor, batch size, and optional long-poll/filter parameters for reading session events. - * - * @returns Batch of session events returned by a read, with cursor and continuation metadata. - */ - read: async (params: EventLogReadRequest): Promise => - connection.sendRequest("session.eventLog.read", { sessionId, ...params }), - /** - * Returns a snapshot of the current tail cursor without consuming events. - * - * @returns Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session). - */ - tail: async (): Promise => - connection.sendRequest("session.eventLog.tail", { sessionId }), - /** - * Registers consumer interest in an event type for runtime gating purposes. - * - * @param params Event type to register consumer interest for, used by runtime gating logic. - * - * @returns Opaque handle representing an event-type interest registration. - */ - registerInterest: async (params: RegisterEventInterestParams): Promise => - connection.sendRequest("session.eventLog.registerInterest", { sessionId, ...params }), - /** - * Releases a consumer's previously-registered interest in an event type. - * - * @param params Opaque handle previously returned by `registerInterest` to release. - * - * @returns Indicates whether the operation succeeded. - */ - releaseInterest: async (params: ReleaseEventInterestParams): Promise => - connection.sendRequest("session.eventLog.releaseInterest", { sessionId, ...params }), + truncate: async (params: HistoryTruncateRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.history.truncate", { sessionId, ...params }); + }, }, /** @experimental */ usage: { @@ -9120,8 +5154,10 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals. */ - getMetrics: async (): Promise => - connection.sendRequest("session.usage.getMetrics", { sessionId }), + getMetrics: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.usage.getMetrics", { sessionId }); + }, }, /** @experimental */ remote: { @@ -9132,41 +5168,20 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns GitHub URL for the session and a flag indicating whether remote steering is enabled. */ - enable: async (params: RemoteEnableRequest): Promise => - connection.sendRequest("session.remote.enable", { sessionId, ...params }), + enable: async (params: RemoteEnableRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.remote.enable", { sessionId, ...params }); + }, /** * Disables remote session export and steering. */ - disable: async (): Promise => - connection.sendRequest("session.remote.disable", { sessionId }), - /** - * Persists a remote-steerability change emitted by the host as a session event. - * - * @param params New remote-steerability state to persist as a `session.remote_steerable_changed` event. - * - * @returns Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. - */ - notifySteerableChanged: async (params: RemoteNotifySteerableChangedRequest): Promise => - connection.sendRequest("session.remote.notifySteerableChanged", { sessionId, ...params }), - }, - /** @experimental */ - schedule: { - /** - * Lists the session's currently active scheduled prompts. - * - * @returns Snapshot of the currently active recurring prompts for this session. - */ - list: async (): Promise => - connection.sendRequest("session.schedule.list", { sessionId }), - /** - * Removes a scheduled prompt by id. - * - * @param params Identifier of the scheduled prompt to remove. - * - * @returns Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. - */ - stop: async (params: ScheduleStopRequest): Promise => - connection.sendRequest("session.schedule.stop", { sessionId, ...params }), + disable: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.remote.disable", { sessionId }); + }, }, }; } diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index 2e501591f..c9cff98e8 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -1791,7 +1791,7 @@ export interface UserMessageData { */ isAutopilotContinuation?: boolean; /** - * Path-backed native document attachments that stayed on the tagged_files path flow because native upload could not read them or would exceed the request size limit + * Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit */ nativeDocumentPathFallbackPaths?: string[]; /** @@ -2623,7 +2623,7 @@ export interface AssistantUsageQuotaSnapshot { */ overageAllowedWithExhaustedQuota: boolean; /** - * Percentage of quota remaining (0 to 100) + * Percentage of quota remaining (0.0 to 1.0) */ remainingPercentage: number; /** @@ -4721,7 +4721,7 @@ export interface PermissionDeniedByRules { */ export interface PermissionRule { /** - * Argument value matched against the request, or null when the rule kind has no argument (e.g. 'read', 'write', 'memory'). + * Optional rule argument matched against the request */ argument: string | null; /** diff --git a/nodejs/src/session.ts b/nodejs/src/session.ts index 6b164cb15..0a5f714d2 100644 --- a/nodejs/src/session.ts +++ b/nodejs/src/session.ts @@ -97,6 +97,9 @@ export class CopilotSession { private _rpc: ReturnType | null = null; private traceContextProvider?: TraceContextProvider; private _capabilities: SessionCapabilities = {}; + private disconnected = false; + private disconnectPromise?: Promise; + private readonly onDisconnected?: (session: CopilotSession) => void; /** @internal Client session API handlers, populated by CopilotClient during create/resume. */ clientSessionApis: ClientSessionApiHandlers = {}; @@ -114,17 +117,22 @@ export class CopilotSession { public readonly sessionId: string, private connection: MessageConnection, private _workspacePath?: string, - traceContextProvider?: TraceContextProvider + traceContextProvider?: TraceContextProvider, + onDisconnected?: (session: CopilotSession) => void ) { this.traceContextProvider = traceContextProvider; + this.onDisconnected = onDisconnected; } /** * Typed session-scoped RPC methods. */ get rpc(): ReturnType { + this.assertActive(); if (!this._rpc) { - this._rpc = createSessionRpc(this.connection, this.sessionId); + this._rpc = createSessionRpc(this.connection, this.sessionId, () => + this.assertActive() + ); } return this._rpc; } @@ -159,6 +167,7 @@ export class CopilotSession { * ``` */ get ui(): SessionUiApi { + this.assertActive(); return { elicitation: (params: ElicitationParams) => this._elicitation(params), confirm: (message: string) => this._confirm(message), @@ -186,6 +195,7 @@ export class CopilotSession { * ``` */ async send(options: MessageOptions): Promise { + this.assertActive(); const response = await this.connection.sendRequest("session.send", { ...(await getTraceContext(this.traceContextProvider)), sessionId: this.sessionId, @@ -225,6 +235,7 @@ export class CopilotSession { options: MessageOptions, timeout?: number ): Promise { + this.assertActive(); const effectiveTimeout = timeout ?? 60_000; let resolveIdle: () => void; @@ -328,6 +339,7 @@ export class CopilotSession { eventTypeOrHandler: K | SessionEventHandler, handler?: TypedSessionEventHandler ): () => void { + this.assertActive(); // Overload 1: on(eventType, handler) - typed event subscription if (typeof eventTypeOrHandler === "string" && handler) { const eventType = eventTypeOrHandler; @@ -720,7 +732,14 @@ export class CopilotSession { this._capabilities = capabilities ?? {}; } + private assertActive(): void { + if (this.disconnected) { + throw new Error("Session has been disconnected."); + } + } + private assertElicitation(): void { + this.assertActive(); if (!this._capabilities.ui?.elicitation) { throw new Error( "Elicitation is not supported by the host. " + @@ -992,6 +1011,7 @@ export class CopilotSession { * ``` */ async getMessages(): Promise { + this.assertActive(); const response = await this.connection.sendRequest("session.getMessages", { sessionId: this.sessionId, }); @@ -1021,17 +1041,48 @@ export class CopilotSession { * ``` */ async disconnect(): Promise { - await this.connection.sendRequest("session.destroy", { - sessionId: this.sessionId, - }); + if (this.disconnected) { + return; + } + if (!this.disconnectPromise) { + this.disconnectPromise = this.disconnectCore(); + } + await this.disconnectPromise; + } + + private async disconnectCore(): Promise { + try { + await this.connection.sendRequest("session.destroy", { + sessionId: this.sessionId, + }); + } finally { + this.markDisconnected(); + } + } + + /** @internal Marks the session unusable after client-side forced cleanup. */ + _markDisconnected(): void { + this.markDisconnected(); + } + + private markDisconnected(): void { + if (this.disconnected) { + return; + } + this.disconnected = true; + this._rpc = null; this.eventHandlers.clear(); this.typedEventHandlers.clear(); this.toolHandlers.clear(); + this.commandHandlers.clear(); this.permissionHandler = undefined; this.userInputHandler = undefined; this.elicitationHandler = undefined; this.exitPlanModeHandler = undefined; this.autoModeSwitchHandler = undefined; + this.hooks = undefined; + this.transformCallbacks = undefined; + this.onDisconnected?.(this); } /** @@ -1073,6 +1124,7 @@ export class CopilotSession { * ``` */ async abort(): Promise { + this.assertActive(); await this.connection.sendRequest("session.abort", { sessionId: this.sessionId, }); @@ -1098,6 +1150,7 @@ export class CopilotSession { modelCapabilities?: ModelCapabilitiesOverride; } ): Promise { + this.assertActive(); await this.rpc.model.switchTo({ modelId: model, ...options }); } @@ -1121,6 +1174,7 @@ export class CopilotSession { message: string, options?: { level?: "info" | "warning" | "error"; ephemeral?: boolean } ): Promise { + this.assertActive(); await this.rpc.log({ message, ...options }); } } diff --git a/nodejs/test/client.test.ts b/nodejs/test/client.test.ts index a92f54253..d3b81928b 100644 --- a/nodejs/test/client.test.ts +++ b/nodejs/test/client.test.ts @@ -5,6 +5,9 @@ import { CopilotSession } from "../src/session.js"; import { defaultJoinSessionPermissionHandler } from "../src/types.js"; // This file is for unit tests. Where relevant, prefer to add e2e tests in e2e/*.test.ts instead +function markInactiveForResume(session: CopilotSession): void { + session._markDisconnected(); +} describe("CopilotClient", () => { it("allows createSession without onPermissionRequest", async () => { @@ -82,6 +85,95 @@ describe("CopilotClient", () => { ); }); + it("keeps a directly disconnected session registered until session.destroy completes", async () => { + const client = new CopilotClient({ autoStart: false }); + let session: CopilotSession; + const connection = { + sendRequest: vi.fn(async (method: string) => { + if (method === "session.destroy") { + expect((client as any).sessions.get("session-1")).toBe(session); + } + return {}; + }), + } as any; + session = new CopilotSession("session-1", connection, undefined, undefined, (s) => + (client as any).unregisterSession(s) + ); + (client as any).registerSession(session); + + await session.disconnect(); + + expect(connection.sendRequest).toHaveBeenCalledWith("session.destroy", { + sessionId: "session-1", + }); + expect((client as any).sessions.has("session-1")).toBe(false); + await expect(session.send({ prompt: "hello" })).rejects.toThrow(/disconnected/); + expect(() => session.rpc).toThrow(/disconnected/); + }); + + it("reports stop errors when session.destroy fails", async () => { + const client = new CopilotClient({ autoStart: false }); + const connection = { + dispose: vi.fn(), + sendRequest: vi.fn(async (method: string) => { + if (method === "session.destroy") { + throw new Error("destroy failed"); + } + return {}; + }), + } as any; + (client as any).connection = connection; + const session = new CopilotSession("session-1", connection, undefined, undefined, (s) => + (client as any).unregisterSession(s) + ); + (client as any).registerSession(session); + + const errors = await client.stop(); + + expect(errors).toHaveLength(1); + expect(errors[0].message).toBe("Failed to disconnect session session-1: destroy failed"); + expect(connection.sendRequest).toHaveBeenCalledTimes(1); + expect((client as any).sessions.size).toBe(0); + await expect(session.send({ prompt: "hello" })).rejects.toThrow(/disconnected/); + }); + + it("does not unregister a replacement session when a stale session disconnects", () => { + const client = new CopilotClient({ autoStart: false }); + const connection = { sendRequest: vi.fn() } as any; + const stale = new CopilotSession("session-1", connection, undefined, undefined, (s) => + (client as any).unregisterSession(s) + ); + const replacement = new CopilotSession("session-1", connection, undefined, undefined, (s) => + (client as any).unregisterSession(s) + ); + + (client as any).sessions.set("session-1", replacement); + stale._markDisconnected(); + + expect((client as any).sessions.get("session-1")).toBe(replacement); + replacement._markDisconnected(); + }); + + it("rejects duplicate active session registrations", () => { + const client = new CopilotClient({ autoStart: false }); + const connection = { sendRequest: vi.fn() } as any; + const first = new CopilotSession("session-1", connection); + const second = new CopilotSession("session-1", connection); + + (client as any).registerSession(first); + + expect(() => (client as any).registerSession(second)).toThrow(/already active/); + first._markDisconnected(); + }); + + it("validates required generated RPC params before sending requests", async () => { + const connection = { sendRequest: vi.fn() } as any; + const session = new CopilotSession("session-1", connection); + + await expect((session.rpc.commands.invoke as any)()).rejects.toThrow("params is required"); + expect(connection.sendRequest).not.toHaveBeenCalled(); + }); + it("forwards clientName in session.resume request", async () => { const client = new CopilotClient(); await client.start(); @@ -95,6 +187,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { clientName: "my-app", onPermissionRequest: approveAll, @@ -136,6 +229,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { enableSessionTelemetry: false, onPermissionRequest: approveAll, @@ -187,6 +281,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll }); const payload = spy.mock.calls.find((c) => c[0] === "session.resume")![1] as any; @@ -206,6 +301,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, includeSubAgentStreamingEvents: false, @@ -228,6 +324,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, continuePendingWork: true, @@ -250,6 +347,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll }); const payload = spy.mock.calls.find((c) => c[0] === "session.resume")![1] as any; @@ -308,6 +406,7 @@ describe("CopilotClient", () => { throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, provider: { @@ -360,6 +459,7 @@ describe("CopilotClient", () => { const session = await client.createSession({ onPermissionRequest: approveAll }); const spy = vi.spyOn((client as any).connection!, "sendRequest"); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { defaultAgent: { excludedTools: ["heavy-tool"] }, onPermissionRequest: approveAll, @@ -404,6 +504,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { instructionDirectories, onPermissionRequest: approveAll, @@ -432,6 +533,7 @@ describe("CopilotClient", () => { throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: defaultJoinSessionPermissionHandler, }); @@ -459,6 +561,7 @@ describe("CopilotClient", () => { throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, }); @@ -486,6 +589,7 @@ describe("CopilotClient", () => { throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, onExitPlanMode: () => ({ approved: true }), @@ -834,6 +938,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, tools: [ @@ -912,6 +1017,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, customAgents: [ @@ -1075,6 +1181,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll }); expect(spy).toHaveBeenCalledWith( @@ -1186,6 +1293,7 @@ describe("CopilotClient", () => { if (method === "session.resume") return { sessionId: params.sessionId }; throw new Error(`Unexpected method: ${method}`); }); + markInactiveForResume(session); await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll, commands: [{ name: "deploy", description: "Deploy", handler: async () => {} }], diff --git a/python/copilot/client.py b/python/copilot/client.py index 6adb52061..4e974429c 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -1022,6 +1022,18 @@ def rpc(self) -> ServerRpc: raise RuntimeError("Client is not connected. Call start() first.") return self._rpc + def _register_session(self, session: CopilotSession) -> None: + with self._sessions_lock: + existing = self._sessions.get(session.session_id) + if existing is not None and existing is not session: + raise RuntimeError(f"Session {session.session_id} is already active.") + self._sessions[session.session_id] = session + + def _unregister_session(self, session: CopilotSession) -> None: + with self._sessions_lock: + if self._sessions.get(session.session_id) is session: + del self._sessions[session.session_id] + @property def actual_port(self) -> int | None: """The actual TCP port the CLI server is listening on, if using TCP transport. @@ -1229,11 +1241,8 @@ async def stop(self) -> None: """ errors: list[StopError] = [] - # Atomically take ownership of all sessions and clear the dict - # so no other thread can access them with self._sessions_lock: sessions_to_destroy = list(self._sessions.values()) - self._sessions.clear() for session in sessions_to_destroy: try: @@ -1248,6 +1257,12 @@ async def stop(self) -> None: StopError(message=f"Failed to disconnect session {session.session_id}: {e}") ) + with self._sessions_lock: + remaining_sessions = list(self._sessions.values()) + self._sessions.clear() + for session in remaining_sessions: + session._mark_disconnected() + # Close client if self._client: await self._client.stop() @@ -1290,9 +1305,11 @@ async def force_stop(self) -> None: ... except asyncio.TimeoutError: ... await client.force_stop() """ - # Clear sessions immediately without trying to destroy them with self._sessions_lock: + sessions_to_destroy = list(self._sessions.values()) self._sessions.clear() + for session in sessions_to_destroy: + session._mark_disconnected() # Close the transport first to signal the server immediately. # For external servers (TCP), this closes the socket. @@ -1621,24 +1638,33 @@ async def create_session( # Create and register the session before issuing the RPC so that # events emitted by the CLI (e.g. session.start) are not dropped. setup_start = time.perf_counter() - session = CopilotSession(actual_session_id, self._client, workspace_path=None) - if self._session_fs_config: - if create_session_fs_handler is None: - raise ValueError( - "create_session_fs_handler is required in session config when " - "session_fs is enabled in client options." - ) - fs_provider: SessionFsProvider = create_session_fs_handler(session) - caps = self._session_fs_config.get("capabilities") - if caps and caps.get("sqlite"): - from .session_fs_provider import SessionFsSqliteProvider - - if not isinstance(fs_provider, SessionFsSqliteProvider): + session = CopilotSession( + actual_session_id, + self._client, + workspace_path=None, + on_disconnected=self._unregister_session, + ) + try: + if self._session_fs_config: + if create_session_fs_handler is None: raise ValueError( - "SessionFs capabilities declare SQLite support but the provider " - "does not implement SessionFsSqliteProvider" + "create_session_fs_handler is required in session config when " + "session_fs is enabled in client options." ) - session._client_session_apis.session_fs = create_session_fs_adapter(fs_provider) + fs_provider: SessionFsProvider = create_session_fs_handler(session) + caps = self._session_fs_config.get("capabilities") + if caps and caps.get("sqlite"): + from .session_fs_provider import SessionFsSqliteProvider + + if not isinstance(fs_provider, SessionFsSqliteProvider): + raise ValueError( + "SessionFs capabilities declare SQLite support but the provider " + "does not implement SessionFsSqliteProvider" + ) + session._client_session_apis.session_fs = create_session_fs_adapter(fs_provider) + except BaseException: + session._mark_disconnected() + raise session._register_tools(tools) session._register_commands(commands) session._register_permission_handler(on_permission_request) @@ -1656,8 +1682,11 @@ async def create_session( session._register_transform_callbacks(transform_callbacks) if on_event: session.on(on_event) - with self._sessions_lock: - self._sessions[actual_session_id] = session + try: + self._register_session(session) + except BaseException: + session._mark_disconnected() + raise log_timing( logger, logging.DEBUG, @@ -1683,8 +1712,8 @@ async def create_session( capabilities = response.get("capabilities") session._set_capabilities(capabilities) except BaseException as exc: - with self._sessions_lock: - self._sessions.pop(actual_session_id, None) + self._unregister_session(session) + session._mark_disconnected() if not isinstance(exc, asyncio.CancelledError): log_timing( logger, @@ -1974,24 +2003,33 @@ async def resume_session( # Create and register the session before issuing the RPC so that # events emitted by the CLI (e.g. session.start) are not dropped. setup_start = time.perf_counter() - session = CopilotSession(session_id, self._client, workspace_path=None) - if self._session_fs_config: - if create_session_fs_handler is None: - raise ValueError( - "create_session_fs_handler is required in session config when " - "session_fs is enabled in client options." - ) - fs_provider: SessionFsProvider = create_session_fs_handler(session) - caps = self._session_fs_config.get("capabilities") - if caps and caps.get("sqlite"): - from .session_fs_provider import SessionFsSqliteProvider - - if not isinstance(fs_provider, SessionFsSqliteProvider): + session = CopilotSession( + session_id, + self._client, + workspace_path=None, + on_disconnected=self._unregister_session, + ) + try: + if self._session_fs_config: + if create_session_fs_handler is None: raise ValueError( - "SessionFs capabilities declare SQLite support but the provider " - "does not implement SessionFsSqliteProvider" + "create_session_fs_handler is required in session config when " + "session_fs is enabled in client options." ) - session._client_session_apis.session_fs = create_session_fs_adapter(fs_provider) + fs_provider: SessionFsProvider = create_session_fs_handler(session) + caps = self._session_fs_config.get("capabilities") + if caps and caps.get("sqlite"): + from .session_fs_provider import SessionFsSqliteProvider + + if not isinstance(fs_provider, SessionFsSqliteProvider): + raise ValueError( + "SessionFs capabilities declare SQLite support but the provider " + "does not implement SessionFsSqliteProvider" + ) + session._client_session_apis.session_fs = create_session_fs_adapter(fs_provider) + except BaseException: + session._mark_disconnected() + raise session._register_tools(tools) session._register_commands(commands) session._register_permission_handler(on_permission_request) @@ -2009,8 +2047,11 @@ async def resume_session( session._register_transform_callbacks(transform_callbacks) if on_event: session.on(on_event) - with self._sessions_lock: - self._sessions[session_id] = session + try: + self._register_session(session) + except BaseException: + session._mark_disconnected() + raise log_timing( logger, logging.DEBUG, @@ -2036,8 +2077,8 @@ async def resume_session( capabilities = response.get("capabilities") session._set_capabilities(capabilities) except BaseException as exc: - with self._sessions_lock: - self._sessions.pop(session_id, None) + self._unregister_session(session) + session._mark_disconnected() if not isinstance(exc, asyncio.CancelledError): log_timing( logger, @@ -2281,8 +2322,9 @@ async def delete_session(self, session_id: str) -> None: # Remove from local sessions map if present with self._sessions_lock: - if session_id in self._sessions: - del self._sessions[session_id] + session = self._sessions.get(session_id) + if session is not None: + session._mark_disconnected() async def get_last_session_id(self) -> str | None: """ diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index b72bd97ad..17bc21ffd 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING -from .session_events import AbortReason, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, PermissionPromptRequest, PermissionRule, ReasoningSummary, SessionEvent, SessionMode, ShutdownType, SkillSource, UserToolSessionApproval +from .session_events import EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, ReasoningSummary, SessionMode, SkillSource if TYPE_CHECKING: from .._jsonrpc import JsonRpcClient @@ -39,18 +39,14 @@ def from_union(fs, x): pass assert False -def to_class(c: type[T], x: Any) -> dict: - assert isinstance(x, c) - return cast(Any, x).to_dict() +def from_int(x: Any) -> int: + assert isinstance(x, int) and not isinstance(x, bool) + return x def from_bool(x: Any) -> bool: assert isinstance(x, bool) return x -def from_int(x: Any) -> int: - assert isinstance(x, int) and not isinstance(x, bool) - return x - def from_float(x: Any) -> float: assert isinstance(x, (float, int)) and not isinstance(x, bool) return float(x) @@ -63,6 +59,10 @@ def from_dict(f: Callable[[Any], T], x: Any) -> dict[str, T]: assert isinstance(x, dict) return { k: f(v) for (k, v) in x.items() } +def to_class(c: type[T], x: Any) -> dict: + assert isinstance(x, c) + return cast(Any, x).to_dict() + def from_list(f: Callable[[Any], T], x: Any) -> list[T]: assert isinstance(x, list) return [f(y) for y in x] @@ -74,49 +74,6 @@ def to_enum(c: type[EnumT], x: Any) -> EnumT: def from_datetime(x: Any) -> datetime: return dateutil.parser.parse(x) -@dataclass -class AbortRequest: - """Parameters for aborting the current turn""" - - reason: AbortReason | None = None - """Finite reason code describing why the current turn was aborted""" - - @staticmethod - def from_dict(obj: Any) -> 'AbortRequest': - assert isinstance(obj, dict) - reason = from_union([AbortReason, from_none], obj.get("reason")) - return AbortRequest(reason) - - def to_dict(self) -> dict: - result: dict = {} - if self.reason is not None: - result["reason"] = from_union([lambda x: to_enum(AbortReason, x), from_none], self.reason) - return result - -@dataclass -class AbortResult: - """Result of aborting the current turn""" - - success: bool - """Whether the abort completed successfully""" - - error: str | None = None - """Error message if the abort failed""" - - @staticmethod - def from_dict(obj: Any) -> 'AbortResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - error = from_union([from_str, from_none], obj.get("error")) - return AbortResult(success, error) - - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - return result - @dataclass class AccountGetQuotaRequest: git_hub_token: str | None = None @@ -191,68 +148,63 @@ def to_dict(self) -> dict: return result # Experimental: this type is part of an experimental API and may change or be removed. -class AgentInfoSource(Enum): - """Where the agent definition was loaded from""" +@dataclass +class AgentInfo: + """Schema for the `AgentInfo` type. - BUILTIN = "builtin" - INHERITED = "inherited" - PLUGIN = "plugin" - PROJECT = "project" - REMOTE = "remote" - USER = "user" + The newly selected custom agent + """ + description: str + """Description of the agent's purpose""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AgentSelectRequest: - """Name of the custom agent to select for subsequent turns.""" + display_name: str + """Human-readable display name""" name: str - """Name of the custom agent to select""" + """Unique identifier of the custom agent""" + + path: str | None = None + """Absolute local file path of the agent definition. Only set for file-based agents loaded + from disk; remote agents do not have a path. + """ @staticmethod - def from_dict(obj: Any) -> 'AgentSelectRequest': + def from_dict(obj: Any) -> 'AgentInfo': assert isinstance(obj, dict) + description = from_str(obj.get("description")) + display_name = from_str(obj.get("displayName")) name = from_str(obj.get("name")) - return AgentSelectRequest(name) + path = from_union([from_str, from_none], obj.get("path")) + return AgentInfo(description, display_name, name, path) def to_dict(self) -> dict: result: dict = {} + result["description"] = from_str(self.description) + result["displayName"] = from_str(self.display_name) result["name"] = from_str(self.name) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class CopilotUserResponseEndpoints: - """Schema for the `CopilotUserResponseEndpoints` type.""" +class AgentSelectRequest: + """Name of the custom agent to select for subsequent turns.""" - api: str | None = None - origin_tracker: str | None = None - proxy: str | None = None - telemetry: str | None = None + name: str + """Name of the custom agent to select""" @staticmethod - def from_dict(obj: Any) -> 'CopilotUserResponseEndpoints': + def from_dict(obj: Any) -> 'AgentSelectRequest': assert isinstance(obj, dict) - api = from_union([from_str, from_none], obj.get("api")) - origin_tracker = from_union([from_str, from_none], obj.get("origin-tracker")) - proxy = from_union([from_str, from_none], obj.get("proxy")) - telemetry = from_union([from_str, from_none], obj.get("telemetry")) - return CopilotUserResponseEndpoints(api, origin_tracker, proxy, telemetry) + name = from_str(obj.get("name")) + return AgentSelectRequest(name) def to_dict(self) -> dict: result: dict = {} - if self.api is not None: - result["api"] = from_union([from_str, from_none], self.api) - if self.origin_tracker is not None: - result["origin-tracker"] = from_union([from_str, from_none], self.origin_tracker) - if self.proxy is not None: - result["proxy"] = from_union([from_str, from_none], self.proxy) - if self.telemetry is not None: - result["telemetry"] = from_union([from_str, from_none], self.telemetry) + result["name"] = from_str(self.name) return result -class APIKeyAuthInfoType(Enum): - API_KEY = "api-key" - class AuthInfoType(Enum): """Authentication type""" @@ -376,11 +328,11 @@ def to_dict(self) -> dict: @dataclass class CommandsRespondToQueuedCommandResult: - """Indicates whether the queued-command response was matched to a pending request.""" + """Indicates whether the queued-command response was accepted by the session.""" success: bool - """Whether a pending queued command with the given request ID was found and resolved. False - when the request was already resolved, cancelled, or unknown. + """Whether the response was accepted (false if the requestId was not found or already + resolved) """ @staticmethod @@ -507,224 +459,23 @@ class ContentFilterMode(Enum): MARKDOWN = "markdown" NONE = "none" -class Host(Enum): - HTTPS_GITHUB_COM = "https://github.com" - -class CopilotAPITokenAuthInfoType(Enum): - COPILOT_API_TOKEN = "copilot-api-token" - -@dataclass -class CopilotUserResponseQuotaSnapshotsChat: - """Schema for the `CopilotUserResponseQuotaSnapshotsChat` type.""" - - entitlement: float | None = None - has_quota: bool | None = None - overage_count: float | None = None - overage_permitted: bool | None = None - percent_remaining: float | None = None - quota_id: str | None = None - quota_remaining: float | None = None - quota_reset_at: float | None = None - remaining: float | None = None - timestamp_utc: str | None = None - token_based_billing: bool | None = None - unlimited: bool | None = None - - @staticmethod - def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshotsChat': - assert isinstance(obj, dict) - entitlement = from_union([from_float, from_none], obj.get("entitlement")) - has_quota = from_union([from_bool, from_none], obj.get("has_quota")) - overage_count = from_union([from_float, from_none], obj.get("overage_count")) - overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) - percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) - quota_id = from_union([from_str, from_none], obj.get("quota_id")) - quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) - quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) - remaining = from_union([from_float, from_none], obj.get("remaining")) - timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) - token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) - unlimited = from_union([from_bool, from_none], obj.get("unlimited")) - return CopilotUserResponseQuotaSnapshotsChat(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) - - def to_dict(self) -> dict: - result: dict = {} - if self.entitlement is not None: - result["entitlement"] = from_union([to_float, from_none], self.entitlement) - if self.has_quota is not None: - result["has_quota"] = from_union([from_bool, from_none], self.has_quota) - if self.overage_count is not None: - result["overage_count"] = from_union([to_float, from_none], self.overage_count) - if self.overage_permitted is not None: - result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) - if self.percent_remaining is not None: - result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) - if self.quota_id is not None: - result["quota_id"] = from_union([from_str, from_none], self.quota_id) - if self.quota_remaining is not None: - result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) - if self.quota_reset_at is not None: - result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) - if self.remaining is not None: - result["remaining"] = from_union([to_float, from_none], self.remaining) - if self.timestamp_utc is not None: - result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) - if self.token_based_billing is not None: - result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) - if self.unlimited is not None: - result["unlimited"] = from_union([from_bool, from_none], self.unlimited) - return result - -@dataclass -class CopilotUserResponseQuotaSnapshotsCompletions: - """Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type.""" - - entitlement: float | None = None - has_quota: bool | None = None - overage_count: float | None = None - overage_permitted: bool | None = None - percent_remaining: float | None = None - quota_id: str | None = None - quota_remaining: float | None = None - quota_reset_at: float | None = None - remaining: float | None = None - timestamp_utc: str | None = None - token_based_billing: bool | None = None - unlimited: bool | None = None - - @staticmethod - def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshotsCompletions': - assert isinstance(obj, dict) - entitlement = from_union([from_float, from_none], obj.get("entitlement")) - has_quota = from_union([from_bool, from_none], obj.get("has_quota")) - overage_count = from_union([from_float, from_none], obj.get("overage_count")) - overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) - percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) - quota_id = from_union([from_str, from_none], obj.get("quota_id")) - quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) - quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) - remaining = from_union([from_float, from_none], obj.get("remaining")) - timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) - token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) - unlimited = from_union([from_bool, from_none], obj.get("unlimited")) - return CopilotUserResponseQuotaSnapshotsCompletions(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) - - def to_dict(self) -> dict: - result: dict = {} - if self.entitlement is not None: - result["entitlement"] = from_union([to_float, from_none], self.entitlement) - if self.has_quota is not None: - result["has_quota"] = from_union([from_bool, from_none], self.has_quota) - if self.overage_count is not None: - result["overage_count"] = from_union([to_float, from_none], self.overage_count) - if self.overage_permitted is not None: - result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) - if self.percent_remaining is not None: - result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) - if self.quota_id is not None: - result["quota_id"] = from_union([from_str, from_none], self.quota_id) - if self.quota_remaining is not None: - result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) - if self.quota_reset_at is not None: - result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) - if self.remaining is not None: - result["remaining"] = from_union([to_float, from_none], self.remaining) - if self.timestamp_utc is not None: - result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) - if self.token_based_billing is not None: - result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) - if self.unlimited is not None: - result["unlimited"] = from_union([from_bool, from_none], self.unlimited) - return result - -@dataclass -class CopilotUserResponseQuotaSnapshotsPremiumInteractions: - """Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type.""" - - entitlement: float | None = None - has_quota: bool | None = None - overage_count: float | None = None - overage_permitted: bool | None = None - percent_remaining: float | None = None - quota_id: str | None = None - quota_remaining: float | None = None - quota_reset_at: float | None = None - remaining: float | None = None - timestamp_utc: str | None = None - token_based_billing: bool | None = None - unlimited: bool | None = None - - @staticmethod - def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshotsPremiumInteractions': - assert isinstance(obj, dict) - entitlement = from_union([from_float, from_none], obj.get("entitlement")) - has_quota = from_union([from_bool, from_none], obj.get("has_quota")) - overage_count = from_union([from_float, from_none], obj.get("overage_count")) - overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) - percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) - quota_id = from_union([from_str, from_none], obj.get("quota_id")) - quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) - quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) - remaining = from_union([from_float, from_none], obj.get("remaining")) - timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) - token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) - unlimited = from_union([from_bool, from_none], obj.get("unlimited")) - return CopilotUserResponseQuotaSnapshotsPremiumInteractions(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) - - def to_dict(self) -> dict: - result: dict = {} - if self.entitlement is not None: - result["entitlement"] = from_union([to_float, from_none], self.entitlement) - if self.has_quota is not None: - result["has_quota"] = from_union([from_bool, from_none], self.has_quota) - if self.overage_count is not None: - result["overage_count"] = from_union([to_float, from_none], self.overage_count) - if self.overage_permitted is not None: - result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) - if self.percent_remaining is not None: - result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) - if self.quota_id is not None: - result["quota_id"] = from_union([from_str, from_none], self.quota_id) - if self.quota_remaining is not None: - result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) - if self.quota_reset_at is not None: - result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) - if self.remaining is not None: - result["remaining"] = from_union([to_float, from_none], self.remaining) - if self.timestamp_utc is not None: - result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) - if self.token_based_billing is not None: - result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) - if self.unlimited is not None: - result["unlimited"] = from_union([from_bool, from_none], self.unlimited) - return result - @dataclass class CurrentModel: - """The currently selected model and reasoning effort for the session.""" + """The currently selected model for the session.""" model_id: str | None = None """Currently active model identifier""" - reasoning_effort: str | None = None - """Reasoning effort level currently applied to the active model, when one is set. Reads - `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the - two values are reported as a snapshot. - """ - @staticmethod def from_dict(obj: Any) -> 'CurrentModel': assert isinstance(obj, dict) model_id = from_union([from_str, from_none], obj.get("modelId")) - reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) - return CurrentModel(model_id, reasoning_effort) + return CurrentModel(model_id) def to_dict(self) -> dict: result: dict = {} if self.model_id is not None: result["modelId"] = from_union([from_str, from_none], self.model_id) - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) return result class DiscoveredMCPServerType(Enum): @@ -735,161 +486,6 @@ class DiscoveredMCPServerType(Enum): SSE = "sse" STDIO = "stdio" -@dataclass -class EnqueueCommandParams: - """Slash-prefixed command string to enqueue for FIFO processing.""" - - command: str - """Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO - with any in-flight items; if the session is idle, processing kicks off immediately. - """ - - @staticmethod - def from_dict(obj: Any) -> 'EnqueueCommandParams': - assert isinstance(obj, dict) - command = from_str(obj.get("command")) - return EnqueueCommandParams(command) - - def to_dict(self) -> dict: - result: dict = {} - result["command"] = from_str(self.command) - return result - -@dataclass -class EnqueueCommandResult: - """Indicates whether the command was accepted into the local execution queue.""" - - queued: bool - """True when the command was accepted into the local execution queue. False when the call - targets a session that does not support local command queueing (e.g. remote sessions). - """ - - @staticmethod - def from_dict(obj: Any) -> 'EnqueueCommandResult': - assert isinstance(obj, dict) - queued = from_bool(obj.get("queued")) - return EnqueueCommandResult(queued) - - def to_dict(self) -> dict: - result: dict = {} - result["queued"] = from_bool(self.queued) - return result - -class EnvAuthInfoType(Enum): - ENV = "env" - -# Experimental: this type is part of an experimental API and may change or be removed. -class EventsAgentScope(Enum): - """Agent-scope filter: 'primary' returns only main-agent events plus events whose type - starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns - events from all agents (matching wildcard-subscription behavior). Default is 'all' to - preserve wildcard semantics for catch-up callers. - """ - ALL = "all" - PRIMARY = "primary" - -# Experimental: this type is part of an experimental API and may change or be removed. -class EventLogTypes(Enum): - EMPTY = "*" - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class EventLogReleaseInterestResult: - """Indicates whether the operation succeeded.""" - - success: bool - """Whether the operation succeeded""" - - @staticmethod - def from_dict(obj: Any) -> 'EventLogReleaseInterestResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return EventLogReleaseInterestResult(success) - - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class EventLogTailResult: - """Snapshot of the current tail cursor without returning any events. Use this when a - consumer wants to subscribe to live events going forward without first paginating through - the entire persisted history (which would happen if `read` were called without a cursor - on a long-lived session). - """ - cursor: str - """Opaque cursor pointing at the current tail of the session's persisted-events history. - Pass back to `read` to receive only events that arrive AFTER this snapshot. When the - session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent - to omitting the cursor on a first read). - """ - - @staticmethod - def from_dict(obj: Any) -> 'EventLogTailResult': - assert isinstance(obj, dict) - cursor = from_str(obj.get("cursor")) - return EventLogTailResult(cursor) - - def to_dict(self) -> dict: - result: dict = {} - result["cursor"] = from_str(self.cursor) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -class EventsCursorStatus(Enum): - """Cursor status: 'ok' means the cursor was applied successfully; 'expired' means the cursor - referred to an event that no longer exists in history (e.g. truncated or compacted away) - and the read started from the beginning of the remaining history. - """ - EXPIRED = "expired" - OK = "ok" - -@dataclass -class ExecuteCommandParams: - """Slash command name and argument string to execute synchronously.""" - - args: str - """Argument string to pass to the command (empty string if none).""" - - command_name: str - """Name of the slash command to invoke (without the leading '/').""" - - @staticmethod - def from_dict(obj: Any) -> 'ExecuteCommandParams': - assert isinstance(obj, dict) - args = from_str(obj.get("args")) - command_name = from_str(obj.get("commandName")) - return ExecuteCommandParams(args, command_name) - - def to_dict(self) -> dict: - result: dict = {} - result["args"] = from_str(self.args) - result["commandName"] = from_str(self.command_name) - return result - -@dataclass -class ExecuteCommandResult: - """Error message produced while executing the command, if any.""" - - error: str | None = None - """Error message produced while executing the command, if any. Omitted when the handler - succeeded. - """ - - @staticmethod - def from_dict(obj: Any) -> 'ExecuteCommandResult': - assert isinstance(obj, dict) - error = from_union([from_str, from_none], obj.get("error")) - return ExecuteCommandResult(error) - - def to_dict(self) -> dict: - result: dict = {} - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - return result - # Experimental: this type is part of an experimental API and may change or be removed. class ExtensionSource(Enum): """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" @@ -1022,9 +618,6 @@ def to_dict(self) -> dict: result["started"] = from_bool(self.started) return result -class GhCLIAuthInfoType(Enum): - GH_CLI = "gh-cli" - @dataclass class HandlePendingToolCallResult: """Indicates whether the external tool call result was handled successfully.""" @@ -1043,48 +636,6 @@ def to_dict(self) -> dict: result["success"] = from_bool(self.success) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class HistoryAbortManualCompactionResult: - """Indicates whether an in-progress manual compaction was aborted.""" - - aborted: bool - """Whether an in-progress manual compaction was aborted. False when no manual compaction was - running, when its abort controller was already aborted, or when the session is remote. - """ - - @staticmethod - def from_dict(obj: Any) -> 'HistoryAbortManualCompactionResult': - assert isinstance(obj, dict) - aborted = from_bool(obj.get("aborted")) - return HistoryAbortManualCompactionResult(aborted) - - def to_dict(self) -> dict: - result: dict = {} - result["aborted"] = from_bool(self.aborted) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class HistoryCancelBackgroundCompactionResult: - """Indicates whether an in-progress background compaction was cancelled.""" - - cancelled: bool - """Whether an in-progress background compaction was cancelled. False when no compaction was - running, when the session is remote, or when the underlying processor was unavailable. - """ - - @staticmethod - def from_dict(obj: Any) -> 'HistoryCancelBackgroundCompactionResult': - assert isinstance(obj, dict) - cancelled = from_bool(obj.get("cancelled")) - return HistoryCancelBackgroundCompactionResult(cancelled) - - def to_dict(self) -> dict: - result: dict = {} - result["cancelled"] = from_bool(self.cancelled) - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class HistoryCompactContextWindow: @@ -1132,27 +683,6 @@ def to_dict(self) -> dict: result["toolDefinitionsTokens"] = from_union([from_int, from_none], self.tool_definitions_tokens) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class HistorySummarizeForHandoffResult: - """Markdown summary of the conversation context (empty when not available).""" - - summary: str - """Markdown summary of the conversation context produced by an LLM. Empty string when there - are no messages or when the session does not support local summarization. - """ - - @staticmethod - def from_dict(obj: Any) -> 'HistorySummarizeForHandoffResult': - assert isinstance(obj, dict) - summary = from_str(obj.get("summary")) - return HistorySummarizeForHandoffResult(summary) - - def to_dict(self) -> dict: - result: dict = {} - result["summary"] = from_str(self.summary) - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class HistoryTruncateRequest: @@ -1191,27 +721,9 @@ def to_dict(self) -> dict: result["eventsRemoved"] = from_int(self.events_removed) return result -class HMACAuthInfoType(Enum): - HMAC = "hmac" +class InstructionsSourcesLocation(Enum): + """Where this source lives — used for UI grouping""" -class PurpleSource(Enum): - GITHUB = "github" - LOCAL = "local" - URL = "url" - -class FluffySource(Enum): - GITHUB = "github" - -class TentacledSource(Enum): - LOCAL = "local" - -class StickySource(Enum): - URL = "url" - -class InstructionsSourcesLocation(Enum): - """Where this source lives — used for UI grouping""" - - PLUGIN = "plugin" REPOSITORY = "repository" USER = "user" WORKING_DIRECTORY = "working-directory" @@ -1223,7 +735,6 @@ class InstructionsSourcesType(Enum): HOME = "home" MODEL = "model" NESTED_AGENTS = "nested-agents" - PLUGIN = "plugin" REPO = "repo" VSCODE = "vscode" @@ -1253,84 +764,6 @@ def to_dict(self) -> dict: result["eventId"] = str(self.event_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class LspInitializeRequest: - """Parameters for (re)loading the merged LSP configuration set.""" - - force: bool | None = None - """Force re-initialization even when LSP configs were already loaded for the working - directory. - """ - git_root: str | None = None - """Git root used as the boundary when traversing for project-level LSP configs (supports - monorepos). - """ - working_directory: str | None = None - """Working directory used to load project-level LSP configs. Defaults to the session working - directory when omitted. - """ - - @staticmethod - def from_dict(obj: Any) -> 'LspInitializeRequest': - assert isinstance(obj, dict) - force = from_union([from_bool, from_none], obj.get("force")) - git_root = from_union([from_str, from_none], obj.get("gitRoot")) - working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) - return LspInitializeRequest(force, git_root, working_directory) - - def to_dict(self) -> dict: - result: dict = {} - if self.force is not None: - result["force"] = from_union([from_bool, from_none], self.force) - if self.git_root is not None: - result["gitRoot"] = from_union([from_str, from_none], self.git_root) - if self.working_directory is not None: - result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPCancelSamplingExecutionParams: - """The requestId previously passed to executeSampling that should be cancelled.""" - - request_id: str - """The requestId previously passed to executeSampling that should be cancelled""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPCancelSamplingExecutionParams': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - return MCPCancelSamplingExecutionParams(request_id) - - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPCancelSamplingExecutionResult: - """Indicates whether an in-flight sampling execution with the given requestId was found and - cancelled. - """ - cancelled: bool - """True if an in-flight execution with the given requestId was found and signalled to - cancel. False when no such execution is in flight (already completed, never started, or - cancelled by another caller). - """ - - @staticmethod - def from_dict(obj: Any) -> 'MCPCancelSamplingExecutionResult': - assert isinstance(obj, dict) - cancelled = from_bool(obj.get("cancelled")) - return MCPCancelSamplingExecutionResult(cancelled) - - def to_dict(self) -> dict: - result: dict = {} - result["cancelled"] = from_bool(self.cancelled) - return result - @dataclass class MCPServerConfigHTTPAuth: """Additional authentication configuration for this server.""" @@ -1551,39 +984,6 @@ def to_dict(self) -> dict: result["authorizationUrl"] = from_union([from_str, from_none], self.authorization_url) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPRemoveGitHubResult: - """Indicates whether the auto-managed `github` MCP server was removed (false when nothing to - remove). - """ - removed: bool - """True when the auto-managed `github` MCP server was removed; false when no removal - happened (e.g. user has explicitly configured a `github` server, or the server was not - registered). - """ - - @staticmethod - def from_dict(obj: Any) -> 'MCPRemoveGitHubResult': - assert isinstance(obj, dict) - removed = from_bool(obj.get("removed")) - return MCPRemoveGitHubResult(removed) - - def to_dict(self) -> dict: - result: dict = {} - result["removed"] = from_bool(self.removed) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -class MCPSamplingExecutionAction(Enum): - """Outcome of the sampling inference. 'success' produced a response; 'failure' encountered - an error (including agent-side rejection by content filter or criteria); 'cancelled' the - caller cancelled this execution via cancelSamplingExecution. - """ - CANCELLED = "cancelled" - FAILURE = "failure" - SUCCESS = "success" - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPServer: @@ -1620,257 +1020,6 @@ def to_dict(self) -> dict: result["source"] = from_union([lambda x: to_enum(McpServerSource, x), from_none], self.source) return result -# Experimental: this type is part of an experimental API and may change or be removed. -class MCPSetEnvValueModeDetails(Enum): - """How environment-variable values supplied to MCP servers are resolved. "direct" passes - literal string values; "indirect" treats values as references (e.g. names of environment - variables on the host) that the runtime resolves before launch. Defaults to the runtime's - startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI - prompt mode and ACP) set this to "direct". - - Mode recorded on the session after the update - - How env values are passed to MCP servers (`direct` inlines literal values; `indirect` - resolves at launch). - """ - DIRECT = "direct" - INDIRECT = "indirect" - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionContextInfo: - """Token-usage breakdown for the session's current context window""" - - buffer_tokens: int - """Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%)""" - - compaction_threshold: int - """Token count at which background compaction starts (configurable percentage of - promptTokenLimit) - """ - conversation_tokens: int - """Tokens consumed by user/assistant/tool messages""" - - limit: int - """Total context limit for /context display. promptTokenLimit + min(32k or 64k, - outputTokenLimit) depending on model. - """ - model_name: str - """The model used for token counting""" - - prompt_token_limit: int - """Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified)""" - - system_tokens: int - """Tokens consumed by the system prompt""" - - tool_definitions_tokens: int - """Tokens consumed by tool definitions sent to the model (excludes deferred tools)""" - - total_tokens: int - """Sum of system, conversation and tool-definition tokens""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionContextInfo': - assert isinstance(obj, dict) - buffer_tokens = from_int(obj.get("bufferTokens")) - compaction_threshold = from_int(obj.get("compactionThreshold")) - conversation_tokens = from_int(obj.get("conversationTokens")) - limit = from_int(obj.get("limit")) - model_name = from_str(obj.get("modelName")) - prompt_token_limit = from_int(obj.get("promptTokenLimit")) - system_tokens = from_int(obj.get("systemTokens")) - tool_definitions_tokens = from_int(obj.get("toolDefinitionsTokens")) - total_tokens = from_int(obj.get("totalTokens")) - return SessionContextInfo(buffer_tokens, compaction_threshold, conversation_tokens, limit, model_name, prompt_token_limit, system_tokens, tool_definitions_tokens, total_tokens) - - def to_dict(self) -> dict: - result: dict = {} - result["bufferTokens"] = from_int(self.buffer_tokens) - result["compactionThreshold"] = from_int(self.compaction_threshold) - result["conversationTokens"] = from_int(self.conversation_tokens) - result["limit"] = from_int(self.limit) - result["modelName"] = from_str(self.model_name) - result["promptTokenLimit"] = from_int(self.prompt_token_limit) - result["systemTokens"] = from_int(self.system_tokens) - result["toolDefinitionsTokens"] = from_int(self.tool_definitions_tokens) - result["totalTokens"] = from_int(self.total_tokens) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataIsProcessingResult: - """Indicates whether the local session is currently processing a turn or background - continuation. - """ - processing: bool - """Whether the session is currently processing user/agent messages. False for non-local - sessions (which don't run a local agentic loop). Reflects an in-flight turn or background - continuation. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataIsProcessingResult': - assert isinstance(obj, dict) - processing = from_bool(obj.get("processing")) - return MetadataIsProcessingResult(processing) - - def to_dict(self) -> dict: - result: dict = {} - result["processing"] = from_bool(self.processing) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataRecomputeContextTokensResult: - """Re-tokenize the session's existing messages against `modelId` and return the token - totals. Useful for hosts that want an initial estimate of context usage on session - resume, before the next agent turn fires `session.context_info_changed` events. Returns - zeros for an empty session. - """ - messages_token_count: int - """Tokens contributed by user/assistant/tool messages (excludes system/developer prompts).""" - - system_token_count: int - """Tokens contributed by system/developer prompt snapshots.""" - - total_tokens: int - """Sum of tokens across chat-context and system-context messages currently held by the - session. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataRecomputeContextTokensResult': - assert isinstance(obj, dict) - messages_token_count = from_int(obj.get("messagesTokenCount")) - system_token_count = from_int(obj.get("systemTokenCount")) - total_tokens = from_int(obj.get("totalTokens")) - return MetadataRecomputeContextTokensResult(messages_token_count, system_token_count, total_tokens) - - def to_dict(self) -> dict: - result: dict = {} - result["messagesTokenCount"] = from_int(self.messages_token_count) - result["systemTokenCount"] = from_int(self.system_token_count) - result["totalTokens"] = from_int(self.total_tokens) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -class SessionContextHostType(Enum): - """Hosting platform type of the repository - - Repository host type - - Repository host type, if known - """ - ADO = "ado" - GITHUB = "github" - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataRecordContextChangeResult: - """Notify the session that its working directory context has changed. Emits a - `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline - UI) can react. Use this when the host has detected a cwd/branch/repo change outside the - session's normal lifecycle (e.g., after a shell command in interactive mode). - """ - @staticmethod - def from_dict(obj: Any) -> 'MetadataRecordContextChangeResult': - assert isinstance(obj, dict) - return MetadataRecordContextChangeResult() - - def to_dict(self) -> dict: - result: dict = {} - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataSetWorkingDirectoryRequest: - """Absolute path to set as the session's new working directory.""" - - working_directory: str - """Absolute path to set as the session's working directory. The runtime updates the - session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) - anchor to it. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataSetWorkingDirectoryRequest': - assert isinstance(obj, dict) - working_directory = from_str(obj.get("workingDirectory")) - return MetadataSetWorkingDirectoryRequest(working_directory) - - def to_dict(self) -> dict: - result: dict = {} - result["workingDirectory"] = from_str(self.working_directory) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataSetWorkingDirectoryResult: - """Update the session's working directory. Used by the host when the user explicitly changes - cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any - related side-effects (file index, etc.); this method only updates the session's own - recorded path. - """ - working_directory: str - """Working directory after the update""" - - @staticmethod - def from_dict(obj: Any) -> 'MetadataSetWorkingDirectoryResult': - assert isinstance(obj, dict) - working_directory = from_str(obj.get("workingDirectory")) - return MetadataSetWorkingDirectoryResult(working_directory) - - def to_dict(self) -> dict: - result: dict = {} - result["workingDirectory"] = from_str(self.working_directory) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -class MetadataSnapshotCurrentMode(Enum): - """The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot')""" - - AUTOPILOT = "autopilot" - INTERACTIVE = "interactive" - PLAN = "plan" - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataSnapshotRemoteMetadataRepository: - """The repository the remote session targets.""" - - branch: str - """The branch the remote session is operating on.""" - - name: str - """The GitHub repository name (without owner).""" - - owner: str - """The GitHub owner (user or organization) of the target repository.""" - - @staticmethod - def from_dict(obj: Any) -> 'MetadataSnapshotRemoteMetadataRepository': - assert isinstance(obj, dict) - branch = from_str(obj.get("branch")) - name = from_str(obj.get("name")) - owner = from_str(obj.get("owner")) - return MetadataSnapshotRemoteMetadataRepository(branch, name, owner) - - def to_dict(self) -> dict: - result: dict = {} - result["branch"] = from_str(self.branch) - result["name"] = from_str(self.name) - result["owner"] = from_str(self.owner) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -class MetadataSnapshotRemoteMetadataTaskType(Enum): - """Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` - invocation. - """ - CCA = "cca" - CLI = "cli" - @dataclass class ModeSetRequest: """Agent interaction mode to apply to the session.""" @@ -2054,46 +1203,6 @@ def to_dict(self) -> dict: result["vision"] = from_union([from_bool, from_none], self.vision) return result -@dataclass -class ModelSetReasoningEffortRequest: - """Reasoning effort level to apply to the currently selected model.""" - - reasoning_effort: str - """Reasoning effort level to apply to the currently selected model. The host is responsible - for validating the value against the model's supported levels before calling. - """ - - @staticmethod - def from_dict(obj: Any) -> 'ModelSetReasoningEffortRequest': - assert isinstance(obj, dict) - reasoning_effort = from_str(obj.get("reasoningEffort")) - return ModelSetReasoningEffortRequest(reasoning_effort) - - def to_dict(self) -> dict: - result: dict = {} - result["reasoningEffort"] = from_str(self.reasoning_effort) - return result - -@dataclass -class ModelSetReasoningEffortResult: - """Update the session's reasoning effort without changing the selected model. Use `switchTo` - instead when you also need to change the model. The runtime stores the effort on the - session and applies it to subsequent turns. - """ - reasoning_effort: str - """Reasoning effort level recorded on the session after the update""" - - @staticmethod - def from_dict(obj: Any) -> 'ModelSetReasoningEffortResult': - assert isinstance(obj, dict) - reasoning_effort = from_str(obj.get("reasoningEffort")) - return ModelSetReasoningEffortResult(reasoning_effort) - - def to_dict(self) -> dict: - result: dict = {} - result["reasoningEffort"] = from_str(self.reasoning_effort) - return result - @dataclass class ModelSwitchToResult: """The model identifier active on the session after the switch.""" @@ -2150,47 +1259,6 @@ def to_dict(self) -> dict: result["name"] = from_union([from_none, from_str], self.name) return result -@dataclass -class NameSetAutoRequest: - """Auto-generated session summary to apply as the session's name when no user-set name - exists. - """ - summary: str - """Auto-generated session summary. Empty/whitespace-only values are ignored; values are - trimmed before persisting. - """ - - @staticmethod - def from_dict(obj: Any) -> 'NameSetAutoRequest': - assert isinstance(obj, dict) - summary = from_str(obj.get("summary")) - return NameSetAutoRequest(summary) - - def to_dict(self) -> dict: - result: dict = {} - result["summary"] = from_str(self.summary) - return result - -@dataclass -class NameSetAutoResult: - """Indicates whether the auto-generated summary was applied as the session's name.""" - - applied: bool - """Whether the auto-generated summary was persisted. False if the session already has a - user-set name, the summary normalized to empty, or the session does not have a workspace. - """ - - @staticmethod - def from_dict(obj: Any) -> 'NameSetAutoResult': - assert isinstance(obj, dict) - applied = from_bool(obj.get("applied")) - return NameSetAutoResult(applied) - - def to_dict(self) -> dict: - result: dict = {} - result["applied"] = from_bool(self.applied) - return result - @dataclass class NameSetRequest: """New friendly name to apply to the session.""" @@ -2209,30 +1277,6 @@ def to_dict(self) -> dict: result["name"] = from_str(self.name) return result -@dataclass -class PendingPermissionRequest: - """Schema for the `PendingPermissionRequest` type.""" - - request: PermissionPromptRequest - """The user-facing permission prompt details (commands, write, read, mcp, url, memory, - custom-tool, path, hook) - """ - request_id: str - """Unique identifier for the pending permission request""" - - @staticmethod - def from_dict(obj: Any) -> 'PendingPermissionRequest': - assert isinstance(obj, dict) - request = PermissionPromptRequest.from_dict(obj.get("request")) - request_id = from_str(obj.get("requestId")) - return PendingPermissionRequest(request, request_id) - - def to_dict(self) -> dict: - result: dict = {} - result["request"] = to_class(PermissionPromptRequest, self.request) - result["requestId"] = from_str(self.request_id) - return result - class ApprovalKind(Enum): COMMANDS = "commands" CUSTOM_TOOL = "custom-tool" @@ -2245,19 +1289,10 @@ class ApprovalKind(Enum): WRITE = "write" class PermissionDecisionKind(Enum): - APPROVED = "approved" - APPROVED_FOR_LOCATION = "approved-for-location" - APPROVED_FOR_SESSION = "approved-for-session" APPROVE_FOR_LOCATION = "approve-for-location" APPROVE_FOR_SESSION = "approve-for-session" APPROVE_ONCE = "approve-once" APPROVE_PERMANENTLY = "approve-permanently" - CANCELLED = "cancelled" - DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" - DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" - DENIED_BY_RULES = "denied-by-rules" - DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" - DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" REJECT = "reject" USER_NOT_AVAILABLE = "user-not-available" @@ -2300,33 +1335,6 @@ class PermissionDecisionApproveOnceKind(Enum): class PermissionDecisionApprovePermanentlyKind(Enum): APPROVE_PERMANENTLY = "approve-permanently" -class PermissionDecisionApprovedKind(Enum): - APPROVED = "approved" - -class PermissionDecisionApprovedForLocationKind(Enum): - APPROVED_FOR_LOCATION = "approved-for-location" - -class PermissionDecisionApprovedForSessionKind(Enum): - APPROVED_FOR_SESSION = "approved-for-session" - -class PermissionDecisionCancelledKind(Enum): - CANCELLED = "cancelled" - -class PermissionDecisionDeniedByContentExclusionPolicyKind(Enum): - DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" - -class PermissionDecisionDeniedByPermissionRequestHookKind(Enum): - DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" - -class PermissionDecisionDeniedByRulesKind(Enum): - DENIED_BY_RULES = "denied-by-rules" - -class PermissionDecisionDeniedInteractivelyByUserKind(Enum): - DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" - -class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind(Enum): - DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" - class PermissionDecisionRejectKind(Enum): REJECT = "reject" @@ -2334,8632 +1342,4550 @@ class PermissionDecisionUserNotAvailableKind(Enum): USER_NOT_AVAILABLE = "user-not-available" @dataclass -class PermissionPathsAddParams: - """Directory path to add to the session's allowed directories.""" - - path: str - """Directory to add to the allow-list. The runtime resolves and validates the path before - adding. +class PermissionRequestResult: + """Indicates whether the permission decision was applied; false when the request was already + resolved. """ + success: bool + """Whether the permission request was handled successfully""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsAddParams': + def from_dict(obj: Any) -> 'PermissionRequestResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return PermissionPathsAddParams(path) + success = from_bool(obj.get("success")) + return PermissionRequestResult(success) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) + result["success"] = from_bool(self.success) return result @dataclass -class PermissionPathsAllowedCheckParams: - """Path to evaluate against the session's allowed directories.""" - - path: str - """Path to check against the session's allowed directories""" - +class PermissionsResetSessionApprovalsRequest: + """No parameters; clears all session-scoped tool permission approvals.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsAllowedCheckParams': + def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return PermissionPathsAllowedCheckParams(path) + return PermissionsResetSessionApprovalsRequest() def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) return result @dataclass -class PermissionPathsAllowedCheckResult: - """Indicates whether the supplied path is within the session's allowed directories.""" +class PermissionsResetSessionApprovalsResult: + """Indicates whether the operation succeeded.""" - allowed: bool - """Whether the path is within the session's allowed directories""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsAllowedCheckResult': + def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsResult': assert isinstance(obj, dict) - allowed = from_bool(obj.get("allowed")) - return PermissionPathsAllowedCheckResult(allowed) + success = from_bool(obj.get("success")) + return PermissionsResetSessionApprovalsResult(success) def to_dict(self) -> dict: result: dict = {} - result["allowed"] = from_bool(self.allowed) + result["success"] = from_bool(self.success) return result @dataclass -class PermissionPathsList: - """Snapshot of the session's allow-listed directories and primary working directory.""" - - directories: list[str] - """All directories currently allowed for tool access on this session.""" +class PermissionsSetApproveAllRequest: + """Whether to auto-approve all tool permission requests for the rest of the session.""" - primary: str - """The primary working directory for this session.""" + enabled: bool + """Whether to auto-approve all tool permission requests""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsList': + def from_dict(obj: Any) -> 'PermissionsSetApproveAllRequest': assert isinstance(obj, dict) - directories = from_list(from_str, obj.get("directories")) - primary = from_str(obj.get("primary")) - return PermissionPathsList(directories, primary) + enabled = from_bool(obj.get("enabled")) + return PermissionsSetApproveAllRequest(enabled) def to_dict(self) -> dict: result: dict = {} - result["directories"] = from_list(from_str, self.directories) - result["primary"] = from_str(self.primary) + result["enabled"] = from_bool(self.enabled) return result @dataclass -class PermissionPathsUpdatePrimaryParams: - """Directory path to set as the session's new primary working directory.""" +class PermissionsSetApproveAllResult: + """Indicates whether the operation succeeded.""" - path: str - """Directory to set as the new primary working directory for the session's permission policy.""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsUpdatePrimaryParams': + def from_dict(obj: Any) -> 'PermissionsSetApproveAllResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return PermissionPathsUpdatePrimaryParams(path) + success = from_bool(obj.get("success")) + return PermissionsSetApproveAllResult(success) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) + result["success"] = from_bool(self.success) return result @dataclass -class PermissionPathsWorkspaceCheckParams: - """Path to evaluate against the session's workspace (primary) directory.""" +class PingRequest: + """Optional message to echo back to the caller.""" - path: str - """Path to check against the session workspace directory""" + message: str | None = None + """Optional message to echo back""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsWorkspaceCheckParams': + def from_dict(obj: Any) -> 'PingRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return PermissionPathsWorkspaceCheckParams(path) + message = from_union([from_str, from_none], obj.get("message")) + return PingRequest(message) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) return result @dataclass -class PermissionPathsWorkspaceCheckResult: - """Indicates whether the supplied path is within the session's workspace directory.""" - - allowed: bool - """Whether the path is within the session workspace directory""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsWorkspaceCheckResult': - assert isinstance(obj, dict) - allowed = from_bool(obj.get("allowed")) - return PermissionPathsWorkspaceCheckResult(allowed) - - def to_dict(self) -> dict: - result: dict = {} - result["allowed"] = from_bool(self.allowed) - return result +class PingResult: + """Server liveness response, including the echoed message, current timestamp, and protocol + version. + """ + message: str + """Echoed message (or default greeting)""" -@dataclass -class PermissionPromptShownNotification: - """Notification payload describing the permission prompt that the client just rendered.""" + protocol_version: int + """Server protocol version number""" - message: str - """Human-readable description of the prompt the user is being asked to approve. Used by the - runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, - desktop notification). - """ + timestamp: int + """Server timestamp in milliseconds""" @staticmethod - def from_dict(obj: Any) -> 'PermissionPromptShownNotification': + def from_dict(obj: Any) -> 'PingResult': assert isinstance(obj, dict) message = from_str(obj.get("message")) - return PermissionPromptShownNotification(message) + protocol_version = from_int(obj.get("protocolVersion")) + timestamp = from_int(obj.get("timestamp")) + return PingResult(message, protocol_version, timestamp) def to_dict(self) -> dict: result: dict = {} result["message"] = from_str(self.message) + result["protocolVersion"] = from_int(self.protocol_version) + result["timestamp"] = from_int(self.timestamp) return result @dataclass -class PermissionRequestResult: - """Indicates whether the permission decision was applied; false when the request was already - resolved. - """ - success: bool - """Whether the permission request was handled successfully""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionRequestResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionRequestResult(success) +class PlanReadResult: + """Existence, contents, and resolved path of the session plan file.""" - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result + exists: bool + """Whether the plan file exists in the workspace""" -@dataclass -class PermissionRulesSet: - """If specified, replaces the session's approved/denied permission rules. Omit to leave the - current rules unchanged. - """ - approved: list[PermissionRule] - """Rules that auto-approve matching requests""" + content: str | None = None + """The content of the plan file, or null if it does not exist""" - denied: list[PermissionRule] - """Rules that auto-deny matching requests""" + path: str | None = None + """Absolute file path of the plan file, or null if workspace is not enabled""" @staticmethod - def from_dict(obj: Any) -> 'PermissionRulesSet': + def from_dict(obj: Any) -> 'PlanReadResult': assert isinstance(obj, dict) - approved = from_list(PermissionRule.from_dict, obj.get("approved")) - denied = from_list(PermissionRule.from_dict, obj.get("denied")) - return PermissionRulesSet(approved, denied) + exists = from_bool(obj.get("exists")) + content = from_union([from_none, from_str], obj.get("content")) + path = from_union([from_none, from_str], obj.get("path")) + return PlanReadResult(exists, content, path) def to_dict(self) -> dict: result: dict = {} - result["approved"] = from_list(lambda x: to_class(PermissionRule, x), self.approved) - result["denied"] = from_list(lambda x: to_class(PermissionRule, x), self.denied) + result["exists"] = from_bool(self.exists) + result["content"] = from_union([from_none, from_str], self.content) + result["path"] = from_union([from_none, from_str], self.path) return result @dataclass -class PermissionUrlsConfig: - """If specified, replaces the session's URL-permission policy. The runtime constructs a - fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy - unchanged. - """ - initial_allowed: list[str] | None = None - """Initial list of allowed URL/domain patterns. Patterns may include path components. - Ignored when `unrestricted` is true. - """ - unrestricted: bool | None = None - """If true, the runtime allows access to all URLs without prompting. Initial allow-list is - ignored when this is true. - """ +class PlanUpdateRequest: + """Replacement contents to write to the session plan file.""" + + content: str + """The new content for the plan file""" @staticmethod - def from_dict(obj: Any) -> 'PermissionUrlsConfig': + def from_dict(obj: Any) -> 'PlanUpdateRequest': assert isinstance(obj, dict) - initial_allowed = from_union([lambda x: from_list(from_str, x), from_none], obj.get("initialAllowed")) - unrestricted = from_union([from_bool, from_none], obj.get("unrestricted")) - return PermissionUrlsConfig(initial_allowed, unrestricted) + content = from_str(obj.get("content")) + return PlanUpdateRequest(content) def to_dict(self) -> dict: result: dict = {} - if self.initial_allowed is not None: - result["initialAllowed"] = from_union([lambda x: from_list(from_str, x), from_none], self.initial_allowed) - if self.unrestricted is not None: - result["unrestricted"] = from_union([from_bool, from_none], self.unrestricted) + result["content"] = from_str(self.content) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionUrlsSetUnrestrictedModeParams: - """Whether the URL-permission policy should run in unrestricted mode.""" +class Plugin: + """Schema for the `Plugin` type.""" enabled: bool - """Whether to allow access to all URLs without prompting. Toggles the runtime's - URL-permission policy in place. - """ + """Whether the plugin is currently enabled""" + + marketplace: str + """Marketplace the plugin came from""" + + name: str + """Plugin name""" + + version: str | None = None + """Installed version""" @staticmethod - def from_dict(obj: Any) -> 'PermissionUrlsSetUnrestrictedModeParams': + def from_dict(obj: Any) -> 'Plugin': assert isinstance(obj, dict) enabled = from_bool(obj.get("enabled")) - return PermissionUrlsSetUnrestrictedModeParams(enabled) + marketplace = from_str(obj.get("marketplace")) + name = from_str(obj.get("name")) + version = from_union([from_str, from_none], obj.get("version")) + return Plugin(enabled, marketplace, name, version) def to_dict(self) -> dict: result: dict = {} result["enabled"] = from_bool(self.enabled) + result["marketplace"] = from_str(self.marketplace) + result["name"] = from_str(self.name) + if self.version is not None: + result["version"] = from_union([from_str, from_none], self.version) return result @dataclass -class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource: - """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.""" +class QueuedCommandHandled: + """Schema for the `QueuedCommandHandled` type.""" - name: str - type: str + handled: bool + """The command was handled""" + + stop_processing_queue: bool | None = None + """If true, stop processing remaining queued items""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsConfigureAdditionalContentExclusionPolicyRuleSource': + def from_dict(obj: Any) -> 'QueuedCommandHandled': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - type = from_str(obj.get("type")) - return PermissionsConfigureAdditionalContentExclusionPolicyRuleSource(name, type) + handled = from_bool(obj.get("handled")) + stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) + return QueuedCommandHandled(handled, stop_processing_queue) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["type"] = from_str(self.type) + result["handled"] = from_bool(self.handled) + if self.stop_processing_queue is not None: + result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) return result -class PermissionsConfigureAdditionalContentExclusionPolicyScope(Enum): - """Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` - enumeration. - """ - ALL = "all" - REPO = "repo" - @dataclass -class PermissionsConfigureResult: - """Indicates whether the operation succeeded.""" +class QueuedCommandNotHandled: + """Schema for the `QueuedCommandNotHandled` type.""" - success: bool - """Whether the operation succeeded""" + handled: bool + """The command was not handled""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsConfigureResult': + def from_dict(obj: Any) -> 'QueuedCommandNotHandled': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsConfigureResult(success) + handled = from_bool(obj.get("handled")) + return QueuedCommandNotHandled(handled) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["handled"] = from_bool(self.handled) return result -class PermissionsModifyRulesScope(Enum): - """Whether the change applies to ephemeral session-scoped rules (cleared at session end) or - to location-scoped rules persisted via the location-permissions config file. +# Experimental: this type is part of an experimental API and may change or be removed. +class RemoteSessionMode(Enum): + """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub + without enabling remote steering, "on" enables both export and remote steering. """ - LOCATION = "location" - SESSION = "session" + EXPORT = "export" + OFF = "off" + ON = "on" +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionsModifyRulesResult: - """Indicates whether the operation succeeded.""" +class RemoteEnableResult: + """GitHub URL for the session and a flag indicating whether remote steering is enabled.""" - success: bool - """Whether the operation succeeded""" + remote_steerable: bool + """Whether remote steering is enabled""" + + url: str | None = None + """GitHub frontend URL for this session""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsModifyRulesResult': + def from_dict(obj: Any) -> 'RemoteEnableResult': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsModifyRulesResult(success) + remote_steerable = from_bool(obj.get("remoteSteerable")) + url = from_union([from_str, from_none], obj.get("url")) + return RemoteEnableResult(remote_steerable, url) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["remoteSteerable"] = from_bool(self.remote_steerable) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) return result @dataclass -class PermissionsNotifyPromptShownResult: - """Indicates whether the operation succeeded.""" +class ServerSkill: + """Schema for the `ServerSkill` type.""" - success: bool - """Whether the operation succeeded""" + description: str + """Description of what the skill does""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionsNotifyPromptShownResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsNotifyPromptShownResult(success) + enabled: bool + """Whether the skill is currently enabled (based on global config)""" - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result + name: str + """Unique identifier for the skill""" -@dataclass -class PermissionsPathsAddResult: - """Indicates whether the operation succeeded.""" + source: SkillSource + """Source location type (e.g., project, personal-copilot, plugin, builtin)""" - success: bool - """Whether the operation succeeded""" + user_invocable: bool + """Whether the skill can be invoked by the user as a slash command""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionsPathsAddResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsPathsAddResult(success) + path: str | None = None + """Absolute path to the skill file""" - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result + project_path: str | None = None + """The project path this skill belongs to (only for project/inherited skills)""" -@dataclass -class PermissionsPathsListRequest: - """No parameters; returns the session's allow-listed directories.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsPathsListRequest': + def from_dict(obj: Any) -> 'ServerSkill': assert isinstance(obj, dict) - return PermissionsPathsListRequest() + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = SkillSource(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_str, from_none], obj.get("path")) + project_path = from_union([from_str, from_none], obj.get("projectPath")) + return ServerSkill(description, enabled, name, source, user_invocable, path, project_path) def to_dict(self) -> dict: result: dict = {} + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(SkillSource, self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.project_path is not None: + result["projectPath"] = from_union([from_str, from_none], self.project_path) return result @dataclass -class PermissionsPathsUpdatePrimaryResult: - """Indicates whether the operation succeeded.""" +class SessionFSAppendFileRequest: + """File path, content to append, and optional mode for the client-provided session + filesystem. + """ + content: str + """Content to append""" - success: bool - """Whether the operation succeeded""" + path: str + """Path using SessionFs conventions""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionsPathsUpdatePrimaryResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsPathsUpdatePrimaryResult(success) + session_id: str + """Target session identifier""" - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result + mode: int | None = None + """Optional POSIX-style mode for newly created files""" -@dataclass -class PermissionsPendingRequestsRequest: - """No parameters; returns currently-pending permission requests for the session.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsPendingRequestsRequest': + def from_dict(obj: Any) -> 'SessionFSAppendFileRequest': assert isinstance(obj, dict) - return PermissionsPendingRequestsRequest() + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + return SessionFSAppendFileRequest(content, path, session_id, mode) def to_dict(self) -> dict: result: dict = {} + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) return result -@dataclass -class PermissionsResetSessionApprovalsRequest: - """No parameters; clears all session-scoped tool permission approvals.""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsRequest': - assert isinstance(obj, dict) - return PermissionsResetSessionApprovalsRequest() +class SessionFSErrorCode(Enum): + """Error classification""" - def to_dict(self) -> dict: - result: dict = {} - return result + ENOENT = "ENOENT" + UNKNOWN = "UNKNOWN" @dataclass -class PermissionsResetSessionApprovalsResult: - """Indicates whether the operation succeeded.""" +class SessionFSExistsRequest: + """Path to test for existence in the client-provided session filesystem.""" - success: bool - """Whether the operation succeeded""" + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsResult': + def from_dict(obj: Any) -> 'SessionFSExistsRequest': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsResetSessionApprovalsResult(success) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSExistsRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class PermissionsSetApproveAllResult: - """Indicates whether the operation succeeded.""" +class SessionFSExistsResult: + """Indicates whether the requested path exists in the client-provided session filesystem.""" - success: bool - """Whether the operation succeeded""" + exists: bool + """Whether the path exists""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsSetApproveAllResult': + def from_dict(obj: Any) -> 'SessionFSExistsResult': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsSetApproveAllResult(success) + exists = from_bool(obj.get("exists")) + return SessionFSExistsResult(exists) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["exists"] = from_bool(self.exists) return result @dataclass -class PermissionsSetRequiredRequest: - """Toggles whether permission prompts should be bridged into session events for this client.""" - - required: bool - """Whether the client wants `permission.requested` events bridged from the session-owned - permission service. CLI clients that render prompt UI set this to `true` for as long as - their listener is mounted; headless callers leave it unset (the default is `false`). +class SessionFSMkdirRequest: + """Directory path to create in the client-provided session filesystem, with options for + recursive creation and POSIX mode. """ + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" + + mode: int | None = None + """Optional POSIX-style mode for newly created directories""" + + recursive: bool | None = None + """Create parent directories as needed""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsSetRequiredRequest': + def from_dict(obj: Any) -> 'SessionFSMkdirRequest': assert isinstance(obj, dict) - required = from_bool(obj.get("required")) - return PermissionsSetRequiredRequest(required) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + recursive = from_union([from_bool, from_none], obj.get("recursive")) + return SessionFSMkdirRequest(path, session_id, mode, recursive) def to_dict(self) -> dict: result: dict = {} - result["required"] = from_bool(self.required) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) + if self.recursive is not None: + result["recursive"] = from_union([from_bool, from_none], self.recursive) return result @dataclass -class PermissionsSetRequiredResult: - """Indicates whether the operation succeeded.""" +class SessionFSReadFileRequest: + """Path of the file to read from the client-provided session filesystem.""" - success: bool - """Whether the operation succeeded""" + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsSetRequiredResult': + def from_dict(obj: Any) -> 'SessionFSReadFileRequest': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsSetRequiredResult(success) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReadFileRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class PermissionsUrlsSetUnrestrictedModeResult: - """Indicates whether the operation succeeded.""" +class SessionFSReaddirRequest: + """Directory path whose entries should be listed from the client-provided session filesystem.""" - success: bool - """Whether the operation succeeded""" + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsUrlsSetUnrestrictedModeResult': + def from_dict(obj: Any) -> 'SessionFSReaddirRequest': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsUrlsSetUnrestrictedModeResult(success) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReaddirRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result +class SessionFSReaddirWithTypesEntryType(Enum): + """Entry type""" + + DIRECTORY = "directory" + FILE = "file" + @dataclass -class PingRequest: - """Optional message to echo back to the caller.""" +class SessionFSReaddirWithTypesRequest: + """Directory path whose entries (with type information) should be listed from the + client-provided session filesystem. + """ + path: str + """Path using SessionFs conventions""" - message: str | None = None - """Optional message to echo back""" + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'PingRequest': + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesRequest': assert isinstance(obj, dict) - message = from_union([from_str, from_none], obj.get("message")) - return PingRequest(message) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReaddirWithTypesRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class PingResult: - """Server liveness response, including the echoed message, current server timestamp, and - protocol version. +class SessionFSRenameRequest: + """Source and destination paths for renaming or moving an entry in the client-provided + session filesystem. """ - message: str - """Echoed message (or default greeting)""" + dest: str + """Destination path using SessionFs conventions""" - protocol_version: int - """Server protocol version number""" + session_id: str + """Target session identifier""" - timestamp: datetime - """ISO 8601 timestamp when the server handled the ping""" + src: str + """Source path using SessionFs conventions""" @staticmethod - def from_dict(obj: Any) -> 'PingResult': + def from_dict(obj: Any) -> 'SessionFSRenameRequest': assert isinstance(obj, dict) - message = from_str(obj.get("message")) - protocol_version = from_int(obj.get("protocolVersion")) - timestamp = from_datetime(obj.get("timestamp")) - return PingResult(message, protocol_version, timestamp) + dest = from_str(obj.get("dest")) + session_id = from_str(obj.get("sessionId")) + src = from_str(obj.get("src")) + return SessionFSRenameRequest(dest, session_id, src) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - result["protocolVersion"] = from_int(self.protocol_version) - result["timestamp"] = self.timestamp.isoformat() + result["dest"] = from_str(self.dest) + result["sessionId"] = from_str(self.session_id) + result["src"] = from_str(self.src) return result @dataclass -class PlanReadResult: - """Existence, contents, and resolved path of the session plan file.""" +class SessionFSRmRequest: + """Path to remove from the client-provided session filesystem, with options for recursive + removal and force. + """ + path: str + """Path using SessionFs conventions""" - exists: bool - """Whether the plan file exists in the workspace""" + session_id: str + """Target session identifier""" - content: str | None = None - """The content of the plan file, or null if it does not exist""" + force: bool | None = None + """Ignore errors if the path does not exist""" - path: str | None = None - """Absolute file path of the plan file, or null if workspace is not enabled""" + recursive: bool | None = None + """Remove directories and their contents recursively""" @staticmethod - def from_dict(obj: Any) -> 'PlanReadResult': + def from_dict(obj: Any) -> 'SessionFSRmRequest': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - content = from_union([from_none, from_str], obj.get("content")) - path = from_union([from_none, from_str], obj.get("path")) - return PlanReadResult(exists, content, path) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + force = from_union([from_bool, from_none], obj.get("force")) + recursive = from_union([from_bool, from_none], obj.get("recursive")) + return SessionFSRmRequest(path, session_id, force, recursive) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) - result["content"] = from_union([from_none, from_str], self.content) - result["path"] = from_union([from_none, from_str], self.path) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.force is not None: + result["force"] = from_union([from_bool, from_none], self.force) + if self.recursive is not None: + result["recursive"] = from_union([from_bool, from_none], self.recursive) return result @dataclass -class PlanUpdateRequest: - """Replacement contents to write to the session plan file.""" +class SessionFSSetProviderCapabilities: + """Optional capabilities declared by the provider""" - content: str - """The new content for the plan file""" + sqlite: bool | None = None + """Whether the provider supports SQLite query/exists operations""" @staticmethod - def from_dict(obj: Any) -> 'PlanUpdateRequest': + def from_dict(obj: Any) -> 'SessionFSSetProviderCapabilities': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - return PlanUpdateRequest(content) + sqlite = from_union([from_bool, from_none], obj.get("sqlite")) + return SessionFSSetProviderCapabilities(sqlite) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) + if self.sqlite is not None: + result["sqlite"] = from_union([from_bool, from_none], self.sqlite) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class Plugin: - """Schema for the `Plugin` type.""" - - enabled: bool - """Whether the plugin is currently enabled""" +class SessionFSSetProviderConventions(Enum): + """Path conventions used by this filesystem""" - marketplace: str - """Marketplace the plugin came from""" + POSIX = "posix" + WINDOWS = "windows" - name: str - """Plugin name""" +@dataclass +class SessionFSSetProviderResult: + """Indicates whether the calling client was registered as the session filesystem provider.""" - version: str | None = None - """Installed version""" + success: bool + """Whether the provider was set successfully""" @staticmethod - def from_dict(obj: Any) -> 'Plugin': + def from_dict(obj: Any) -> 'SessionFSSetProviderResult': assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - marketplace = from_str(obj.get("marketplace")) - name = from_str(obj.get("name")) - version = from_union([from_str, from_none], obj.get("version")) - return Plugin(enabled, marketplace, name, version) + success = from_bool(obj.get("success")) + return SessionFSSetProviderResult(success) def to_dict(self) -> dict: result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["marketplace"] = from_str(self.marketplace) - result["name"] = from_str(self.name) - if self.version is not None: - result["version"] = from_union([from_str, from_none], self.version) + result["success"] = from_bool(self.success) return result -# Experimental: this type is part of an experimental API and may change or be removed. -class QueuePendingItemsKind(Enum): - """Whether this item is a queued user message or a queued slash command / model change""" - - COMMAND = "command" - MESSAGE = "message" - -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class QueueRemoveMostRecentResult: - """Indicates whether a user-facing pending item was removed.""" +class SessionFSSqliteExistsRequest: + """Identifies the target session.""" - removed: bool - """True if a user-facing pending item was removed (LIFO across both queues); false when no - removable items remained. - """ + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'QueueRemoveMostRecentResult': + def from_dict(obj: Any) -> 'SessionFSSqliteExistsRequest': assert isinstance(obj, dict) - removed = from_bool(obj.get("removed")) - return QueueRemoveMostRecentResult(removed) + session_id = from_str(obj.get("sessionId")) + return SessionFSSqliteExistsRequest(session_id) def to_dict(self) -> dict: result: dict = {} - result["removed"] = from_bool(self.removed) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class QueuedCommandHandled: - """Schema for the `QueuedCommandHandled` type.""" - - handled: bool - """The host actually executed the queued command.""" +class SessionFSSqliteExistsResult: + """Indicates whether the per-session SQLite database already exists.""" - stop_processing_queue: bool | None = None - """When true, the runtime will not process subsequent queued commands until a new request - comes in. - """ + exists: bool + """Whether the session database already exists""" @staticmethod - def from_dict(obj: Any) -> 'QueuedCommandHandled': + def from_dict(obj: Any) -> 'SessionFSSqliteExistsResult': assert isinstance(obj, dict) - handled = from_bool(obj.get("handled")) - stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) - return QueuedCommandHandled(handled, stop_processing_queue) + exists = from_bool(obj.get("exists")) + return SessionFSSqliteExistsResult(exists) def to_dict(self) -> dict: result: dict = {} - result["handled"] = from_bool(self.handled) - if self.stop_processing_queue is not None: - result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) + result["exists"] = from_bool(self.exists) return result +class SessionFSSqliteQueryType(Enum): + """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT + (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) + """ + EXEC = "exec" + QUERY = "query" + RUN = "run" + @dataclass -class QueuedCommandNotHandled: - """Schema for the `QueuedCommandNotHandled` type.""" +class SessionFSStatRequest: + """Path whose metadata should be returned from the client-provided session filesystem.""" - handled: bool - """The host did not execute the queued command. Unblocks the queue without claiming the - command was processed (e.g. when the handler threw before completing). - """ + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'QueuedCommandNotHandled': + def from_dict(obj: Any) -> 'SessionFSStatRequest': assert isinstance(obj, dict) - handled = from_bool(obj.get("handled")) - return QueuedCommandNotHandled(handled) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSStatRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["handled"] = from_bool(self.handled) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RegisterEventInterestParams: - """Event type to register consumer interest for, used by runtime gating logic.""" - - event_type: str - """The event type the consumer wants the runtime to treat as 'observed' for - behavior-switching gating. Some runtime code paths inspect whether any consumer is - interested in a specific event type and choose a different implementation accordingly - (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates the full - interactive OAuth flow to the consumer; when no interest is registered the runtime - installs a browserless fallback that silently reuses cached tokens). SDK clients that - long-poll events do NOT automatically appear as listeners to these gating checks — they - must explicitly call `registerInterest` for each event type they want the runtime to - count as having a consumer. Multiple registrations for the same event type from the same - or different consumers are tracked independently and must each be released. See: - `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, - `user_input.requested`, `elicitation.requested`, `command.queued`, - `exit_plan_mode.requested`. - """ +class SessionFSWriteFileRequest: + """File path, content to write, and optional mode for the client-provided session filesystem.""" - @staticmethod - def from_dict(obj: Any) -> 'RegisterEventInterestParams': - assert isinstance(obj, dict) - event_type = from_str(obj.get("eventType")) - return RegisterEventInterestParams(event_type) + content: str + """Content to write""" - def to_dict(self) -> dict: - result: dict = {} - result["eventType"] = from_str(self.event_type) - return result + path: str + """Path using SessionFs conventions""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class RegisterEventInterestResult: - """Opaque handle representing an event-type interest registration.""" + session_id: str + """Target session identifier""" - handle: str - """Opaque handle for this registration. Pass to releaseInterest to release. Each call to - registerInterest produces a fresh handle, even when the same eventType is registered - multiple times. - """ + mode: int | None = None + """Optional POSIX-style mode for newly created files""" @staticmethod - def from_dict(obj: Any) -> 'RegisterEventInterestResult': + def from_dict(obj: Any) -> 'SessionFSWriteFileRequest': assert isinstance(obj, dict) - handle = from_str(obj.get("handle")) - return RegisterEventInterestResult(handle) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + return SessionFSWriteFileRequest(content, path, session_id, mode) def to_dict(self) -> dict: result: dict = {} - result["handle"] = from_str(self.handle) + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ReleaseEventInterestParams: - """Opaque handle previously returned by `registerInterest` to release.""" - - handle: str - """Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown - or already-released handle is a no-op (returns success). When the last outstanding handle - for an event type is released, the runtime reverts to its 'no consumer' code path for - that event type. +class SessionsForkRequest: + """Source session identifier to fork from, optional event-ID boundary, and optional friendly + name for the new session. + """ + session_id: str + """Source session ID to fork from""" + + name: str | None = None + """Optional friendly name to assign to the forked session.""" + + to_event_id: str | None = None + """Optional event ID boundary. When provided, the fork includes only events before this ID + (exclusive). When omitted, all events are included. """ @staticmethod - def from_dict(obj: Any) -> 'ReleaseEventInterestParams': + def from_dict(obj: Any) -> 'SessionsForkRequest': assert isinstance(obj, dict) - handle = from_str(obj.get("handle")) - return ReleaseEventInterestParams(handle) + session_id = from_str(obj.get("sessionId")) + name = from_union([from_str, from_none], obj.get("name")) + to_event_id = from_union([from_str, from_none], obj.get("toEventId")) + return SessionsForkRequest(session_id, name, to_event_id) def to_dict(self) -> dict: result: dict = {} - result["handle"] = from_str(self.handle) + result["sessionId"] = from_str(self.session_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.to_event_id is not None: + result["toEventId"] = from_union([from_str, from_none], self.to_event_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. -class RemoteSessionMode(Enum): - """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub - without enabling remote steering, "on" enables both export and remote steering. - """ - EXPORT = "export" - OFF = "off" - ON = "on" - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteEnableResult: - """GitHub URL for the session and a flag indicating whether remote steering is enabled.""" +class SessionsForkResult: + """Identifier and optional friendly name assigned to the newly forked session.""" - remote_steerable: bool - """Whether remote steering is enabled""" + session_id: str + """The new forked session's ID""" - url: str | None = None - """GitHub frontend URL for this session""" + name: str | None = None + """Friendly name assigned to the forked session, if any.""" @staticmethod - def from_dict(obj: Any) -> 'RemoteEnableResult': + def from_dict(obj: Any) -> 'SessionsForkResult': assert isinstance(obj, dict) - remote_steerable = from_bool(obj.get("remoteSteerable")) - url = from_union([from_str, from_none], obj.get("url")) - return RemoteEnableResult(remote_steerable, url) + session_id = from_str(obj.get("sessionId")) + name = from_union([from_str, from_none], obj.get("name")) + return SessionsForkResult(session_id, name) def to_dict(self) -> dict: result: dict = {} - result["remoteSteerable"] = from_bool(self.remote_steerable) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["sessionId"] = from_str(self.session_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteNotifySteerableChangedRequest: - """New remote-steerability state to persist as a `session.remote_steerable_changed` event.""" +class ShellExecRequest: + """Shell command to run, with optional working directory and timeout in milliseconds.""" - remote_steerable: bool - """Whether the session now supports remote steering via GitHub. The runtime persists this as - a `session.remote_steerable_changed` event so resume/replay sees the up-to-date - capability. - """ + command: str + """Shell command to execute""" + + cwd: str | None = None + """Working directory (defaults to session working directory)""" + + timeout: int | None = None + """Timeout in milliseconds (default: 30000)""" @staticmethod - def from_dict(obj: Any) -> 'RemoteNotifySteerableChangedRequest': + def from_dict(obj: Any) -> 'ShellExecRequest': assert isinstance(obj, dict) - remote_steerable = from_bool(obj.get("remoteSteerable")) - return RemoteNotifySteerableChangedRequest(remote_steerable) + command = from_str(obj.get("command")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + return ShellExecRequest(command, cwd, timeout) def to_dict(self) -> dict: result: dict = {} - result["remoteSteerable"] = from_bool(self.remote_steerable) + result["command"] = from_str(self.command) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteNotifySteerableChangedResult: - """Persist a steerability change as a `session.remote_steerable_changed` event. Used by the - host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a - remote exporter that the runtime does not directly own. +class ShellExecResult: + """Identifier of the spawned process, used to correlate streamed output and exit + notifications. """ + process_id: str + """Unique identifier for tracking streamed output""" + @staticmethod - def from_dict(obj: Any) -> 'RemoteNotifySteerableChangedResult': + def from_dict(obj: Any) -> 'ShellExecResult': assert isinstance(obj, dict) - return RemoteNotifySteerableChangedResult() + process_id = from_str(obj.get("processId")) + return ShellExecResult(process_id) def to_dict(self) -> dict: result: dict = {} + result["processId"] = from_str(self.process_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class ScheduleEntry: - """Schema for the `ScheduleEntry` type. +class ShellKillSignal(Enum): + """Signal to send (default: SIGTERM)""" - The removed entry, or omitted if no entry matched. - """ - id: int - """Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt - from the event log). + SIGINT = "SIGINT" + SIGKILL = "SIGKILL" + SIGTERM = "SIGTERM" + +@dataclass +class ShellKillResult: + """Indicates whether the signal was delivered; false if the process was unknown or already + exited. """ - interval_ms: int - """Interval between scheduled ticks, in milliseconds.""" + killed: bool + """Whether the signal was sent successfully""" - next_run_at: datetime - """ISO 8601 timestamp when the next tick is scheduled to fire.""" + @staticmethod + def from_dict(obj: Any) -> 'ShellKillResult': + assert isinstance(obj, dict) + killed = from_bool(obj.get("killed")) + return ShellKillResult(killed) - prompt: str - """Prompt text that gets enqueued on every tick.""" + def to_dict(self) -> dict: + result: dict = {} + result["killed"] = from_bool(self.killed) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class Skill: + """Schema for the `Skill` type.""" - recurring: bool - """Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`).""" + description: str + """Description of what the skill does""" - display_prompt: str | None = None - """Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a - skill-invocation schedule). The actual enqueued prompt is `prompt`. - """ + enabled: bool + """Whether the skill is currently enabled""" + + name: str + """Unique identifier for the skill""" + + source: SkillSource + """Source location type (e.g., project, personal-copilot, plugin, builtin)""" + + user_invocable: bool + """Whether the skill can be invoked by the user as a slash command""" + + path: str | None = None + """Absolute path to the skill file""" @staticmethod - def from_dict(obj: Any) -> 'ScheduleEntry': + def from_dict(obj: Any) -> 'Skill': assert isinstance(obj, dict) - id = from_int(obj.get("id")) - interval_ms = from_int(obj.get("intervalMs")) - next_run_at = from_datetime(obj.get("nextRunAt")) - prompt = from_str(obj.get("prompt")) - recurring = from_bool(obj.get("recurring")) - display_prompt = from_union([from_str, from_none], obj.get("displayPrompt")) - return ScheduleEntry(id, interval_ms, next_run_at, prompt, recurring, display_prompt) + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = SkillSource(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_str, from_none], obj.get("path")) + return Skill(description, enabled, name, source, user_invocable, path) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_int(self.id) - result["intervalMs"] = from_int(self.interval_ms) - result["nextRunAt"] = self.next_run_at.isoformat() - result["prompt"] = from_str(self.prompt) - result["recurring"] = from_bool(self.recurring) - if self.display_prompt is not None: - result["displayPrompt"] = from_union([from_str, from_none], self.display_prompt) + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(SkillSource, self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ScheduleStopRequest: - """Identifier of the scheduled prompt to remove.""" +class SkillsDisableRequest: + """Name of the skill to disable for the session.""" - id: int - """Id of the scheduled prompt to remove.""" + name: str + """Name of the skill to disable""" @staticmethod - def from_dict(obj: Any) -> 'ScheduleStopRequest': + def from_dict(obj: Any) -> 'SkillsDisableRequest': assert isinstance(obj, dict) - id = from_int(obj.get("id")) - return ScheduleStopRequest(id) + name = from_str(obj.get("name")) + return SkillsDisableRequest(name) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_int(self.id) + result["name"] = from_str(self.name) return result -class SendAgentMode(Enum): - """The UI mode the agent was in when this message was sent. Defaults to the session's - current mode. - """ - AUTOPILOT = "autopilot" - INTERACTIVE = "interactive" - PLAN = "plan" - SHELL = "shell" - @dataclass -class SendAttachmentFileLineRange: - """Optional line range to scope the attachment to a specific section of the file""" +class SkillsDiscoverRequest: + """Optional project paths and additional skill directories to include in discovery.""" - end: int - """End line number (1-based, inclusive)""" + project_paths: list[str] | None = None + """Optional list of project directory paths to scan for project-scoped skills""" - start: int - """Start line number (1-based)""" + skill_directories: list[str] | None = None + """Optional list of additional skill directory paths to include""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentFileLineRange': + def from_dict(obj: Any) -> 'SkillsDiscoverRequest': assert isinstance(obj, dict) - end = from_int(obj.get("end")) - start = from_int(obj.get("start")) - return SendAttachmentFileLineRange(end, start) + project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) + skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) + return SkillsDiscoverRequest(project_paths, skill_directories) def to_dict(self) -> dict: result: dict = {} - result["end"] = from_int(self.end) - result["start"] = from_int(self.start) + if self.project_paths is not None: + result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) + if self.skill_directories is not None: + result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) return result -class SendAttachmentGithubReferenceTypeEnum(Enum): - """Type of GitHub reference""" - - DISCUSSION = "discussion" - ISSUE = "issue" - PR = "pr" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SendAttachmentSelectionDetailsEnd: - """End position of the selection""" - - character: int - """End character offset within the line (0-based)""" +class SkillsEnableRequest: + """Name of the skill to enable for the session.""" - line: int - """End line number (0-based)""" + name: str + """Name of the skill to enable""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentSelectionDetailsEnd': + def from_dict(obj: Any) -> 'SkillsEnableRequest': assert isinstance(obj, dict) - character = from_int(obj.get("character")) - line = from_int(obj.get("line")) - return SendAttachmentSelectionDetailsEnd(character, line) + name = from_str(obj.get("name")) + return SkillsEnableRequest(name) def to_dict(self) -> dict: result: dict = {} - result["character"] = from_int(self.character) - result["line"] = from_int(self.line) + result["name"] = from_str(self.name) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SendAttachmentSelectionDetailsStart: - """Start position of the selection""" +class SkillsLoadDiagnostics: + """Diagnostics from reloading skill definitions, with warnings and errors as separate lists.""" - character: int - """Start character offset within the line (0-based)""" + errors: list[str] + """Errors emitted while loading skills (e.g. skills that failed to load entirely)""" - line: int - """Start line number (0-based)""" + warnings: list[str] + """Warnings emitted while loading skills (e.g. skills that loaded but had issues)""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentSelectionDetailsStart': + def from_dict(obj: Any) -> 'SkillsLoadDiagnostics': assert isinstance(obj, dict) - character = from_int(obj.get("character")) - line = from_int(obj.get("line")) - return SendAttachmentSelectionDetailsStart(character, line) + errors = from_list(from_str, obj.get("errors")) + warnings = from_list(from_str, obj.get("warnings")) + return SkillsLoadDiagnostics(errors, warnings) def to_dict(self) -> dict: result: dict = {} - result["character"] = from_int(self.character) - result["line"] = from_int(self.line) + result["errors"] = from_list(from_str, self.errors) + result["warnings"] = from_list(from_str, self.warnings) return result -class SendAttachmentType(Enum): - BLOB = "blob" - DIRECTORY = "directory" - FILE = "file" - GITHUB_REFERENCE = "github_reference" - SELECTION = "selection" +class SlashCommandAgentPromptResultKind(Enum): + AGENT_PROMPT = "agent-prompt" -class SendAttachmentBlobType(Enum): - BLOB = "blob" +class SlashCommandCompletedResultKind(Enum): + COMPLETED = "completed" -class SendAttachmentFileType(Enum): - FILE = "file" +class SlashCommandInvocationResultKind(Enum): + AGENT_PROMPT = "agent-prompt" + COMPLETED = "completed" + TEXT = "text" + +# Experimental: this type is part of an experimental API and may change or be removed. +class TaskExecutionMode(Enum): + """Whether task execution is synchronously awaited or managed in the background""" + + BACKGROUND = "background" + SYNC = "sync" + +# Experimental: this type is part of an experimental API and may change or be removed. +class TaskStatus(Enum): + """Current lifecycle status of the task""" -class SendAttachmentGithubReferenceType(Enum): - GITHUB_REFERENCE = "github_reference" + CANCELLED = "cancelled" + COMPLETED = "completed" + FAILED = "failed" + IDLE = "idle" + RUNNING = "running" -class SendAttachmentSelectionType(Enum): - SELECTION = "selection" +class TaskAgentInfoType(Enum): + AGENT = "agent" -class SendMode(Enum): - """How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` - interjects during an in-progress turn. +# Experimental: this type is part of an experimental API and may change or be removed. +class TaskShellInfoAttachmentMode(Enum): + """Whether the shell runs inside a managed PTY session or as an independent background + process """ - ENQUEUE = "enqueue" - IMMEDIATE = "immediate" + ATTACHED = "attached" + DETACHED = "detached" + +class TaskInfoType(Enum): + AGENT = "agent" + SHELL = "shell" + +class TaskShellInfoType(Enum): + SHELL = "shell" +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SendResult: - """Result of sending a user message""" +class TasksCancelRequest: + """Identifier of the background task to cancel.""" - message_id: str - """Unique identifier assigned to the message""" + id: str + """Task identifier""" @staticmethod - def from_dict(obj: Any) -> 'SendResult': + def from_dict(obj: Any) -> 'TasksCancelRequest': assert isinstance(obj, dict) - message_id = from_str(obj.get("messageId")) - return SendResult(message_id) + id = from_str(obj.get("id")) + return TasksCancelRequest(id) def to_dict(self) -> dict: result: dict = {} - result["messageId"] = from_str(self.message_id) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ServerSkill: - """Schema for the `ServerSkill` type.""" - - description: str - """Description of what the skill does""" - - enabled: bool - """Whether the skill is currently enabled (based on global config)""" - - name: str - """Unique identifier for the skill""" - - source: SkillSource - """Source location type (e.g., project, personal-copilot, plugin, builtin)""" - - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" - - path: str | None = None - """Absolute path to the skill file""" +class TasksCancelResult: + """Indicates whether the background task was successfully cancelled.""" - project_path: str | None = None - """The project path this skill belongs to (only for project/inherited skills)""" + cancelled: bool + """Whether the task was successfully cancelled""" @staticmethod - def from_dict(obj: Any) -> 'ServerSkill': + def from_dict(obj: Any) -> 'TasksCancelResult': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = SkillSource(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - project_path = from_union([from_str, from_none], obj.get("projectPath")) - return ServerSkill(description, enabled, name, source, user_invocable, path, project_path) + cancelled = from_bool(obj.get("cancelled")) + return TasksCancelResult(cancelled) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(SkillSource, self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.project_path is not None: - result["projectPath"] = from_union([from_str, from_none], self.project_path) + result["cancelled"] = from_bool(self.cancelled) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionBulkDeleteResult: - """Map of sessionId -> bytes freed by removing the session's workspace directory.""" +class TasksPromoteToBackgroundRequest: + """Identifier of the task to promote to background mode.""" - freed_bytes: dict[str, int] - """Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions - whose deletion failed are omitted from this map (failures are logged on the server but - not surfaced per-id; check the map for absent IDs to detect them). - """ + id: str + """Task identifier""" @staticmethod - def from_dict(obj: Any) -> 'SessionBulkDeleteResult': + def from_dict(obj: Any) -> 'TasksPromoteToBackgroundRequest': assert isinstance(obj, dict) - freed_bytes = from_dict(from_int, obj.get("freedBytes")) - return SessionBulkDeleteResult(freed_bytes) + id = from_str(obj.get("id")) + return TasksPromoteToBackgroundRequest(id) def to_dict(self) -> dict: result: dict = {} - result["freedBytes"] = from_dict(from_int, self.freed_bytes) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSAppendFileRequest: - """File path, content to append, and optional mode for the client-provided session - filesystem. - """ - content: str - """Content to append""" - - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" +class TasksPromoteToBackgroundResult: + """Indicates whether the task was successfully promoted to background mode.""" - mode: int | None = None - """Optional POSIX-style mode for newly created files""" + promoted: bool + """Whether the task was successfully promoted to background mode""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSAppendFileRequest': + def from_dict(obj: Any) -> 'TasksPromoteToBackgroundResult': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - return SessionFSAppendFileRequest(content, path, session_id, mode) + promoted = from_bool(obj.get("promoted")) + return TasksPromoteToBackgroundResult(promoted) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) + result["promoted"] = from_bool(self.promoted) return result -class SessionFSErrorCode(Enum): - """Error classification""" - - ENOENT = "ENOENT" - UNKNOWN = "UNKNOWN" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSExistsRequest: - """Path to test for existence in the client-provided session filesystem.""" - - path: str - """Path using SessionFs conventions""" +class TasksRemoveRequest: + """Identifier of the completed or cancelled task to remove from tracking.""" - session_id: str - """Target session identifier""" + id: str + """Task identifier""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSExistsRequest': + def from_dict(obj: Any) -> 'TasksRemoveRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSExistsRequest(path, session_id) + id = from_str(obj.get("id")) + return TasksRemoveRequest(id) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSExistsResult: - """Indicates whether the requested path exists in the client-provided session filesystem.""" - - exists: bool - """Whether the path exists""" +class TasksRemoveResult: + """Indicates whether the task was removed. False when the task does not exist or is still + running/idle. + """ + removed: bool + """Whether the task was removed. Returns false if the task does not exist or is still + running/idle (cancel it first). + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSExistsResult': + def from_dict(obj: Any) -> 'TasksRemoveResult': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - return SessionFSExistsResult(exists) + removed = from_bool(obj.get("removed")) + return TasksRemoveResult(removed) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) + result["removed"] = from_bool(self.removed) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSMkdirRequest: - """Directory path to create in the client-provided session filesystem, with options for - recursive creation and POSIX mode. - """ - path: str - """Path using SessionFs conventions""" +class TasksSendMessageRequest: + """Identifier of the target agent task, message content, and optional sender agent ID.""" - session_id: str - """Target session identifier""" + id: str + """Agent task identifier""" - mode: int | None = None - """Optional POSIX-style mode for newly created directories""" + message: str + """Message content to send to the agent""" - recursive: bool | None = None - """Create parent directories as needed""" + from_agent_id: str | None = None + """Agent ID of the sender, if sent on behalf of another agent""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSMkdirRequest': + def from_dict(obj: Any) -> 'TasksSendMessageRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - recursive = from_union([from_bool, from_none], obj.get("recursive")) - return SessionFSMkdirRequest(path, session_id, mode, recursive) + id = from_str(obj.get("id")) + message = from_str(obj.get("message")) + from_agent_id = from_union([from_str, from_none], obj.get("fromAgentId")) + return TasksSendMessageRequest(id, message, from_agent_id) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) - if self.recursive is not None: - result["recursive"] = from_union([from_bool, from_none], self.recursive) + result["id"] = from_str(self.id) + result["message"] = from_str(self.message) + if self.from_agent_id is not None: + result["fromAgentId"] = from_union([from_str, from_none], self.from_agent_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSReadFileRequest: - """Path of the file to read from the client-provided session filesystem.""" +class TasksSendMessageResult: + """Indicates whether the message was delivered, with an error message when delivery failed.""" - path: str - """Path using SessionFs conventions""" + sent: bool + """Whether the message was successfully delivered or steered""" - session_id: str - """Target session identifier""" + error: str | None = None + """Error message if delivery failed""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReadFileRequest': + def from_dict(obj: Any) -> 'TasksSendMessageResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReadFileRequest(path, session_id) + sent = from_bool(obj.get("sent")) + error = from_union([from_str, from_none], obj.get("error")) + return TasksSendMessageResult(sent, error) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["sent"] = from_bool(self.sent) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSReaddirRequest: - """Directory path whose entries should be listed from the client-provided session filesystem.""" +class TasksStartAgentRequest: + """Agent type, prompt, name, and optional description and model override for the new task.""" - path: str - """Path using SessionFs conventions""" + agent_type: str + """Type of agent to start (e.g., 'explore', 'task', 'general-purpose')""" - session_id: str - """Target session identifier""" + name: str + """Short name for the agent, used to generate a human-readable ID""" + + prompt: str + """Task prompt for the agent""" + + description: str | None = None + """Short description of the task""" + + model: str | None = None + """Optional model override""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirRequest': + def from_dict(obj: Any) -> 'TasksStartAgentRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReaddirRequest(path, session_id) + agent_type = from_str(obj.get("agentType")) + name = from_str(obj.get("name")) + prompt = from_str(obj.get("prompt")) + description = from_union([from_str, from_none], obj.get("description")) + model = from_union([from_str, from_none], obj.get("model")) + return TasksStartAgentRequest(agent_type, name, prompt, description, model) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["agentType"] = from_str(self.agent_type) + result["name"] = from_str(self.name) + result["prompt"] = from_str(self.prompt) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) return result -class SessionFSReaddirWithTypesEntryType(Enum): - """Entry type""" - - DIRECTORY = "directory" - FILE = "file" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSReaddirWithTypesRequest: - """Directory path whose entries (with type information) should be listed from the - client-provided session filesystem. - """ - path: str - """Path using SessionFs conventions""" +class TasksStartAgentResult: + """Identifier assigned to the newly started background agent task.""" - session_id: str - """Target session identifier""" + agent_id: str + """Generated agent ID for the background task""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesRequest': + def from_dict(obj: Any) -> 'TasksStartAgentResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReaddirWithTypesRequest(path, session_id) + agent_id = from_str(obj.get("agentId")) + return TasksStartAgentResult(agent_id) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["agentId"] = from_str(self.agent_id) return result @dataclass -class SessionFSRenameRequest: - """Source and destination paths for renaming or moving an entry in the client-provided - session filesystem. - """ - dest: str - """Destination path using SessionFs conventions""" +class Tool: + """Schema for the `Tool` type.""" - session_id: str - """Target session identifier""" + description: str + """Description of what the tool does""" - src: str - """Source path using SessionFs conventions""" + name: str + """Tool identifier (e.g., "bash", "grep", "str_replace_editor")""" + + instructions: str | None = None + """Optional instructions for how to use this tool effectively""" + + namespaced_name: str | None = None + """Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP + tools) + """ + parameters: dict[str, Any] | None = None + """JSON Schema for the tool's input parameters""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSRenameRequest': + def from_dict(obj: Any) -> 'Tool': assert isinstance(obj, dict) - dest = from_str(obj.get("dest")) - session_id = from_str(obj.get("sessionId")) - src = from_str(obj.get("src")) - return SessionFSRenameRequest(dest, session_id, src) + description = from_str(obj.get("description")) + name = from_str(obj.get("name")) + instructions = from_union([from_str, from_none], obj.get("instructions")) + namespaced_name = from_union([from_str, from_none], obj.get("namespacedName")) + parameters = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("parameters")) + return Tool(description, name, instructions, namespaced_name, parameters) def to_dict(self) -> dict: result: dict = {} - result["dest"] = from_str(self.dest) - result["sessionId"] = from_str(self.session_id) - result["src"] = from_str(self.src) + result["description"] = from_str(self.description) + result["name"] = from_str(self.name) + if self.instructions is not None: + result["instructions"] = from_union([from_str, from_none], self.instructions) + if self.namespaced_name is not None: + result["namespacedName"] = from_union([from_str, from_none], self.namespaced_name) + if self.parameters is not None: + result["parameters"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.parameters) return result @dataclass -class SessionFSRmRequest: - """Path to remove from the client-provided session filesystem, with options for recursive - removal and force. - """ - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - force: bool | None = None - """Ignore errors if the path does not exist""" +class ToolsListRequest: + """Optional model identifier whose tool overrides should be applied to the listing.""" - recursive: bool | None = None - """Remove directories and their contents recursively""" + model: str | None = None + """Optional model ID — when provided, the returned tool list reflects model-specific + overrides + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSRmRequest': + def from_dict(obj: Any) -> 'ToolsListRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - force = from_union([from_bool, from_none], obj.get("force")) - recursive = from_union([from_bool, from_none], obj.get("recursive")) - return SessionFSRmRequest(path, session_id, force, recursive) + model = from_union([from_str, from_none], obj.get("model")) + return ToolsListRequest(model) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.force is not None: - result["force"] = from_union([from_bool, from_none], self.force) - if self.recursive is not None: - result["recursive"] = from_union([from_bool, from_none], self.recursive) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) return result @dataclass -class SessionFSSetProviderCapabilities: - """Optional capabilities declared by the provider""" +class UIElicitationArrayAnyOfFieldItemsAnyOf: + """Schema for the `UIElicitationArrayAnyOfFieldItemsAnyOf` type.""" - sqlite: bool | None = None - """Whether the provider supports SQLite query/exists operations""" + const: str + """Value submitted when this option is selected.""" + + title: str + """Display label for this option.""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderCapabilities': + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItemsAnyOf': assert isinstance(obj, dict) - sqlite = from_union([from_bool, from_none], obj.get("sqlite")) - return SessionFSSetProviderCapabilities(sqlite) + const = from_str(obj.get("const")) + title = from_str(obj.get("title")) + return UIElicitationArrayAnyOfFieldItemsAnyOf(const, title) def to_dict(self) -> dict: result: dict = {} - if self.sqlite is not None: - result["sqlite"] = from_union([from_bool, from_none], self.sqlite) + result["const"] = from_str(self.const) + result["title"] = from_str(self.title) return result -class SessionFSSetProviderConventions(Enum): - """Path conventions used by this filesystem""" +class UIElicitationArrayAnyOfFieldType(Enum): + ARRAY = "array" - POSIX = "posix" - WINDOWS = "windows" +class UIElicitationArrayEnumFieldItemsType(Enum): + STRING = "string" + +class UIElicitationSchemaPropertyStringFormat(Enum): + """Optional format hint that constrains the accepted input.""" + + DATE = "date" + DATE_TIME = "date-time" + EMAIL = "email" + URI = "uri" @dataclass -class SessionFSSetProviderResult: - """Indicates whether the calling client was registered as the session filesystem provider.""" +class UIElicitationStringOneOfFieldOneOf: + """Schema for the `UIElicitationStringOneOfFieldOneOf` type.""" - success: bool - """Whether the provider was set successfully""" + const: str + """Value submitted when this option is selected.""" + + title: str + """Display label for this option.""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderResult': + def from_dict(obj: Any) -> 'UIElicitationStringOneOfFieldOneOf': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return SessionFSSetProviderResult(success) + const = from_str(obj.get("const")) + title = from_str(obj.get("title")) + return UIElicitationStringOneOfFieldOneOf(const, title) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["const"] = from_str(self.const) + result["title"] = from_str(self.title) return result -@dataclass -class SessionFSSqliteExistsRequest: - """Identifies the target session.""" +class UIElicitationSchemaPropertyType(Enum): + """Numeric type accepted by the field.""" - session_id: str - """Target session identifier""" + ARRAY = "array" + BOOLEAN = "boolean" + INTEGER = "integer" + NUMBER = "number" + STRING = "string" - @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteExistsRequest': - assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionFSSqliteExistsRequest(session_id) +class UIElicitationSchemaType(Enum): + OBJECT = "object" - def to_dict(self) -> dict: - result: dict = {} - result["sessionId"] = from_str(self.session_id) - return result +class UIElicitationResponseAction(Enum): + """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" -@dataclass -class SessionFSSqliteExistsResult: - """Indicates whether the per-session SQLite database already exists.""" + ACCEPT = "accept" + CANCEL = "cancel" + DECLINE = "decline" - exists: bool - """Whether the session database already exists""" +@dataclass +class UIElicitationResult: + """Indicates whether the elicitation response was accepted; false if it was already resolved + by another client. + """ + success: bool + """Whether the response was accepted. False if the request was already resolved by another + client. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteExistsResult': + def from_dict(obj: Any) -> 'UIElicitationResult': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - return SessionFSSqliteExistsResult(exists) + success = from_bool(obj.get("success")) + return UIElicitationResult(success) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) + result["success"] = from_bool(self.success) return result -class SessionFSSqliteQueryType(Enum): - """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT - (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) - """ - EXEC = "exec" - QUERY = "query" - RUN = "run" +class UIElicitationSchemaPropertyBooleanType(Enum): + BOOLEAN = "boolean" + +class UIElicitationSchemaPropertyNumberType(Enum): + """Numeric type accepted by the field.""" + + INTEGER = "integer" + NUMBER = "number" +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSStatRequest: - """Path whose metadata should be returned from the client-provided session filesystem.""" +class UsageMetricsCodeChanges: + """Aggregated code change metrics""" - path: str - """Path using SessionFs conventions""" + files_modified_count: int + """Number of distinct files modified""" - session_id: str - """Target session identifier""" + lines_added: int + """Total lines of code added""" + + lines_removed: int + """Total lines of code removed""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSStatRequest': + def from_dict(obj: Any) -> 'UsageMetricsCodeChanges': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSStatRequest(path, session_id) + files_modified_count = from_int(obj.get("filesModifiedCount")) + lines_added = from_int(obj.get("linesAdded")) + lines_removed = from_int(obj.get("linesRemoved")) + return UsageMetricsCodeChanges(files_modified_count, lines_added, lines_removed) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["filesModifiedCount"] = from_int(self.files_modified_count) + result["linesAdded"] = from_int(self.lines_added) + result["linesRemoved"] = from_int(self.lines_removed) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSWriteFileRequest: - """File path, content to write, and optional mode for the client-provided session filesystem.""" - - content: str - """Content to write""" - - path: str - """Path using SessionFs conventions""" +class UsageMetricsModelMetricRequests: + """Request count and cost metrics for this model""" - session_id: str - """Target session identifier""" + cost: float + """User-initiated premium request cost (with multiplier applied)""" - mode: int | None = None - """Optional POSIX-style mode for newly created files""" + count: int + """Number of API requests made with this model""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSWriteFileRequest': + def from_dict(obj: Any) -> 'UsageMetricsModelMetricRequests': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - return SessionFSWriteFileRequest(content, path, session_id, mode) + cost = from_float(obj.get("cost")) + count = from_int(obj.get("count")) + return UsageMetricsModelMetricRequests(cost, count) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) + result["cost"] = to_float(self.cost) + result["count"] = from_int(self.count) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionLoadDeferredRepoHooksResult: - """Queued repo-level startup prompts and the total hook command count after loading.""" +class UsageMetricsModelMetricTokenDetail: + """Schema for the `UsageMetricsModelMetricTokenDetail` type.""" - hook_count: int - """Total hook command count (user + plugin + repo) loaded for the session by this call. - Captured atomically with startupPrompts so callers don't need to read a separate counter. - """ - startup_prompts: list[str] - """Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo - configs were pending, or when disableAllHooks is set. - """ + token_count: int + """Accumulated token count for this token type""" @staticmethod - def from_dict(obj: Any) -> 'SessionLoadDeferredRepoHooksResult': + def from_dict(obj: Any) -> 'UsageMetricsModelMetricTokenDetail': assert isinstance(obj, dict) - hook_count = from_int(obj.get("hookCount")) - startup_prompts = from_list(from_str, obj.get("startupPrompts")) - return SessionLoadDeferredRepoHooksResult(hook_count, startup_prompts) + token_count = from_int(obj.get("tokenCount")) + return UsageMetricsModelMetricTokenDetail(token_count) def to_dict(self) -> dict: result: dict = {} - result["hookCount"] = from_int(self.hook_count) - result["startupPrompts"] = from_list(from_str, self.startup_prompts) + result["tokenCount"] = from_int(self.token_count) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionPruneResult: - """Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes - freed, and the dry-run flag. - """ - candidates: list[str] - """Session IDs that would be deleted in dry-run mode (always empty otherwise)""" +class UsageMetricsModelMetricUsage: + """Token usage metrics for this model""" + + cache_read_tokens: int + """Total tokens read from prompt cache""" - deleted: list[str] - """Session IDs that were deleted (always empty in dry-run mode)""" + cache_write_tokens: int + """Total tokens written to prompt cache""" - dry_run: bool - """True when no deletions were actually performed""" + input_tokens: int + """Total input tokens consumed""" - freed_bytes: int - """Total bytes freed (actual when not dry-run, projected when dry-run)""" + output_tokens: int + """Total output tokens produced""" - skipped: list[str] - """Session IDs that were skipped (e.g., named sessions)""" + reasoning_tokens: int | None = None + """Total output tokens used for reasoning""" @staticmethod - def from_dict(obj: Any) -> 'SessionPruneResult': + def from_dict(obj: Any) -> 'UsageMetricsModelMetricUsage': assert isinstance(obj, dict) - candidates = from_list(from_str, obj.get("candidates")) - deleted = from_list(from_str, obj.get("deleted")) - dry_run = from_bool(obj.get("dryRun")) - freed_bytes = from_int(obj.get("freedBytes")) - skipped = from_list(from_str, obj.get("skipped")) - return SessionPruneResult(candidates, deleted, dry_run, freed_bytes, skipped) + cache_read_tokens = from_int(obj.get("cacheReadTokens")) + cache_write_tokens = from_int(obj.get("cacheWriteTokens")) + input_tokens = from_int(obj.get("inputTokens")) + output_tokens = from_int(obj.get("outputTokens")) + reasoning_tokens = from_union([from_int, from_none], obj.get("reasoningTokens")) + return UsageMetricsModelMetricUsage(cache_read_tokens, cache_write_tokens, input_tokens, output_tokens, reasoning_tokens) def to_dict(self) -> dict: result: dict = {} - result["candidates"] = from_list(from_str, self.candidates) - result["deleted"] = from_list(from_str, self.deleted) - result["dryRun"] = from_bool(self.dry_run) - result["freedBytes"] = from_int(self.freed_bytes) - result["skipped"] = from_list(from_str, self.skipped) + result["cacheReadTokens"] = from_int(self.cache_read_tokens) + result["cacheWriteTokens"] = from_int(self.cache_write_tokens) + result["inputTokens"] = from_int(self.input_tokens) + result["outputTokens"] = from_int(self.output_tokens) + if self.reasoning_tokens is not None: + result["reasoningTokens"] = from_union([from_int, from_none], self.reasoning_tokens) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionSetCredentialsResult: - """Indicates whether the credential update succeeded.""" +class UsageMetricsTokenDetail: + """Schema for the `UsageMetricsTokenDetail` type.""" - success: bool - """Whether the operation succeeded""" + token_count: int + """Accumulated token count for this token type""" @staticmethod - def from_dict(obj: Any) -> 'SessionSetCredentialsResult': + def from_dict(obj: Any) -> 'UsageMetricsTokenDetail': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return SessionSetCredentialsResult(success) + token_count = from_int(obj.get("tokenCount")) + return UsageMetricsTokenDetail(token_count) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["tokenCount"] = from_int(self.token_count) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionSizes: - """Map of sessionId -> on-disk size in bytes for each session's workspace directory.""" +class WorkspacesCreateFileRequest: + """Relative path and UTF-8 content for the workspace file to create or overwrite.""" + + content: str + """File content to write as a UTF-8 string""" - sizes: dict[str, int] - """Map of sessionId -> on-disk size in bytes for the session's workspace directory""" + path: str + """Relative path within the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SessionSizes': + def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': assert isinstance(obj, dict) - sizes = from_dict(from_int, obj.get("sizes")) - return SessionSizes(sizes) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + return WorkspacesCreateFileRequest(content, path) def to_dict(self) -> dict: result: dict = {} - result["sizes"] = from_dict(from_int, self.sizes) + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) return result -# Experimental: this type is part of an experimental API and may change or be removed. +class HostType(Enum): + ADO = "ado" + GITHUB = "github" + @dataclass -class SessionUpdateOptionsResult: - """Indicates whether the session options patch was applied successfully.""" +class WorkspacesListFilesResult: + """Relative paths of files stored in the session workspace files directory.""" - success: bool - """Whether the operation succeeded""" + files: list[str] + """Relative file paths in the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SessionUpdateOptionsResult': + def from_dict(obj: Any) -> 'WorkspacesListFilesResult': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return SessionUpdateOptionsResult(success) + files = from_list(from_str, obj.get("files")) + return WorkspacesListFilesResult(files) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["files"] = from_list(from_str, self.files) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsBulkDeleteRequest: - """Session IDs to close, deactivate, and delete from disk.""" +class WorkspacesReadFileRequest: + """Relative path of the workspace file to read.""" - session_ids: list[str] - """Session IDs to close, deactivate, and delete from disk""" + path: str + """Relative path within the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SessionsBulkDeleteRequest': + def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': assert isinstance(obj, dict) - session_ids = from_list(from_str, obj.get("sessionIds")) - return SessionsBulkDeleteRequest(session_ids) + path = from_str(obj.get("path")) + return WorkspacesReadFileRequest(path) def to_dict(self) -> dict: result: dict = {} - result["sessionIds"] = from_list(from_str, self.session_ids) + result["path"] = from_str(self.path) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsCheckInUseRequest: - """Session IDs to test for live in-use locks.""" +class WorkspacesReadFileResult: + """Contents of the requested workspace file as a UTF-8 string.""" - session_ids: list[str] - """Session IDs to test for live in-use locks""" + content: str + """File content as a UTF-8 string""" @staticmethod - def from_dict(obj: Any) -> 'SessionsCheckInUseRequest': + def from_dict(obj: Any) -> 'WorkspacesReadFileResult': assert isinstance(obj, dict) - session_ids = from_list(from_str, obj.get("sessionIds")) - return SessionsCheckInUseRequest(session_ids) + content = from_str(obj.get("content")) + return WorkspacesReadFileResult(content) def to_dict(self) -> dict: result: dict = {} - result["sessionIds"] = from_list(from_str, self.session_ids) + result["content"] = from_str(self.content) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsCheckInUseResult: - """Session IDs from the input set that are currently in use by another process.""" +class AccountGetQuotaResult: + """Quota usage snapshots for the resolved user, keyed by quota type.""" - in_use: list[str] - """Session IDs from the input set that are currently held by another running process via an - alive lock file - """ + quota_snapshots: dict[str, AccountQuotaSnapshot] + """Quota snapshots keyed by type (e.g., chat, completions, premium_interactions)""" @staticmethod - def from_dict(obj: Any) -> 'SessionsCheckInUseResult': + def from_dict(obj: Any) -> 'AccountGetQuotaResult': assert isinstance(obj, dict) - in_use = from_list(from_str, obj.get("inUse")) - return SessionsCheckInUseResult(in_use) + quota_snapshots = from_dict(AccountQuotaSnapshot.from_dict, obj.get("quotaSnapshots")) + return AccountGetQuotaResult(quota_snapshots) def to_dict(self) -> dict: result: dict = {} - result["inUse"] = from_list(from_str, self.in_use) + result["quotaSnapshots"] = from_dict(lambda x: to_class(AccountQuotaSnapshot, x), self.quota_snapshots) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsCloseRequest: - """Session ID to close.""" +class AgentGetCurrentResult: + """The currently selected custom agent, or null when using the default agent.""" - session_id: str - """Session ID to close""" + agent: AgentInfo | None = None + """Currently selected custom agent, or null if using the default agent""" @staticmethod - def from_dict(obj: Any) -> 'SessionsCloseRequest': + def from_dict(obj: Any) -> 'AgentGetCurrentResult': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsCloseRequest(session_id) + agent = from_union([AgentInfo.from_dict, from_none], obj.get("agent")) + return AgentGetCurrentResult(agent) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) + if self.agent is not None: + result["agent"] = from_union([lambda x: to_class(AgentInfo, x), from_none], self.agent) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsCloseResult: - """Closes a session: emits shutdown, flushes pending events to disk, releases the in-use - lock, disposes the active session. Idempotent: succeeds even if the session is not - currently active. - """ +class AgentList: + """Custom agents available to the session.""" + + agents: list[AgentInfo] + """Available custom agents""" + @staticmethod - def from_dict(obj: Any) -> 'SessionsCloseResult': + def from_dict(obj: Any) -> 'AgentList': assert isinstance(obj, dict) - return SessionsCloseResult() + agents = from_list(AgentInfo.from_dict, obj.get("agents")) + return AgentList(agents) def to_dict(self) -> dict: result: dict = {} + result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsFindByPrefixRequest: - """UUID prefix to resolve to a unique session ID.""" +class AgentReloadResult: + """Custom agents available to the session after reloading definitions from disk.""" - prefix: str - """UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when - there is no match or the prefix matches multiple sessions. - """ + agents: list[AgentInfo] + """Reloaded custom agents""" @staticmethod - def from_dict(obj: Any) -> 'SessionsFindByPrefixRequest': + def from_dict(obj: Any) -> 'AgentReloadResult': assert isinstance(obj, dict) - prefix = from_str(obj.get("prefix")) - return SessionsFindByPrefixRequest(prefix) + agents = from_list(AgentInfo.from_dict, obj.get("agents")) + return AgentReloadResult(agents) def to_dict(self) -> dict: result: dict = {} - result["prefix"] = from_str(self.prefix) + result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsFindByPrefixResult: - """Session ID matching the prefix, omitted when no unique match exists.""" +class AgentSelectResult: + """The newly selected custom agent.""" - session_id: str | None = None - """Omitted when no unique session matches the prefix (no match or ambiguous)""" + agent: AgentInfo + """The newly selected custom agent""" @staticmethod - def from_dict(obj: Any) -> 'SessionsFindByPrefixResult': + def from_dict(obj: Any) -> 'AgentSelectResult': assert isinstance(obj, dict) - session_id = from_union([from_str, from_none], obj.get("sessionId")) - return SessionsFindByPrefixResult(session_id) + agent = AgentInfo.from_dict(obj.get("agent")) + return AgentSelectResult(agent) def to_dict(self) -> dict: result: dict = {} - if self.session_id is not None: - result["sessionId"] = from_union([from_str, from_none], self.session_id) + result["agent"] = to_class(AgentInfo, self.agent) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsFindByTaskIDRequest: - """GitHub task ID to look up.""" +class SessionAuthStatus: + """Authentication status and account metadata for the session.""" - task_id: str - """GitHub task ID to look up""" + is_authenticated: bool + """Whether the session has resolved authentication""" - @staticmethod - def from_dict(obj: Any) -> 'SessionsFindByTaskIDRequest': - assert isinstance(obj, dict) - task_id = from_str(obj.get("taskId")) - return SessionsFindByTaskIDRequest(task_id) + auth_type: AuthInfoType | None = None + """Authentication type""" - def to_dict(self) -> dict: - result: dict = {} - result["taskId"] = from_str(self.task_id) - return result + copilot_plan: str | None = None + """Copilot plan tier (e.g., individual_pro, business)""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsFindByTaskIDResult: - """ID of the local session bound to the given GitHub task, or omitted when none.""" + host: str | None = None + """Authentication host URL""" - session_id: str | None = None - """Omitted when no local session is bound to that GitHub task""" + login: str | None = None + """Authenticated login/username, if available""" + + status_message: str | None = None + """Human-readable authentication status description""" @staticmethod - def from_dict(obj: Any) -> 'SessionsFindByTaskIDResult': + def from_dict(obj: Any) -> 'SessionAuthStatus': assert isinstance(obj, dict) - session_id = from_union([from_str, from_none], obj.get("sessionId")) - return SessionsFindByTaskIDResult(session_id) + is_authenticated = from_bool(obj.get("isAuthenticated")) + auth_type = from_union([AuthInfoType, from_none], obj.get("authType")) + copilot_plan = from_union([from_str, from_none], obj.get("copilotPlan")) + host = from_union([from_str, from_none], obj.get("host")) + login = from_union([from_str, from_none], obj.get("login")) + status_message = from_union([from_str, from_none], obj.get("statusMessage")) + return SessionAuthStatus(is_authenticated, auth_type, copilot_plan, host, login, status_message) def to_dict(self) -> dict: result: dict = {} - if self.session_id is not None: - result["sessionId"] = from_union([from_str, from_none], self.session_id) + result["isAuthenticated"] = from_bool(self.is_authenticated) + if self.auth_type is not None: + result["authType"] = from_union([lambda x: to_enum(AuthInfoType, x), from_none], self.auth_type) + if self.copilot_plan is not None: + result["copilotPlan"] = from_union([from_str, from_none], self.copilot_plan) + if self.host is not None: + result["host"] = from_union([from_str, from_none], self.host) + if self.login is not None: + result["login"] = from_union([from_str, from_none], self.login) + if self.status_message is not None: + result["statusMessage"] = from_union([from_str, from_none], self.status_message) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsForkRequest: - """Source session identifier to fork from, optional event-ID boundary, and optional friendly - name for the new session. - """ - session_id: str - """Source session ID to fork from""" +class SlashCommandInput: + """Optional unstructured input hint""" - name: str | None = None - """Optional friendly name to assign to the forked session.""" + hint: str + """Hint to display when command input has not been provided""" - to_event_id: str | None = None - """Optional event ID boundary. When provided, the fork includes only events before this ID - (exclusive). When omitted, all events are included. + completion: SlashCommandInputCompletion | None = None + """Optional completion hint for the input (e.g. 'directory' for filesystem path completion)""" + + preserve_multiline_input: bool | None = None + """When true, clients should pass the full text after the command name as a single argument + rather than splitting on whitespace + """ + required: bool | None = None + """When true, the command requires non-empty input; clients should render the input hint as + required """ @staticmethod - def from_dict(obj: Any) -> 'SessionsForkRequest': + def from_dict(obj: Any) -> 'SlashCommandInput': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - name = from_union([from_str, from_none], obj.get("name")) - to_event_id = from_union([from_str, from_none], obj.get("toEventId")) - return SessionsForkRequest(session_id, name, to_event_id) + hint = from_str(obj.get("hint")) + completion = from_union([SlashCommandInputCompletion, from_none], obj.get("completion")) + preserve_multiline_input = from_union([from_bool, from_none], obj.get("preserveMultilineInput")) + required = from_union([from_bool, from_none], obj.get("required")) + return SlashCommandInput(hint, completion, preserve_multiline_input, required) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.to_event_id is not None: - result["toEventId"] = from_union([from_str, from_none], self.to_event_id) + result["hint"] = from_str(self.hint) + if self.completion is not None: + result["completion"] = from_union([lambda x: to_enum(SlashCommandInputCompletion, x), from_none], self.completion) + if self.preserve_multiline_input is not None: + result["preserveMultilineInput"] = from_union([from_bool, from_none], self.preserve_multiline_input) + if self.required is not None: + result["required"] = from_union([from_bool, from_none], self.required) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsForkResult: - """Identifier and optional friendly name assigned to the newly forked session.""" +class ConnectedRemoteSessionMetadata: + """Metadata for a connected remote session.""" + + kind: ConnectedRemoteSessionMetadataKind + """Neutral SDK discriminator for the connected remote session kind.""" + + modified_time: datetime + """Last session update time as an ISO 8601 string.""" + + repository: ConnectedRemoteSessionMetadataRepository + """Repository associated with the connected remote session.""" session_id: str - """The new forked session's ID""" + """SDK session ID for the connected remote session.""" + + start_time: datetime + """Session start time as an ISO 8601 string.""" name: str | None = None - """Friendly name assigned to the forked session, if any.""" + """Optional friendly session name.""" + + pull_request_number: int | None = None + """Pull request number associated with the session.""" + + resource_id: str | None = None + """Original remote resource identifier.""" + + stale_at: datetime | None = None + """Remote session staleness deadline as an ISO 8601 string.""" + + state: str | None = None + """Remote session state returned by the backing service.""" + + summary: str | None = None + """Optional session summary.""" @staticmethod - def from_dict(obj: Any) -> 'SessionsForkResult': + def from_dict(obj: Any) -> 'ConnectedRemoteSessionMetadata': assert isinstance(obj, dict) + kind = ConnectedRemoteSessionMetadataKind(obj.get("kind")) + modified_time = from_datetime(obj.get("modifiedTime")) + repository = ConnectedRemoteSessionMetadataRepository.from_dict(obj.get("repository")) session_id = from_str(obj.get("sessionId")) + start_time = from_datetime(obj.get("startTime")) name = from_union([from_str, from_none], obj.get("name")) - return SessionsForkResult(session_id, name) + pull_request_number = from_union([from_int, from_none], obj.get("pullRequestNumber")) + resource_id = from_union([from_str, from_none], obj.get("resourceId")) + stale_at = from_union([from_datetime, from_none], obj.get("staleAt")) + state = from_union([from_str, from_none], obj.get("state")) + summary = from_union([from_str, from_none], obj.get("summary")) + return ConnectedRemoteSessionMetadata(kind, modified_time, repository, session_id, start_time, name, pull_request_number, resource_id, stale_at, state, summary) def to_dict(self) -> dict: result: dict = {} + result["kind"] = to_enum(ConnectedRemoteSessionMetadataKind, self.kind) + result["modifiedTime"] = self.modified_time.isoformat() + result["repository"] = to_class(ConnectedRemoteSessionMetadataRepository, self.repository) result["sessionId"] = from_str(self.session_id) + result["startTime"] = self.start_time.isoformat() if self.name is not None: result["name"] = from_union([from_str, from_none], self.name) + if self.pull_request_number is not None: + result["pullRequestNumber"] = from_union([from_int, from_none], self.pull_request_number) + if self.resource_id is not None: + result["resourceId"] = from_union([from_str, from_none], self.resource_id) + if self.stale_at is not None: + result["staleAt"] = from_union([lambda x: x.isoformat(), from_none], self.stale_at) + if self.state is not None: + result["state"] = from_union([from_str, from_none], self.state) + if self.summary is not None: + result["summary"] = from_union([from_str, from_none], self.summary) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsGetEventFilePathRequest: - """Session ID whose event-log file path to compute.""" - - session_id: str - """Session ID whose event-log file path to compute""" +class MCPServerConfigStdio: + """Stdio MCP server configuration launched as a child process.""" - @staticmethod - def from_dict(obj: Any) -> 'SessionsGetEventFilePathRequest': - assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsGetEventFilePathRequest(session_id) + command: str + """Executable command used to start the Stdio MCP server process.""" - def to_dict(self) -> dict: - result: dict = {} - result["sessionId"] = from_str(self.session_id) - return result + args: list[str] | None = None + """Command-line arguments passed to the Stdio MCP server process.""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsGetEventFilePathResult: - """Absolute path to the session's events.jsonl file on disk.""" + cwd: str | None = None + """Working directory for the Stdio MCP server process.""" + + env: dict[str, str] | None = None + """Environment variables to pass to the Stdio MCP server process.""" + + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None + """Content filtering mode to apply to all tools, or a map of tool name to content filtering + mode. + """ + is_default_server: bool | None = None + """Whether this server is a built-in fallback used when the user has not configured their + own server. + """ + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" - file_path: str - """Absolute path to the session's events.jsonl file""" + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" @staticmethod - def from_dict(obj: Any) -> 'SessionsGetEventFilePathResult': + def from_dict(obj: Any) -> 'MCPServerConfigStdio': assert isinstance(obj, dict) - file_path = from_str(obj.get("filePath")) - return SessionsGetEventFilePathResult(file_path) + command = from_str(obj.get("command")) + args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) + filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + return MCPServerConfigStdio(command, args, cwd, env, filter_mapping, is_default_server, timeout, tools) def to_dict(self) -> dict: result: dict = {} - result["filePath"] = from_str(self.file_path) + result["command"] = from_str(self.command) + if self.args is not None: + result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.env is not None: + result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsGetLastForContextResult: - """Most-relevant session ID for the supplied context, or omitted when no sessions exist.""" +class DiscoveredMCPServer: + """Schema for the `DiscoveredMcpServer` type.""" + + enabled: bool + """Whether the server is enabled (not in the disabled list)""" + + name: str + """Server name (config key)""" + + source: McpServerSource + """Configuration source: user, workspace, plugin, or builtin""" - session_id: str | None = None - """Most-relevant session ID for the supplied context, or omitted when no sessions exist""" + type: DiscoveredMCPServerType | None = None + """Server transport type: stdio, http, sse, or memory""" @staticmethod - def from_dict(obj: Any) -> 'SessionsGetLastForContextResult': + def from_dict(obj: Any) -> 'DiscoveredMCPServer': assert isinstance(obj, dict) - session_id = from_union([from_str, from_none], obj.get("sessionId")) - return SessionsGetLastForContextResult(session_id) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = McpServerSource(obj.get("source")) + type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) + return DiscoveredMCPServer(enabled, name, source, type) def to_dict(self) -> dict: result: dict = {} - if self.session_id is not None: - result["sessionId"] = from_union([from_str, from_none], self.session_id) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(McpServerSource, self.source) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsGetPersistedRemoteSteerableRequest: - """Session ID to look up the persisted remote-steerable flag for.""" +class Extension: + """Schema for the `Extension` type.""" - session_id: str - """Session ID to look up the persisted remote-steerable flag for""" + id: str + """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')""" - @staticmethod - def from_dict(obj: Any) -> 'SessionsGetPersistedRemoteSteerableRequest': - assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsGetPersistedRemoteSteerableRequest(session_id) + name: str + """Extension name (directory name)""" - def to_dict(self) -> dict: - result: dict = {} - result["sessionId"] = from_str(self.session_id) - return result + source: ExtensionSource + """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsGetPersistedRemoteSteerableResult: - """The session's persisted remote-steerable flag, or omitted when no value has been - persisted. - """ - remote_steerable: bool | None = None - """The session's persisted remote-steerable flag if recorded; omitted when no value has been - persisted - """ + status: ExtensionStatus + """Current status: running, disabled, failed, or starting""" + + pid: int | None = None + """Process ID if the extension is running""" @staticmethod - def from_dict(obj: Any) -> 'SessionsGetPersistedRemoteSteerableResult': + def from_dict(obj: Any) -> 'Extension': assert isinstance(obj, dict) - remote_steerable = from_union([from_bool, from_none], obj.get("remoteSteerable")) - return SessionsGetPersistedRemoteSteerableResult(remote_steerable) + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + source = ExtensionSource(obj.get("source")) + status = ExtensionStatus(obj.get("status")) + pid = from_union([from_int, from_none], obj.get("pid")) + return Extension(id, name, source, status, pid) def to_dict(self) -> dict: result: dict = {} - if self.remote_steerable is not None: - result["remoteSteerable"] = from_union([from_bool, from_none], self.remote_steerable) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + result["source"] = to_enum(ExtensionSource, self.source) + result["status"] = to_enum(ExtensionStatus, self.status) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) return result @dataclass -class Filter: - """Optional filter applied to the returned sessions""" - - branch: str | None = None - """Match sessions whose context.branch equals this value""" +class ExternalToolTextResultForLlmBinaryResultsForLlm: + """Binary result returned by a tool for the model""" - cwd: str | None = None - """Match sessions whose context.cwd equals this value""" + data: str + """Base64-encoded binary data""" - git_root: str | None = None - """Match sessions whose context.gitRoot equals this value""" + mime_type: str + """MIME type of the binary data""" - repository: str | None = None - """Match sessions whose context.repository equals this value""" + type: ExternalToolTextResultForLlmBinaryResultsForLlmType + """Binary result type discriminator. Use "image" for images and "resource" for other binary + data. + """ + description: str | None = None + """Human-readable description of the binary data""" @staticmethod - def from_dict(obj: Any) -> 'Filter': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmBinaryResultsForLlm': assert isinstance(obj, dict) - branch = from_union([from_str, from_none], obj.get("branch")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - git_root = from_union([from_str, from_none], obj.get("gitRoot")) - repository = from_union([from_str, from_none], obj.get("repository")) - return Filter(branch, cwd, git_root, repository) + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = ExternalToolTextResultForLlmBinaryResultsForLlmType(obj.get("type")) + description = from_union([from_str, from_none], obj.get("description")) + return ExternalToolTextResultForLlmBinaryResultsForLlm(data, mime_type, type, description) def to_dict(self) -> dict: result: dict = {} - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.git_root is not None: - result["gitRoot"] = from_union([from_str, from_none], self.git_root) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(ExternalToolTextResultForLlmBinaryResultsForLlmType, self.type) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsLoadDeferredRepoHooksRequest: - """Active session ID whose deferred repo-level hooks should be loaded.""" +class ExternalToolTextResultForLlmContentResourceLinkIcon: + """Icon image for a resource""" - session_id: str - """Active session ID whose deferred repo-level hooks should be loaded""" + src: str + """URL or path to the icon image""" + + mime_type: str | None = None + """MIME type of the icon image""" + + sizes: list[str] | None = None + """Available icon sizes (e.g., ['16x16', '32x32'])""" + + theme: ExternalToolTextResultForLlmContentResourceLinkIconTheme | None = None + """Theme variant this icon is intended for""" @staticmethod - def from_dict(obj: Any) -> 'SessionsLoadDeferredRepoHooksRequest': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLinkIcon': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsLoadDeferredRepoHooksRequest(session_id) + src = from_str(obj.get("src")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + sizes = from_union([lambda x: from_list(from_str, x), from_none], obj.get("sizes")) + theme = from_union([ExternalToolTextResultForLlmContentResourceLinkIconTheme, from_none], obj.get("theme")) + return ExternalToolTextResultForLlmContentResourceLinkIcon(src, mime_type, sizes, theme) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) + result["src"] = from_str(self.src) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + if self.sizes is not None: + result["sizes"] = from_union([lambda x: from_list(from_str, x), from_none], self.sizes) + if self.theme is not None: + result["theme"] = from_union([lambda x: to_enum(ExternalToolTextResultForLlmContentResourceLinkIconTheme, x), from_none], self.theme) return result -# Experimental: this type is part of an experimental API and may change or be removed. +ExternalToolTextResultForLlmContentResourceDetails = EmbeddedTextResourceContents | EmbeddedBlobResourceContents + @dataclass -class SessionsPruneOldRequest: - """Age threshold and optional flags controlling which old sessions are pruned (or simulated - when dryRun is true). - """ - older_than_days: int - """Delete sessions whose modifiedTime is at least this many days old""" +class ExternalToolTextResultForLlmContentAudio: + """Audio content block with base64-encoded data""" - dry_run: bool | None = None - """When true, only report what would be deleted without performing any deletion""" + data: str + """Base64-encoded audio data""" - exclude_session_ids: list[str] | None = None - """Session IDs that should never be considered for pruning""" + mime_type: str + """MIME type of the audio (e.g., audio/wav, audio/mpeg)""" - include_named: bool | None = None - """When true, named sessions (set via /rename) are also eligible for pruning""" + type: ExternalToolTextResultForLlmContentAudioType + """Content block type discriminator""" @staticmethod - def from_dict(obj: Any) -> 'SessionsPruneOldRequest': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentAudio': assert isinstance(obj, dict) - older_than_days = from_int(obj.get("olderThanDays")) - dry_run = from_union([from_bool, from_none], obj.get("dryRun")) - exclude_session_ids = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludeSessionIds")) - include_named = from_union([from_bool, from_none], obj.get("includeNamed")) - return SessionsPruneOldRequest(older_than_days, dry_run, exclude_session_ids, include_named) + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = ExternalToolTextResultForLlmContentAudioType(obj.get("type")) + return ExternalToolTextResultForLlmContentAudio(data, mime_type, type) def to_dict(self) -> dict: result: dict = {} - result["olderThanDays"] = from_int(self.older_than_days) - if self.dry_run is not None: - result["dryRun"] = from_union([from_bool, from_none], self.dry_run) - if self.exclude_session_ids is not None: - result["excludeSessionIds"] = from_union([lambda x: from_list(from_str, x), from_none], self.exclude_session_ids) - if self.include_named is not None: - result["includeNamed"] = from_union([from_bool, from_none], self.include_named) + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(ExternalToolTextResultForLlmContentAudioType, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsReleaseLockRequest: - """Session ID whose in-use lock should be released.""" +class ExternalToolTextResultForLlmContentImage: + """Image content block with base64-encoded data""" - session_id: str - """Session ID whose in-use lock should be released""" + data: str + """Base64-encoded image data""" - @staticmethod - def from_dict(obj: Any) -> 'SessionsReleaseLockRequest': - assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsReleaseLockRequest(session_id) + mime_type: str + """MIME type of the image (e.g., image/png, image/jpeg)""" - def to_dict(self) -> dict: - result: dict = {} - result["sessionId"] = from_str(self.session_id) - return result + type: ExternalToolTextResultForLlmContentImageType + """Content block type discriminator""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsReleaseLockResult: - """Release the in-use lock held by this process for the given session. No-op when this - process does not currently hold a lock for the session. - """ @staticmethod - def from_dict(obj: Any) -> 'SessionsReleaseLockResult': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentImage': assert isinstance(obj, dict) - return SessionsReleaseLockResult() + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = ExternalToolTextResultForLlmContentImageType(obj.get("type")) + return ExternalToolTextResultForLlmContentImage(data, mime_type, type) def to_dict(self) -> dict: result: dict = {} + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(ExternalToolTextResultForLlmContentImageType, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsReloadPluginHooksRequest: - """Active session ID and an optional flag for deferring repo-level hooks until folder trust.""" +class ExternalToolTextResultForLlmContentResource: + """Embedded resource content block with inline text or binary data""" - session_id: str - """Active session ID to reload hooks for""" + resource: ExternalToolTextResultForLlmContentResourceDetails + """The embedded resource contents, either text or base64-encoded binary""" - defer_repo_hooks: bool | None = None - """When true, skip repo-level hooks. Use before folder trust is confirmed; - loadDeferredRepoHooks loads them post-trust. - """ + type: ExternalToolTextResultForLlmContentResourceType + """Content block type discriminator""" @staticmethod - def from_dict(obj: Any) -> 'SessionsReloadPluginHooksRequest': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResource': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - defer_repo_hooks = from_union([from_bool, from_none], obj.get("deferRepoHooks")) - return SessionsReloadPluginHooksRequest(session_id, defer_repo_hooks) + resource = (lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x))(obj.get("resource")) + type = ExternalToolTextResultForLlmContentResourceType(obj.get("type")) + return ExternalToolTextResultForLlmContentResource(resource, type) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) - if self.defer_repo_hooks is not None: - result["deferRepoHooks"] = from_union([from_bool, from_none], self.defer_repo_hooks) + result["resource"] = from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], self.resource) + result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceType, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsReloadPluginHooksResult: - """Reload all hooks (user, plugin, optionally repo) and apply them to the active session. - Call after installing or removing plugins so their hooks take effect immediately. No-op - when no active session matches the given sessionId. - """ - @staticmethod - def from_dict(obj: Any) -> 'SessionsReloadPluginHooksResult': - assert isinstance(obj, dict) - return SessionsReloadPluginHooksResult() +class ExternalToolTextResultForLlmContentTerminal: + """Terminal/shell output content block with optional exit code and working directory""" - def to_dict(self) -> dict: - result: dict = {} - return result + text: str + """Terminal/shell output text""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsSaveRequest: - """Session ID whose pending events should be flushed to disk.""" + type: ExternalToolTextResultForLlmContentTerminalType + """Content block type discriminator""" - session_id: str - """Session ID whose pending events should be flushed to disk""" + cwd: str | None = None + """Working directory where the command was executed""" + + exit_code: float | None = None + """Process exit code, if the command has completed""" @staticmethod - def from_dict(obj: Any) -> 'SessionsSaveRequest': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentTerminal': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionsSaveRequest(session_id) + text = from_str(obj.get("text")) + type = ExternalToolTextResultForLlmContentTerminalType(obj.get("type")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + exit_code = from_union([from_float, from_none], obj.get("exitCode")) + return ExternalToolTextResultForLlmContentTerminal(text, type, cwd, exit_code) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) + result["text"] = from_str(self.text) + result["type"] = to_enum(ExternalToolTextResultForLlmContentTerminalType, self.type) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.exit_code is not None: + result["exitCode"] = from_union([to_float, from_none], self.exit_code) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsSaveResult: - """Flush a session's pending events to disk. No-op when no writer exists for the session - (e.g., already closed). - """ +class ExternalToolTextResultForLlmContentText: + """Plain text content block""" + + text: str + """The text content""" + + type: KindEnum + """Content block type discriminator""" + @staticmethod - def from_dict(obj: Any) -> 'SessionsSaveResult': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentText': assert isinstance(obj, dict) - return SessionsSaveResult() + text = from_str(obj.get("text")) + type = KindEnum(obj.get("type")) + return ExternalToolTextResultForLlmContentText(text, type) def to_dict(self) -> dict: result: dict = {} + result["text"] = from_str(self.text) + result["type"] = to_enum(KindEnum, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsSetAdditionalPluginsResult: - """Replace the manager-wide additional plugins. New session creations and subsequent hook - reloads see the new set; already-running sessions keep their existing hook installation - until the next reload. +class SlashCommandTextResult: + """Schema for the `SlashCommandTextResult` type.""" + + kind: KindEnum + """Text result discriminator""" + + text: str + """Text output for the client to render""" + + markdown: bool | None = None + """Whether text contains Markdown""" + + preserve_ansi: bool | None = None + """Whether ANSI sequences should be preserved""" + + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh """ + @staticmethod - def from_dict(obj: Any) -> 'SessionsSetAdditionalPluginsResult': + def from_dict(obj: Any) -> 'SlashCommandTextResult': assert isinstance(obj, dict) - return SessionsSetAdditionalPluginsResult() + kind = KindEnum(obj.get("kind")) + text = from_str(obj.get("text")) + markdown = from_union([from_bool, from_none], obj.get("markdown")) + preserve_ansi = from_union([from_bool, from_none], obj.get("preserveAnsi")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + return SlashCommandTextResult(kind, text, markdown, preserve_ansi, runtime_settings_changed) def to_dict(self) -> dict: result: dict = {} + result["kind"] = to_enum(KindEnum, self.kind) + result["text"] = from_str(self.text) + if self.markdown is not None: + result["markdown"] = from_union([from_bool, from_none], self.markdown) + if self.preserve_ansi is not None: + result["preserveAnsi"] = from_union([from_bool, from_none], self.preserve_ansi) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ShellExecRequest: - """Shell command to run, with optional working directory and timeout in milliseconds.""" +class HistoryCompactResult: + """Compaction outcome with the number of tokens and messages removed and the resulting + context window breakdown. + """ + messages_removed: int + """Number of messages removed during compaction""" - command: str - """Shell command to execute""" + success: bool + """Whether compaction completed successfully""" - cwd: str | None = None - """Working directory (defaults to session working directory)""" + tokens_removed: int + """Number of tokens freed by compaction""" - timeout: int | None = None - """Timeout in milliseconds (default: 30000)""" + context_window: HistoryCompactContextWindow | None = None + """Post-compaction context window usage breakdown""" @staticmethod - def from_dict(obj: Any) -> 'ShellExecRequest': + def from_dict(obj: Any) -> 'HistoryCompactResult': assert isinstance(obj, dict) - command = from_str(obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - return ShellExecRequest(command, cwd, timeout) + messages_removed = from_int(obj.get("messagesRemoved")) + success = from_bool(obj.get("success")) + tokens_removed = from_int(obj.get("tokensRemoved")) + context_window = from_union([HistoryCompactContextWindow.from_dict, from_none], obj.get("contextWindow")) + return HistoryCompactResult(messages_removed, success, tokens_removed, context_window) def to_dict(self) -> dict: result: dict = {} - result["command"] = from_str(self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) + result["messagesRemoved"] = from_int(self.messages_removed) + result["success"] = from_bool(self.success) + result["tokensRemoved"] = from_int(self.tokens_removed) + if self.context_window is not None: + result["contextWindow"] = from_union([lambda x: to_class(HistoryCompactContextWindow, x), from_none], self.context_window) return result @dataclass -class ShellExecResult: - """Identifier of the spawned process, used to correlate streamed output and exit - notifications. - """ - process_id: str - """Unique identifier for tracking streamed output""" +class InstructionsSources: + """Schema for the `InstructionsSources` type.""" - @staticmethod - def from_dict(obj: Any) -> 'ShellExecResult': - assert isinstance(obj, dict) - process_id = from_str(obj.get("processId")) - return ShellExecResult(process_id) + content: str + """Raw content of the instruction file""" - def to_dict(self) -> dict: - result: dict = {} - result["processId"] = from_str(self.process_id) - return result + id: str + """Unique identifier for this source (used for toggling)""" -class ShellKillSignal(Enum): - """Signal to send (default: SIGTERM)""" + label: str + """Human-readable label""" - SIGINT = "SIGINT" - SIGKILL = "SIGKILL" - SIGTERM = "SIGTERM" + location: InstructionsSourcesLocation + """Where this source lives — used for UI grouping""" -@dataclass -class ShellKillResult: - """Indicates whether the signal was delivered; false if the process was unknown or already - exited. - """ - killed: bool - """Whether the signal was sent successfully""" + source_path: str + """File path relative to repo or absolute for home""" + + type: InstructionsSourcesType + """Category of instruction source — used for merge logic""" + + apply_to: str | None = None + """Glob pattern from frontmatter — when set, this instruction applies only to matching files""" + + description: str | None = None + """Short description (body after frontmatter) for use in instruction tables""" @staticmethod - def from_dict(obj: Any) -> 'ShellKillResult': + def from_dict(obj: Any) -> 'InstructionsSources': assert isinstance(obj, dict) - killed = from_bool(obj.get("killed")) - return ShellKillResult(killed) + content = from_str(obj.get("content")) + id = from_str(obj.get("id")) + label = from_str(obj.get("label")) + location = InstructionsSourcesLocation(obj.get("location")) + source_path = from_str(obj.get("sourcePath")) + type = InstructionsSourcesType(obj.get("type")) + apply_to = from_union([from_str, from_none], obj.get("applyTo")) + description = from_union([from_str, from_none], obj.get("description")) + return InstructionsSources(content, id, label, location, source_path, type, apply_to, description) def to_dict(self) -> dict: result: dict = {} - result["killed"] = from_bool(self.killed) + result["content"] = from_str(self.content) + result["id"] = from_str(self.id) + result["label"] = from_str(self.label) + result["location"] = to_enum(InstructionsSourcesLocation, self.location) + result["sourcePath"] = from_str(self.source_path) + result["type"] = to_enum(InstructionsSourcesType, self.type) + if self.apply_to is not None: + result["applyTo"] = from_union([from_str, from_none], self.apply_to) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) return result @dataclass -class ShutdownRequest: - """Parameters for shutting down the session""" +class LogRequest: + """Message text, optional severity level, persistence flag, and optional follow-up URL.""" + + message: str + """Human-readable message""" - reason: str | None = None - """Optional human-readable reason. Typically the message of the error that triggered - shutdown when type is 'error'. + ephemeral: bool | None = None + """When true, the message is transient and not persisted to the session event log on disk""" + + level: SessionLogLevel | None = None + """Log severity level. Determines how the message is displayed in the timeline. Defaults to + "info". """ - type: ShutdownType | None = None - """Why the session is being shut down. Defaults to "routine" when omitted.""" + url: str | None = None + """Optional URL the user can open in their browser for more details""" @staticmethod - def from_dict(obj: Any) -> 'ShutdownRequest': + def from_dict(obj: Any) -> 'LogRequest': assert isinstance(obj, dict) - reason = from_union([from_str, from_none], obj.get("reason")) - type = from_union([ShutdownType, from_none], obj.get("type")) - return ShutdownRequest(reason, type) + message = from_str(obj.get("message")) + ephemeral = from_union([from_bool, from_none], obj.get("ephemeral")) + level = from_union([SessionLogLevel, from_none], obj.get("level")) + url = from_union([from_str, from_none], obj.get("url")) + return LogRequest(message, ephemeral, level, url) def to_dict(self) -> dict: result: dict = {} - if self.reason is not None: - result["reason"] = from_union([from_str, from_none], self.reason) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(ShutdownType, x), from_none], self.type) + result["message"] = from_str(self.message) + if self.ephemeral is not None: + result["ephemeral"] = from_union([from_bool, from_none], self.ephemeral) + if self.level is not None: + result["level"] = from_union([lambda x: to_enum(SessionLogLevel, x), from_none], self.level) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class Skill: - """Schema for the `Skill` type.""" +class MCPServerConfig: + """MCP server configuration (stdio process or remote HTTP/SSE) - description: str - """Description of what the skill does""" + Stdio MCP server configuration launched as a child process. - enabled: bool - """Whether the skill is currently enabled""" + Remote MCP server configuration accessed over HTTP or SSE. + """ + args: list[str] | None = None + """Command-line arguments passed to the Stdio MCP server process.""" - name: str - """Unique identifier for the skill""" + command: str | None = None + """Executable command used to start the Stdio MCP server process.""" - source: SkillSource - """Source location type (e.g., project, personal-copilot, plugin, builtin)""" + cwd: str | None = None + """Working directory for the Stdio MCP server process.""" - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" + env: dict[str, str] | None = None + """Environment variables to pass to the Stdio MCP server process.""" - path: str | None = None - """Absolute path to the skill file""" + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None + """Content filtering mode to apply to all tools, or a map of tool name to content filtering + mode. + """ + is_default_server: bool | None = None + """Whether this server is a built-in fallback used when the user has not configured their + own server. + """ + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" - plugin_name: str | None = None - """Name of the plugin that provides the skill, when source is 'plugin'""" + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" - @staticmethod - def from_dict(obj: Any) -> 'Skill': - assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = SkillSource(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - plugin_name = from_union([from_str, from_none], obj.get("pluginName")) - return Skill(description, enabled, name, source, user_invocable, path, plugin_name) - - def to_dict(self) -> dict: - result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(SkillSource, self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.plugin_name is not None: - result["pluginName"] = from_union([from_str, from_none], self.plugin_name) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SkillsDisableRequest: - """Name of the skill to disable for the session.""" - - name: str - """Name of the skill to disable""" - - @staticmethod - def from_dict(obj: Any) -> 'SkillsDisableRequest': - assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return SkillsDisableRequest(name) - - def to_dict(self) -> dict: - result: dict = {} - result["name"] = from_str(self.name) - return result - -@dataclass -class SkillsDiscoverRequest: - """Optional project paths and additional skill directories to include in discovery.""" - - project_paths: list[str] | None = None - """Optional list of project directory paths to scan for project-scoped skills""" - - skill_directories: list[str] | None = None - """Optional list of additional skill directory paths to include""" - - @staticmethod - def from_dict(obj: Any) -> 'SkillsDiscoverRequest': - assert isinstance(obj, dict) - project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) - return SkillsDiscoverRequest(project_paths, skill_directories) - - def to_dict(self) -> dict: - result: dict = {} - if self.project_paths is not None: - result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) - if self.skill_directories is not None: - result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SkillsEnableRequest: - """Name of the skill to enable for the session.""" - - name: str - """Name of the skill to enable""" - - @staticmethod - def from_dict(obj: Any) -> 'SkillsEnableRequest': - assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return SkillsEnableRequest(name) - - def to_dict(self) -> dict: - result: dict = {} - result["name"] = from_str(self.name) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SkillsInvokedSkill: - """Schema for the `SkillsInvokedSkill` type.""" - - content: str - """Full content of the skill file""" - - invoked_at_turn: int - """Turn number when the skill was invoked""" - - name: str - """Unique identifier for the skill""" - - path: str - """Path to the SKILL.md file""" - - allowed_tools: list[str] | None = None - """Tools that should be auto-approved when this skill is active, captured at invocation time""" - - @staticmethod - def from_dict(obj: Any) -> 'SkillsInvokedSkill': - assert isinstance(obj, dict) - content = from_str(obj.get("content")) - invoked_at_turn = from_int(obj.get("invokedAtTurn")) - name = from_str(obj.get("name")) - path = from_str(obj.get("path")) - allowed_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("allowedTools")) - return SkillsInvokedSkill(content, invoked_at_turn, name, path, allowed_tools) - - def to_dict(self) -> dict: - result: dict = {} - result["content"] = from_str(self.content) - result["invokedAtTurn"] = from_int(self.invoked_at_turn) - result["name"] = from_str(self.name) - result["path"] = from_str(self.path) - if self.allowed_tools is not None: - result["allowedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.allowed_tools) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SkillsLoadDiagnostics: - """Diagnostics from reloading skill definitions, with warnings and errors as separate lists.""" - - errors: list[str] - """Errors emitted while loading skills (e.g. skills that failed to load entirely)""" - - warnings: list[str] - """Warnings emitted while loading skills (e.g. skills that loaded but had issues)""" - - @staticmethod - def from_dict(obj: Any) -> 'SkillsLoadDiagnostics': - assert isinstance(obj, dict) - errors = from_list(from_str, obj.get("errors")) - warnings = from_list(from_str, obj.get("warnings")) - return SkillsLoadDiagnostics(errors, warnings) - - def to_dict(self) -> dict: - result: dict = {} - result["errors"] = from_list(from_str, self.errors) - result["warnings"] = from_list(from_str, self.warnings) - return result - -class SlashCommandAgentPromptResultKind(Enum): - AGENT_PROMPT = "agent-prompt" - -class SlashCommandCompletedResultKind(Enum): - COMPLETED = "completed" - -class SlashCommandInvocationResultKind(Enum): - AGENT_PROMPT = "agent-prompt" - COMPLETED = "completed" - TEXT = "text" - -# Experimental: this type is part of an experimental API and may change or be removed. -class TaskExecutionMode(Enum): - """Whether task execution is synchronously awaited or managed in the background""" - - BACKGROUND = "background" - SYNC = "sync" - -# Experimental: this type is part of an experimental API and may change or be removed. -class TaskStatus(Enum): - """Current lifecycle status of the task""" - - CANCELLED = "cancelled" - COMPLETED = "completed" - FAILED = "failed" - IDLE = "idle" - RUNNING = "running" - -class TaskAgentInfoType(Enum): - AGENT = "agent" - -@dataclass -class RecentActivity: - message: str - """Display message, e.g., "▸ bash", "✓ edit src/foo.ts\"""" - - timestamp: datetime - """ISO 8601 timestamp when this event occurred""" - - @staticmethod - def from_dict(obj: Any) -> 'RecentActivity': - assert isinstance(obj, dict) - message = from_str(obj.get("message")) - timestamp = from_datetime(obj.get("timestamp")) - return RecentActivity(message, timestamp) - - def to_dict(self) -> dict: - result: dict = {} - result["message"] = from_str(self.message) - result["timestamp"] = self.timestamp.isoformat() - return result - -class TaskAgentProgressType(Enum): - AGENT = "agent" - SHELL = "shell" - -# Experimental: this type is part of an experimental API and may change or be removed. -class TaskShellInfoAttachmentMode(Enum): - """Whether the shell runs inside a managed PTY session or as an independent background - process - """ - ATTACHED = "attached" - DETACHED = "detached" - -class TaskShellInfoType(Enum): - SHELL = "shell" - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksCancelRequest: - """Identifier of the background task to cancel.""" - - id: str - """Task identifier""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksCancelRequest': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksCancelRequest(id) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksCancelResult: - """Indicates whether the background task was successfully cancelled.""" - - cancelled: bool - """Whether the task was successfully cancelled""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksCancelResult': - assert isinstance(obj, dict) - cancelled = from_bool(obj.get("cancelled")) - return TasksCancelResult(cancelled) - - def to_dict(self) -> dict: - result: dict = {} - result["cancelled"] = from_bool(self.cancelled) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksGetProgressRequest: - """Identifier of the background task to fetch progress for.""" - - id: str - """Task identifier (agent ID or shell ID)""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksGetProgressRequest': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksGetProgressRequest(id) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksPromoteToBackgroundRequest: - """Identifier of the task to promote to background mode.""" - - id: str - """Task identifier""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksPromoteToBackgroundRequest': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksPromoteToBackgroundRequest(id) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksPromoteToBackgroundResult: - """Indicates whether the task was successfully promoted to background mode.""" - - promoted: bool - """Whether the task was successfully promoted to background mode""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksPromoteToBackgroundResult': - assert isinstance(obj, dict) - promoted = from_bool(obj.get("promoted")) - return TasksPromoteToBackgroundResult(promoted) - - def to_dict(self) -> dict: - result: dict = {} - result["promoted"] = from_bool(self.promoted) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksRefreshResult: - """Refresh metadata for any detached background shells the runtime knows about. Use after a - long pause to pick up exit/output state for shells running outside the agent loop. - """ - @staticmethod - def from_dict(obj: Any) -> 'TasksRefreshResult': - assert isinstance(obj, dict) - return TasksRefreshResult() - - def to_dict(self) -> dict: - result: dict = {} - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksRemoveRequest: - """Identifier of the completed or cancelled task to remove from tracking.""" - - id: str - """Task identifier""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksRemoveRequest': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksRemoveRequest(id) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksRemoveResult: - """Indicates whether the task was removed. False when the task does not exist or is still - running/idle. - """ - removed: bool - """Whether the task was removed. Returns false if the task does not exist or is still - running/idle (cancel it first). - """ - - @staticmethod - def from_dict(obj: Any) -> 'TasksRemoveResult': - assert isinstance(obj, dict) - removed = from_bool(obj.get("removed")) - return TasksRemoveResult(removed) - - def to_dict(self) -> dict: - result: dict = {} - result["removed"] = from_bool(self.removed) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksSendMessageRequest: - """Identifier of the target agent task, message content, and optional sender agent ID.""" - - id: str - """Agent task identifier""" - - message: str - """Message content to send to the agent""" - - from_agent_id: str | None = None - """Agent ID of the sender, if sent on behalf of another agent""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksSendMessageRequest': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - message = from_str(obj.get("message")) - from_agent_id = from_union([from_str, from_none], obj.get("fromAgentId")) - return TasksSendMessageRequest(id, message, from_agent_id) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - result["message"] = from_str(self.message) - if self.from_agent_id is not None: - result["fromAgentId"] = from_union([from_str, from_none], self.from_agent_id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksSendMessageResult: - """Indicates whether the message was delivered, with an error message when delivery failed.""" - - sent: bool - """Whether the message was successfully delivered or steered""" - - error: str | None = None - """Error message if delivery failed""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksSendMessageResult': - assert isinstance(obj, dict) - sent = from_bool(obj.get("sent")) - error = from_union([from_str, from_none], obj.get("error")) - return TasksSendMessageResult(sent, error) - - def to_dict(self) -> dict: - result: dict = {} - result["sent"] = from_bool(self.sent) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksStartAgentRequest: - """Agent type, prompt, name, and optional description and model override for the new task.""" - - agent_type: str - """Type of agent to start (e.g., 'explore', 'task', 'general-purpose')""" - - name: str - """Short name for the agent, used to generate a human-readable ID""" - - prompt: str - """Task prompt for the agent""" - - description: str | None = None - """Short description of the task""" - - model: str | None = None - """Optional model override""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksStartAgentRequest': - assert isinstance(obj, dict) - agent_type = from_str(obj.get("agentType")) - name = from_str(obj.get("name")) - prompt = from_str(obj.get("prompt")) - description = from_union([from_str, from_none], obj.get("description")) - model = from_union([from_str, from_none], obj.get("model")) - return TasksStartAgentRequest(agent_type, name, prompt, description, model) - - def to_dict(self) -> dict: - result: dict = {} - result["agentType"] = from_str(self.agent_type) - result["name"] = from_str(self.name) - result["prompt"] = from_str(self.prompt) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksStartAgentResult: - """Identifier assigned to the newly started background agent task.""" - - agent_id: str - """Generated agent ID for the background task""" - - @staticmethod - def from_dict(obj: Any) -> 'TasksStartAgentResult': - assert isinstance(obj, dict) - agent_id = from_str(obj.get("agentId")) - return TasksStartAgentResult(agent_id) - - def to_dict(self) -> dict: - result: dict = {} - result["agentId"] = from_str(self.agent_id) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksWaitForPendingResult: - """Wait until all in-flight background tasks (agents + shells) and any follow-up turns - scheduled by their completions have settled. Returns when the runtime is fully drained or - after an internal timeout (default 10 minutes; configurable via - COPILOT_TASK_WAIT_TIMEOUT_SECONDS). - """ - @staticmethod - def from_dict(obj: Any) -> 'TasksWaitForPendingResult': - assert isinstance(obj, dict) - return TasksWaitForPendingResult() - - def to_dict(self) -> dict: - result: dict = {} - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TelemetrySetFeatureOverridesRequest: - """Feature override key/value pairs to attach to subsequent telemetry events from this - session. - """ - features: dict[str, str] - """Override key/value pairs to attach to subsequent telemetry events from this session. - Replaces any previously-set overrides. - """ - - @staticmethod - def from_dict(obj: Any) -> 'TelemetrySetFeatureOverridesRequest': - assert isinstance(obj, dict) - features = from_dict(from_str, obj.get("features")) - return TelemetrySetFeatureOverridesRequest(features) - - def to_dict(self) -> dict: - result: dict = {} - result["features"] = from_dict(from_str, self.features) - return result - -class TokenAuthInfoType(Enum): - TOKEN = "token" - -@dataclass -class Tool: - """Schema for the `Tool` type.""" - - description: str - """Description of what the tool does""" - - name: str - """Tool identifier (e.g., "bash", "grep", "str_replace_editor")""" - - instructions: str | None = None - """Optional instructions for how to use this tool effectively""" - - namespaced_name: str | None = None - """Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP - tools) - """ - parameters: dict[str, Any] | None = None - """JSON Schema for the tool's input parameters""" - - @staticmethod - def from_dict(obj: Any) -> 'Tool': - assert isinstance(obj, dict) - description = from_str(obj.get("description")) - name = from_str(obj.get("name")) - instructions = from_union([from_str, from_none], obj.get("instructions")) - namespaced_name = from_union([from_str, from_none], obj.get("namespacedName")) - parameters = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("parameters")) - return Tool(description, name, instructions, namespaced_name, parameters) - - def to_dict(self) -> dict: - result: dict = {} - result["description"] = from_str(self.description) - result["name"] = from_str(self.name) - if self.instructions is not None: - result["instructions"] = from_union([from_str, from_none], self.instructions) - if self.namespaced_name is not None: - result["namespacedName"] = from_union([from_str, from_none], self.namespaced_name) - if self.parameters is not None: - result["parameters"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.parameters) - return result - -@dataclass -class ToolsInitializeAndValidateResult: - """Resolve, build, and validate the runtime tool list for this session. Subagent sessions - and consumer flows that need an initialized tool set before `send` invoke this. Default - base-class implementation is a no-op for sessions that don't support tool validation. - """ - @staticmethod - def from_dict(obj: Any) -> 'ToolsInitializeAndValidateResult': - assert isinstance(obj, dict) - return ToolsInitializeAndValidateResult() - - def to_dict(self) -> dict: - result: dict = {} - return result - -@dataclass -class ToolsListRequest: - """Optional model identifier whose tool overrides should be applied to the listing.""" - - model: str | None = None - """Optional model ID — when provided, the returned tool list reflects model-specific - overrides - """ - - @staticmethod - def from_dict(obj: Any) -> 'ToolsListRequest': - assert isinstance(obj, dict) - model = from_union([from_str, from_none], obj.get("model")) - return ToolsListRequest(model) - - def to_dict(self) -> dict: - result: dict = {} - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) - return result - -class UIAutoModeSwitchResponse(Enum): - """User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist - as setting), or no (decline). - """ - NO = "no" - YES = "yes" - YES_ALWAYS = "yes_always" - -@dataclass -class UIElicitationArrayAnyOfFieldItemsAnyOf: - """Schema for the `UIElicitationArrayAnyOfFieldItemsAnyOf` type.""" - - const: str - """Value submitted when this option is selected.""" - - title: str - """Display label for this option.""" - - @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItemsAnyOf': - assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return UIElicitationArrayAnyOfFieldItemsAnyOf(const, title) - - def to_dict(self) -> dict: - result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) - return result - -class UIElicitationArrayAnyOfFieldType(Enum): - ARRAY = "array" - -class UIElicitationArrayEnumFieldItemsType(Enum): - STRING = "string" - -class UIElicitationSchemaPropertyStringFormat(Enum): - """Optional format hint that constrains the accepted input.""" - - DATE = "date" - DATE_TIME = "date-time" - EMAIL = "email" - URI = "uri" - -@dataclass -class UIElicitationStringOneOfFieldOneOf: - """Schema for the `UIElicitationStringOneOfFieldOneOf` type.""" - - const: str - """Value submitted when this option is selected.""" - - title: str - """Display label for this option.""" - - @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringOneOfFieldOneOf': - assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return UIElicitationStringOneOfFieldOneOf(const, title) - - def to_dict(self) -> dict: - result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) - return result - -class UIElicitationSchemaPropertyType(Enum): - """Numeric type accepted by the field.""" - - ARRAY = "array" - BOOLEAN = "boolean" - INTEGER = "integer" - NUMBER = "number" - STRING = "string" - -class UIElicitationSchemaType(Enum): - OBJECT = "object" - -class UIElicitationResponseAction(Enum): - """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" - - ACCEPT = "accept" - CANCEL = "cancel" - DECLINE = "decline" - -@dataclass -class UIElicitationResult: - """Indicates whether the elicitation response was accepted; false if it was already resolved - by another client. - """ - success: bool - """Whether the response was accepted. False if the request was already resolved by another - client. - """ - - @staticmethod - def from_dict(obj: Any) -> 'UIElicitationResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return UIElicitationResult(success) - - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result - -class UIElicitationSchemaPropertyBooleanType(Enum): - BOOLEAN = "boolean" - -class UIElicitationSchemaPropertyNumberType(Enum): - """Numeric type accepted by the field.""" - - INTEGER = "integer" - NUMBER = "number" - -class UIExitPlanModeAction(Enum): - """The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, - otherwise 'interactive'. - """ - AUTOPILOT = "autopilot" - AUTOPILOT_FLEET = "autopilot_fleet" - EXIT_ONLY = "exit_only" - INTERACTIVE = "interactive" - -@dataclass -class UIHandlePendingResult: - """Indicates whether the pending UI request was resolved by this call.""" - - success: bool - """True if the request was still pending and was resolved by this call. False if the request - ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise - no longer pending. - """ - - @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingResult': - assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return UIHandlePendingResult(success) - - def to_dict(self) -> dict: - result: dict = {} - result["success"] = from_bool(self.success) - return result - -@dataclass -class UIHandlePendingSamplingRequest: - """Request ID of a pending `sampling.requested` event and an optional sampling result - payload (omit to reject). - """ - request_id: str - """The unique request ID from the sampling.requested event""" - - response: dict[str, Any] | None = None - """Optional sampling result payload. Omit to reject/cancel the sampling request without - providing a result. - """ - - @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingSamplingRequest': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - response = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("response")) - return UIHandlePendingSamplingRequest(request_id, response) - - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.response is not None: - result["response"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.response) - return result - -@dataclass -class UIUserInputResponse: - """Schema for the `UIUserInputResponse` type.""" - - answer: str - """The user's answer text""" - - was_freeform: bool - """True if the user typed a freeform response, false if they selected a presented choice. - Used by telemetry to differentiate between free text input and choice selection. - """ - - @staticmethod - def from_dict(obj: Any) -> 'UIUserInputResponse': - assert isinstance(obj, dict) - answer = from_str(obj.get("answer")) - was_freeform = from_bool(obj.get("wasFreeform")) - return UIUserInputResponse(answer, was_freeform) - - def to_dict(self) -> dict: - result: dict = {} - result["answer"] = from_str(self.answer) - result["wasFreeform"] = from_bool(self.was_freeform) - return result - -@dataclass -class UIRegisterDirectAutoModeSwitchHandlerResult: - """Register an in-process handler for `auto_mode_switch.requested` events. The caller still - attaches the actual listener via the standard event-subscription mechanism; this - registration solely tells the server bridge to skip its own dispatch (so a remote client - doesn't race the in-process handler for the same requestId). - """ - handle: str - """Opaque handle representing the registration. Pass this same handle to - `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. - Multiple registrations are reference-counted; the server bridge will only dispatch - auto-mode-switch requests when no handles are active. - """ - - @staticmethod - def from_dict(obj: Any) -> 'UIRegisterDirectAutoModeSwitchHandlerResult': - assert isinstance(obj, dict) - handle = from_str(obj.get("handle")) - return UIRegisterDirectAutoModeSwitchHandlerResult(handle) - - def to_dict(self) -> dict: - result: dict = {} - result["handle"] = from_str(self.handle) - return result - -@dataclass -class UIUnregisterDirectAutoModeSwitchHandlerRequest: - """Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release.""" - - handle: str - """Handle previously returned by `registerDirectAutoModeSwitchHandler`""" - - @staticmethod - def from_dict(obj: Any) -> 'UIUnregisterDirectAutoModeSwitchHandlerRequest': - assert isinstance(obj, dict) - handle = from_str(obj.get("handle")) - return UIUnregisterDirectAutoModeSwitchHandlerRequest(handle) - - def to_dict(self) -> dict: - result: dict = {} - result["handle"] = from_str(self.handle) - return result - -@dataclass -class UIUnregisterDirectAutoModeSwitchHandlerResult: - """Indicates whether the handle was active and the registration count was decremented.""" - - unregistered: bool - """True if the handle was active and decremented the counter; false if the handle was - unknown. - """ - - @staticmethod - def from_dict(obj: Any) -> 'UIUnregisterDirectAutoModeSwitchHandlerResult': - assert isinstance(obj, dict) - unregistered = from_bool(obj.get("unregistered")) - return UIUnregisterDirectAutoModeSwitchHandlerResult(unregistered) - - def to_dict(self) -> dict: - result: dict = {} - result["unregistered"] = from_bool(self.unregistered) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class UsageMetricsCodeChanges: - """Aggregated code change metrics""" - - files_modified: list[str] - """Distinct file paths modified during the session""" - - files_modified_count: int - """Number of distinct files modified""" - - lines_added: int - """Total lines of code added""" - - lines_removed: int - """Total lines of code removed""" - - @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsCodeChanges': - assert isinstance(obj, dict) - files_modified = from_list(from_str, obj.get("filesModified")) - files_modified_count = from_int(obj.get("filesModifiedCount")) - lines_added = from_int(obj.get("linesAdded")) - lines_removed = from_int(obj.get("linesRemoved")) - return UsageMetricsCodeChanges(files_modified, files_modified_count, lines_added, lines_removed) - - def to_dict(self) -> dict: - result: dict = {} - result["filesModified"] = from_list(from_str, self.files_modified) - result["filesModifiedCount"] = from_int(self.files_modified_count) - result["linesAdded"] = from_int(self.lines_added) - result["linesRemoved"] = from_int(self.lines_removed) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class UsageMetricsModelMetricRequests: - """Request count and cost metrics for this model""" - - cost: float - """User-initiated premium request cost (with multiplier applied)""" - - count: int - """Number of API requests made with this model""" - - @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetricRequests': - assert isinstance(obj, dict) - cost = from_float(obj.get("cost")) - count = from_int(obj.get("count")) - return UsageMetricsModelMetricRequests(cost, count) - - def to_dict(self) -> dict: - result: dict = {} - result["cost"] = to_float(self.cost) - result["count"] = from_int(self.count) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class UsageMetricsModelMetricTokenDetail: - """Schema for the `UsageMetricsModelMetricTokenDetail` type.""" - - token_count: int - """Accumulated token count for this token type""" - - @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetricTokenDetail': - assert isinstance(obj, dict) - token_count = from_int(obj.get("tokenCount")) - return UsageMetricsModelMetricTokenDetail(token_count) - - def to_dict(self) -> dict: - result: dict = {} - result["tokenCount"] = from_int(self.token_count) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class UsageMetricsModelMetricUsage: - """Token usage metrics for this model""" - - cache_read_tokens: int - """Total tokens read from prompt cache""" - - cache_write_tokens: int - """Total tokens written to prompt cache""" - - input_tokens: int - """Total input tokens consumed""" - - output_tokens: int - """Total output tokens produced""" - - reasoning_tokens: int | None = None - """Total output tokens used for reasoning""" - - @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetricUsage': - assert isinstance(obj, dict) - cache_read_tokens = from_int(obj.get("cacheReadTokens")) - cache_write_tokens = from_int(obj.get("cacheWriteTokens")) - input_tokens = from_int(obj.get("inputTokens")) - output_tokens = from_int(obj.get("outputTokens")) - reasoning_tokens = from_union([from_int, from_none], obj.get("reasoningTokens")) - return UsageMetricsModelMetricUsage(cache_read_tokens, cache_write_tokens, input_tokens, output_tokens, reasoning_tokens) - - def to_dict(self) -> dict: - result: dict = {} - result["cacheReadTokens"] = from_int(self.cache_read_tokens) - result["cacheWriteTokens"] = from_int(self.cache_write_tokens) - result["inputTokens"] = from_int(self.input_tokens) - result["outputTokens"] = from_int(self.output_tokens) - if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_int, from_none], self.reasoning_tokens) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class UsageMetricsTokenDetail: - """Schema for the `UsageMetricsTokenDetail` type.""" - - token_count: int - """Accumulated token count for this token type""" - - @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsTokenDetail': - assert isinstance(obj, dict) - token_count = from_int(obj.get("tokenCount")) - return UsageMetricsTokenDetail(token_count) - - def to_dict(self) -> dict: - result: dict = {} - result["tokenCount"] = from_int(self.token_count) - return result - -class UserAuthInfoType(Enum): - USER = "user" - -@dataclass -class WorkspacesCheckpoints: - """Schema for the `WorkspacesCheckpoints` type.""" - - filename: str - """Filename of the checkpoint within the workspace checkpoints directory""" - - number: int - """Checkpoint number assigned by the workspace manager""" - - title: str - """Human-readable checkpoint title""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesCheckpoints': - assert isinstance(obj, dict) - filename = from_str(obj.get("filename")) - number = from_int(obj.get("number")) - title = from_str(obj.get("title")) - return WorkspacesCheckpoints(filename, number, title) - - def to_dict(self) -> dict: - result: dict = {} - result["filename"] = from_str(self.filename) - result["number"] = from_int(self.number) - result["title"] = from_str(self.title) - return result - -@dataclass -class WorkspacesCreateFileRequest: - """Relative path and UTF-8 content for the workspace file to create or overwrite.""" - - content: str - """File content to write as a UTF-8 string""" - - path: str - """Relative path within the workspace files directory""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': - assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - return WorkspacesCreateFileRequest(content, path) - - def to_dict(self) -> dict: - result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) - return result - -@dataclass -class WorkspacesListFilesResult: - """Relative paths of files stored in the session workspace files directory.""" - - files: list[str] - """Relative file paths in the workspace files directory""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesListFilesResult': - assert isinstance(obj, dict) - files = from_list(from_str, obj.get("files")) - return WorkspacesListFilesResult(files) - - def to_dict(self) -> dict: - result: dict = {} - result["files"] = from_list(from_str, self.files) - return result - -@dataclass -class WorkspacesReadCheckpointRequest: - """Checkpoint number to read.""" - - number: int - """Checkpoint number to read""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadCheckpointRequest': - assert isinstance(obj, dict) - number = from_int(obj.get("number")) - return WorkspacesReadCheckpointRequest(number) - - def to_dict(self) -> dict: - result: dict = {} - result["number"] = from_int(self.number) - return result - -@dataclass -class WorkspacesReadCheckpointResult: - """Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing.""" - - content: str | None = None - """Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadCheckpointResult': - assert isinstance(obj, dict) - content = from_union([from_none, from_str], obj.get("content")) - return WorkspacesReadCheckpointResult(content) - - def to_dict(self) -> dict: - result: dict = {} - result["content"] = from_union([from_none, from_str], self.content) - return result - -@dataclass -class WorkspacesReadFileRequest: - """Relative path of the workspace file to read.""" - - path: str - """Relative path within the workspace files directory""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return WorkspacesReadFileRequest(path) - - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - return result - -@dataclass -class WorkspacesReadFileResult: - """Contents of the requested workspace file as a UTF-8 string.""" - - content: str - """File content as a UTF-8 string""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadFileResult': - assert isinstance(obj, dict) - content = from_str(obj.get("content")) - return WorkspacesReadFileResult(content) - - def to_dict(self) -> dict: - result: dict = {} - result["content"] = from_str(self.content) - return result - -@dataclass -class WorkspacesSaveLargePasteRequest: - """Pasted content to save as a UTF-8 file in the session workspace.""" - - content: str - """Pasted content to save as a UTF-8 file""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesSaveLargePasteRequest': - assert isinstance(obj, dict) - content = from_str(obj.get("content")) - return WorkspacesSaveLargePasteRequest(content) - - def to_dict(self) -> dict: - result: dict = {} - result["content"] = from_str(self.content) - return result - -@dataclass -class Saved: - filename: str - """Filename within the workspace files directory""" - - file_path: str - """Absolute filesystem path to the saved paste file""" - - size_bytes: int - """Size of the saved file in bytes""" - - @staticmethod - def from_dict(obj: Any) -> 'Saved': - assert isinstance(obj, dict) - filename = from_str(obj.get("filename")) - file_path = from_str(obj.get("filePath")) - size_bytes = from_int(obj.get("sizeBytes")) - return Saved(filename, file_path, size_bytes) - - def to_dict(self) -> dict: - result: dict = {} - result["filename"] = from_str(self.filename) - result["filePath"] = from_str(self.file_path) - result["sizeBytes"] = from_int(self.size_bytes) - return result - -@dataclass -class AccountGetQuotaResult: - """Quota usage snapshots for the resolved user, keyed by quota type.""" - - quota_snapshots: dict[str, AccountQuotaSnapshot] - """Quota snapshots keyed by type (e.g., chat, completions, premium_interactions)""" - - @staticmethod - def from_dict(obj: Any) -> 'AccountGetQuotaResult': - assert isinstance(obj, dict) - quota_snapshots = from_dict(AccountQuotaSnapshot.from_dict, obj.get("quotaSnapshots")) - return AccountGetQuotaResult(quota_snapshots) - - def to_dict(self) -> dict: - result: dict = {} - result["quotaSnapshots"] = from_dict(lambda x: to_class(AccountQuotaSnapshot, x), self.quota_snapshots) - return result - -@dataclass -class SessionAuthStatus: - """Authentication status and account metadata for the session.""" - - is_authenticated: bool - """Whether the session has resolved authentication""" - - auth_type: AuthInfoType | None = None - """Authentication type""" - - copilot_plan: str | None = None - """Copilot plan tier (e.g., individual_pro, business)""" - - host: str | None = None - """Authentication host URL""" - - login: str | None = None - """Authenticated login/username, if available""" - - status_message: str | None = None - """Human-readable authentication status description""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionAuthStatus': - assert isinstance(obj, dict) - is_authenticated = from_bool(obj.get("isAuthenticated")) - auth_type = from_union([AuthInfoType, from_none], obj.get("authType")) - copilot_plan = from_union([from_str, from_none], obj.get("copilotPlan")) - host = from_union([from_str, from_none], obj.get("host")) - login = from_union([from_str, from_none], obj.get("login")) - status_message = from_union([from_str, from_none], obj.get("statusMessage")) - return SessionAuthStatus(is_authenticated, auth_type, copilot_plan, host, login, status_message) - - def to_dict(self) -> dict: - result: dict = {} - result["isAuthenticated"] = from_bool(self.is_authenticated) - if self.auth_type is not None: - result["authType"] = from_union([lambda x: to_enum(AuthInfoType, x), from_none], self.auth_type) - if self.copilot_plan is not None: - result["copilotPlan"] = from_union([from_str, from_none], self.copilot_plan) - if self.host is not None: - result["host"] = from_union([from_str, from_none], self.host) - if self.login is not None: - result["login"] = from_union([from_str, from_none], self.login) - if self.status_message is not None: - result["statusMessage"] = from_union([from_str, from_none], self.status_message) - return result - -@dataclass -class SlashCommandInput: - """Optional unstructured input hint""" - - hint: str - """Hint to display when command input has not been provided""" - - completion: SlashCommandInputCompletion | None = None - """Optional completion hint for the input (e.g. 'directory' for filesystem path completion)""" - - preserve_multiline_input: bool | None = None - """When true, clients should pass the full text after the command name as a single argument - rather than splitting on whitespace - """ - required: bool | None = None - """When true, the command requires non-empty input; clients should render the input hint as - required - """ - - @staticmethod - def from_dict(obj: Any) -> 'SlashCommandInput': - assert isinstance(obj, dict) - hint = from_str(obj.get("hint")) - completion = from_union([SlashCommandInputCompletion, from_none], obj.get("completion")) - preserve_multiline_input = from_union([from_bool, from_none], obj.get("preserveMultilineInput")) - required = from_union([from_bool, from_none], obj.get("required")) - return SlashCommandInput(hint, completion, preserve_multiline_input, required) - - def to_dict(self) -> dict: - result: dict = {} - result["hint"] = from_str(self.hint) - if self.completion is not None: - result["completion"] = from_union([lambda x: to_enum(SlashCommandInputCompletion, x), from_none], self.completion) - if self.preserve_multiline_input is not None: - result["preserveMultilineInput"] = from_union([from_bool, from_none], self.preserve_multiline_input) - if self.required is not None: - result["required"] = from_union([from_bool, from_none], self.required) - return result - -@dataclass -class SendAttachmentDirectory: - """Directory attachment""" - - display_name: str - """User-facing display name for the attachment""" - - path: str - """Absolute directory path""" - - type: SlashCommandInputCompletion - """Attachment type discriminator""" - - @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentDirectory': - assert isinstance(obj, dict) - display_name = from_str(obj.get("displayName")) - path = from_str(obj.get("path")) - type = SlashCommandInputCompletion(obj.get("type")) - return SendAttachmentDirectory(display_name, path, type) - - def to_dict(self) -> dict: - result: dict = {} - result["displayName"] = from_str(self.display_name) - result["path"] = from_str(self.path) - result["type"] = to_enum(SlashCommandInputCompletion, self.type) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class ConnectedRemoteSessionMetadata: - """Metadata for a connected remote session.""" - - kind: ConnectedRemoteSessionMetadataKind - """Neutral SDK discriminator for the connected remote session kind.""" - - modified_time: datetime - """Last session update time as an ISO 8601 string.""" - - repository: ConnectedRemoteSessionMetadataRepository - """Repository associated with the connected remote session.""" - - session_id: str - """SDK session ID for the connected remote session.""" - - start_time: datetime - """Session start time as an ISO 8601 string.""" - - name: str | None = None - """Optional friendly session name.""" - - pull_request_number: int | None = None - """Pull request number associated with the session.""" - - resource_id: str | None = None - """Original remote resource identifier.""" - - stale_at: datetime | None = None - """Remote session staleness deadline as an ISO 8601 string.""" - - state: str | None = None - """Remote session state returned by the backing service.""" - - summary: str | None = None - """Optional session summary.""" - - @staticmethod - def from_dict(obj: Any) -> 'ConnectedRemoteSessionMetadata': - assert isinstance(obj, dict) - kind = ConnectedRemoteSessionMetadataKind(obj.get("kind")) - modified_time = from_datetime(obj.get("modifiedTime")) - repository = ConnectedRemoteSessionMetadataRepository.from_dict(obj.get("repository")) - session_id = from_str(obj.get("sessionId")) - start_time = from_datetime(obj.get("startTime")) - name = from_union([from_str, from_none], obj.get("name")) - pull_request_number = from_union([from_int, from_none], obj.get("pullRequestNumber")) - resource_id = from_union([from_str, from_none], obj.get("resourceId")) - stale_at = from_union([from_datetime, from_none], obj.get("staleAt")) - state = from_union([from_str, from_none], obj.get("state")) - summary = from_union([from_str, from_none], obj.get("summary")) - return ConnectedRemoteSessionMetadata(kind, modified_time, repository, session_id, start_time, name, pull_request_number, resource_id, stale_at, state, summary) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(ConnectedRemoteSessionMetadataKind, self.kind) - result["modifiedTime"] = self.modified_time.isoformat() - result["repository"] = to_class(ConnectedRemoteSessionMetadataRepository, self.repository) - result["sessionId"] = from_str(self.session_id) - result["startTime"] = self.start_time.isoformat() - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.pull_request_number is not None: - result["pullRequestNumber"] = from_union([from_int, from_none], self.pull_request_number) - if self.resource_id is not None: - result["resourceId"] = from_union([from_str, from_none], self.resource_id) - if self.stale_at is not None: - result["staleAt"] = from_union([lambda x: x.isoformat(), from_none], self.stale_at) - if self.state is not None: - result["state"] = from_union([from_str, from_none], self.state) - if self.summary is not None: - result["summary"] = from_union([from_str, from_none], self.summary) - return result - -@dataclass -class MCPServerConfigStdio: - """Stdio MCP server configuration launched as a child process.""" - - command: str - """Executable command used to start the Stdio MCP server process.""" - - args: list[str] | None = None - """Command-line arguments passed to the Stdio MCP server process.""" - - cwd: str | None = None - """Working directory for the Stdio MCP server process.""" - - env: dict[str, str] | None = None - """Environment variables to pass to the Stdio MCP server process.""" - - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None - """Content filtering mode to apply to all tools, or a map of tool name to content filtering - mode. - """ - is_default_server: bool | None = None - """Whether this server is a built-in fallback used when the user has not configured their - own server. - """ - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" - - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfigStdio': - assert isinstance(obj, dict) - command = from_str(obj.get("command")) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - return MCPServerConfigStdio(command, args, cwd, env, filter_mapping, is_default_server, timeout, tools) - - def to_dict(self) -> dict: - result: dict = {} - result["command"] = from_str(self.command) - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - return result - -@dataclass -class CopilotUserResponseQuotaSnapshots: - """Schema for the `CopilotUserResponseQuotaSnapshotsChat` type. - - Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type. - - Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type. - """ - entitlement: float | None = None - has_quota: bool | None = None - overage_count: float | None = None - overage_permitted: bool | None = None - percent_remaining: float | None = None - quota_id: str | None = None - quota_remaining: float | None = None - quota_reset_at: float | None = None - remaining: float | None = None - timestamp_utc: str | None = None - token_based_billing: bool | None = None - unlimited: bool | None = None - - @staticmethod - def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshots': - assert isinstance(obj, dict) - entitlement = from_union([from_float, from_none], obj.get("entitlement")) - has_quota = from_union([from_bool, from_none], obj.get("has_quota")) - overage_count = from_union([from_float, from_none], obj.get("overage_count")) - overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) - percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) - quota_id = from_union([from_str, from_none], obj.get("quota_id")) - quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) - quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) - remaining = from_union([from_float, from_none], obj.get("remaining")) - timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) - token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) - unlimited = from_union([from_bool, from_none], obj.get("unlimited")) - return CopilotUserResponseQuotaSnapshots(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) - - def to_dict(self) -> dict: - result: dict = {} - if self.entitlement is not None: - result["entitlement"] = from_union([to_float, from_none], self.entitlement) - if self.has_quota is not None: - result["has_quota"] = from_union([from_bool, from_none], self.has_quota) - if self.overage_count is not None: - result["overage_count"] = from_union([to_float, from_none], self.overage_count) - if self.overage_permitted is not None: - result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) - if self.percent_remaining is not None: - result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) - if self.quota_id is not None: - result["quota_id"] = from_union([from_str, from_none], self.quota_id) - if self.quota_remaining is not None: - result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) - if self.quota_reset_at is not None: - result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) - if self.remaining is not None: - result["remaining"] = from_union([to_float, from_none], self.remaining) - if self.timestamp_utc is not None: - result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) - if self.token_based_billing is not None: - result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) - if self.unlimited is not None: - result["unlimited"] = from_union([from_bool, from_none], self.unlimited) - return result - -@dataclass -class DiscoveredMCPServer: - """Schema for the `DiscoveredMcpServer` type.""" - - enabled: bool - """Whether the server is enabled (not in the disabled list)""" - - name: str - """Server name (config key)""" - - source: McpServerSource - """Configuration source: user, workspace, plugin, or builtin""" - - type: DiscoveredMCPServerType | None = None - """Server transport type: stdio, http, sse, or memory""" - - @staticmethod - def from_dict(obj: Any) -> 'DiscoveredMCPServer': - assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = McpServerSource(obj.get("source")) - type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) - return DiscoveredMCPServer(enabled, name, source, type) - - def to_dict(self) -> dict: - result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(McpServerSource, self.source) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class EventLogReadRequest: - """Cursor, batch size, and optional long-poll/filter parameters for reading session events.""" - - agent_scope: EventsAgentScope | None = None - """Agent-scope filter: 'primary' returns only main-agent events plus events whose type - starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns - events from all agents (matching wildcard-subscription behavior). Default is 'all' to - preserve wildcard semantics for catch-up callers. - """ - cursor: str | None = None - """Opaque cursor returned by a previous read. Omit on the first call to start from the - beginning of the session's persisted history. - """ - max: int | None = None - """Maximum number of events to return in this batch (1–1000, default 200).""" - - types: list[str] | EventLogTypes | None = None - """Either '*' to receive all event types, or a non-empty list of event types to receive""" - - wait_ms: int | None = None - """Milliseconds to wait for new events when the cursor is at the tail of history. 0 - (default) returns immediately even if no events are available. Capped at 30000ms. - Ephemeral events that arrive during the wait are delivered in this batch but are NOT - replayable on a subsequent read (use a non-zero waitMs in your next call to capture - future ephemerals as they happen). - """ - - @staticmethod - def from_dict(obj: Any) -> 'EventLogReadRequest': - assert isinstance(obj, dict) - agent_scope = from_union([EventsAgentScope, from_none], obj.get("agentScope")) - cursor = from_union([from_str, from_none], obj.get("cursor")) - max = from_union([from_int, from_none], obj.get("max")) - types = from_union([lambda x: from_list(from_str, x), EventLogTypes, from_none], obj.get("types")) - wait_ms = from_union([from_int, from_none], obj.get("waitMs")) - return EventLogReadRequest(agent_scope, cursor, max, types, wait_ms) - - def to_dict(self) -> dict: - result: dict = {} - if self.agent_scope is not None: - result["agentScope"] = from_union([lambda x: to_enum(EventsAgentScope, x), from_none], self.agent_scope) - if self.cursor is not None: - result["cursor"] = from_union([from_str, from_none], self.cursor) - if self.max is not None: - result["max"] = from_union([from_int, from_none], self.max) - if self.types is not None: - result["types"] = from_union([lambda x: from_list(from_str, x), lambda x: to_enum(EventLogTypes, x), from_none], self.types) - if self.wait_ms is not None: - result["waitMs"] = from_union([from_int, from_none], self.wait_ms) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class EventsReadResult: - """Batch of session events returned by a read, with cursor and continuation metadata.""" - - cursor: str - """Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue - from where this read left off. Always present, even when no events were returned. - """ - cursor_status: EventsCursorStatus - """Cursor status: 'ok' means the cursor was applied successfully; 'expired' means the cursor - referred to an event that no longer exists in history (e.g. truncated or compacted away) - and the read started from the beginning of the remaining history. - """ - events: list[SessionEvent] - """Events are delivered in two batches per read: persisted events first (in append order), - then ephemeral events (in seq order). When `waitMs > 0` and the catch-up batches were - empty, post-wait events follow the same two-batch ordering. Persisted and ephemeral - events do not interleave within a single read. - """ - has_more: bool - """True when the read returned `max` events and more events are available immediately. When - false, the next read with a non-zero `waitMs` will block until a new event arrives or the - wait expires. - """ - - @staticmethod - def from_dict(obj: Any) -> 'EventsReadResult': - assert isinstance(obj, dict) - cursor = from_str(obj.get("cursor")) - cursor_status = EventsCursorStatus(obj.get("cursorStatus")) - events = from_list(SessionEvent.from_dict, obj.get("events")) - has_more = from_bool(obj.get("hasMore")) - return EventsReadResult(cursor, cursor_status, events, has_more) - - def to_dict(self) -> dict: - result: dict = {} - result["cursor"] = from_str(self.cursor) - result["cursorStatus"] = to_enum(EventsCursorStatus, self.cursor_status) - result["events"] = from_list(lambda x: to_class(SessionEvent, x), self.events) - result["hasMore"] = from_bool(self.has_more) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class Extension: - """Schema for the `Extension` type.""" - - id: str - """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')""" - - name: str - """Extension name (directory name)""" - - source: ExtensionSource - """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" - - status: ExtensionStatus - """Current status: running, disabled, failed, or starting""" - - pid: int | None = None - """Process ID if the extension is running""" - - @staticmethod - def from_dict(obj: Any) -> 'Extension': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - source = ExtensionSource(obj.get("source")) - status = ExtensionStatus(obj.get("status")) - pid = from_union([from_int, from_none], obj.get("pid")) - return Extension(id, name, source, status, pid) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - result["source"] = to_enum(ExtensionSource, self.source) - result["status"] = to_enum(ExtensionStatus, self.status) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) - return result - -@dataclass -class ExternalToolTextResultForLlmBinaryResultsForLlm: - """Binary result returned by a tool for the model""" - - data: str - """Base64-encoded binary data""" - - mime_type: str - """MIME type of the binary data""" - - type: ExternalToolTextResultForLlmBinaryResultsForLlmType - """Binary result type discriminator. Use "image" for images and "resource" for other binary - data. - """ - description: str | None = None - """Human-readable description of the binary data""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmBinaryResultsForLlm': - assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = ExternalToolTextResultForLlmBinaryResultsForLlmType(obj.get("type")) - description = from_union([from_str, from_none], obj.get("description")) - return ExternalToolTextResultForLlmBinaryResultsForLlm(data, mime_type, type, description) - - def to_dict(self) -> dict: - result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(ExternalToolTextResultForLlmBinaryResultsForLlmType, self.type) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - return result - -@dataclass -class ExternalToolTextResultForLlmContentResourceLinkIcon: - """Icon image for a resource""" - - src: str - """URL or path to the icon image""" - - mime_type: str | None = None - """MIME type of the icon image""" - - sizes: list[str] | None = None - """Available icon sizes (e.g., ['16x16', '32x32'])""" - - theme: ExternalToolTextResultForLlmContentResourceLinkIconTheme | None = None - """Theme variant this icon is intended for""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLinkIcon': - assert isinstance(obj, dict) - src = from_str(obj.get("src")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) - sizes = from_union([lambda x: from_list(from_str, x), from_none], obj.get("sizes")) - theme = from_union([ExternalToolTextResultForLlmContentResourceLinkIconTheme, from_none], obj.get("theme")) - return ExternalToolTextResultForLlmContentResourceLinkIcon(src, mime_type, sizes, theme) - - def to_dict(self) -> dict: - result: dict = {} - result["src"] = from_str(self.src) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) - if self.sizes is not None: - result["sizes"] = from_union([lambda x: from_list(from_str, x), from_none], self.sizes) - if self.theme is not None: - result["theme"] = from_union([lambda x: to_enum(ExternalToolTextResultForLlmContentResourceLinkIconTheme, x), from_none], self.theme) - return result - -ExternalToolTextResultForLlmContentResourceDetails = EmbeddedTextResourceContents | EmbeddedBlobResourceContents - -@dataclass -class ExternalToolTextResultForLlmContentAudio: - """Audio content block with base64-encoded data""" - - data: str - """Base64-encoded audio data""" - - mime_type: str - """MIME type of the audio (e.g., audio/wav, audio/mpeg)""" - - type: ExternalToolTextResultForLlmContentAudioType - """Content block type discriminator""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentAudio': - assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = ExternalToolTextResultForLlmContentAudioType(obj.get("type")) - return ExternalToolTextResultForLlmContentAudio(data, mime_type, type) - - def to_dict(self) -> dict: - result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(ExternalToolTextResultForLlmContentAudioType, self.type) - return result - -@dataclass -class ExternalToolTextResultForLlmContentImage: - """Image content block with base64-encoded data""" - - data: str - """Base64-encoded image data""" - - mime_type: str - """MIME type of the image (e.g., image/png, image/jpeg)""" - - type: ExternalToolTextResultForLlmContentImageType - """Content block type discriminator""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentImage': - assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = ExternalToolTextResultForLlmContentImageType(obj.get("type")) - return ExternalToolTextResultForLlmContentImage(data, mime_type, type) - - def to_dict(self) -> dict: - result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(ExternalToolTextResultForLlmContentImageType, self.type) - return result - -@dataclass -class ExternalToolTextResultForLlmContentResource: - """Embedded resource content block with inline text or binary data""" - - resource: ExternalToolTextResultForLlmContentResourceDetails - """The embedded resource contents, either text or base64-encoded binary""" - - type: ExternalToolTextResultForLlmContentResourceType - """Content block type discriminator""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResource': - assert isinstance(obj, dict) - resource = (lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x))(obj.get("resource")) - type = ExternalToolTextResultForLlmContentResourceType(obj.get("type")) - return ExternalToolTextResultForLlmContentResource(resource, type) - - def to_dict(self) -> dict: - result: dict = {} - result["resource"] = from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], self.resource) - result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceType, self.type) - return result - -@dataclass -class ExternalToolTextResultForLlmContentTerminal: - """Terminal/shell output content block with optional exit code and working directory""" - - text: str - """Terminal/shell output text""" - - type: ExternalToolTextResultForLlmContentTerminalType - """Content block type discriminator""" - - cwd: str | None = None - """Working directory where the command was executed""" - - exit_code: int | None = None - """Process exit code, if the command has completed""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentTerminal': - assert isinstance(obj, dict) - text = from_str(obj.get("text")) - type = ExternalToolTextResultForLlmContentTerminalType(obj.get("type")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - exit_code = from_union([from_int, from_none], obj.get("exitCode")) - return ExternalToolTextResultForLlmContentTerminal(text, type, cwd, exit_code) - - def to_dict(self) -> dict: - result: dict = {} - result["text"] = from_str(self.text) - result["type"] = to_enum(ExternalToolTextResultForLlmContentTerminalType, self.type) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.exit_code is not None: - result["exitCode"] = from_union([from_int, from_none], self.exit_code) - return result - -@dataclass -class ExternalToolTextResultForLlmContentText: - """Plain text content block""" - - text: str - """The text content""" - - type: KindEnum - """Content block type discriminator""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentText': - assert isinstance(obj, dict) - text = from_str(obj.get("text")) - type = KindEnum(obj.get("type")) - return ExternalToolTextResultForLlmContentText(text, type) - - def to_dict(self) -> dict: - result: dict = {} - result["text"] = from_str(self.text) - result["type"] = to_enum(KindEnum, self.type) - return result - -@dataclass -class SlashCommandTextResult: - """Schema for the `SlashCommandTextResult` type.""" - - kind: KindEnum - """Text result discriminator""" - - text: str - """Text output for the client to render""" - - markdown: bool | None = None - """Whether text contains Markdown""" - - preserve_ansi: bool | None = None - """Whether ANSI sequences should be preserved""" - - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh - """ - - @staticmethod - def from_dict(obj: Any) -> 'SlashCommandTextResult': - assert isinstance(obj, dict) - kind = KindEnum(obj.get("kind")) - text = from_str(obj.get("text")) - markdown = from_union([from_bool, from_none], obj.get("markdown")) - preserve_ansi = from_union([from_bool, from_none], obj.get("preserveAnsi")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - return SlashCommandTextResult(kind, text, markdown, preserve_ansi, runtime_settings_changed) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(KindEnum, self.kind) - result["text"] = from_str(self.text) - if self.markdown is not None: - result["markdown"] = from_union([from_bool, from_none], self.markdown) - if self.preserve_ansi is not None: - result["preserveAnsi"] = from_union([from_bool, from_none], self.preserve_ansi) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class HistoryCompactResult: - """Compaction outcome with the number of tokens and messages removed, summary text, and the - resulting context window breakdown. - """ - messages_removed: int - """Number of messages removed during compaction""" - - success: bool - """Whether compaction completed successfully""" - - tokens_removed: int - """Number of tokens freed by compaction""" - - context_window: HistoryCompactContextWindow | None = None - """Post-compaction context window usage breakdown""" - - summary_content: str | None = None - """Summary text produced by compaction. Omitted when compaction did not produce a summary - (e.g. failure path). - """ - - @staticmethod - def from_dict(obj: Any) -> 'HistoryCompactResult': - assert isinstance(obj, dict) - messages_removed = from_int(obj.get("messagesRemoved")) - success = from_bool(obj.get("success")) - tokens_removed = from_int(obj.get("tokensRemoved")) - context_window = from_union([HistoryCompactContextWindow.from_dict, from_none], obj.get("contextWindow")) - summary_content = from_union([from_str, from_none], obj.get("summaryContent")) - return HistoryCompactResult(messages_removed, success, tokens_removed, context_window, summary_content) - - def to_dict(self) -> dict: - result: dict = {} - result["messagesRemoved"] = from_int(self.messages_removed) - result["success"] = from_bool(self.success) - result["tokensRemoved"] = from_int(self.tokens_removed) - if self.context_window is not None: - result["contextWindow"] = from_union([lambda x: to_class(HistoryCompactContextWindow, x), from_none], self.context_window) - if self.summary_content is not None: - result["summaryContent"] = from_union([from_str, from_none], self.summary_content) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class InstalledPluginSourceGithub: - """Schema for the `InstalledPluginSourceGithub` type.""" - - repo: str - source: FluffySource - """Constant value. Always "github".""" - - path: str | None = None - ref: str | None = None - - @staticmethod - def from_dict(obj: Any) -> 'InstalledPluginSourceGithub': - assert isinstance(obj, dict) - repo = from_str(obj.get("repo")) - source = FluffySource(obj.get("source")) - path = from_union([from_str, from_none], obj.get("path")) - ref = from_union([from_str, from_none], obj.get("ref")) - return InstalledPluginSourceGithub(repo, source, path, ref) - - def to_dict(self) -> dict: - result: dict = {} - result["repo"] = from_str(self.repo) - result["source"] = to_enum(FluffySource, self.source) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.ref is not None: - result["ref"] = from_union([from_str, from_none], self.ref) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionInstalledPluginSourceGithub: - """Schema for the `SessionInstalledPluginSourceGithub` type.""" - - repo: str - source: FluffySource - """Constant value. Always "github".""" - - path: str | None = None - ref: str | None = None - - @staticmethod - def from_dict(obj: Any) -> 'SessionInstalledPluginSourceGithub': - assert isinstance(obj, dict) - repo = from_str(obj.get("repo")) - source = FluffySource(obj.get("source")) - path = from_union([from_str, from_none], obj.get("path")) - ref = from_union([from_str, from_none], obj.get("ref")) - return SessionInstalledPluginSourceGithub(repo, source, path, ref) - - def to_dict(self) -> dict: - result: dict = {} - result["repo"] = from_str(self.repo) - result["source"] = to_enum(FluffySource, self.source) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.ref is not None: - result["ref"] = from_union([from_str, from_none], self.ref) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class InstalledPluginSourceLocal: - """Schema for the `InstalledPluginSourceLocal` type.""" - - path: str - source: TentacledSource - """Constant value. Always "local".""" - - @staticmethod - def from_dict(obj: Any) -> 'InstalledPluginSourceLocal': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - source = TentacledSource(obj.get("source")) - return InstalledPluginSourceLocal(path, source) - - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - result["source"] = to_enum(TentacledSource, self.source) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionInstalledPluginSourceLocal: - """Schema for the `SessionInstalledPluginSourceLocal` type.""" - - path: str - source: TentacledSource - """Constant value. Always "local".""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionInstalledPluginSourceLocal': - assert isinstance(obj, dict) - path = from_str(obj.get("path")) - source = TentacledSource(obj.get("source")) - return SessionInstalledPluginSourceLocal(path, source) - - def to_dict(self) -> dict: - result: dict = {} - result["path"] = from_str(self.path) - result["source"] = to_enum(TentacledSource, self.source) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class InstalledPluginSourceURL: - """Schema for the `InstalledPluginSourceUrl` type.""" - - source: StickySource - """Constant value. Always "url".""" - - url: str - path: str | None = None - ref: str | None = None - - @staticmethod - def from_dict(obj: Any) -> 'InstalledPluginSourceURL': - assert isinstance(obj, dict) - source = StickySource(obj.get("source")) - url = from_str(obj.get("url")) - path = from_union([from_str, from_none], obj.get("path")) - ref = from_union([from_str, from_none], obj.get("ref")) - return InstalledPluginSourceURL(source, url, path, ref) - - def to_dict(self) -> dict: - result: dict = {} - result["source"] = to_enum(StickySource, self.source) - result["url"] = from_str(self.url) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.ref is not None: - result["ref"] = from_union([from_str, from_none], self.ref) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionInstalledPluginSourceURL: - """Schema for the `SessionInstalledPluginSourceUrl` type.""" - - source: StickySource - """Constant value. Always "url".""" - - url: str - path: str | None = None - ref: str | None = None - - @staticmethod - def from_dict(obj: Any) -> 'SessionInstalledPluginSourceURL': - assert isinstance(obj, dict) - source = StickySource(obj.get("source")) - url = from_str(obj.get("url")) - path = from_union([from_str, from_none], obj.get("path")) - ref = from_union([from_str, from_none], obj.get("ref")) - return SessionInstalledPluginSourceURL(source, url, path, ref) - - def to_dict(self) -> dict: - result: dict = {} - result["source"] = to_enum(StickySource, self.source) - result["url"] = from_str(self.url) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.ref is not None: - result["ref"] = from_union([from_str, from_none], self.ref) - return result - -@dataclass -class InstructionsSources: - """Schema for the `InstructionsSources` type.""" - - content: str - """Raw content of the instruction file""" - - id: str - """Unique identifier for this source (used for toggling)""" - - label: str - """Human-readable label""" - - location: InstructionsSourcesLocation - """Where this source lives — used for UI grouping""" - - source_path: str - """File path relative to repo or absolute for home""" - - type: InstructionsSourcesType - """Category of instruction source — used for merge logic""" - - apply_to: list[str] | None = None - """Glob pattern(s) from frontmatter — when set, this instruction applies only to matching - files - """ - default_disabled: bool | None = None - """When true, this source starts disabled and must be toggled on by the user""" - - description: str | None = None - """Short description (body after frontmatter) for use in instruction tables""" - - @staticmethod - def from_dict(obj: Any) -> 'InstructionsSources': - assert isinstance(obj, dict) - content = from_str(obj.get("content")) - id = from_str(obj.get("id")) - label = from_str(obj.get("label")) - location = InstructionsSourcesLocation(obj.get("location")) - source_path = from_str(obj.get("sourcePath")) - type = InstructionsSourcesType(obj.get("type")) - apply_to = from_union([lambda x: from_list(from_str, x), from_none], obj.get("applyTo")) - default_disabled = from_union([from_bool, from_none], obj.get("defaultDisabled")) - description = from_union([from_str, from_none], obj.get("description")) - return InstructionsSources(content, id, label, location, source_path, type, apply_to, default_disabled, description) - - def to_dict(self) -> dict: - result: dict = {} - result["content"] = from_str(self.content) - result["id"] = from_str(self.id) - result["label"] = from_str(self.label) - result["location"] = to_enum(InstructionsSourcesLocation, self.location) - result["sourcePath"] = from_str(self.source_path) - result["type"] = to_enum(InstructionsSourcesType, self.type) - if self.apply_to is not None: - result["applyTo"] = from_union([lambda x: from_list(from_str, x), from_none], self.apply_to) - if self.default_disabled is not None: - result["defaultDisabled"] = from_union([from_bool, from_none], self.default_disabled) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - return result - -@dataclass -class LogRequest: - """Message text, optional severity level, persistence flag, optional follow-up URL, and - optional tip. - """ - message: str - """Human-readable message""" - - ephemeral: bool | None = None - """When true, the message is transient and not persisted to the session event log on disk""" - - level: SessionLogLevel | None = None - """Log severity level. Determines how the message is displayed in the timeline. Defaults to - "info". - """ - tip: str | None = None - """Optional actionable tip displayed alongside the message. Only honored on `level: "info"`.""" - - type: str | None = None - """Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps - to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". - """ - url: str | None = None - """Optional URL the user can open in their browser for more details""" - - @staticmethod - def from_dict(obj: Any) -> 'LogRequest': - assert isinstance(obj, dict) - message = from_str(obj.get("message")) - ephemeral = from_union([from_bool, from_none], obj.get("ephemeral")) - level = from_union([SessionLogLevel, from_none], obj.get("level")) - tip = from_union([from_str, from_none], obj.get("tip")) - type = from_union([from_str, from_none], obj.get("type")) - url = from_union([from_str, from_none], obj.get("url")) - return LogRequest(message, ephemeral, level, tip, type, url) - - def to_dict(self) -> dict: - result: dict = {} - result["message"] = from_str(self.message) - if self.ephemeral is not None: - result["ephemeral"] = from_union([from_bool, from_none], self.ephemeral) - if self.level is not None: - result["level"] = from_union([lambda x: to_enum(SessionLogLevel, x), from_none], self.level) - if self.tip is not None: - result["tip"] = from_union([from_str, from_none], self.tip) - if self.type is not None: - result["type"] = from_union([from_str, from_none], self.type) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) - return result - -@dataclass -class MCPServerConfig: - """MCP server configuration (stdio process or remote HTTP/SSE) - - Stdio MCP server configuration launched as a child process. - - Remote MCP server configuration accessed over HTTP or SSE. - """ - args: list[str] | None = None - """Command-line arguments passed to the Stdio MCP server process.""" - - command: str | None = None - """Executable command used to start the Stdio MCP server process.""" - - cwd: str | None = None - """Working directory for the Stdio MCP server process.""" - - env: dict[str, str] | None = None - """Environment variables to pass to the Stdio MCP server process.""" - - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None - """Content filtering mode to apply to all tools, or a map of tool name to content filtering - mode. - """ - is_default_server: bool | None = None - """Whether this server is a built-in fallback used when the user has not configured their - own server. - """ - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" - - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" - - auth: MCPServerConfigHTTPAuth | None = None - """Additional authentication configuration for this server.""" - - headers: dict[str, str] | None = None - """HTTP headers to include in requests to the remote MCP server.""" - - oauth_client_id: str | None = None - """OAuth client ID for a pre-registered remote MCP OAuth client.""" - - oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None - """OAuth grant type to use when authenticating to the remote MCP server.""" - - oauth_public_client: bool | None = None - """Whether the configured OAuth client is public and does not require a client secret.""" - - type: MCPServerConfigHTTPType | None = None - """Remote transport type. Defaults to "http" when omitted.""" - - url: str | None = None - """URL of the remote MCP server endpoint.""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfig': - assert isinstance(obj, dict) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - command = from_union([from_str, from_none], obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) - type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) - url = from_union([from_str, from_none], obj.get("url")) - return MCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, auth, headers, oauth_client_id, oauth_grant_type, oauth_public_client, type, url) - - def to_dict(self) -> dict: - result: dict = {} - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.command is not None: - result["command"] = from_union([from_str, from_none], self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.auth is not None: - result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_grant_type is not None: - result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) - return result - -@dataclass -class MCPServerConfigHTTP: - """Remote MCP server configuration accessed over HTTP or SSE.""" - - url: str - """URL of the remote MCP server endpoint.""" - - auth: MCPServerConfigHTTPAuth | None = None - """Additional authentication configuration for this server.""" - - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None - """Content filtering mode to apply to all tools, or a map of tool name to content filtering - mode. - """ - headers: dict[str, str] | None = None - """HTTP headers to include in requests to the remote MCP server.""" - - is_default_server: bool | None = None - """Whether this server is a built-in fallback used when the user has not configured their - own server. - """ - oauth_client_id: str | None = None - """OAuth client ID for a pre-registered remote MCP OAuth client.""" - - oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None - """OAuth grant type to use when authenticating to the remote MCP server.""" - - oauth_public_client: bool | None = None - """Whether the configured OAuth client is public and does not require a client secret.""" - - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" - - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" - - type: MCPServerConfigHTTPType | None = None - """Remote transport type. Defaults to "http" when omitted.""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfigHTTP': - assert isinstance(obj, dict) - url = from_str(obj.get("url")) - auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) - filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) - return MCPServerConfigHTTP(url, auth, filter_mapping, headers, is_default_server, oauth_client_id, oauth_grant_type, oauth_public_client, timeout, tools, type) - - def to_dict(self) -> dict: - result: dict = {} - result["url"] = from_str(self.url) - if self.auth is not None: - result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_grant_type is not None: - result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPSamplingExecutionResult: - """Outcome of an MCP sampling execution: success result, failure error, or cancellation.""" - - action: MCPSamplingExecutionAction - """Outcome of the sampling inference. 'success' produced a response; 'failure' encountered - an error (including agent-side rejection by content filter or criteria); 'cancelled' the - caller cancelled this execution via cancelSamplingExecution. - """ - error: str | None = None - """Error description, present when action='failure'.""" - - result: dict[str, Any] | None = None - """MCP CreateMessageResult payload (with optional 'tools' extension), present when - action='success'. Treated as opaque at the schema layer; consumers should - construct/consume it per the MCP CreateMessageResult shape. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MCPSamplingExecutionResult': - assert isinstance(obj, dict) - action = MCPSamplingExecutionAction(obj.get("action")) - error = from_union([from_str, from_none], obj.get("error")) - result = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("result")) - return MCPSamplingExecutionResult(action, error, result) - - def to_dict(self) -> dict: - result: dict = {} - result["action"] = to_enum(MCPSamplingExecutionAction, self.action) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result is not None: - result["result"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.result) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPServerList: - """MCP servers configured for the session, with their connection status.""" - - servers: list[MCPServer] - """Configured MCP servers""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPServerList': - assert isinstance(obj, dict) - servers = from_list(MCPServer.from_dict, obj.get("servers")) - return MCPServerList(servers) - - def to_dict(self) -> dict: - result: dict = {} - result["servers"] = from_list(lambda x: to_class(MCPServer, x), self.servers) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPSetEnvValueModeParams: - """Mode controlling how MCP server env values are resolved (`direct` or `indirect`).""" - - mode: MCPSetEnvValueModeDetails - """How environment-variable values supplied to MCP servers are resolved. "direct" passes - literal string values; "indirect" treats values as references (e.g. names of environment - variables on the host) that the runtime resolves before launch. Defaults to the runtime's - startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI - prompt mode and ACP) set this to "direct". - """ - - @staticmethod - def from_dict(obj: Any) -> 'MCPSetEnvValueModeParams': - assert isinstance(obj, dict) - mode = MCPSetEnvValueModeDetails(obj.get("mode")) - return MCPSetEnvValueModeParams(mode) - - def to_dict(self) -> dict: - result: dict = {} - result["mode"] = to_enum(MCPSetEnvValueModeDetails, self.mode) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPSetEnvValueModeResult: - """Env-value mode recorded on the session after the update.""" - - mode: MCPSetEnvValueModeDetails - """Mode recorded on the session after the update""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPSetEnvValueModeResult': - assert isinstance(obj, dict) - mode = MCPSetEnvValueModeDetails(obj.get("mode")) - return MCPSetEnvValueModeResult(mode) - - def to_dict(self) -> dict: - result: dict = {} - result["mode"] = to_enum(MCPSetEnvValueModeDetails, self.mode) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataContextInfoResult: - """Token breakdown for the session's current context window, or null if uninitialized.""" - - context_info: SessionContextInfo | None = None - """Token breakdown for the current context window, or null if the session has not yet been - initialized (no system prompt or tool metadata cached). - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataContextInfoResult': - assert isinstance(obj, dict) - context_info = from_union([SessionContextInfo.from_dict, from_none], obj.get("contextInfo")) - return MetadataContextInfoResult(context_info) - - def to_dict(self) -> dict: - result: dict = {} - if self.context_info is not None: - result["contextInfo"] = from_union([lambda x: to_class(SessionContextInfo, x), from_none], self.context_info) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionWorkingDirectoryContext: - """Updated working directory and git context. Emitted as the new payload of - `session.context_changed`. - """ - cwd: str - """Current working directory path""" - - base_commit: str | None = None - """Merge-base commit SHA (fork point from the remote default branch)""" - - branch: str | None = None - """Current git branch name""" - - git_root: str | None = None - """Root directory of the git repository, resolved via git rev-parse""" - - head_commit: str | None = None - """Head commit of the current git branch""" - - host_type: SessionContextHostType | None = None - """Hosting platform type of the repository""" - - repository: str | None = None - """Repository identifier derived from the git remote URL ("owner/name" for GitHub, - "org/project/repo" for Azure DevOps) - """ - repository_host: str | None = None - """Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com")""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionWorkingDirectoryContext': - assert isinstance(obj, dict) - cwd = from_str(obj.get("cwd")) - base_commit = from_union([from_str, from_none], obj.get("baseCommit")) - branch = from_union([from_str, from_none], obj.get("branch")) - git_root = from_union([from_str, from_none], obj.get("gitRoot")) - head_commit = from_union([from_str, from_none], obj.get("headCommit")) - host_type = from_union([SessionContextHostType, from_none], obj.get("hostType")) - repository = from_union([from_str, from_none], obj.get("repository")) - repository_host = from_union([from_str, from_none], obj.get("repositoryHost")) - return SessionWorkingDirectoryContext(cwd, base_commit, branch, git_root, head_commit, host_type, repository, repository_host) - - def to_dict(self) -> dict: - result: dict = {} - result["cwd"] = from_str(self.cwd) - if self.base_commit is not None: - result["baseCommit"] = from_union([from_str, from_none], self.base_commit) - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.git_root is not None: - result["gitRoot"] = from_union([from_str, from_none], self.git_root) - if self.head_commit is not None: - result["headCommit"] = from_union([from_str, from_none], self.head_commit) - if self.host_type is not None: - result["hostType"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) - if self.repository_host is not None: - result["repositoryHost"] = from_union([from_str, from_none], self.repository_host) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionContext: - """Schema for the `SessionContext` type. - - Optional working-directory context used to score session relevance. When omitted the - most-recently-modified session wins. - """ - cwd: str - """Most recent working directory for this session""" - - branch: str | None = None - """Active git branch""" - - git_root: str | None = None - """Git repository root, if the cwd was inside a git repo""" - - host_type: SessionContextHostType | None = None - """Repository host type""" - - repository: str | None = None - """Repository slug in `owner/name` form, when known""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionContext': - assert isinstance(obj, dict) - cwd = from_str(obj.get("cwd")) - branch = from_union([from_str, from_none], obj.get("branch")) - git_root = from_union([from_str, from_none], obj.get("gitRoot")) - host_type = from_union([SessionContextHostType, from_none], obj.get("hostType")) - repository = from_union([from_str, from_none], obj.get("repository")) - return SessionContext(cwd, branch, git_root, host_type, repository) - - def to_dict(self) -> dict: - result: dict = {} - result["cwd"] = from_str(self.cwd) - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.git_root is not None: - result["gitRoot"] = from_union([from_str, from_none], self.git_root) - if self.host_type is not None: - result["hostType"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) - return result - -@dataclass -class Workspace: - id: UUID - branch: str | None = None - chronicle_sync_dismissed: bool | None = None - created_at: datetime | None = None - cwd: str | None = None - git_root: str | None = None - host_type: SessionContextHostType | None = None - mc_last_event_id: str | None = None - mc_session_id: str | None = None - mc_task_id: str | None = None - name: str | None = None - remote_steerable: bool | None = None - repository: str | None = None - summary_count: int | None = None - updated_at: datetime | None = None - user_named: bool | None = None - - @staticmethod - def from_dict(obj: Any) -> 'Workspace': - assert isinstance(obj, dict) - id = UUID(obj.get("id")) - branch = from_union([from_str, from_none], obj.get("branch")) - chronicle_sync_dismissed = from_union([from_bool, from_none], obj.get("chronicle_sync_dismissed")) - created_at = from_union([from_datetime, from_none], obj.get("created_at")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - git_root = from_union([from_str, from_none], obj.get("git_root")) - host_type = from_union([SessionContextHostType, from_none], obj.get("host_type")) - mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) - mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) - mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) - name = from_union([from_str, from_none], obj.get("name")) - remote_steerable = from_union([from_bool, from_none], obj.get("remote_steerable")) - repository = from_union([from_str, from_none], obj.get("repository")) - summary_count = from_union([from_int, from_none], obj.get("summary_count")) - updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) - user_named = from_union([from_bool, from_none], obj.get("user_named")) - return Workspace(id, branch, chronicle_sync_dismissed, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, remote_steerable, repository, summary_count, updated_at, user_named) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = str(self.id) - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.chronicle_sync_dismissed is not None: - result["chronicle_sync_dismissed"] = from_union([from_bool, from_none], self.chronicle_sync_dismissed) - if self.created_at is not None: - result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.git_root is not None: - result["git_root"] = from_union([from_str, from_none], self.git_root) - if self.host_type is not None: - result["host_type"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) - if self.mc_last_event_id is not None: - result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) - if self.mc_session_id is not None: - result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) - if self.mc_task_id is not None: - result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.remote_steerable is not None: - result["remote_steerable"] = from_union([from_bool, from_none], self.remote_steerable) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) - if self.summary_count is not None: - result["summary_count"] = from_union([from_int, from_none], self.summary_count) - if self.updated_at is not None: - result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) - if self.user_named is not None: - result["user_named"] = from_union([from_bool, from_none], self.user_named) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataSnapshotRemoteMetadata: - """Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are - immutable for the lifetime of the session. - """ - repository: MetadataSnapshotRemoteMetadataRepository - """The repository the remote session targets.""" - - pull_request_number: int | None = None - """The pull request number the remote session is associated with, if any.""" - - resource_id: str | None = None - """The original resource identifier (task ID or PR node ID), preserved across event-replay - reconstructions. Falls back to `sessionId` when absent. - """ - task_type: MetadataSnapshotRemoteMetadataTaskType | None = None - """Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` - invocation. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataSnapshotRemoteMetadata': - assert isinstance(obj, dict) - repository = MetadataSnapshotRemoteMetadataRepository.from_dict(obj.get("repository")) - pull_request_number = from_union([from_int, from_none], obj.get("pullRequestNumber")) - resource_id = from_union([from_str, from_none], obj.get("resourceId")) - task_type = from_union([MetadataSnapshotRemoteMetadataTaskType, from_none], obj.get("taskType")) - return MetadataSnapshotRemoteMetadata(repository, pull_request_number, resource_id, task_type) - - def to_dict(self) -> dict: - result: dict = {} - result["repository"] = to_class(MetadataSnapshotRemoteMetadataRepository, self.repository) - if self.pull_request_number is not None: - result["pullRequestNumber"] = from_union([from_int, from_none], self.pull_request_number) - if self.resource_id is not None: - result["resourceId"] = from_union([from_str, from_none], self.resource_id) - if self.task_type is not None: - result["taskType"] = from_union([lambda x: to_enum(MetadataSnapshotRemoteMetadataTaskType, x), from_none], self.task_type) - return result - -@dataclass -class ModelBilling: - """Billing information""" - - multiplier: float | None = None - """Billing cost multiplier relative to the base rate""" - - token_prices: ModelBillingTokenPrices | None = None - """Token-level pricing information for this model""" - - @staticmethod - def from_dict(obj: Any) -> 'ModelBilling': - assert isinstance(obj, dict) - multiplier = from_union([from_float, from_none], obj.get("multiplier")) - token_prices = from_union([ModelBillingTokenPrices.from_dict, from_none], obj.get("tokenPrices")) - return ModelBilling(multiplier, token_prices) - - def to_dict(self) -> dict: - result: dict = {} - if self.multiplier is not None: - result["multiplier"] = from_union([to_float, from_none], self.multiplier) - if self.token_prices is not None: - result["tokenPrices"] = from_union([lambda x: to_class(ModelBillingTokenPrices, x), from_none], self.token_prices) - return result - -@dataclass -class ModelCapabilitiesLimits: - """Token limits for prompts, outputs, and context window""" - - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" - - max_output_tokens: int | None = None - """Maximum number of output/completion tokens""" - - max_prompt_tokens: int | None = None - """Maximum number of prompt/input tokens""" - - vision: ModelCapabilitiesLimitsVision | None = None - """Vision-specific limits""" - - @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesLimits': - assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([ModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) - - def to_dict(self) -> dict: - result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesLimitsVision, x), from_none], self.vision) - return result - -@dataclass -class ModelPolicy: - """Policy state (if applicable)""" - - state: ModelPolicyState - """Current policy state for this model""" - - terms: str | None = None - """Usage terms or conditions for this model""" - - @staticmethod - def from_dict(obj: Any) -> 'ModelPolicy': - assert isinstance(obj, dict) - state = ModelPolicyState(obj.get("state")) - terms = from_union([from_str, from_none], obj.get("terms")) - return ModelPolicy(state, terms) - - def to_dict(self) -> dict: - result: dict = {} - result["state"] = to_enum(ModelPolicyState, self.state) - if self.terms is not None: - result["terms"] = from_union([from_str, from_none], self.terms) - return result - -@dataclass -class ModelCapabilitiesOverrideLimits: - """Token limits for prompts, outputs, and context window""" - - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" - - max_output_tokens: int | None = None - """Maximum number of output/completion tokens""" - - max_prompt_tokens: int | None = None - """Maximum number of prompt/input tokens""" - - vision: ModelCapabilitiesOverrideLimitsVision | None = None - """Vision-specific limits""" - - @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimits': - assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([ModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesOverrideLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) - - def to_dict(self) -> dict: - result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) - return result - -@dataclass -class PendingPermissionRequestList: - """List of pending permission requests reconstructed from event history.""" - - items: list[PendingPermissionRequest] - """Pending permission prompts reconstructed from the session's event history. Equivalent to - the set of `permission.requested` events that have not yet been followed by a matching - `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts - that were emitted before the client attached to the session. - """ - - @staticmethod - def from_dict(obj: Any) -> 'PendingPermissionRequestList': - assert isinstance(obj, dict) - items = from_list(PendingPermissionRequest.from_dict, obj.get("items")) - return PendingPermissionRequestList(items) - - def to_dict(self) -> dict: - result: dict = {} - result["items"] = from_list(lambda x: to_class(PendingPermissionRequest, x), self.items) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalCommands: - """Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type.""" - - command_identifiers: list[str] - """Command identifiers covered by this approval.""" - - kind: PermissionDecisionApproveForLocationApprovalCommandsKind - """Approval scoped to specific command identifiers.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCommands': - assert isinstance(obj, dict) - command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) - kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalCommands(command_identifiers, kind) - - def to_dict(self) -> dict: - result: dict = {} - result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalCommands: - """Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type.""" - - command_identifiers: list[str] - """Command identifiers covered by this approval.""" - - kind: PermissionDecisionApproveForLocationApprovalCommandsKind - """Approval scoped to specific command identifiers.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCommands': - assert isinstance(obj, dict) - command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) - kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalCommands(command_identifiers, kind) - - def to_dict(self) -> dict: - result: dict = {} - result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) - return result - -@dataclass -class UserToolSessionApprovalCommands: - """Schema for the `UserToolSessionApprovalCommands` type.""" - - command_identifiers: list[str] - """Command identifiers approved by the user""" - - kind: PermissionDecisionApproveForLocationApprovalCommandsKind - """Command approval kind""" - - @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalCommands': - assert isinstance(obj, dict) - command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) - kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) - return UserToolSessionApprovalCommands(command_identifiers, kind) - - def to_dict(self) -> dict: - result: dict = {} - result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalCustomTool: - """Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type.""" - - kind: PermissionDecisionApproveForLocationApprovalCustomToolKind - """Approval covering a custom tool.""" - - tool_name: str - """Custom tool name.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCustomTool': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) - tool_name = from_str(obj.get("toolName")) - return PermissionDecisionApproveForLocationApprovalCustomTool(kind, tool_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) - result["toolName"] = from_str(self.tool_name) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalCustomTool: - """Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type.""" - - kind: PermissionDecisionApproveForLocationApprovalCustomToolKind - """Approval covering a custom tool.""" - - tool_name: str - """Custom tool name.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCustomTool': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) - tool_name = from_str(obj.get("toolName")) - return PermissionDecisionApproveForSessionApprovalCustomTool(kind, tool_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) - result["toolName"] = from_str(self.tool_name) - return result - -@dataclass -class UserToolSessionApprovalCustomTool: - """Schema for the `UserToolSessionApprovalCustomTool` type.""" - - kind: PermissionDecisionApproveForLocationApprovalCustomToolKind - """Custom tool approval kind""" - - tool_name: str - """Custom tool name""" - - @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalCustomTool': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) - tool_name = from_str(obj.get("toolName")) - return UserToolSessionApprovalCustomTool(kind, tool_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) - result["toolName"] = from_str(self.tool_name) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalExtensionManagement: - """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type.""" - - kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind - """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. - """ - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionManagement': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) - operation = from_union([from_str, from_none], obj.get("operation")) - return PermissionDecisionApproveForLocationApprovalExtensionManagement(kind, operation) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalExtensionManagement: - """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type.""" - - kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind - """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. - """ - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionManagement': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) - operation = from_union([from_str, from_none], obj.get("operation")) - return PermissionDecisionApproveForSessionApprovalExtensionManagement(kind, operation) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalMCP: - """Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPKind - """Approval covering an MCP tool.""" - - server_name: str - """MCP server name.""" - - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCP': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - return PermissionDecisionApproveForLocationApprovalMCP(kind, server_name, tool_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) - result["serverName"] = from_str(self.server_name) - result["toolName"] = from_union([from_none, from_str], self.tool_name) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalMCP: - """Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPKind - """Approval covering an MCP tool.""" - - server_name: str - """MCP server name.""" - - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCP': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - return PermissionDecisionApproveForSessionApprovalMCP(kind, server_name, tool_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) - result["serverName"] = from_str(self.server_name) - result["toolName"] = from_union([from_none, from_str], self.tool_name) - return result - -@dataclass -class UserToolSessionApprovalMCP: - """Schema for the `UserToolSessionApprovalMcp` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPKind - """MCP tool approval kind""" - - server_name: str - """MCP server name""" - - tool_name: str | None = None - """Optional MCP tool name, or null for all tools on the server""" - - @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalMCP': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - return UserToolSessionApprovalMCP(kind, server_name, tool_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) - result["serverName"] = from_str(self.server_name) - result["toolName"] = from_union([from_none, from_str], self.tool_name) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalMCPSampling: - """Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind - """Approval covering MCP sampling requests for a server.""" - - server_name: str - """MCP server name.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCPSampling': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - return PermissionDecisionApproveForLocationApprovalMCPSampling(kind, server_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) - result["serverName"] = from_str(self.server_name) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalMCPSampling: - """Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind - """Approval covering MCP sampling requests for a server.""" - - server_name: str - """MCP server name.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCPSampling': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - return PermissionDecisionApproveForSessionApprovalMCPSampling(kind, server_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) - result["serverName"] = from_str(self.server_name) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalMemory: - """Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMemoryKind - """Approval covering writes to long-term memory.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMemory': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalMemory(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalMemory: - """Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMemoryKind - """Approval covering writes to long-term memory.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMemory': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalMemory(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) - return result - -@dataclass -class UserToolSessionApprovalMemory: - """Schema for the `UserToolSessionApprovalMemory` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMemoryKind - """Memory approval kind""" - - @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalMemory': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) - return UserToolSessionApprovalMemory(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalRead: - """Schema for the `PermissionDecisionApproveForLocationApprovalRead` type.""" - - kind: PermissionDecisionApproveForLocationApprovalReadKind - """Approval covering read-only filesystem operations.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalRead': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalRead(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalRead: - """Schema for the `PermissionDecisionApproveForSessionApprovalRead` type.""" - - kind: PermissionDecisionApproveForLocationApprovalReadKind - """Approval covering read-only filesystem operations.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalRead': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalRead(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) - return result - -@dataclass -class UserToolSessionApprovalRead: - """Schema for the `UserToolSessionApprovalRead` type.""" - - kind: PermissionDecisionApproveForLocationApprovalReadKind - """Read approval kind""" - - @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalRead': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) - return UserToolSessionApprovalRead(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForLocationApprovalWrite: - """Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type.""" - - kind: PermissionDecisionApproveForLocationApprovalWriteKind - """Approval covering filesystem write operations.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalWrite': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalWrite(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveForSessionApprovalWrite: - """Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type.""" - - kind: PermissionDecisionApproveForLocationApprovalWriteKind - """Approval covering filesystem write operations.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalWrite': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalWrite(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) - return result - -@dataclass -class UserToolSessionApprovalWrite: - """Schema for the `UserToolSessionApprovalWrite` type.""" - - kind: PermissionDecisionApproveForLocationApprovalWriteKind - """Write approval kind""" - - @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalWrite': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) - return UserToolSessionApprovalWrite(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproveOnce: - """Schema for the `PermissionDecisionApproveOnce` type.""" - - kind: PermissionDecisionApproveOnceKind - """Approve this single request only""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveOnce': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveOnceKind(obj.get("kind")) - return PermissionDecisionApproveOnce(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveOnceKind, self.kind) - return result - -@dataclass -class PermissionDecisionApprovePermanently: - """Schema for the `PermissionDecisionApprovePermanently` type.""" - - domain: str - """URL domain to approve permanently""" - - kind: PermissionDecisionApprovePermanentlyKind - """Approve and persist across sessions (URL prompts only)""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApprovePermanently': - assert isinstance(obj, dict) - domain = from_str(obj.get("domain")) - kind = PermissionDecisionApprovePermanentlyKind(obj.get("kind")) - return PermissionDecisionApprovePermanently(domain, kind) - - def to_dict(self) -> dict: - result: dict = {} - result["domain"] = from_str(self.domain) - result["kind"] = to_enum(PermissionDecisionApprovePermanentlyKind, self.kind) - return result - -@dataclass -class PermissionDecisionApproved: - """Schema for the `PermissionDecisionApproved` type.""" - - kind: PermissionDecisionApprovedKind - """The permission request was approved""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproved': - assert isinstance(obj, dict) - kind = PermissionDecisionApprovedKind(obj.get("kind")) - return PermissionDecisionApproved(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApprovedKind, self.kind) - return result - -@dataclass -class PermissionDecisionApprovedForLocation: - """Schema for the `PermissionDecisionApprovedForLocation` type.""" - - approval: UserToolSessionApproval - """The approval to persist for this location""" - - kind: PermissionDecisionApprovedForLocationKind - """Approved and persisted for this project location""" - - location_key: str - """The location key (git root or cwd) to persist the approval to""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApprovedForLocation': - assert isinstance(obj, dict) - approval = UserToolSessionApproval.from_dict(obj.get("approval")) - kind = PermissionDecisionApprovedForLocationKind(obj.get("kind")) - location_key = from_str(obj.get("locationKey")) - return PermissionDecisionApprovedForLocation(approval, kind, location_key) - - def to_dict(self) -> dict: - result: dict = {} - result["approval"] = to_class(UserToolSessionApproval, self.approval) - result["kind"] = to_enum(PermissionDecisionApprovedForLocationKind, self.kind) - result["locationKey"] = from_str(self.location_key) - return result - -@dataclass -class PermissionDecisionApprovedForSession: - """Schema for the `PermissionDecisionApprovedForSession` type.""" - - approval: UserToolSessionApproval - """The approval to add as a session-scoped rule""" - - kind: PermissionDecisionApprovedForSessionKind - """Approved and remembered for the rest of the session""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApprovedForSession': - assert isinstance(obj, dict) - approval = UserToolSessionApproval.from_dict(obj.get("approval")) - kind = PermissionDecisionApprovedForSessionKind(obj.get("kind")) - return PermissionDecisionApprovedForSession(approval, kind) - - def to_dict(self) -> dict: - result: dict = {} - result["approval"] = to_class(UserToolSessionApproval, self.approval) - result["kind"] = to_enum(PermissionDecisionApprovedForSessionKind, self.kind) - return result - -@dataclass -class PermissionDecisionCancelled: - """Schema for the `PermissionDecisionCancelled` type.""" - - kind: PermissionDecisionCancelledKind - """The permission request was cancelled before a response was used""" - - reason: str | None = None - """Optional explanation of why the request was cancelled""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionCancelled': - assert isinstance(obj, dict) - kind = PermissionDecisionCancelledKind(obj.get("kind")) - reason = from_union([from_str, from_none], obj.get("reason")) - return PermissionDecisionCancelled(kind, reason) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionCancelledKind, self.kind) - if self.reason is not None: - result["reason"] = from_union([from_str, from_none], self.reason) - return result - -@dataclass -class PermissionDecisionDeniedByContentExclusionPolicy: - """Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type.""" - - kind: PermissionDecisionDeniedByContentExclusionPolicyKind - """Denied by the organization's content exclusion policy""" - - message: str - """Human-readable explanation of why the path was excluded""" - - path: str - """File path that triggered the exclusion""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionDeniedByContentExclusionPolicy': - assert isinstance(obj, dict) - kind = PermissionDecisionDeniedByContentExclusionPolicyKind(obj.get("kind")) - message = from_str(obj.get("message")) - path = from_str(obj.get("path")) - return PermissionDecisionDeniedByContentExclusionPolicy(kind, message, path) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionDeniedByContentExclusionPolicyKind, self.kind) - result["message"] = from_str(self.message) - result["path"] = from_str(self.path) - return result - -@dataclass -class PermissionDecisionDeniedByPermissionRequestHook: - """Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type.""" - - kind: PermissionDecisionDeniedByPermissionRequestHookKind - """Denied by a permission request hook registered by an extension or plugin""" - - interrupt: bool | None = None - """Whether to interrupt the current agent turn""" - - message: str | None = None - """Optional message from the hook explaining the denial""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionDeniedByPermissionRequestHook': - assert isinstance(obj, dict) - kind = PermissionDecisionDeniedByPermissionRequestHookKind(obj.get("kind")) - interrupt = from_union([from_bool, from_none], obj.get("interrupt")) - message = from_union([from_str, from_none], obj.get("message")) - return PermissionDecisionDeniedByPermissionRequestHook(kind, interrupt, message) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionDeniedByPermissionRequestHookKind, self.kind) - if self.interrupt is not None: - result["interrupt"] = from_union([from_bool, from_none], self.interrupt) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) - return result - -@dataclass -class PermissionDecisionDeniedByRules: - """Schema for the `PermissionDecisionDeniedByRules` type.""" - - kind: PermissionDecisionDeniedByRulesKind - """Denied because approval rules explicitly blocked it""" - - rules: list[PermissionRule] - """Rules that denied the request""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionDeniedByRules': - assert isinstance(obj, dict) - kind = PermissionDecisionDeniedByRulesKind(obj.get("kind")) - rules = from_list(PermissionRule.from_dict, obj.get("rules")) - return PermissionDecisionDeniedByRules(kind, rules) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionDeniedByRulesKind, self.kind) - result["rules"] = from_list(lambda x: to_class(PermissionRule, x), self.rules) - return result - -@dataclass -class PermissionDecisionDeniedInteractivelyByUser: - """Schema for the `PermissionDecisionDeniedInteractivelyByUser` type.""" - - kind: PermissionDecisionDeniedInteractivelyByUserKind - """Denied by the user during an interactive prompt""" - - feedback: str | None = None - """Optional feedback from the user explaining the denial""" - - force_reject: bool | None = None - """Whether to force-reject the current agent turn""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionDeniedInteractivelyByUser': - assert isinstance(obj, dict) - kind = PermissionDecisionDeniedInteractivelyByUserKind(obj.get("kind")) - feedback = from_union([from_str, from_none], obj.get("feedback")) - force_reject = from_union([from_bool, from_none], obj.get("forceReject")) - return PermissionDecisionDeniedInteractivelyByUser(kind, feedback, force_reject) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionDeniedInteractivelyByUserKind, self.kind) - if self.feedback is not None: - result["feedback"] = from_union([from_str, from_none], self.feedback) - if self.force_reject is not None: - result["forceReject"] = from_union([from_bool, from_none], self.force_reject) - return result - -@dataclass -class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser: - """Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type.""" - - kind: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind - """Denied because no approval rule matched and user confirmation was unavailable""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser': - assert isinstance(obj, dict) - kind = PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind(obj.get("kind")) - return PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser(kind) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind, self.kind) - return result - -@dataclass -class PermissionDecisionReject: - """Schema for the `PermissionDecisionReject` type.""" + auth: MCPServerConfigHTTPAuth | None = None + """Additional authentication configuration for this server.""" - kind: PermissionDecisionRejectKind - """Reject the request""" + headers: dict[str, str] | None = None + """HTTP headers to include in requests to the remote MCP server.""" - feedback: str | None = None - """Optional feedback explaining the rejection""" + oauth_client_id: str | None = None + """OAuth client ID for a pre-registered remote MCP OAuth client.""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionReject': - assert isinstance(obj, dict) - kind = PermissionDecisionRejectKind(obj.get("kind")) - feedback = from_union([from_str, from_none], obj.get("feedback")) - return PermissionDecisionReject(kind, feedback) + oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None + """OAuth grant type to use when authenticating to the remote MCP server.""" - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionRejectKind, self.kind) - if self.feedback is not None: - result["feedback"] = from_union([from_str, from_none], self.feedback) - return result + oauth_public_client: bool | None = None + """Whether the configured OAuth client is public and does not require a client secret.""" -@dataclass -class PermissionDecisionUserNotAvailable: - """Schema for the `PermissionDecisionUserNotAvailable` type.""" + type: MCPServerConfigHTTPType | None = None + """Remote transport type. Defaults to "http" when omitted.""" - kind: PermissionDecisionUserNotAvailableKind - """No user is available to confirm the request""" + url: str | None = None + """URL of the remote MCP server endpoint.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionUserNotAvailable': + def from_dict(obj: Any) -> 'MCPServerConfig': assert isinstance(obj, dict) - kind = PermissionDecisionUserNotAvailableKind(obj.get("kind")) - return PermissionDecisionUserNotAvailable(kind) + args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) + command = from_union([from_str, from_none], obj.get("command")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) + filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) + headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) + oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) + oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) + oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) + type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) + url = from_union([from_str, from_none], obj.get("url")) + return MCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, auth, headers, oauth_client_id, oauth_grant_type, oauth_public_client, type, url) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionUserNotAvailableKind, self.kind) + if self.args is not None: + result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) + if self.command is not None: + result["command"] = from_union([from_str, from_none], self.command) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.env is not None: + result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.auth is not None: + result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) + if self.headers is not None: + result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) + if self.oauth_client_id is not None: + result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) + if self.oauth_grant_type is not None: + result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) + if self.oauth_public_client is not None: + result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) return result @dataclass -class PermissionsConfigureAdditionalContentExclusionPolicyRule: - """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRule` type.""" - - paths: list[str] - source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource - """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.""" - - if_any_match: list[str] | None = None - if_none_match: list[str] | None = None - - @staticmethod - def from_dict(obj: Any) -> 'PermissionsConfigureAdditionalContentExclusionPolicyRule': - assert isinstance(obj, dict) - paths = from_list(from_str, obj.get("paths")) - source = PermissionsConfigureAdditionalContentExclusionPolicyRuleSource.from_dict(obj.get("source")) - if_any_match = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ifAnyMatch")) - if_none_match = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ifNoneMatch")) - return PermissionsConfigureAdditionalContentExclusionPolicyRule(paths, source, if_any_match, if_none_match) +class MCPServerConfigHTTP: + """Remote MCP server configuration accessed over HTTP or SSE.""" - def to_dict(self) -> dict: - result: dict = {} - result["paths"] = from_list(from_str, self.paths) - result["source"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicyRuleSource, self.source) - if self.if_any_match is not None: - result["ifAnyMatch"] = from_union([lambda x: from_list(from_str, x), from_none], self.if_any_match) - if self.if_none_match is not None: - result["ifNoneMatch"] = from_union([lambda x: from_list(from_str, x), from_none], self.if_none_match) - return result + url: str + """URL of the remote MCP server endpoint.""" -@dataclass -class PermissionsModifyRulesParams: - """Scope and add/remove instructions for modifying session- or location-scoped permission - rules. - """ - scope: PermissionsModifyRulesScope - """Whether the change applies to ephemeral session-scoped rules (cleared at session end) or - to location-scoped rules persisted via the location-permissions config file. - """ - add: list[PermissionRule] | None = None - """Rules to add to the scope. Applied before `remove`/`removeAll`.""" + auth: MCPServerConfigHTTPAuth | None = None + """Additional authentication configuration for this server.""" - remove: list[PermissionRule] | None = None - """Specific rules to remove from the scope. Ignored when `removeAll` is true.""" + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None + """Content filtering mode to apply to all tools, or a map of tool name to content filtering + mode. + """ + headers: dict[str, str] | None = None + """HTTP headers to include in requests to the remote MCP server.""" - remove_all: bool | None = None - """When true, removes every rule currently in the scope (after any `add` is applied). Useful - for clearing the location scope wholesale. + is_default_server: bool | None = None + """Whether this server is a built-in fallback used when the user has not configured their + own server. """ + oauth_client_id: str | None = None + """OAuth client ID for a pre-registered remote MCP OAuth client.""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionsModifyRulesParams': - assert isinstance(obj, dict) - scope = PermissionsModifyRulesScope(obj.get("scope")) - add = from_union([lambda x: from_list(PermissionRule.from_dict, x), from_none], obj.get("add")) - remove = from_union([lambda x: from_list(PermissionRule.from_dict, x), from_none], obj.get("remove")) - remove_all = from_union([from_bool, from_none], obj.get("removeAll")) - return PermissionsModifyRulesParams(scope, add, remove, remove_all) + oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None + """OAuth grant type to use when authenticating to the remote MCP server.""" - def to_dict(self) -> dict: - result: dict = {} - result["scope"] = to_enum(PermissionsModifyRulesScope, self.scope) - if self.add is not None: - result["add"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRule, x), x), from_none], self.add) - if self.remove is not None: - result["remove"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRule, x), x), from_none], self.remove) - if self.remove_all is not None: - result["removeAll"] = from_union([from_bool, from_none], self.remove_all) - return result + oauth_public_client: bool | None = None + """Whether the configured OAuth client is public and does not require a client secret.""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class PluginList: - """Plugins installed for the session, with their enabled state and version metadata.""" + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" - plugins: list[Plugin] - """Installed plugins""" + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" + + type: MCPServerConfigHTTPType | None = None + """Remote transport type. Defaults to "http" when omitted.""" @staticmethod - def from_dict(obj: Any) -> 'PluginList': + def from_dict(obj: Any) -> 'MCPServerConfigHTTP': assert isinstance(obj, dict) - plugins = from_list(Plugin.from_dict, obj.get("plugins")) - return PluginList(plugins) + url = from_str(obj.get("url")) + auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) + filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) + headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) + oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) + oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) + return MCPServerConfigHTTP(url, auth, filter_mapping, headers, is_default_server, oauth_client_id, oauth_grant_type, oauth_public_client, timeout, tools, type) def to_dict(self) -> dict: result: dict = {} - result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins) + result["url"] = from_str(self.url) + if self.auth is not None: + result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) + if self.headers is not None: + result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.oauth_client_id is not None: + result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) + if self.oauth_grant_type is not None: + result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) + if self.oauth_public_client is not None: + result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class QueuePendingItems: - """Schema for the `QueuePendingItems` type.""" - - display_text: str - """Human-readable text to display for this queue entry in the UI""" +class MCPServerList: + """MCP servers configured for the session, with their connection status.""" - kind: QueuePendingItemsKind - """Whether this item is a queued user message or a queued slash command / model change""" + servers: list[MCPServer] + """Configured MCP servers""" @staticmethod - def from_dict(obj: Any) -> 'QueuePendingItems': + def from_dict(obj: Any) -> 'MCPServerList': assert isinstance(obj, dict) - display_text = from_str(obj.get("displayText")) - kind = QueuePendingItemsKind(obj.get("kind")) - return QueuePendingItems(display_text, kind) + servers = from_list(MCPServer.from_dict, obj.get("servers")) + return MCPServerList(servers) def to_dict(self) -> dict: result: dict = {} - result["displayText"] = from_str(self.display_text) - result["kind"] = to_enum(QueuePendingItemsKind, self.kind) + result["servers"] = from_list(lambda x: to_class(MCPServer, x), self.servers) return result @dataclass -class QueuedCommandResult: - """Result of the queued command execution. - - Schema for the `QueuedCommandHandled` type. - - Schema for the `QueuedCommandNotHandled` type. - """ - handled: bool - """The host actually executed the queued command. - - The host did not execute the queued command. Unblocks the queue without claiming the - command was processed (e.g. when the handler threw before completing). - """ - stop_processing_queue: bool | None = None - """When true, the runtime will not process subsequent queued commands until a new request - comes in. - """ - - @staticmethod - def from_dict(obj: Any) -> 'QueuedCommandResult': - assert isinstance(obj, dict) - handled = from_bool(obj.get("handled")) - stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) - return QueuedCommandResult(handled, stop_processing_queue) +class ModelBilling: + """Billing information""" - def to_dict(self) -> dict: - result: dict = {} - result["handled"] = from_bool(self.handled) - if self.stop_processing_queue is not None: - result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) - return result + multiplier: float | None = None + """Billing cost multiplier relative to the base rate""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class RemoteEnableRequest: - """Optional remote session mode ("off", "export", or "on"); defaults to enabling both export - and remote steering. - """ - mode: RemoteSessionMode | None = None - """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub - without enabling remote steering, "on" enables both export and remote steering. - """ + token_prices: ModelBillingTokenPrices | None = None + """Token-level pricing information for this model""" @staticmethod - def from_dict(obj: Any) -> 'RemoteEnableRequest': + def from_dict(obj: Any) -> 'ModelBilling': assert isinstance(obj, dict) - mode = from_union([RemoteSessionMode, from_none], obj.get("mode")) - return RemoteEnableRequest(mode) + multiplier = from_union([from_float, from_none], obj.get("multiplier")) + token_prices = from_union([ModelBillingTokenPrices.from_dict, from_none], obj.get("tokenPrices")) + return ModelBilling(multiplier, token_prices) def to_dict(self) -> dict: result: dict = {} - if self.mode is not None: - result["mode"] = from_union([lambda x: to_enum(RemoteSessionMode, x), from_none], self.mode) + if self.multiplier is not None: + result["multiplier"] = from_union([to_float, from_none], self.multiplier) + if self.token_prices is not None: + result["tokenPrices"] = from_union([lambda x: to_class(ModelBillingTokenPrices, x), from_none], self.token_prices) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ScheduleList: - """Snapshot of the currently active recurring prompts for this session.""" - - entries: list[ScheduleEntry] - """Active scheduled prompts, ordered by id.""" +class ModelCapabilitiesLimits: + """Token limits for prompts, outputs, and context window""" - @staticmethod - def from_dict(obj: Any) -> 'ScheduleList': - assert isinstance(obj, dict) - entries = from_list(ScheduleEntry.from_dict, obj.get("entries")) - return ScheduleList(entries) + max_context_window_tokens: int | None = None + """Maximum total context window size in tokens""" - def to_dict(self) -> dict: - result: dict = {} - result["entries"] = from_list(lambda x: to_class(ScheduleEntry, x), self.entries) - return result + max_output_tokens: int | None = None + """Maximum number of output/completion tokens""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class ScheduleStopResult: - """Remove a scheduled prompt by id. The result entry is omitted if the id was unknown.""" + max_prompt_tokens: int | None = None + """Maximum number of prompt/input tokens""" - entry: ScheduleEntry | None = None - """The removed entry, or omitted if no entry matched.""" + vision: ModelCapabilitiesLimitsVision | None = None + """Vision-specific limits""" @staticmethod - def from_dict(obj: Any) -> 'ScheduleStopResult': + def from_dict(obj: Any) -> 'ModelCapabilitiesLimits': assert isinstance(obj, dict) - entry = from_union([ScheduleEntry.from_dict, from_none], obj.get("entry")) - return ScheduleStopResult(entry) + max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) + max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) + max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) + vision = from_union([ModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) + return ModelCapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) def to_dict(self) -> dict: result: dict = {} - if self.entry is not None: - result["entry"] = from_union([lambda x: to_class(ScheduleEntry, x), from_none], self.entry) + if self.max_context_window_tokens is not None: + result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) + if self.max_output_tokens is not None: + result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) + if self.max_prompt_tokens is not None: + result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) + if self.vision is not None: + result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesLimitsVision, x), from_none], self.vision) return result @dataclass -class SendAttachmentSelectionDetails: - """Position range of the selection within the file""" +class ModelPolicy: + """Policy state (if applicable)""" - end: SendAttachmentSelectionDetailsEnd - """End position of the selection""" + state: ModelPolicyState + """Current policy state for this model""" - start: SendAttachmentSelectionDetailsStart - """Start position of the selection""" + terms: str | None = None + """Usage terms or conditions for this model""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentSelectionDetails': + def from_dict(obj: Any) -> 'ModelPolicy': assert isinstance(obj, dict) - end = SendAttachmentSelectionDetailsEnd.from_dict(obj.get("end")) - start = SendAttachmentSelectionDetailsStart.from_dict(obj.get("start")) - return SendAttachmentSelectionDetails(end, start) + state = ModelPolicyState(obj.get("state")) + terms = from_union([from_str, from_none], obj.get("terms")) + return ModelPolicy(state, terms) def to_dict(self) -> dict: result: dict = {} - result["end"] = to_class(SendAttachmentSelectionDetailsEnd, self.end) - result["start"] = to_class(SendAttachmentSelectionDetailsStart, self.start) + result["state"] = to_enum(ModelPolicyState, self.state) + if self.terms is not None: + result["terms"] = from_union([from_str, from_none], self.terms) return result @dataclass -class SendAttachmentBlob: - """Blob attachment with inline base64-encoded data""" +class ModelCapabilitiesOverrideLimits: + """Token limits for prompts, outputs, and context window""" - data: str - """Base64-encoded content""" + max_context_window_tokens: int | None = None + """Maximum total context window size in tokens""" - mime_type: str - """MIME type of the inline data""" + max_output_tokens: int | None = None + """Maximum number of output/completion tokens""" - type: SendAttachmentBlobType - """Attachment type discriminator""" + max_prompt_tokens: int | None = None + """Maximum number of prompt/input tokens""" - display_name: str | None = None - """User-facing display name for the attachment""" + vision: ModelCapabilitiesOverrideLimitsVision | None = None + """Vision-specific limits""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentBlob': + def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimits': assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = SendAttachmentBlobType(obj.get("type")) - display_name = from_union([from_str, from_none], obj.get("displayName")) - return SendAttachmentBlob(data, mime_type, type, display_name) + max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) + max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) + max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) + vision = from_union([ModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) + return ModelCapabilitiesOverrideLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) def to_dict(self) -> dict: result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(SendAttachmentBlobType, self.type) - if self.display_name is not None: - result["displayName"] = from_union([from_str, from_none], self.display_name) + if self.max_context_window_tokens is not None: + result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) + if self.max_output_tokens is not None: + result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) + if self.max_prompt_tokens is not None: + result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) + if self.vision is not None: + result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) return result @dataclass -class SendAttachmentFile: - """File attachment""" - - display_name: str - """User-facing display name for the attachment""" - - path: str - """Absolute file path""" +class PermissionDecisionApproveForLocationApprovalCommands: + """Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type.""" - type: SendAttachmentFileType - """Attachment type discriminator""" + command_identifiers: list[str] + """Command identifiers covered by this approval.""" - line_range: SendAttachmentFileLineRange | None = None - """Optional line range to scope the attachment to a specific section of the file""" + kind: PermissionDecisionApproveForLocationApprovalCommandsKind + """Approval scoped to specific command identifiers.""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentFile': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCommands': assert isinstance(obj, dict) - display_name = from_str(obj.get("displayName")) - path = from_str(obj.get("path")) - type = SendAttachmentFileType(obj.get("type")) - line_range = from_union([SendAttachmentFileLineRange.from_dict, from_none], obj.get("lineRange")) - return SendAttachmentFile(display_name, path, type, line_range) + command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) + kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalCommands(command_identifiers, kind) def to_dict(self) -> dict: result: dict = {} - result["displayName"] = from_str(self.display_name) - result["path"] = from_str(self.path) - result["type"] = to_enum(SendAttachmentFileType, self.type) - if self.line_range is not None: - result["lineRange"] = from_union([lambda x: to_class(SendAttachmentFileLineRange, x), from_none], self.line_range) + result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) return result @dataclass -class SendAttachmentGithubReference: - """GitHub issue, pull request, or discussion reference""" - - number: int - """Issue, pull request, or discussion number""" - - reference_type: SendAttachmentGithubReferenceTypeEnum - """Type of GitHub reference""" - - state: str - """Current state of the referenced item (e.g., open, closed, merged)""" - - title: str - """Title of the referenced item""" +class PermissionDecisionApproveForSessionApprovalCommands: + """Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type.""" - type: SendAttachmentGithubReferenceType - """Attachment type discriminator""" + command_identifiers: list[str] + """Command identifiers covered by this approval.""" - url: str - """URL to the referenced item on GitHub""" + kind: PermissionDecisionApproveForLocationApprovalCommandsKind + """Approval scoped to specific command identifiers.""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentGithubReference': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCommands': assert isinstance(obj, dict) - number = from_int(obj.get("number")) - reference_type = SendAttachmentGithubReferenceTypeEnum(obj.get("referenceType")) - state = from_str(obj.get("state")) - title = from_str(obj.get("title")) - type = SendAttachmentGithubReferenceType(obj.get("type")) - url = from_str(obj.get("url")) - return SendAttachmentGithubReference(number, reference_type, state, title, type, url) + command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) + kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalCommands(command_identifiers, kind) def to_dict(self) -> dict: result: dict = {} - result["number"] = from_int(self.number) - result["referenceType"] = to_enum(SendAttachmentGithubReferenceTypeEnum, self.reference_type) - result["state"] = from_str(self.state) - result["title"] = from_str(self.title) - result["type"] = to_enum(SendAttachmentGithubReferenceType, self.type) - result["url"] = from_str(self.url) + result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) return result @dataclass -class ServerSkillList: - """Skills discovered across global and project sources.""" +class PermissionDecisionApproveForLocationApprovalCustomTool: + """Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type.""" - skills: list[ServerSkill] - """All discovered skills across all sources""" + kind: PermissionDecisionApproveForLocationApprovalCustomToolKind + """Approval covering a custom tool.""" + + tool_name: str + """Custom tool name.""" @staticmethod - def from_dict(obj: Any) -> 'ServerSkillList': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCustomTool': assert isinstance(obj, dict) - skills = from_list(ServerSkill.from_dict, obj.get("skills")) - return ServerSkillList(skills) + kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) + tool_name = from_str(obj.get("toolName")) + return PermissionDecisionApproveForLocationApprovalCustomTool(kind, tool_name) def to_dict(self) -> dict: result: dict = {} - result["skills"] = from_list(lambda x: to_class(ServerSkill, x), self.skills) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) + result["toolName"] = from_str(self.tool_name) return result @dataclass -class SessionFSError: - """Describes a filesystem error.""" +class PermissionDecisionApproveForSessionApprovalCustomTool: + """Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type.""" - code: SessionFSErrorCode - """Error classification""" + kind: PermissionDecisionApproveForLocationApprovalCustomToolKind + """Approval covering a custom tool.""" - message: str | None = None - """Free-form detail about the error, for logging/diagnostics""" + tool_name: str + """Custom tool name.""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSError': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCustomTool': assert isinstance(obj, dict) - code = SessionFSErrorCode(obj.get("code")) - message = from_union([from_str, from_none], obj.get("message")) - return SessionFSError(code, message) + kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) + tool_name = from_str(obj.get("toolName")) + return PermissionDecisionApproveForSessionApprovalCustomTool(kind, tool_name) def to_dict(self) -> dict: result: dict = {} - result["code"] = to_enum(SessionFSErrorCode, self.code) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) + result["toolName"] = from_str(self.tool_name) return result @dataclass -class SessionFSReaddirWithTypesEntry: - """Schema for the `SessionFsReaddirWithTypesEntry` type.""" +class PermissionDecisionApproveForLocationApprovalExtensionManagement: + """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type.""" - name: str - """Entry name""" + kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind + """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - type: SessionFSReaddirWithTypesEntryType - """Entry type""" + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesEntry': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionManagement': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - type = SessionFSReaddirWithTypesEntryType(obj.get("type")) - return SessionFSReaddirWithTypesEntry(name, type) + kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) + operation = from_union([from_str, from_none], obj.get("operation")) + return PermissionDecisionApproveForLocationApprovalExtensionManagement(kind, operation) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["type"] = to_enum(SessionFSReaddirWithTypesEntryType, self.type) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) return result @dataclass -class SessionFSSetProviderRequest: - """Initial working directory, session-state path layout, and path conventions used to - register the calling SDK client as the session filesystem provider. - """ - conventions: SessionFSSetProviderConventions - """Path conventions used by this filesystem""" - - initial_cwd: str - """Initial working directory for sessions""" +class PermissionDecisionApproveForSessionApprovalExtensionManagement: + """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type.""" - session_state_path: str - """Path within each session's SessionFs where the runtime stores files for that session""" + kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind + """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - capabilities: SessionFSSetProviderCapabilities | None = None - """Optional capabilities declared by the provider""" + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderRequest': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionManagement': assert isinstance(obj, dict) - conventions = SessionFSSetProviderConventions(obj.get("conventions")) - initial_cwd = from_str(obj.get("initialCwd")) - session_state_path = from_str(obj.get("sessionStatePath")) - capabilities = from_union([SessionFSSetProviderCapabilities.from_dict, from_none], obj.get("capabilities")) - return SessionFSSetProviderRequest(conventions, initial_cwd, session_state_path, capabilities) + kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) + operation = from_union([from_str, from_none], obj.get("operation")) + return PermissionDecisionApproveForSessionApprovalExtensionManagement(kind, operation) def to_dict(self) -> dict: result: dict = {} - result["conventions"] = to_enum(SessionFSSetProviderConventions, self.conventions) - result["initialCwd"] = from_str(self.initial_cwd) - result["sessionStatePath"] = from_str(self.session_state_path) - if self.capabilities is not None: - result["capabilities"] = from_union([lambda x: to_class(SessionFSSetProviderCapabilities, x), from_none], self.capabilities) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) return result @dataclass -class SessionFSSqliteQueryRequest: - """SQL query, query type, and optional bind parameters for executing a SQLite query against - the per-session database. - """ - query: str - """SQL query to execute""" +class PermissionDecisionApproveForLocationApprovalMCP: + """Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.""" - query_type: SessionFSSqliteQueryType - """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT - (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) - """ - session_id: str - """Target session identifier""" + kind: PermissionDecisionApproveForLocationApprovalMCPKind + """Approval covering an MCP tool.""" - params: dict[str, float | str | None] | None = None - """Optional named bind parameters""" + server_name: str + """MCP server name.""" + + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server.""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteQueryRequest': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCP': assert isinstance(obj, dict) - query = from_str(obj.get("query")) - query_type = SessionFSSqliteQueryType(obj.get("queryType")) - session_id = from_str(obj.get("sessionId")) - params = from_union([lambda x: from_dict(lambda x: from_union([from_none, from_float, from_str], x), x), from_none], obj.get("params")) - return SessionFSSqliteQueryRequest(query, query_type, session_id, params) + kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + return PermissionDecisionApproveForLocationApprovalMCP(kind, server_name, tool_name) def to_dict(self) -> dict: result: dict = {} - result["query"] = from_str(self.query) - result["queryType"] = to_enum(SessionFSSqliteQueryType, self.query_type) - result["sessionId"] = from_str(self.session_id) - if self.params is not None: - result["params"] = from_union([lambda x: from_dict(lambda x: from_union([from_none, to_float, from_str], x), x), from_none], self.params) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) + result["serverName"] = from_str(self.server_name) + result["toolName"] = from_union([from_none, from_str], self.tool_name) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsListRequest: - """Optional metadata-load limit and context filter applied to the returned sessions.""" +class PermissionDecisionApproveForSessionApprovalMCP: + """Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.""" - filter: Filter | None = None - """Optional filter applied to the returned sessions""" + kind: PermissionDecisionApproveForLocationApprovalMCPKind + """Approval covering an MCP tool.""" - metadata_limit: int | None = None - """When provided, only the first N sessions (sorted by modification time, newest first) load - full metadata; remaining sessions return basic info only. Use 0 to return only basic info - for every session. - """ + server_name: str + """MCP server name.""" + + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server.""" @staticmethod - def from_dict(obj: Any) -> 'SessionsListRequest': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCP': assert isinstance(obj, dict) - filter = from_union([Filter.from_dict, from_none], obj.get("filter")) - metadata_limit = from_union([from_int, from_none], obj.get("metadataLimit")) - return SessionsListRequest(filter, metadata_limit) + kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + return PermissionDecisionApproveForSessionApprovalMCP(kind, server_name, tool_name) def to_dict(self) -> dict: result: dict = {} - if self.filter is not None: - result["filter"] = from_union([lambda x: to_class(Filter, x), from_none], self.filter) - if self.metadata_limit is not None: - result["metadataLimit"] = from_union([from_int, from_none], self.metadata_limit) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) + result["serverName"] = from_str(self.server_name) + result["toolName"] = from_union([from_none, from_str], self.tool_name) return result @dataclass -class ShellKillRequest: - """Identifier of a process previously returned by "shell.exec" and the signal to send.""" +class PermissionDecisionApproveForLocationApprovalMCPSampling: + """Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.""" - process_id: str - """Process identifier returned by shell.exec""" + kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind + """Approval covering MCP sampling requests for a server.""" - signal: ShellKillSignal | None = None - """Signal to send (default: SIGTERM)""" + server_name: str + """MCP server name.""" @staticmethod - def from_dict(obj: Any) -> 'ShellKillRequest': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCPSampling': assert isinstance(obj, dict) - process_id = from_str(obj.get("processId")) - signal = from_union([ShellKillSignal, from_none], obj.get("signal")) - return ShellKillRequest(process_id, signal) + kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + return PermissionDecisionApproveForLocationApprovalMCPSampling(kind, server_name) def to_dict(self) -> dict: result: dict = {} - result["processId"] = from_str(self.process_id) - if self.signal is not None: - result["signal"] = from_union([lambda x: to_enum(ShellKillSignal, x), from_none], self.signal) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) + result["serverName"] = from_str(self.server_name) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentInfo: - """Schema for the `AgentInfo` type. - - The newly selected custom agent - """ - description: str - """Description of the agent's purpose""" - - display_name: str - """Human-readable display name""" - - id: str - """Stable identifier for selection. For most agents this is the same as `name`; for - plugin/builtin agents it may differ. Always populated; defaults to `name` when no - distinct id was assigned. - """ - name: str - """Unique identifier of the custom agent""" - - mcp_servers: dict[str, Any] | None = None - """MCP server configurations attached to this agent, keyed by server name. Server config - shape mirrors the MCP `mcpServers` schema. - """ - model: str | None = None - """Preferred model id for this agent. When omitted, inherits the outer agent's model.""" - - path: str | None = None - """Absolute local file path of the agent definition. Only set for file-based agents loaded - from disk; remote agents do not have a path. - """ - skills: list[str] | None = None - """Skill names preloaded into this agent's context. Omitted means none.""" - - source: AgentInfoSource | None = None - """Where the agent definition was loaded from""" +class PermissionDecisionApproveForSessionApprovalMCPSampling: + """Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.""" - tools: list[str] | None = None - """Allowed tool names for this agent. Empty array means none; omitted means inherit defaults.""" + kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind + """Approval covering MCP sampling requests for a server.""" - user_invocable: bool | None = None - """Whether the agent can be selected directly by the user. Agents marked `false` are - subagent-only. - """ + server_name: str + """MCP server name.""" @staticmethod - def from_dict(obj: Any) -> 'AgentInfo': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCPSampling': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - display_name = from_str(obj.get("displayName")) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - mcp_servers = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("mcpServers")) - model = from_union([from_str, from_none], obj.get("model")) - path = from_union([from_str, from_none], obj.get("path")) - skills = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skills")) - source = from_union([AgentInfoSource, from_none], obj.get("source")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - user_invocable = from_union([from_bool, from_none], obj.get("userInvocable")) - return AgentInfo(description, display_name, id, name, mcp_servers, model, path, skills, source, tools, user_invocable) + kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + return PermissionDecisionApproveForSessionApprovalMCPSampling(kind, server_name) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["displayName"] = from_str(self.display_name) - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - if self.mcp_servers is not None: - result["mcpServers"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.mcp_servers) - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.skills is not None: - result["skills"] = from_union([lambda x: from_list(from_str, x), from_none], self.skills) - if self.source is not None: - result["source"] = from_union([lambda x: to_enum(AgentInfoSource, x), from_none], self.source) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.user_invocable is not None: - result["userInvocable"] = from_union([from_bool, from_none], self.user_invocable) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) + result["serverName"] = from_str(self.server_name) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillList: - """Skills available to the session, with their enabled state.""" +class PermissionDecisionApproveForLocationApprovalMemory: + """Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.""" - skills: list[Skill] - """Available skills""" + kind: PermissionDecisionApproveForLocationApprovalMemoryKind + """Approval covering writes to long-term memory.""" @staticmethod - def from_dict(obj: Any) -> 'SkillList': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMemory': assert isinstance(obj, dict) - skills = from_list(Skill.from_dict, obj.get("skills")) - return SkillList(skills) + kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalMemory(kind) def to_dict(self) -> dict: result: dict = {} - result["skills"] = from_list(lambda x: to_class(Skill, x), self.skills) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) return result @dataclass -class SkillsConfigSetDisabledSkillsRequest: - """Skill names to mark as disabled in global configuration, replacing any previous list.""" +class PermissionDecisionApproveForSessionApprovalMemory: + """Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.""" - disabled_skills: list[str] - """List of skill names to disable""" + kind: PermissionDecisionApproveForLocationApprovalMemoryKind + """Approval covering writes to long-term memory.""" @staticmethod - def from_dict(obj: Any) -> 'SkillsConfigSetDisabledSkillsRequest': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMemory': assert isinstance(obj, dict) - disabled_skills = from_list(from_str, obj.get("disabledSkills")) - return SkillsConfigSetDisabledSkillsRequest(disabled_skills) + kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalMemory(kind) def to_dict(self) -> dict: result: dict = {} - result["disabledSkills"] = from_list(from_str, self.disabled_skills) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillsGetInvokedResult: - """Skills invoked during this session, ordered by invocation time (most recent last).""" +class PermissionDecisionApproveForLocationApprovalRead: + """Schema for the `PermissionDecisionApproveForLocationApprovalRead` type.""" - skills: list[SkillsInvokedSkill] - """Skills invoked during this session, ordered by invocation time (most recent last)""" + kind: PermissionDecisionApproveForLocationApprovalReadKind + """Approval covering read-only filesystem operations.""" @staticmethod - def from_dict(obj: Any) -> 'SkillsGetInvokedResult': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalRead': assert isinstance(obj, dict) - skills = from_list(SkillsInvokedSkill.from_dict, obj.get("skills")) - return SkillsGetInvokedResult(skills) + kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalRead(kind) def to_dict(self) -> dict: result: dict = {} - result["skills"] = from_list(lambda x: to_class(SkillsInvokedSkill, x), self.skills) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) return result @dataclass -class SlashCommandAgentPromptResult: - """Schema for the `SlashCommandAgentPromptResult` type.""" - - display_prompt: str - """Prompt text to display to the user""" - - kind: SlashCommandAgentPromptResultKind - """Agent prompt result discriminator""" - - prompt: str - """Prompt to submit to the agent""" - - mode: SessionMode | None = None - """Optional target session mode for the agent prompt""" +class PermissionDecisionApproveForSessionApprovalRead: + """Schema for the `PermissionDecisionApproveForSessionApprovalRead` type.""" - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh - """ + kind: PermissionDecisionApproveForLocationApprovalReadKind + """Approval covering read-only filesystem operations.""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandAgentPromptResult': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalRead': assert isinstance(obj, dict) - display_prompt = from_str(obj.get("displayPrompt")) - kind = SlashCommandAgentPromptResultKind(obj.get("kind")) - prompt = from_str(obj.get("prompt")) - mode = from_union([SessionMode, from_none], obj.get("mode")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - return SlashCommandAgentPromptResult(display_prompt, kind, prompt, mode, runtime_settings_changed) + kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalRead(kind) def to_dict(self) -> dict: result: dict = {} - result["displayPrompt"] = from_str(self.display_prompt) - result["kind"] = to_enum(SlashCommandAgentPromptResultKind, self.kind) - result["prompt"] = from_str(self.prompt) - if self.mode is not None: - result["mode"] = from_union([lambda x: to_enum(SessionMode, x), from_none], self.mode) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) return result @dataclass -class SlashCommandCompletedResult: - """Schema for the `SlashCommandCompletedResult` type.""" - - kind: SlashCommandCompletedResultKind - """Completed result discriminator""" - - message: str | None = None - """Optional user-facing message describing the completed command""" +class PermissionDecisionApproveForLocationApprovalWrite: + """Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type.""" - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh - """ + kind: PermissionDecisionApproveForLocationApprovalWriteKind + """Approval covering filesystem write operations.""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandCompletedResult': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalWrite': assert isinstance(obj, dict) - kind = SlashCommandCompletedResultKind(obj.get("kind")) - message = from_union([from_str, from_none], obj.get("message")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - return SlashCommandCompletedResult(kind, message, runtime_settings_changed) + kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalWrite(kind) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(SlashCommandCompletedResultKind, self.kind) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskAgentProgress: - """Schema for the `TaskAgentProgress` type.""" - - type: TaskAgentProgressType - """Progress kind""" - - latest_intent: str | None = None - """The most recent intent reported by the agent""" - - recent_activity: list[RecentActivity] | None = None - """Recent tool execution events converted to display lines""" - - pid: int | None = None - """Process ID when available""" +class PermissionDecisionApproveForSessionApprovalWrite: + """Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type.""" - recent_output: str | None = None - """Recent stdout/stderr lines from the running shell command""" + kind: PermissionDecisionApproveForLocationApprovalWriteKind + """Approval covering filesystem write operations.""" @staticmethod - def from_dict(obj: Any) -> 'TaskAgentProgress': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalWrite': assert isinstance(obj, dict) - type = TaskAgentProgressType(obj.get("type")) - latest_intent = from_union([from_str, from_none], obj.get("latestIntent")) - recent_activity = from_union([lambda x: from_list(RecentActivity.from_dict, x), from_none], obj.get("recentActivity")) - pid = from_union([from_int, from_none], obj.get("pid")) - recent_output = from_union([from_str, from_none], obj.get("recentOutput")) - return TaskAgentProgress(type, latest_intent, recent_activity, pid, recent_output) + kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalWrite(kind) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(TaskAgentProgressType, self.type) - if self.latest_intent is not None: - result["latestIntent"] = from_union([from_str, from_none], self.latest_intent) - if self.recent_activity is not None: - result["recentActivity"] = from_union([lambda x: from_list(lambda x: to_class(RecentActivity, x), x), from_none], self.recent_activity) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) - if self.recent_output is not None: - result["recentOutput"] = from_union([from_str, from_none], self.recent_output) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskProgressClass: - type: TaskAgentProgressType - """Progress kind""" - - latest_intent: str | None = None - """The most recent intent reported by the agent""" - - recent_activity: list[RecentActivity] | None = None - """Recent tool execution events converted to display lines""" - - pid: int | None = None - """Process ID when available""" +class PermissionDecisionApproveOnce: + """Schema for the `PermissionDecisionApproveOnce` type.""" - recent_output: str | None = None - """Recent stdout/stderr lines from the running shell command""" + kind: PermissionDecisionApproveOnceKind + """The permission request was approved for this one instance""" @staticmethod - def from_dict(obj: Any) -> 'TaskProgressClass': + def from_dict(obj: Any) -> 'PermissionDecisionApproveOnce': assert isinstance(obj, dict) - type = TaskAgentProgressType(obj.get("type")) - latest_intent = from_union([from_str, from_none], obj.get("latestIntent")) - recent_activity = from_union([lambda x: from_list(RecentActivity.from_dict, x), from_none], obj.get("recentActivity")) - pid = from_union([from_int, from_none], obj.get("pid")) - recent_output = from_union([from_str, from_none], obj.get("recentOutput")) - return TaskProgressClass(type, latest_intent, recent_activity, pid, recent_output) + kind = PermissionDecisionApproveOnceKind(obj.get("kind")) + return PermissionDecisionApproveOnce(kind) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(TaskAgentProgressType, self.type) - if self.latest_intent is not None: - result["latestIntent"] = from_union([from_str, from_none], self.latest_intent) - if self.recent_activity is not None: - result["recentActivity"] = from_union([lambda x: from_list(lambda x: to_class(RecentActivity, x), x), from_none], self.recent_activity) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) - if self.recent_output is not None: - result["recentOutput"] = from_union([from_str, from_none], self.recent_output) + result["kind"] = to_enum(PermissionDecisionApproveOnceKind, self.kind) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskShellInfo: - """Schema for the `TaskShellInfo` type.""" +class PermissionDecisionApprovePermanently: + """Schema for the `PermissionDecisionApprovePermanently` type.""" - attachment_mode: TaskShellInfoAttachmentMode - """Whether the shell runs inside a managed PTY session or as an independent background - process - """ - command: str - """Command being executed""" + domain: str + """The URL domain to approve permanently""" - description: str - """Short description of the task""" + kind: PermissionDecisionApprovePermanentlyKind + """Approved and persisted across sessions""" - id: str - """Unique task identifier""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApprovePermanently': + assert isinstance(obj, dict) + domain = from_str(obj.get("domain")) + kind = PermissionDecisionApprovePermanentlyKind(obj.get("kind")) + return PermissionDecisionApprovePermanently(domain, kind) - started_at: datetime - """ISO 8601 timestamp when the task was started""" + def to_dict(self) -> dict: + result: dict = {} + result["domain"] = from_str(self.domain) + result["kind"] = to_enum(PermissionDecisionApprovePermanentlyKind, self.kind) + return result - status: TaskStatus - """Current lifecycle status of the task""" +@dataclass +class PermissionDecisionReject: + """Schema for the `PermissionDecisionReject` type.""" - type: TaskShellInfoType - """Task kind""" + kind: PermissionDecisionRejectKind + """Denied by the user during an interactive prompt""" - can_promote_to_background: bool | None = None - """Whether this shell task can be promoted to background mode""" + feedback: str | None = None + """Optional feedback from the user explaining the denial""" - completed_at: datetime | None = None - """ISO 8601 timestamp when the task finished""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionReject': + assert isinstance(obj, dict) + kind = PermissionDecisionRejectKind(obj.get("kind")) + feedback = from_union([from_str, from_none], obj.get("feedback")) + return PermissionDecisionReject(kind, feedback) - execution_mode: TaskExecutionMode | None = None - """Whether task execution is synchronously awaited or managed in the background""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionRejectKind, self.kind) + if self.feedback is not None: + result["feedback"] = from_union([from_str, from_none], self.feedback) + return result - log_path: str | None = None - """Path to the detached shell log, when available""" +@dataclass +class PermissionDecisionUserNotAvailable: + """Schema for the `PermissionDecisionUserNotAvailable` type.""" - pid: int | None = None - """Process ID when available""" + kind: PermissionDecisionUserNotAvailableKind + """Denied because user confirmation was unavailable""" @staticmethod - def from_dict(obj: Any) -> 'TaskShellInfo': + def from_dict(obj: Any) -> 'PermissionDecisionUserNotAvailable': assert isinstance(obj, dict) - attachment_mode = TaskShellInfoAttachmentMode(obj.get("attachmentMode")) - command = from_str(obj.get("command")) - description = from_str(obj.get("description")) - id = from_str(obj.get("id")) - started_at = from_datetime(obj.get("startedAt")) - status = TaskStatus(obj.get("status")) - type = TaskShellInfoType(obj.get("type")) - can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) - completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) - execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) - log_path = from_union([from_str, from_none], obj.get("logPath")) - pid = from_union([from_int, from_none], obj.get("pid")) - return TaskShellInfo(attachment_mode, command, description, id, started_at, status, type, can_promote_to_background, completed_at, execution_mode, log_path, pid) + kind = PermissionDecisionUserNotAvailableKind(obj.get("kind")) + return PermissionDecisionUserNotAvailable(kind) def to_dict(self) -> dict: result: dict = {} - result["attachmentMode"] = to_enum(TaskShellInfoAttachmentMode, self.attachment_mode) - result["command"] = from_str(self.command) - result["description"] = from_str(self.description) - result["id"] = from_str(self.id) - result["startedAt"] = self.started_at.isoformat() - result["status"] = to_enum(TaskStatus, self.status) - result["type"] = to_enum(TaskShellInfoType, self.type) - if self.can_promote_to_background is not None: - result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) - if self.completed_at is not None: - result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) - if self.execution_mode is not None: - result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) - if self.log_path is not None: - result["logPath"] = from_union([from_str, from_none], self.log_path) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) + result["kind"] = to_enum(PermissionDecisionUserNotAvailableKind, self.kind) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ToolList: - """Built-in tools available for the requested model, with their parameters and instructions.""" - - tools: list[Tool] - """List of available built-in tools with metadata""" +class PluginList: + """Plugins installed for the session, with their enabled state and version metadata.""" + + plugins: list[Plugin] + """Installed plugins""" @staticmethod - def from_dict(obj: Any) -> 'ToolList': + def from_dict(obj: Any) -> 'PluginList': assert isinstance(obj, dict) - tools = from_list(Tool.from_dict, obj.get("tools")) - return ToolList(tools) + plugins = from_list(Plugin.from_dict, obj.get("plugins")) + return PluginList(plugins) def to_dict(self) -> dict: result: dict = {} - result["tools"] = from_list(lambda x: to_class(Tool, x), self.tools) + result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins) return result @dataclass -class UIHandlePendingAutoModeSwitchRequest: - """Request ID of a pending `auto_mode_switch.requested` event and the user's response.""" +class QueuedCommandResult: + """Result of the queued command execution - request_id: str - """The unique request ID from the auto_mode_switch.requested event""" + Schema for the `QueuedCommandHandled` type. + + Schema for the `QueuedCommandNotHandled` type. + """ + handled: bool + """The command was handled - response: UIAutoModeSwitchResponse - """User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist - as setting), or no (decline). + The command was not handled """ + stop_processing_queue: bool | None = None + """If true, stop processing remaining queued items""" @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingAutoModeSwitchRequest': + def from_dict(obj: Any) -> 'QueuedCommandResult': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - response = UIAutoModeSwitchResponse(obj.get("response")) - return UIHandlePendingAutoModeSwitchRequest(request_id, response) + handled = from_bool(obj.get("handled")) + stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) + return QueuedCommandResult(handled, stop_processing_queue) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["response"] = to_enum(UIAutoModeSwitchResponse, self.response) + result["handled"] = from_bool(self.handled) + if self.stop_processing_queue is not None: + result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationArrayAnyOfFieldItems: - """Schema applied to each item in the array.""" - - any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] - """Selectable options, each with a value and a display label.""" +class RemoteEnableRequest: + """Optional remote session mode ("off", "export", or "on"); defaults to enabling both export + and remote steering. + """ + mode: RemoteSessionMode | None = None + """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub + without enabling remote steering, "on" enables both export and remote steering. + """ @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItems': + def from_dict(obj: Any) -> 'RemoteEnableRequest': assert isinstance(obj, dict) - any_of = from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, obj.get("anyOf")) - return UIElicitationArrayAnyOfFieldItems(any_of) + mode = from_union([RemoteSessionMode, from_none], obj.get("mode")) + return RemoteEnableRequest(mode) def to_dict(self) -> dict: result: dict = {} - result["anyOf"] = from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), self.any_of) + if self.mode is not None: + result["mode"] = from_union([lambda x: to_enum(RemoteSessionMode, x), from_none], self.mode) return result @dataclass -class UIElicitationArrayEnumFieldItems: - """Schema applied to each item in the array.""" - - enum: list[str] - """Allowed string values for each selected item.""" +class ServerSkillList: + """Skills discovered across global and project sources.""" - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" + skills: list[ServerSkill] + """All discovered skills across all sources""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayEnumFieldItems': + def from_dict(obj: Any) -> 'ServerSkillList': assert isinstance(obj, dict) - enum = from_list(from_str, obj.get("enum")) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - return UIElicitationArrayEnumFieldItems(enum, type) + skills = from_list(ServerSkill.from_dict, obj.get("skills")) + return ServerSkillList(skills) def to_dict(self) -> dict: result: dict = {} - result["enum"] = from_list(from_str, self.enum) - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + result["skills"] = from_list(lambda x: to_class(ServerSkill, x), self.skills) return result @dataclass -class UIElicitationArrayFieldItems: - """Schema applied to each item in the array.""" - - enum: list[str] | None = None - """Allowed string values for each selected item.""" +class SessionFSError: + """Describes a filesystem error.""" - type: UIElicitationArrayEnumFieldItemsType | None = None - """Type discriminator. Always "string".""" + code: SessionFSErrorCode + """Error classification""" - any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] | None = None - """Selectable options, each with a value and a display label.""" + message: str | None = None + """Free-form detail about the error, for logging/diagnostics""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayFieldItems': + def from_dict(obj: Any) -> 'SessionFSError': assert isinstance(obj, dict) - enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) - type = from_union([UIElicitationArrayEnumFieldItemsType, from_none], obj.get("type")) - any_of = from_union([lambda x: from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, x), from_none], obj.get("anyOf")) - return UIElicitationArrayFieldItems(enum, type, any_of) + code = SessionFSErrorCode(obj.get("code")) + message = from_union([from_str, from_none], obj.get("message")) + return SessionFSError(code, message) def to_dict(self) -> dict: result: dict = {} - if self.enum is not None: - result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(UIElicitationArrayEnumFieldItemsType, x), from_none], self.type) - if self.any_of is not None: - result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), x), from_none], self.any_of) + result["code"] = to_enum(SessionFSErrorCode, self.code) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) return result @dataclass -class UIElicitationStringEnumField: - """Single-select string field whose allowed values are defined inline.""" - - enum: list[str] - """Allowed string values.""" - - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" - - default: str | None = None - """Default value selected when the form is first shown.""" - - description: str | None = None - """Help text describing the field.""" +class SessionFSReaddirWithTypesEntry: + """Schema for the `SessionFsReaddirWithTypesEntry` type.""" - enum_names: list[str] | None = None - """Optional display labels for each enum value, in the same order as `enum`.""" + name: str + """Entry name""" - title: str | None = None - """Human-readable label for the field.""" + type: SessionFSReaddirWithTypesEntryType + """Entry type""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringEnumField': + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesEntry': assert isinstance(obj, dict) - enum = from_list(from_str, obj.get("enum")) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationStringEnumField(enum, type, default, description, enum_names, title) + name = from_str(obj.get("name")) + type = SessionFSReaddirWithTypesEntryType(obj.get("type")) + return SessionFSReaddirWithTypesEntry(name, type) def to_dict(self) -> dict: result: dict = {} - result["enum"] = from_list(from_str, self.enum) - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.enum_names is not None: - result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["name"] = from_str(self.name) + result["type"] = to_enum(SessionFSReaddirWithTypesEntryType, self.type) return result @dataclass -class UIElicitationSchemaPropertyString: - """Free-text string field with optional length and format constraints.""" +class SessionFSSetProviderRequest: + """Initial working directory, session-state path layout, and path conventions used to + register the calling SDK client as the session filesystem provider. + """ + conventions: SessionFSSetProviderConventions + """Path conventions used by this filesystem""" - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" + initial_cwd: str + """Initial working directory for sessions""" - default: str | None = None - """Default value populated in the input when the form is first shown.""" + session_state_path: str + """Path within each session's SessionFs where the runtime stores files for that session""" - description: str | None = None - """Help text describing the field.""" + capabilities: SessionFSSetProviderCapabilities | None = None + """Optional capabilities declared by the provider""" - format: UIElicitationSchemaPropertyStringFormat | None = None - """Optional format hint that constrains the accepted input.""" + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSetProviderRequest': + assert isinstance(obj, dict) + conventions = SessionFSSetProviderConventions(obj.get("conventions")) + initial_cwd = from_str(obj.get("initialCwd")) + session_state_path = from_str(obj.get("sessionStatePath")) + capabilities = from_union([SessionFSSetProviderCapabilities.from_dict, from_none], obj.get("capabilities")) + return SessionFSSetProviderRequest(conventions, initial_cwd, session_state_path, capabilities) - max_length: int | None = None - """Maximum number of characters allowed.""" + def to_dict(self) -> dict: + result: dict = {} + result["conventions"] = to_enum(SessionFSSetProviderConventions, self.conventions) + result["initialCwd"] = from_str(self.initial_cwd) + result["sessionStatePath"] = from_str(self.session_state_path) + if self.capabilities is not None: + result["capabilities"] = from_union([lambda x: to_class(SessionFSSetProviderCapabilities, x), from_none], self.capabilities) + return result - min_length: int | None = None - """Minimum number of characters required.""" +@dataclass +class SessionFSSqliteQueryRequest: + """SQL query, query type, and optional bind parameters for executing a SQLite query against + the per-session database. + """ + query: str + """SQL query to execute""" - title: str | None = None - """Human-readable label for the field.""" + query_type: SessionFSSqliteQueryType + """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT + (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) + """ + session_id: str + """Target session identifier""" + + params: dict[str, float | str | None] | None = None + """Optional named bind parameters""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyString': + def from_dict(obj: Any) -> 'SessionFSSqliteQueryRequest': assert isinstance(obj, dict) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) - max_length = from_union([from_int, from_none], obj.get("maxLength")) - min_length = from_union([from_int, from_none], obj.get("minLength")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationSchemaPropertyString(type, default, description, format, max_length, min_length, title) + query = from_str(obj.get("query")) + query_type = SessionFSSqliteQueryType(obj.get("queryType")) + session_id = from_str(obj.get("sessionId")) + params = from_union([lambda x: from_dict(lambda x: from_union([from_none, from_float, from_str], x), x), from_none], obj.get("params")) + return SessionFSSqliteQueryRequest(query, query_type, session_id, params) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.format is not None: - result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) - if self.max_length is not None: - result["maxLength"] = from_union([from_int, from_none], self.max_length) - if self.min_length is not None: - result["minLength"] = from_union([from_int, from_none], self.min_length) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["query"] = from_str(self.query) + result["queryType"] = to_enum(SessionFSSqliteQueryType, self.query_type) + result["sessionId"] = from_str(self.session_id) + if self.params is not None: + result["params"] = from_union([lambda x: from_dict(lambda x: from_union([from_none, to_float, from_str], x), x), from_none], self.params) return result @dataclass -class UIElicitationStringOneOfField: - """Single-select string field where each option pairs a value with a display label.""" - - one_of: list[UIElicitationStringOneOfFieldOneOf] - """Selectable options, each with a value and a display label.""" - - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" - - default: str | None = None - """Default value selected when the form is first shown.""" +class ShellKillRequest: + """Identifier of a process previously returned by "shell.exec" and the signal to send.""" - description: str | None = None - """Help text describing the field.""" + process_id: str + """Process identifier returned by shell.exec""" - title: str | None = None - """Human-readable label for the field.""" + signal: ShellKillSignal | None = None + """Signal to send (default: SIGTERM)""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringOneOfField': + def from_dict(obj: Any) -> 'ShellKillRequest': assert isinstance(obj, dict) - one_of = from_list(UIElicitationStringOneOfFieldOneOf.from_dict, obj.get("oneOf")) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationStringOneOfField(one_of, type, default, description, title) + process_id = from_str(obj.get("processId")) + signal = from_union([ShellKillSignal, from_none], obj.get("signal")) + return ShellKillRequest(process_id, signal) def to_dict(self) -> dict: result: dict = {} - result["oneOf"] = from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), self.one_of) - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["processId"] = from_str(self.process_id) + if self.signal is not None: + result["signal"] = from_union([lambda x: to_enum(ShellKillSignal, x), from_none], self.signal) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationResponse: - """The elicitation response (accept with form values, decline, or cancel)""" - - action: UIElicitationResponseAction - """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" +class SkillList: + """Skills available to the session, with their enabled state.""" - content: dict[str, float | bool | list[str] | str] | None = None - """The form values submitted by the user (present when action is 'accept')""" + skills: list[Skill] + """Available skills""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationResponse': + def from_dict(obj: Any) -> 'SkillList': assert isinstance(obj, dict) - action = UIElicitationResponseAction(obj.get("action")) - content = from_union([lambda x: from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], obj.get("content")) - return UIElicitationResponse(action, content) + skills = from_list(Skill.from_dict, obj.get("skills")) + return SkillList(skills) def to_dict(self) -> dict: result: dict = {} - result["action"] = to_enum(UIElicitationResponseAction, self.action) - if self.content is not None: - result["content"] = from_union([lambda x: from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], self.content) + result["skills"] = from_list(lambda x: to_class(Skill, x), self.skills) return result @dataclass -class UIElicitationSchemaPropertyBoolean: - """Boolean field rendered as a yes/no toggle.""" - - type: UIElicitationSchemaPropertyBooleanType - """Type discriminator. Always "boolean".""" - - default: bool | None = None - """Default value selected when the form is first shown.""" - - description: str | None = None - """Help text describing the field.""" +class SkillsConfigSetDisabledSkillsRequest: + """Skill names to mark as disabled in global configuration, replacing any previous list.""" - title: str | None = None - """Human-readable label for the field.""" + disabled_skills: list[str] + """List of skill names to disable""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyBoolean': + def from_dict(obj: Any) -> 'SkillsConfigSetDisabledSkillsRequest': assert isinstance(obj, dict) - type = UIElicitationSchemaPropertyBooleanType(obj.get("type")) - default = from_union([from_bool, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationSchemaPropertyBoolean(type, default, description, title) + disabled_skills = from_list(from_str, obj.get("disabledSkills")) + return SkillsConfigSetDisabledSkillsRequest(disabled_skills) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationSchemaPropertyBooleanType, self.type) - if self.default is not None: - result["default"] = from_union([from_bool, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["disabledSkills"] = from_list(from_str, self.disabled_skills) return result @dataclass -class UIElicitationSchemaPropertyNumber: - """Numeric field accepting either a number or an integer.""" - - type: UIElicitationSchemaPropertyNumberType - """Numeric type accepted by the field.""" +class SlashCommandAgentPromptResult: + """Schema for the `SlashCommandAgentPromptResult` type.""" - default: float | None = None - """Default value populated in the input when the form is first shown.""" + display_prompt: str + """Prompt text to display to the user""" - description: str | None = None - """Help text describing the field.""" + kind: SlashCommandAgentPromptResultKind + """Agent prompt result discriminator""" - maximum: float | None = None - """Maximum allowed value (inclusive).""" + prompt: str + """Prompt to submit to the agent""" - minimum: float | None = None - """Minimum allowed value (inclusive).""" + mode: SessionMode | None = None + """Optional target session mode for the agent prompt""" - title: str | None = None - """Human-readable label for the field.""" + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh + """ @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyNumber': + def from_dict(obj: Any) -> 'SlashCommandAgentPromptResult': assert isinstance(obj, dict) - type = UIElicitationSchemaPropertyNumberType(obj.get("type")) - default = from_union([from_float, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - maximum = from_union([from_float, from_none], obj.get("maximum")) - minimum = from_union([from_float, from_none], obj.get("minimum")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationSchemaPropertyNumber(type, default, description, maximum, minimum, title) + display_prompt = from_str(obj.get("displayPrompt")) + kind = SlashCommandAgentPromptResultKind(obj.get("kind")) + prompt = from_str(obj.get("prompt")) + mode = from_union([SessionMode, from_none], obj.get("mode")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + return SlashCommandAgentPromptResult(display_prompt, kind, prompt, mode, runtime_settings_changed) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationSchemaPropertyNumberType, self.type) - if self.default is not None: - result["default"] = from_union([to_float, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.maximum is not None: - result["maximum"] = from_union([to_float, from_none], self.maximum) - if self.minimum is not None: - result["minimum"] = from_union([to_float, from_none], self.minimum) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["displayPrompt"] = from_str(self.display_prompt) + result["kind"] = to_enum(SlashCommandAgentPromptResultKind, self.kind) + result["prompt"] = from_str(self.prompt) + if self.mode is not None: + result["mode"] = from_union([lambda x: to_enum(SessionMode, x), from_none], self.mode) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) return result @dataclass -class UIExitPlanModeResponse: - """Schema for the `UIExitPlanModeResponse` type.""" - - approved: bool - """Whether the plan was approved.""" +class SlashCommandCompletedResult: + """Schema for the `SlashCommandCompletedResult` type.""" - auto_approve_edits: bool | None = None - """Whether subsequent edits should be auto-approved without confirmation.""" + kind: SlashCommandCompletedResultKind + """Completed result discriminator""" - feedback: str | None = None - """Feedback from the user when they declined the plan or requested changes.""" + message: str | None = None + """Optional user-facing message describing the completed command""" - selected_action: UIExitPlanModeAction | None = None - """The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, - otherwise 'interactive'. + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh """ @staticmethod - def from_dict(obj: Any) -> 'UIExitPlanModeResponse': + def from_dict(obj: Any) -> 'SlashCommandCompletedResult': assert isinstance(obj, dict) - approved = from_bool(obj.get("approved")) - auto_approve_edits = from_union([from_bool, from_none], obj.get("autoApproveEdits")) - feedback = from_union([from_str, from_none], obj.get("feedback")) - selected_action = from_union([UIExitPlanModeAction, from_none], obj.get("selectedAction")) - return UIExitPlanModeResponse(approved, auto_approve_edits, feedback, selected_action) + kind = SlashCommandCompletedResultKind(obj.get("kind")) + message = from_union([from_str, from_none], obj.get("message")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + return SlashCommandCompletedResult(kind, message, runtime_settings_changed) def to_dict(self) -> dict: result: dict = {} - result["approved"] = from_bool(self.approved) - if self.auto_approve_edits is not None: - result["autoApproveEdits"] = from_union([from_bool, from_none], self.auto_approve_edits) - if self.feedback is not None: - result["feedback"] = from_union([from_str, from_none], self.feedback) - if self.selected_action is not None: - result["selectedAction"] = from_union([lambda x: to_enum(UIExitPlanModeAction, x), from_none], self.selected_action) + result["kind"] = to_enum(SlashCommandCompletedResultKind, self.kind) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIHandlePendingUserInputRequest: - """Request ID of a pending `user_input.requested` event and the user's response.""" +class TaskShellInfo: + """Schema for the `TaskShellInfo` type.""" - request_id: str - """The unique request ID from the user_input.requested event""" + attachment_mode: TaskShellInfoAttachmentMode + """Whether the shell runs inside a managed PTY session or as an independent background + process + """ + command: str + """Command being executed""" + + description: str + """Short description of the task""" + + id: str + """Unique task identifier""" + + started_at: datetime + """ISO 8601 timestamp when the task was started""" + + status: TaskStatus + """Current lifecycle status of the task""" - response: UIUserInputResponse - """Schema for the `UIUserInputResponse` type.""" + type: TaskShellInfoType + """Task kind""" + + can_promote_to_background: bool | None = None + """Whether this shell task can be promoted to background mode""" + + completed_at: datetime | None = None + """ISO 8601 timestamp when the task finished""" + + execution_mode: TaskExecutionMode | None = None + """Whether task execution is synchronously awaited or managed in the background""" + + log_path: str | None = None + """Path to the detached shell log, when available""" + + pid: int | None = None + """Process ID when available""" @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingUserInputRequest': + def from_dict(obj: Any) -> 'TaskShellInfo': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - response = UIUserInputResponse.from_dict(obj.get("response")) - return UIHandlePendingUserInputRequest(request_id, response) + attachment_mode = TaskShellInfoAttachmentMode(obj.get("attachmentMode")) + command = from_str(obj.get("command")) + description = from_str(obj.get("description")) + id = from_str(obj.get("id")) + started_at = from_datetime(obj.get("startedAt")) + status = TaskStatus(obj.get("status")) + type = TaskShellInfoType(obj.get("type")) + can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) + completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) + execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) + log_path = from_union([from_str, from_none], obj.get("logPath")) + pid = from_union([from_int, from_none], obj.get("pid")) + return TaskShellInfo(attachment_mode, command, description, id, started_at, status, type, can_promote_to_background, completed_at, execution_mode, log_path, pid) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["response"] = to_class(UIUserInputResponse, self.response) + result["attachmentMode"] = to_enum(TaskShellInfoAttachmentMode, self.attachment_mode) + result["command"] = from_str(self.command) + result["description"] = from_str(self.description) + result["id"] = from_str(self.id) + result["startedAt"] = self.started_at.isoformat() + result["status"] = to_enum(TaskStatus, self.status) + result["type"] = to_enum(TaskShellInfoType, self.type) + if self.can_promote_to_background is not None: + result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) + if self.completed_at is not None: + result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) + if self.execution_mode is not None: + result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) + if self.log_path is not None: + result["logPath"] = from_union([from_str, from_none], self.log_path) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsModelMetric: - """Schema for the `UsageMetricsModelMetric` type.""" - - requests: UsageMetricsModelMetricRequests - """Request count and cost metrics for this model""" - - usage: UsageMetricsModelMetricUsage - """Token usage metrics for this model""" - - token_details: dict[str, UsageMetricsModelMetricTokenDetail] | None = None - """Token count details per type""" +class ToolList: + """Built-in tools available for the requested model, with their parameters and instructions.""" - total_nano_aiu: int | None = None - """Accumulated nano-AI units cost for this model""" + tools: list[Tool] + """List of available built-in tools with metadata""" @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetric': + def from_dict(obj: Any) -> 'ToolList': assert isinstance(obj, dict) - requests = UsageMetricsModelMetricRequests.from_dict(obj.get("requests")) - usage = UsageMetricsModelMetricUsage.from_dict(obj.get("usage")) - token_details = from_union([lambda x: from_dict(UsageMetricsModelMetricTokenDetail.from_dict, x), from_none], obj.get("tokenDetails")) - total_nano_aiu = from_union([from_int, from_none], obj.get("totalNanoAiu")) - return UsageMetricsModelMetric(requests, usage, token_details, total_nano_aiu) + tools = from_list(Tool.from_dict, obj.get("tools")) + return ToolList(tools) def to_dict(self) -> dict: result: dict = {} - result["requests"] = to_class(UsageMetricsModelMetricRequests, self.requests) - result["usage"] = to_class(UsageMetricsModelMetricUsage, self.usage) - if self.token_details is not None: - result["tokenDetails"] = from_union([lambda x: from_dict(lambda x: to_class(UsageMetricsModelMetricTokenDetail, x), x), from_none], self.token_details) - if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_int, from_none], self.total_nano_aiu) + result["tools"] = from_list(lambda x: to_class(Tool, x), self.tools) return result @dataclass -class WorkspacesSaveLargePasteResult: - """Descriptor for the saved paste file, or null when the workspace is unavailable.""" +class UIElicitationArrayAnyOfFieldItems: + """Schema applied to each item in the array.""" - saved: Saved | None = None - """Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, - non-infinite sessions, remote sessions) - """ + any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] + """Selectable options, each with a value and a display label.""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesSaveLargePasteResult': + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItems': assert isinstance(obj, dict) - saved = from_union([Saved.from_dict, from_none], obj.get("saved")) - return WorkspacesSaveLargePasteResult(saved) + any_of = from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, obj.get("anyOf")) + return UIElicitationArrayAnyOfFieldItems(any_of) def to_dict(self) -> dict: result: dict = {} - result["saved"] = from_union([lambda x: to_class(Saved, x), from_none], self.saved) + result["anyOf"] = from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), self.any_of) return result @dataclass -class SlashCommandInfo: - """Schema for the `SlashCommandInfo` type.""" - - allow_during_agent_execution: bool - """Whether the command may run while an agent turn is active""" - - description: str - """Human-readable command description""" - - kind: SlashCommandKind - """Coarse command category for grouping and behavior: runtime built-in, skill-backed - command, or SDK/client-owned command - """ - name: str - """Canonical command name without a leading slash""" - - aliases: list[str] | None = None - """Canonical aliases without leading slashes""" +class UIElicitationArrayEnumFieldItems: + """Schema applied to each item in the array.""" - experimental: bool | None = None - """Whether the command is experimental""" + enum: list[str] + """Allowed string values for each selected item.""" - input: SlashCommandInput | None = None - """Optional unstructured input hint""" + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandInfo': + def from_dict(obj: Any) -> 'UIElicitationArrayEnumFieldItems': assert isinstance(obj, dict) - allow_during_agent_execution = from_bool(obj.get("allowDuringAgentExecution")) - description = from_str(obj.get("description")) - kind = SlashCommandKind(obj.get("kind")) - name = from_str(obj.get("name")) - aliases = from_union([lambda x: from_list(from_str, x), from_none], obj.get("aliases")) - experimental = from_union([from_bool, from_none], obj.get("experimental")) - input = from_union([SlashCommandInput.from_dict, from_none], obj.get("input")) - return SlashCommandInfo(allow_during_agent_execution, description, kind, name, aliases, experimental, input) + enum = from_list(from_str, obj.get("enum")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + return UIElicitationArrayEnumFieldItems(enum, type) def to_dict(self) -> dict: result: dict = {} - result["allowDuringAgentExecution"] = from_bool(self.allow_during_agent_execution) - result["description"] = from_str(self.description) - result["kind"] = to_enum(SlashCommandKind, self.kind) - result["name"] = from_str(self.name) - if self.aliases is not None: - result["aliases"] = from_union([lambda x: from_list(from_str, x), from_none], self.aliases) - if self.experimental is not None: - result["experimental"] = from_union([from_bool, from_none], self.experimental) - if self.input is not None: - result["input"] = from_union([lambda x: to_class(SlashCommandInput, x), from_none], self.input) + result["enum"] = from_list(from_str, self.enum) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteSessionConnectionResult: - """Remote session connection result.""" +class UIElicitationArrayFieldItems: + """Schema applied to each item in the array.""" - metadata: ConnectedRemoteSessionMetadata - """Metadata for a connected remote session.""" + enum: list[str] | None = None + """Allowed string values for each selected item.""" - session_id: str - """SDK session ID for the connected remote session.""" + type: UIElicitationArrayEnumFieldItemsType | None = None + """Type discriminator. Always "string".""" + + any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] | None = None + """Selectable options, each with a value and a display label.""" @staticmethod - def from_dict(obj: Any) -> 'RemoteSessionConnectionResult': + def from_dict(obj: Any) -> 'UIElicitationArrayFieldItems': assert isinstance(obj, dict) - metadata = ConnectedRemoteSessionMetadata.from_dict(obj.get("metadata")) - session_id = from_str(obj.get("sessionId")) - return RemoteSessionConnectionResult(metadata, session_id) + enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) + type = from_union([UIElicitationArrayEnumFieldItemsType, from_none], obj.get("type")) + any_of = from_union([lambda x: from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, x), from_none], obj.get("anyOf")) + return UIElicitationArrayFieldItems(enum, type, any_of) def to_dict(self) -> dict: result: dict = {} - result["metadata"] = to_class(ConnectedRemoteSessionMetadata, self.metadata) - result["sessionId"] = from_str(self.session_id) + if self.enum is not None: + result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(UIElicitationArrayEnumFieldItemsType, x), from_none], self.type) + if self.any_of is not None: + result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), x), from_none], self.any_of) return result @dataclass -class CopilotUserResponse: - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - access_type_sku: str | None = None - analytics_tracking_id: str | None = None - assigned_date: Any = None - can_signup_for_limited: bool | None = None - chat_enabled: bool | None = None - cli_remote_control_enabled: bool | None = None - cloud_session_storage_enabled: bool | None = None - codex_agent_enabled: bool | None = None - copilot_plan: str | None = None - copilotignore_enabled: bool | None = None - endpoints: CopilotUserResponseEndpoints | None = None - """Schema for the `CopilotUserResponseEndpoints` type.""" +class UIElicitationStringEnumField: + """Single-select string field whose allowed values are defined inline.""" - is_mcp_enabled: Any = None - limited_user_quotas: dict[str, float] | None = None - limited_user_reset_date: str | None = None - login: str | None = None - monthly_quotas: dict[str, float] | None = None - organization_list: Any = None - organization_login_list: list[str] | None = None - quota_reset_date: str | None = None - quota_reset_date_utc: str | None = None - quota_snapshots: dict[str, CopilotUserResponseQuotaSnapshots | None] | None = None - """Schema for the `CopilotUserResponseQuotaSnapshots` type.""" + enum: list[str] + """Allowed string values.""" - restricted_telemetry: bool | None = None - token_based_billing: bool | None = None + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" - @staticmethod - def from_dict(obj: Any) -> 'CopilotUserResponse': - assert isinstance(obj, dict) - access_type_sku = from_union([from_str, from_none], obj.get("access_type_sku")) - analytics_tracking_id = from_union([from_str, from_none], obj.get("analytics_tracking_id")) - assigned_date = obj.get("assigned_date") - can_signup_for_limited = from_union([from_bool, from_none], obj.get("can_signup_for_limited")) - chat_enabled = from_union([from_bool, from_none], obj.get("chat_enabled")) - cli_remote_control_enabled = from_union([from_bool, from_none], obj.get("cli_remote_control_enabled")) - cloud_session_storage_enabled = from_union([from_bool, from_none], obj.get("cloud_session_storage_enabled")) - codex_agent_enabled = from_union([from_bool, from_none], obj.get("codex_agent_enabled")) - copilot_plan = from_union([from_str, from_none], obj.get("copilot_plan")) - copilotignore_enabled = from_union([from_bool, from_none], obj.get("copilotignore_enabled")) - endpoints = from_union([CopilotUserResponseEndpoints.from_dict, from_none], obj.get("endpoints")) - is_mcp_enabled = obj.get("is_mcp_enabled") - limited_user_quotas = from_union([lambda x: from_dict(from_float, x), from_none], obj.get("limited_user_quotas")) - limited_user_reset_date = from_union([from_str, from_none], obj.get("limited_user_reset_date")) - login = from_union([from_str, from_none], obj.get("login")) - monthly_quotas = from_union([lambda x: from_dict(from_float, x), from_none], obj.get("monthly_quotas")) - organization_list = obj.get("organization_list") - organization_login_list = from_union([lambda x: from_list(from_str, x), from_none], obj.get("organization_login_list")) - quota_reset_date = from_union([from_str, from_none], obj.get("quota_reset_date")) - quota_reset_date_utc = from_union([from_str, from_none], obj.get("quota_reset_date_utc")) - quota_snapshots = from_union([lambda x: from_dict(lambda x: from_union([CopilotUserResponseQuotaSnapshots.from_dict, from_none], x), x), from_none], obj.get("quota_snapshots")) - restricted_telemetry = from_union([from_bool, from_none], obj.get("restricted_telemetry")) - token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) - return CopilotUserResponse(access_type_sku, analytics_tracking_id, assigned_date, can_signup_for_limited, chat_enabled, cli_remote_control_enabled, cloud_session_storage_enabled, codex_agent_enabled, copilot_plan, copilotignore_enabled, endpoints, is_mcp_enabled, limited_user_quotas, limited_user_reset_date, login, monthly_quotas, organization_list, organization_login_list, quota_reset_date, quota_reset_date_utc, quota_snapshots, restricted_telemetry, token_based_billing) + default: str | None = None + """Default value selected when the form is first shown.""" - def to_dict(self) -> dict: - result: dict = {} - if self.access_type_sku is not None: - result["access_type_sku"] = from_union([from_str, from_none], self.access_type_sku) - if self.analytics_tracking_id is not None: - result["analytics_tracking_id"] = from_union([from_str, from_none], self.analytics_tracking_id) - if self.assigned_date is not None: - result["assigned_date"] = self.assigned_date - if self.can_signup_for_limited is not None: - result["can_signup_for_limited"] = from_union([from_bool, from_none], self.can_signup_for_limited) - if self.chat_enabled is not None: - result["chat_enabled"] = from_union([from_bool, from_none], self.chat_enabled) - if self.cli_remote_control_enabled is not None: - result["cli_remote_control_enabled"] = from_union([from_bool, from_none], self.cli_remote_control_enabled) - if self.cloud_session_storage_enabled is not None: - result["cloud_session_storage_enabled"] = from_union([from_bool, from_none], self.cloud_session_storage_enabled) - if self.codex_agent_enabled is not None: - result["codex_agent_enabled"] = from_union([from_bool, from_none], self.codex_agent_enabled) - if self.copilot_plan is not None: - result["copilot_plan"] = from_union([from_str, from_none], self.copilot_plan) - if self.copilotignore_enabled is not None: - result["copilotignore_enabled"] = from_union([from_bool, from_none], self.copilotignore_enabled) - if self.endpoints is not None: - result["endpoints"] = from_union([lambda x: to_class(CopilotUserResponseEndpoints, x), from_none], self.endpoints) - if self.is_mcp_enabled is not None: - result["is_mcp_enabled"] = self.is_mcp_enabled - if self.limited_user_quotas is not None: - result["limited_user_quotas"] = from_union([lambda x: from_dict(to_float, x), from_none], self.limited_user_quotas) - if self.limited_user_reset_date is not None: - result["limited_user_reset_date"] = from_union([from_str, from_none], self.limited_user_reset_date) - if self.login is not None: - result["login"] = from_union([from_str, from_none], self.login) - if self.monthly_quotas is not None: - result["monthly_quotas"] = from_union([lambda x: from_dict(to_float, x), from_none], self.monthly_quotas) - if self.organization_list is not None: - result["organization_list"] = self.organization_list - if self.organization_login_list is not None: - result["organization_login_list"] = from_union([lambda x: from_list(from_str, x), from_none], self.organization_login_list) - if self.quota_reset_date is not None: - result["quota_reset_date"] = from_union([from_str, from_none], self.quota_reset_date) - if self.quota_reset_date_utc is not None: - result["quota_reset_date_utc"] = from_union([from_str, from_none], self.quota_reset_date_utc) - if self.quota_snapshots is not None: - result["quota_snapshots"] = from_union([lambda x: from_dict(lambda x: from_union([lambda x: to_class(CopilotUserResponseQuotaSnapshots, x), from_none], x), x), from_none], self.quota_snapshots) - if self.restricted_telemetry is not None: - result["restricted_telemetry"] = from_union([from_bool, from_none], self.restricted_telemetry) - if self.token_based_billing is not None: - result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) - return result + description: str | None = None + """Help text describing the field.""" -@dataclass -class MCPDiscoverResult: - """MCP servers discovered from user, workspace, plugin, and built-in sources.""" + enum_names: list[str] | None = None + """Optional display labels for each enum value, in the same order as `enum`.""" - servers: list[DiscoveredMCPServer] - """MCP servers discovered from all sources""" + title: str | None = None + """Human-readable label for the field.""" @staticmethod - def from_dict(obj: Any) -> 'MCPDiscoverResult': + def from_dict(obj: Any) -> 'UIElicitationStringEnumField': assert isinstance(obj, dict) - servers = from_list(DiscoveredMCPServer.from_dict, obj.get("servers")) - return MCPDiscoverResult(servers) + enum = from_list(from_str, obj.get("enum")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationStringEnumField(enum, type, default, description, enum_names, title) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_list(lambda x: to_class(DiscoveredMCPServer, x), self.servers) + result["enum"] = from_list(from_str, self.enum) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.enum_names is not None: + result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExtensionList: - """Extensions discovered for the session, with their current status.""" +class UIElicitationSchemaPropertyString: + """Free-text string field with optional length and format constraints.""" - extensions: list[Extension] - """Discovered extensions and their current status""" + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" - @staticmethod - def from_dict(obj: Any) -> 'ExtensionList': - assert isinstance(obj, dict) - extensions = from_list(Extension.from_dict, obj.get("extensions")) - return ExtensionList(extensions) + default: str | None = None + """Default value populated in the input when the form is first shown.""" - def to_dict(self) -> dict: - result: dict = {} - result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions) - return result + description: str | None = None + """Help text describing the field.""" -@dataclass -class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess: - """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` - type. - """ - extension_name: str - """Extension name.""" + format: UIElicitationSchemaPropertyStringFormat | None = None + """Optional format hint that constrains the accepted input.""" - kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind - """Approval covering an extension's request to access a permission-gated capability.""" + max_length: float | None = None + """Maximum number of characters allowed.""" + + min_length: float | None = None + """Minimum number of characters required.""" + + title: str | None = None + """Human-readable label for the field.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess': + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyString': assert isinstance(obj, dict) - extension_name = from_str(obj.get("extensionName")) - kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess(extension_name, kind) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) + max_length = from_union([from_float, from_none], obj.get("maxLength")) + min_length = from_union([from_float, from_none], obj.get("minLength")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyString(type, default, description, format, max_length, min_length, title) def to_dict(self) -> dict: result: dict = {} - result["extensionName"] = from_str(self.extension_name) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.format is not None: + result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) + if self.max_length is not None: + result["maxLength"] = from_union([to_float, from_none], self.max_length) + if self.min_length is not None: + result["minLength"] = from_union([to_float, from_none], self.min_length) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result @dataclass -class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess: - """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` - type. - """ - extension_name: str - """Extension name.""" - - kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind - """Approval covering an extension's request to access a permission-gated capability.""" +class UIElicitationStringOneOfField: + """Single-select string field where each option pairs a value with a display label.""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess': - assert isinstance(obj, dict) - extension_name = from_str(obj.get("extensionName")) - kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess(extension_name, kind) + one_of: list[UIElicitationStringOneOfFieldOneOf] + """Selectable options, each with a value and a display label.""" - def to_dict(self) -> dict: - result: dict = {} - result["extensionName"] = from_str(self.extension_name) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) - return result + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" -@dataclass -class UserToolSessionApprovalExtensionManagement: - """Schema for the `UserToolSessionApprovalExtensionManagement` type.""" + default: str | None = None + """Default value selected when the form is first shown.""" - kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind - """Extension management approval kind""" + description: str | None = None + """Help text describing the field.""" - operation: str | None = None - """Optional operation identifier""" + title: str | None = None + """Human-readable label for the field.""" @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalExtensionManagement': + def from_dict(obj: Any) -> 'UIElicitationStringOneOfField': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) - operation = from_union([from_str, from_none], obj.get("operation")) - return UserToolSessionApprovalExtensionManagement(kind, operation) + one_of = from_list(UIElicitationStringOneOfFieldOneOf.from_dict, obj.get("oneOf")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationStringOneOfField(one_of, type, default, description, title) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) + result["oneOf"] = from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), self.one_of) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result @dataclass -class UserToolSessionApprovalExtensionPermissionAccess: - """Schema for the `UserToolSessionApprovalExtensionPermissionAccess` type.""" +class UIElicitationResponse: + """The elicitation response (accept with form values, decline, or cancel)""" - extension_name: str - """Extension name""" + action: UIElicitationResponseAction + """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" - kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind - """Extension permission access approval kind""" + content: dict[str, float | bool | list[str] | str] | None = None + """The form values submitted by the user (present when action is 'accept')""" @staticmethod - def from_dict(obj: Any) -> 'UserToolSessionApprovalExtensionPermissionAccess': + def from_dict(obj: Any) -> 'UIElicitationResponse': assert isinstance(obj, dict) - extension_name = from_str(obj.get("extensionName")) - kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) - return UserToolSessionApprovalExtensionPermissionAccess(extension_name, kind) + action = UIElicitationResponseAction(obj.get("action")) + content = from_union([lambda x: from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], obj.get("content")) + return UIElicitationResponse(action, content) def to_dict(self) -> dict: result: dict = {} - result["extensionName"] = from_str(self.extension_name) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + result["action"] = to_enum(UIElicitationResponseAction, self.action) + if self.content is not None: + result["content"] = from_union([lambda x: from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], self.content) return result @dataclass -class ExternalToolTextResultForLlmContent: - """A content block within a tool result, which may be text, terminal output, image, audio, - or a resource - - Plain text content block - - Terminal/shell output content block with optional exit code and working directory - - Image content block with base64-encoded data - - Audio content block with base64-encoded data - - Resource link content block referencing an external resource - - Embedded resource content block with inline text or binary data - """ - type: ExternalToolTextResultForLlmContentType - """Content block type discriminator""" - - text: str | None = None - """The text content - - Terminal/shell output text - """ - cwd: str | None = None - """Working directory where the command was executed""" - - exit_code: int | None = None - """Process exit code, if the command has completed""" - - data: str | None = None - """Base64-encoded image data +class UIElicitationSchemaPropertyBoolean: + """Boolean field rendered as a yes/no toggle.""" - Base64-encoded audio data - """ - mime_type: str | None = None - """MIME type of the image (e.g., image/png, image/jpeg) + type: UIElicitationSchemaPropertyBooleanType + """Type discriminator. Always "boolean".""" - MIME type of the audio (e.g., audio/wav, audio/mpeg) + default: bool | None = None + """Default value selected when the form is first shown.""" - MIME type of the resource content - """ description: str | None = None - """Human-readable description of the resource""" - - icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None - """Icons associated with this resource""" - - name: str | None = None - """Resource name identifier""" - - size: int | None = None - """Size of the resource in bytes""" + """Help text describing the field.""" title: str | None = None - """Human-readable display title for the resource""" - - uri: str | None = None - """URI identifying the resource""" - - resource: ExternalToolTextResultForLlmContentResourceDetails | None = None - """The embedded resource contents, either text or base64-encoded binary""" + """Human-readable label for the field.""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContent': + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyBoolean': assert isinstance(obj, dict) - type = ExternalToolTextResultForLlmContentType(obj.get("type")) - text = from_union([from_str, from_none], obj.get("text")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - exit_code = from_union([from_int, from_none], obj.get("exitCode")) - data = from_union([from_str, from_none], obj.get("data")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) + type = UIElicitationSchemaPropertyBooleanType(obj.get("type")) + default = from_union([from_bool, from_none], obj.get("default")) description = from_union([from_str, from_none], obj.get("description")) - icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) - name = from_union([from_str, from_none], obj.get("name")) - size = from_union([from_int, from_none], obj.get("size")) title = from_union([from_str, from_none], obj.get("title")) - uri = from_union([from_str, from_none], obj.get("uri")) - resource = from_union([(lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x)), from_none], obj.get("resource")) - return ExternalToolTextResultForLlmContent(type, text, cwd, exit_code, data, mime_type, description, icons, name, size, title, uri, resource) + return UIElicitationSchemaPropertyBoolean(type, default, description, title) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(ExternalToolTextResultForLlmContentType, self.type) - if self.text is not None: - result["text"] = from_union([from_str, from_none], self.text) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.exit_code is not None: - result["exitCode"] = from_union([from_int, from_none], self.exit_code) - if self.data is not None: - result["data"] = from_union([from_str, from_none], self.data) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) + result["type"] = to_enum(UIElicitationSchemaPropertyBooleanType, self.type) + if self.default is not None: + result["default"] = from_union([from_bool, from_none], self.default) if self.description is not None: result["description"] = from_union([from_str, from_none], self.description) - if self.icons is not None: - result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.size is not None: - result["size"] = from_union([from_int, from_none], self.size) if self.title is not None: result["title"] = from_union([from_str, from_none], self.title) - if self.uri is not None: - result["uri"] = from_union([from_str, from_none], self.uri) - if self.resource is not None: - result["resource"] = from_union([lambda x: from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], x), from_none], self.resource) return result @dataclass -class ExternalToolTextResultForLlmContentResourceLink: - """Resource link content block referencing an external resource""" - - name: str - """Resource name identifier""" +class UIElicitationSchemaPropertyNumber: + """Numeric field accepting either a number or an integer.""" - type: ExternalToolTextResultForLlmContentResourceLinkType - """Content block type discriminator""" + type: UIElicitationSchemaPropertyNumberType + """Numeric type accepted by the field.""" - uri: str - """URI identifying the resource""" + default: float | None = None + """Default value populated in the input when the form is first shown.""" description: str | None = None - """Human-readable description of the resource""" - - icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None - """Icons associated with this resource""" + """Help text describing the field.""" - mime_type: str | None = None - """MIME type of the resource content""" + maximum: float | None = None + """Maximum allowed value (inclusive).""" - size: int | None = None - """Size of the resource in bytes""" + minimum: float | None = None + """Minimum allowed value (inclusive).""" title: str | None = None - """Human-readable display title for the resource""" + """Human-readable label for the field.""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLink': + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyNumber': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - type = ExternalToolTextResultForLlmContentResourceLinkType(obj.get("type")) - uri = from_str(obj.get("uri")) + type = UIElicitationSchemaPropertyNumberType(obj.get("type")) + default = from_union([from_float, from_none], obj.get("default")) description = from_union([from_str, from_none], obj.get("description")) - icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) - size = from_union([from_int, from_none], obj.get("size")) + maximum = from_union([from_float, from_none], obj.get("maximum")) + minimum = from_union([from_float, from_none], obj.get("minimum")) title = from_union([from_str, from_none], obj.get("title")) - return ExternalToolTextResultForLlmContentResourceLink(name, type, uri, description, icons, mime_type, size, title) + return UIElicitationSchemaPropertyNumber(type, default, description, maximum, minimum, title) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceLinkType, self.type) - result["uri"] = from_str(self.uri) + result["type"] = to_enum(UIElicitationSchemaPropertyNumberType, self.type) + if self.default is not None: + result["default"] = from_union([to_float, from_none], self.default) if self.description is not None: result["description"] = from_union([from_str, from_none], self.description) - if self.icons is not None: - result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) - if self.size is not None: - result["size"] = from_union([from_int, from_none], self.size) + if self.maximum is not None: + result["maximum"] = from_union([to_float, from_none], self.maximum) + if self.minimum is not None: + result["minimum"] = from_union([to_float, from_none], self.minimum) if self.title is not None: result["title"] = from_union([from_str, from_none], self.title) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class InstalledPluginSource: - """Schema for the `InstalledPluginSourceGithub` type. +class UsageMetricsModelMetric: + """Schema for the `UsageMetricsModelMetric` type.""" - Schema for the `InstalledPluginSourceUrl` type. + requests: UsageMetricsModelMetricRequests + """Request count and cost metrics for this model""" - Schema for the `InstalledPluginSourceLocal` type. - """ - source: PurpleSource - """Constant value. Always "github". + usage: UsageMetricsModelMetricUsage + """Token usage metrics for this model""" - Constant value. Always "url". + token_details: dict[str, UsageMetricsModelMetricTokenDetail] | None = None + """Token count details per type""" - Constant value. Always "local". - """ - path: str | None = None - ref: str | None = None - repo: str | None = None - url: str | None = None + total_nano_aiu: int | None = None + """Accumulated nano-AI units cost for this model""" @staticmethod - def from_dict(obj: Any) -> 'InstalledPluginSource': + def from_dict(obj: Any) -> 'UsageMetricsModelMetric': assert isinstance(obj, dict) - source = PurpleSource(obj.get("source")) - path = from_union([from_str, from_none], obj.get("path")) - ref = from_union([from_str, from_none], obj.get("ref")) - repo = from_union([from_str, from_none], obj.get("repo")) - url = from_union([from_str, from_none], obj.get("url")) - return InstalledPluginSource(source, path, ref, repo, url) + requests = UsageMetricsModelMetricRequests.from_dict(obj.get("requests")) + usage = UsageMetricsModelMetricUsage.from_dict(obj.get("usage")) + token_details = from_union([lambda x: from_dict(UsageMetricsModelMetricTokenDetail.from_dict, x), from_none], obj.get("tokenDetails")) + total_nano_aiu = from_union([from_int, from_none], obj.get("totalNanoAiu")) + return UsageMetricsModelMetric(requests, usage, token_details, total_nano_aiu) def to_dict(self) -> dict: result: dict = {} - result["source"] = to_enum(PurpleSource, self.source) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.ref is not None: - result["ref"] = from_union([from_str, from_none], self.ref) - if self.repo is not None: - result["repo"] = from_union([from_str, from_none], self.repo) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["requests"] = to_class(UsageMetricsModelMetricRequests, self.requests) + result["usage"] = to_class(UsageMetricsModelMetricUsage, self.usage) + if self.token_details is not None: + result["tokenDetails"] = from_union([lambda x: from_dict(lambda x: to_class(UsageMetricsModelMetricTokenDetail, x), x), from_none], self.token_details) + if self.total_nano_aiu is not None: + result["totalNanoAiu"] = from_union([from_int, from_none], self.total_nano_aiu) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionInstalledPluginSource: - """Schema for the `SessionInstalledPluginSourceGithub` type. - - Schema for the `SessionInstalledPluginSourceUrl` type. - - Schema for the `SessionInstalledPluginSourceLocal` type. - """ - source: PurpleSource - """Constant value. Always "github". - - Constant value. Always "url". - - Constant value. Always "local". - """ - path: str | None = None - ref: str | None = None - repo: str | None = None - url: str | None = None +class Workspace: + id: UUID + branch: str | None = None + chronicle_sync_dismissed: bool | None = None + created_at: datetime | None = None + cwd: str | None = None + git_root: str | None = None + host_type: HostType | None = None + mc_last_event_id: str | None = None + mc_session_id: str | None = None + mc_task_id: str | None = None + name: str | None = None + remote_steerable: bool | None = None + repository: str | None = None + summary_count: int | None = None + updated_at: datetime | None = None + user_named: bool | None = None @staticmethod - def from_dict(obj: Any) -> 'SessionInstalledPluginSource': + def from_dict(obj: Any) -> 'Workspace': assert isinstance(obj, dict) - source = PurpleSource(obj.get("source")) - path = from_union([from_str, from_none], obj.get("path")) - ref = from_union([from_str, from_none], obj.get("ref")) - repo = from_union([from_str, from_none], obj.get("repo")) - url = from_union([from_str, from_none], obj.get("url")) - return SessionInstalledPluginSource(source, path, ref, repo, url) + id = UUID(obj.get("id")) + branch = from_union([from_str, from_none], obj.get("branch")) + chronicle_sync_dismissed = from_union([from_bool, from_none], obj.get("chronicle_sync_dismissed")) + created_at = from_union([from_datetime, from_none], obj.get("created_at")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + git_root = from_union([from_str, from_none], obj.get("git_root")) + host_type = from_union([HostType, from_none], obj.get("host_type")) + mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) + mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) + mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) + name = from_union([from_str, from_none], obj.get("name")) + remote_steerable = from_union([from_bool, from_none], obj.get("remote_steerable")) + repository = from_union([from_str, from_none], obj.get("repository")) + summary_count = from_union([from_int, from_none], obj.get("summary_count")) + updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) + user_named = from_union([from_bool, from_none], obj.get("user_named")) + return Workspace(id, branch, chronicle_sync_dismissed, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, remote_steerable, repository, summary_count, updated_at, user_named) def to_dict(self) -> dict: result: dict = {} - result["source"] = to_enum(PurpleSource, self.source) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.ref is not None: - result["ref"] = from_union([from_str, from_none], self.ref) - if self.repo is not None: - result["repo"] = from_union([from_str, from_none], self.repo) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["id"] = str(self.id) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.chronicle_sync_dismissed is not None: + result["chronicle_sync_dismissed"] = from_union([from_bool, from_none], self.chronicle_sync_dismissed) + if self.created_at is not None: + result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.git_root is not None: + result["git_root"] = from_union([from_str, from_none], self.git_root) + if self.host_type is not None: + result["host_type"] = from_union([lambda x: to_enum(HostType, x), from_none], self.host_type) + if self.mc_last_event_id is not None: + result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) + if self.mc_session_id is not None: + result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) + if self.mc_task_id is not None: + result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.remote_steerable is not None: + result["remote_steerable"] = from_union([from_bool, from_none], self.remote_steerable) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + if self.summary_count is not None: + result["summary_count"] = from_union([from_int, from_none], self.summary_count) + if self.updated_at is not None: + result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + if self.user_named is not None: + result["user_named"] = from_union([from_bool, from_none], self.user_named) return result @dataclass -class InstructionsGetSourcesResult: - """Instruction sources loaded for the session, in merge order.""" +class SlashCommandInfo: + """Schema for the `SlashCommandInfo` type.""" - sources: list[InstructionsSources] - """Instruction sources for the session""" + allow_during_agent_execution: bool + """Whether the command may run while an agent turn is active""" - @staticmethod - def from_dict(obj: Any) -> 'InstructionsGetSourcesResult': - assert isinstance(obj, dict) - sources = from_list(InstructionsSources.from_dict, obj.get("sources")) - return InstructionsGetSourcesResult(sources) + description: str + """Human-readable command description""" - def to_dict(self) -> dict: - result: dict = {} - result["sources"] = from_list(lambda x: to_class(InstructionsSources, x), self.sources) - return result + kind: SlashCommandKind + """Coarse command category for grouping and behavior: runtime built-in, skill-backed + command, or SDK/client-owned command + """ + name: str + """Canonical command name without a leading slash""" -@dataclass -class MCPConfigAddRequest: - """MCP server name and configuration to add to user configuration.""" + aliases: list[str] | None = None + """Canonical aliases without leading slashes""" - config: MCPServerConfig - """MCP server configuration (stdio process or remote HTTP/SSE)""" + experimental: bool | None = None + """Whether the command is experimental""" - name: str - """Unique name for the MCP server""" + input: SlashCommandInput | None = None + """Optional unstructured input hint""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigAddRequest': + def from_dict(obj: Any) -> 'SlashCommandInfo': assert isinstance(obj, dict) - config = MCPServerConfig.from_dict(obj.get("config")) + allow_during_agent_execution = from_bool(obj.get("allowDuringAgentExecution")) + description = from_str(obj.get("description")) + kind = SlashCommandKind(obj.get("kind")) name = from_str(obj.get("name")) - return MCPConfigAddRequest(config, name) + aliases = from_union([lambda x: from_list(from_str, x), from_none], obj.get("aliases")) + experimental = from_union([from_bool, from_none], obj.get("experimental")) + input = from_union([SlashCommandInput.from_dict, from_none], obj.get("input")) + return SlashCommandInfo(allow_during_agent_execution, description, kind, name, aliases, experimental, input) def to_dict(self) -> dict: result: dict = {} - result["config"] = to_class(MCPServerConfig, self.config) + result["allowDuringAgentExecution"] = from_bool(self.allow_during_agent_execution) + result["description"] = from_str(self.description) + result["kind"] = to_enum(SlashCommandKind, self.kind) result["name"] = from_str(self.name) + if self.aliases is not None: + result["aliases"] = from_union([lambda x: from_list(from_str, x), from_none], self.aliases) + if self.experimental is not None: + result["experimental"] = from_union([from_bool, from_none], self.experimental) + if self.input is not None: + result["input"] = from_union([lambda x: to_class(SlashCommandInput, x), from_none], self.input) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPConfigList: - """User-configured MCP servers, keyed by server name.""" +class RemoteSessionConnectionResult: + """Remote session connection result.""" - servers: dict[str, MCPServerConfig] - """All MCP servers from user config, keyed by name""" + metadata: ConnectedRemoteSessionMetadata + """Metadata for a connected remote session.""" + + session_id: str + """SDK session ID for the connected remote session.""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigList': + def from_dict(obj: Any) -> 'RemoteSessionConnectionResult': assert isinstance(obj, dict) - servers = from_dict(MCPServerConfig.from_dict, obj.get("servers")) - return MCPConfigList(servers) + metadata = ConnectedRemoteSessionMetadata.from_dict(obj.get("metadata")) + session_id = from_str(obj.get("sessionId")) + return RemoteSessionConnectionResult(metadata, session_id) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_dict(lambda x: to_class(MCPServerConfig, x), self.servers) + result["metadata"] = to_class(ConnectedRemoteSessionMetadata, self.metadata) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class MCPConfigUpdateRequest: - """MCP server name and replacement configuration to write to user configuration.""" - - config: MCPServerConfig - """MCP server configuration (stdio process or remote HTTP/SSE)""" +class MCPDiscoverResult: + """MCP servers discovered from user, workspace, plugin, and built-in sources.""" - name: str - """Name of the MCP server to update""" + servers: list[DiscoveredMCPServer] + """MCP servers discovered from all sources""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigUpdateRequest': + def from_dict(obj: Any) -> 'MCPDiscoverResult': assert isinstance(obj, dict) - config = MCPServerConfig.from_dict(obj.get("config")) - name = from_str(obj.get("name")) - return MCPConfigUpdateRequest(config, name) + servers = from_list(DiscoveredMCPServer.from_dict, obj.get("servers")) + return MCPDiscoverResult(servers) def to_dict(self) -> dict: result: dict = {} - result["config"] = to_class(MCPServerConfig, self.config) - result["name"] = from_str(self.name) + result["servers"] = from_list(lambda x: to_class(DiscoveredMCPServer, x), self.servers) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MetadataRecordContextChangeRequest: - """Updated working-directory/git context to record on the session.""" +class ExtensionList: + """Extensions discovered for the session, with their current status.""" - context: SessionWorkingDirectoryContext - """Updated working directory and git context. Emitted as the new payload of - `session.context_changed`. - """ + extensions: list[Extension] + """Discovered extensions and their current status""" @staticmethod - def from_dict(obj: Any) -> 'MetadataRecordContextChangeRequest': + def from_dict(obj: Any) -> 'ExtensionList': assert isinstance(obj, dict) - context = SessionWorkingDirectoryContext.from_dict(obj.get("context")) - return MetadataRecordContextChangeRequest(context) + extensions = from_list(Extension.from_dict, obj.get("extensions")) + return ExtensionList(extensions) def to_dict(self) -> dict: result: dict = {} - result["context"] = to_class(SessionWorkingDirectoryContext, self.context) + result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionMetadata: - """Schema for the `SessionMetadata` type.""" - - is_remote: bool - """True for remote (GitHub) sessions; false for local""" - - modified_time: str - """Last-modified time of the session's persisted state, as ISO 8601""" - - session_id: str - """Stable session identifier""" - - start_time: str - """Session creation time as an ISO 8601 timestamp""" - - context: SessionContext | None = None - """Schema for the `SessionContext` type.""" - - mc_task_id: str | None = None - """GitHub task ID, when this local session is bound to one. Only present for local sessions - exported to remote control. +class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess: + """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` + type. """ - name: str | None = None - """Optional human-friendly name set via /rename""" + extension_name: str + """Extension name.""" - summary: str | None = None - """Short summary of the session, when one has been derived""" + kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind + """Approval covering an extension's request to access a permission-gated capability.""" @staticmethod - def from_dict(obj: Any) -> 'SessionMetadata': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess': assert isinstance(obj, dict) - is_remote = from_bool(obj.get("isRemote")) - modified_time = from_str(obj.get("modifiedTime")) - session_id = from_str(obj.get("sessionId")) - start_time = from_str(obj.get("startTime")) - context = from_union([SessionContext.from_dict, from_none], obj.get("context")) - mc_task_id = from_union([from_str, from_none], obj.get("mcTaskId")) - name = from_union([from_str, from_none], obj.get("name")) - summary = from_union([from_str, from_none], obj.get("summary")) - return SessionMetadata(is_remote, modified_time, session_id, start_time, context, mc_task_id, name, summary) + extension_name = from_str(obj.get("extensionName")) + kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess(extension_name, kind) def to_dict(self) -> dict: result: dict = {} - result["isRemote"] = from_bool(self.is_remote) - result["modifiedTime"] = from_str(self.modified_time) - result["sessionId"] = from_str(self.session_id) - result["startTime"] = from_str(self.start_time) - if self.context is not None: - result["context"] = from_union([lambda x: to_class(SessionContext, x), from_none], self.context) - if self.mc_task_id is not None: - result["mcTaskId"] = from_union([from_str, from_none], self.mc_task_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.summary is not None: - result["summary"] = from_union([from_str, from_none], self.summary) + result["extensionName"] = from_str(self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsGetLastForContextRequest: - """Optional working-directory context used to score session relevance.""" - - context: SessionContext | None = None - """Optional working-directory context used to score session relevance. When omitted the - most-recently-modified session wins. +class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess: + """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` + type. """ + extension_name: str + """Extension name.""" + + kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind + """Approval covering an extension's request to access a permission-gated capability.""" @staticmethod - def from_dict(obj: Any) -> 'SessionsGetLastForContextRequest': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess': assert isinstance(obj, dict) - context = from_union([SessionContext.from_dict, from_none], obj.get("context")) - return SessionsGetLastForContextRequest(context) + extension_name = from_str(obj.get("extensionName")) + kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess(extension_name, kind) def to_dict(self) -> dict: result: dict = {} - if self.context is not None: - result["context"] = from_union([lambda x: to_class(SessionContext, x), from_none], self.context) + result["extensionName"] = from_str(self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) return result @dataclass -class PermissionPathsConfig: - """If specified, replaces the session's path-permission policy. The runtime constructs the - appropriate PathManager based on these inputs (rooted at the session's working - directory). Omit to leave the current path policy unchanged. - """ - additional_directories: list[str] | None = None - """Additional directories to allow tool access to (in addition to the session's working - directory). When `unrestricted` is true, these are still pre-populated on the - UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention - completion). - """ - include_temp_directory: bool | None = None - """Whether to include the system temp directory in the allowed list (defaults to true). - Ignored when `unrestricted` is true. - """ - unrestricted: bool | None = None - """If true, the runtime allows access to all paths without prompting. Equivalent to - constructing an UnrestrictedPathManager. - """ - workspace_path: str | None = None - """Workspace root path (special-cased to be allowed even before the directory exists). - Ignored when `unrestricted` is true. - """ +class ExternalToolTextResultForLlmContent: + """A content block within a tool result, which may be text, terminal output, image, audio, + or a resource - @staticmethod - def from_dict(obj: Any) -> 'PermissionPathsConfig': - assert isinstance(obj, dict) - additional_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("additionalDirectories")) - include_temp_directory = from_union([from_bool, from_none], obj.get("includeTempDirectory")) - unrestricted = from_union([from_bool, from_none], obj.get("unrestricted")) - workspace_path = from_union([from_str, from_none], obj.get("workspacePath")) - return PermissionPathsConfig(additional_directories, include_temp_directory, unrestricted, workspace_path) + Plain text content block - def to_dict(self) -> dict: - result: dict = {} - if self.additional_directories is not None: - result["additionalDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.additional_directories) - if self.include_temp_directory is not None: - result["includeTempDirectory"] = from_union([from_bool, from_none], self.include_temp_directory) - if self.unrestricted is not None: - result["unrestricted"] = from_union([from_bool, from_none], self.unrestricted) - if self.workspace_path is not None: - result["workspacePath"] = from_union([from_str, from_none], self.workspace_path) - return result + Terminal/shell output content block with optional exit code and working directory -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class WorkspaceSummary: - """Public-facing projection of workspace metadata for SDK / TUI consumers""" + Image content block with base64-encoded data - id: UUID - """Workspace identifier (1:1 with sessionId)""" + Audio content block with base64-encoded data + + Resource link content block referencing an external resource + + Embedded resource content block with inline text or binary data + """ + type: ExternalToolTextResultForLlmContentType + """Content block type discriminator""" + + text: str | None = None + """The text content + + Terminal/shell output text + """ + cwd: str | None = None + """Working directory where the command was executed""" + + exit_code: float | None = None + """Process exit code, if the command has completed""" - branch: str | None = None - """Branch checked out at session start, if any""" + data: str | None = None + """Base64-encoded image data - created_at: datetime | None = None - """ISO 8601 timestamp when the workspace was created""" + Base64-encoded audio data + """ + mime_type: str | None = None + """MIME type of the image (e.g., image/png, image/jpeg) - cwd: str | None = None - """Current working directory at session start""" + MIME type of the audio (e.g., audio/wav, audio/mpeg) - git_root: str | None = None - """Resolved git root for cwd, if any""" + MIME type of the resource content + """ + description: str | None = None + """Human-readable description of the resource""" - host_type: SessionContextHostType | None = None - """Repository host type, if known""" + icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None + """Icons associated with this resource""" name: str | None = None - """Display name for the session, if set""" + """Resource name identifier""" - repository: str | None = None - """Repository identifier in 'owner/repo' or 'org/project/repo' format, if any""" + size: float | None = None + """Size of the resource in bytes""" - updated_at: datetime | None = None - """ISO 8601 timestamp when the workspace was last updated""" + title: str | None = None + """Human-readable display title for the resource""" + + uri: str | None = None + """URI identifying the resource""" + + resource: ExternalToolTextResultForLlmContentResourceDetails | None = None + """The embedded resource contents, either text or base64-encoded binary""" @staticmethod - def from_dict(obj: Any) -> 'WorkspaceSummary': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContent': assert isinstance(obj, dict) - id = UUID(obj.get("id")) - branch = from_union([from_str, from_none], obj.get("branch")) - created_at = from_union([from_datetime, from_none], obj.get("created_at")) + type = ExternalToolTextResultForLlmContentType(obj.get("type")) + text = from_union([from_str, from_none], obj.get("text")) cwd = from_union([from_str, from_none], obj.get("cwd")) - git_root = from_union([from_str, from_none], obj.get("git_root")) - host_type = from_union([SessionContextHostType, from_none], obj.get("host_type")) + exit_code = from_union([from_float, from_none], obj.get("exitCode")) + data = from_union([from_str, from_none], obj.get("data")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + description = from_union([from_str, from_none], obj.get("description")) + icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) name = from_union([from_str, from_none], obj.get("name")) - repository = from_union([from_str, from_none], obj.get("repository")) - updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) - return WorkspaceSummary(id, branch, created_at, cwd, git_root, host_type, name, repository, updated_at) + size = from_union([from_float, from_none], obj.get("size")) + title = from_union([from_str, from_none], obj.get("title")) + uri = from_union([from_str, from_none], obj.get("uri")) + resource = from_union([(lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x)), from_none], obj.get("resource")) + return ExternalToolTextResultForLlmContent(type, text, cwd, exit_code, data, mime_type, description, icons, name, size, title, uri, resource) def to_dict(self) -> dict: result: dict = {} - result["id"] = str(self.id) - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.created_at is not None: - result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) + result["type"] = to_enum(ExternalToolTextResultForLlmContentType, self.type) + if self.text is not None: + result["text"] = from_union([from_str, from_none], self.text) if self.cwd is not None: result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.git_root is not None: - result["git_root"] = from_union([from_str, from_none], self.git_root) - if self.host_type is not None: - result["host_type"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) + if self.exit_code is not None: + result["exitCode"] = from_union([to_float, from_none], self.exit_code) + if self.data is not None: + result["data"] = from_union([from_str, from_none], self.data) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.icons is not None: + result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) if self.name is not None: result["name"] = from_union([from_str, from_none], self.name) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) - if self.updated_at is not None: - result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + if self.size is not None: + result["size"] = from_union([to_float, from_none], self.size) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + if self.uri is not None: + result["uri"] = from_union([from_str, from_none], self.uri) + if self.resource is not None: + result["resource"] = from_union([lambda x: from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], x), from_none], self.resource) return result @dataclass -class WorkspacesGetWorkspaceResult: - """Current workspace metadata for the session, including its absolute filesystem path when - available. - """ - path: str | None = None - """Absolute filesystem path to the workspace directory. Omitted when the session has no - workspace (e.g. remote sessions). - """ - workspace: Workspace | None = None - """Current workspace metadata, or null if not available""" - - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': - assert isinstance(obj, dict) - path = from_union([from_str, from_none], obj.get("path")) - workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) - return WorkspacesGetWorkspaceResult(path, workspace) +class ExternalToolTextResultForLlmContentResourceLink: + """Resource link content block referencing an external resource""" - def to_dict(self) -> dict: - result: dict = {} - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) - return result + name: str + """Resource name identifier""" -@dataclass -class WorkspacesListCheckpointsResult: - """Workspace checkpoints in chronological order; empty when the workspace is not enabled.""" + type: ExternalToolTextResultForLlmContentResourceLinkType + """Content block type discriminator""" - checkpoints: list[WorkspacesCheckpoints] - """Workspace checkpoints in chronological order. Empty when workspace is not enabled.""" + uri: str + """URI identifying the resource""" - @staticmethod - def from_dict(obj: Any) -> 'WorkspacesListCheckpointsResult': - assert isinstance(obj, dict) - checkpoints = from_list(WorkspacesCheckpoints.from_dict, obj.get("checkpoints")) - return WorkspacesListCheckpointsResult(checkpoints) + description: str | None = None + """Human-readable description of the resource""" - def to_dict(self) -> dict: - result: dict = {} - result["checkpoints"] = from_list(lambda x: to_class(WorkspacesCheckpoints, x), self.checkpoints) - return result + icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None + """Icons associated with this resource""" -@dataclass -class ModelCapabilitiesOverride: - """Override individual model capabilities resolved by the runtime""" + mime_type: str | None = None + """MIME type of the resource content""" - limits: ModelCapabilitiesOverrideLimits | None = None - """Token limits for prompts, outputs, and context window""" + size: float | None = None + """Size of the resource in bytes""" - supports: ModelCapabilitiesOverrideSupports | None = None - """Feature flags indicating what the model supports""" + title: str | None = None + """Human-readable display title for the resource""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesOverride': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLink': assert isinstance(obj, dict) - limits = from_union([ModelCapabilitiesOverrideLimits.from_dict, from_none], obj.get("limits")) - supports = from_union([ModelCapabilitiesOverrideSupports.from_dict, from_none], obj.get("supports")) - return ModelCapabilitiesOverride(limits, supports) + name = from_str(obj.get("name")) + type = ExternalToolTextResultForLlmContentResourceLinkType(obj.get("type")) + uri = from_str(obj.get("uri")) + description = from_union([from_str, from_none], obj.get("description")) + icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + size = from_union([from_float, from_none], obj.get("size")) + title = from_union([from_str, from_none], obj.get("title")) + return ExternalToolTextResultForLlmContentResourceLink(name, type, uri, description, icons, mime_type, size, title) def to_dict(self) -> dict: result: dict = {} - if self.limits is not None: - result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimits, x), from_none], self.limits) - if self.supports is not None: - result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideSupports, x), from_none], self.supports) + result["name"] = from_str(self.name) + result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceLinkType, self.type) + result["uri"] = from_str(self.uri) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.icons is not None: + result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + if self.size is not None: + result["size"] = from_union([to_float, from_none], self.size) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) return result @dataclass -class PermissionsConfigureAdditionalContentExclusionPolicy: - """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicy` type.""" - - last_updated_at: float | str - rules: list[PermissionsConfigureAdditionalContentExclusionPolicyRule] - scope: PermissionsConfigureAdditionalContentExclusionPolicyScope - """Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` - enumeration. - """ +class InstructionsGetSourcesResult: + """Instruction sources loaded for the session, in merge order.""" + + sources: list[InstructionsSources] + """Instruction sources for the session""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsConfigureAdditionalContentExclusionPolicy': + def from_dict(obj: Any) -> 'InstructionsGetSourcesResult': assert isinstance(obj, dict) - last_updated_at = from_union([from_float, from_str], obj.get("last_updated_at")) - rules = from_list(PermissionsConfigureAdditionalContentExclusionPolicyRule.from_dict, obj.get("rules")) - scope = PermissionsConfigureAdditionalContentExclusionPolicyScope(obj.get("scope")) - return PermissionsConfigureAdditionalContentExclusionPolicy(last_updated_at, rules, scope) + sources = from_list(InstructionsSources.from_dict, obj.get("sources")) + return InstructionsGetSourcesResult(sources) def to_dict(self) -> dict: result: dict = {} - result["last_updated_at"] = from_union([to_float, from_str], self.last_updated_at) - result["rules"] = from_list(lambda x: to_class(PermissionsConfigureAdditionalContentExclusionPolicyRule, x), self.rules) - result["scope"] = to_enum(PermissionsConfigureAdditionalContentExclusionPolicyScope, self.scope) + result["sources"] = from_list(lambda x: to_class(InstructionsSources, x), self.sources) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class QueuePendingItemsResult: - """Snapshot of the session's pending queued items and immediate-steering messages.""" +class MCPConfigAddRequest: + """MCP server name and configuration to add to user configuration.""" - items: list[QueuePendingItems] - """Pending queued items in submission order. Includes user messages, queued slash commands, - and queued model changes; omits internal system items. - """ - steering_messages: list[str] - """Display text for messages currently in the immediate steering queue (interjections sent - during a running turn). - """ + config: MCPServerConfig + """MCP server configuration (stdio process or remote HTTP/SSE)""" + + name: str + """Unique name for the MCP server""" @staticmethod - def from_dict(obj: Any) -> 'QueuePendingItemsResult': + def from_dict(obj: Any) -> 'MCPConfigAddRequest': assert isinstance(obj, dict) - items = from_list(QueuePendingItems.from_dict, obj.get("items")) - steering_messages = from_list(from_str, obj.get("steeringMessages")) - return QueuePendingItemsResult(items, steering_messages) + config = MCPServerConfig.from_dict(obj.get("config")) + name = from_str(obj.get("name")) + return MCPConfigAddRequest(config, name) def to_dict(self) -> dict: result: dict = {} - result["items"] = from_list(lambda x: to_class(QueuePendingItems, x), self.items) - result["steeringMessages"] = from_list(from_str, self.steering_messages) + result["config"] = to_class(MCPServerConfig, self.config) + result["name"] = from_str(self.name) return result @dataclass -class CommandsRespondToQueuedCommandRequest: - """Queued-command request ID and the result indicating whether the host executed it (and - whether to stop processing further queued commands). - """ - request_id: str - """Request ID from the `command.queued` event the host is responding to.""" +class MCPConfigList: + """User-configured MCP servers, keyed by server name.""" - result: QueuedCommandResult - """Result of the queued command execution.""" + servers: dict[str, MCPServerConfig] + """All MCP servers from user config, keyed by name""" @staticmethod - def from_dict(obj: Any) -> 'CommandsRespondToQueuedCommandRequest': + def from_dict(obj: Any) -> 'MCPConfigList': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = QueuedCommandResult.from_dict(obj.get("result")) - return CommandsRespondToQueuedCommandRequest(request_id, result) + servers = from_dict(MCPServerConfig.from_dict, obj.get("servers")) + return MCPConfigList(servers) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(QueuedCommandResult, self.result) + result["servers"] = from_dict(lambda x: to_class(MCPServerConfig, x), self.servers) return result @dataclass -class SendAttachment: - """A user message attachment — a file, directory, code selection, blob, or GitHub reference - - File attachment - - Directory attachment - - Code selection attachment from an editor - - GitHub issue, pull request, or discussion reference - - Blob attachment with inline base64-encoded data - """ - type: SendAttachmentType - """Attachment type discriminator""" - - display_name: str | None = None - """User-facing display name for the attachment - - User-facing display name for the selection - """ - line_range: SendAttachmentFileLineRange | None = None - """Optional line range to scope the attachment to a specific section of the file""" - - path: str | None = None - """Absolute file path - - Absolute directory path - """ - file_path: str | None = None - """Absolute path to the file containing the selection""" - - selection: SendAttachmentSelectionDetails | None = None - """Position range of the selection within the file""" - - text: str | None = None - """The selected text content""" - - number: int | None = None - """Issue, pull request, or discussion number""" - - reference_type: SendAttachmentGithubReferenceTypeEnum | None = None - """Type of GitHub reference""" - - state: str | None = None - """Current state of the referenced item (e.g., open, closed, merged)""" - - title: str | None = None - """Title of the referenced item""" - - url: str | None = None - """URL to the referenced item on GitHub""" +class MCPConfigUpdateRequest: + """MCP server name and replacement configuration to write to user configuration.""" - data: str | None = None - """Base64-encoded content""" + config: MCPServerConfig + """MCP server configuration (stdio process or remote HTTP/SSE)""" - mime_type: str | None = None - """MIME type of the inline data""" + name: str + """Name of the MCP server to update""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachment': + def from_dict(obj: Any) -> 'MCPConfigUpdateRequest': assert isinstance(obj, dict) - type = SendAttachmentType(obj.get("type")) - display_name = from_union([from_str, from_none], obj.get("displayName")) - line_range = from_union([SendAttachmentFileLineRange.from_dict, from_none], obj.get("lineRange")) - path = from_union([from_str, from_none], obj.get("path")) - file_path = from_union([from_str, from_none], obj.get("filePath")) - selection = from_union([SendAttachmentSelectionDetails.from_dict, from_none], obj.get("selection")) - text = from_union([from_str, from_none], obj.get("text")) - number = from_union([from_int, from_none], obj.get("number")) - reference_type = from_union([SendAttachmentGithubReferenceTypeEnum, from_none], obj.get("referenceType")) - state = from_union([from_str, from_none], obj.get("state")) - title = from_union([from_str, from_none], obj.get("title")) - url = from_union([from_str, from_none], obj.get("url")) - data = from_union([from_str, from_none], obj.get("data")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) - return SendAttachment(type, display_name, line_range, path, file_path, selection, text, number, reference_type, state, title, url, data, mime_type) - - def to_dict(self) -> dict: - result: dict = {} - result["type"] = to_enum(SendAttachmentType, self.type) - if self.display_name is not None: - result["displayName"] = from_union([from_str, from_none], self.display_name) - if self.line_range is not None: - result["lineRange"] = from_union([lambda x: to_class(SendAttachmentFileLineRange, x), from_none], self.line_range) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.file_path is not None: - result["filePath"] = from_union([from_str, from_none], self.file_path) - if self.selection is not None: - result["selection"] = from_union([lambda x: to_class(SendAttachmentSelectionDetails, x), from_none], self.selection) - if self.text is not None: - result["text"] = from_union([from_str, from_none], self.text) - if self.number is not None: - result["number"] = from_union([from_int, from_none], self.number) - if self.reference_type is not None: - result["referenceType"] = from_union([lambda x: to_enum(SendAttachmentGithubReferenceTypeEnum, x), from_none], self.reference_type) - if self.state is not None: - result["state"] = from_union([from_str, from_none], self.state) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) - if self.data is not None: - result["data"] = from_union([from_str, from_none], self.data) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) + config = MCPServerConfig.from_dict(obj.get("config")) + name = from_str(obj.get("name")) + return MCPConfigUpdateRequest(config, name) + + def to_dict(self) -> dict: + result: dict = {} + result["config"] = to_class(MCPServerConfig, self.config) + result["name"] = from_str(self.name) return result @dataclass -class SendAttachmentSelection: - """Code selection attachment from an editor""" +class ModelCapabilitiesOverride: + """Override individual model capabilities resolved by the runtime""" - display_name: str - """User-facing display name for the selection""" + limits: ModelCapabilitiesOverrideLimits | None = None + """Token limits for prompts, outputs, and context window""" + + supports: ModelCapabilitiesOverrideSupports | None = None + """Feature flags indicating what the model supports""" - file_path: str - """Absolute path to the file containing the selection""" + @staticmethod + def from_dict(obj: Any) -> 'ModelCapabilitiesOverride': + assert isinstance(obj, dict) + limits = from_union([ModelCapabilitiesOverrideLimits.from_dict, from_none], obj.get("limits")) + supports = from_union([ModelCapabilitiesOverrideSupports.from_dict, from_none], obj.get("supports")) + return ModelCapabilitiesOverride(limits, supports) - selection: SendAttachmentSelectionDetails - """Position range of the selection within the file""" + def to_dict(self) -> dict: + result: dict = {} + if self.limits is not None: + result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimits, x), from_none], self.limits) + if self.supports is not None: + result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideSupports, x), from_none], self.supports) + return result - text: str - """The selected text content""" +@dataclass +class CommandsRespondToQueuedCommandRequest: + """Queued command request ID and the result indicating whether the client handled it.""" - type: SendAttachmentSelectionType - """Attachment type discriminator""" + request_id: str + """Request ID from the queued command event""" + + result: QueuedCommandResult + """Result of the queued command execution""" @staticmethod - def from_dict(obj: Any) -> 'SendAttachmentSelection': + def from_dict(obj: Any) -> 'CommandsRespondToQueuedCommandRequest': assert isinstance(obj, dict) - display_name = from_str(obj.get("displayName")) - file_path = from_str(obj.get("filePath")) - selection = SendAttachmentSelectionDetails.from_dict(obj.get("selection")) - text = from_str(obj.get("text")) - type = SendAttachmentSelectionType(obj.get("type")) - return SendAttachmentSelection(display_name, file_path, selection, text, type) + request_id = from_str(obj.get("requestId")) + result = QueuedCommandResult.from_dict(obj.get("result")) + return CommandsRespondToQueuedCommandRequest(request_id, result) def to_dict(self) -> dict: result: dict = {} - result["displayName"] = from_str(self.display_name) - result["filePath"] = from_str(self.file_path) - result["selection"] = to_class(SendAttachmentSelectionDetails, self.selection) - result["text"] = from_str(self.text) - result["type"] = to_enum(SendAttachmentSelectionType, self.type) + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(QueuedCommandResult, self.result) return result @dataclass @@ -11027,8 +5953,8 @@ class SessionFSSqliteQueryResult: error: SessionFSError | None = None """Describes a filesystem error.""" - last_insert_rowid: int | None = None - """SQLite last_insert_rowid() value for INSERT.""" + last_insert_rowid: float | None = None + """Last inserted row ID (for INSERT)""" @staticmethod def from_dict(obj: Any) -> 'SessionFSSqliteQueryResult': @@ -11037,7 +5963,7 @@ def from_dict(obj: Any) -> 'SessionFSSqliteQueryResult': rows = from_list(lambda x: from_dict(lambda x: x, x), obj.get("rows")) rows_affected = from_int(obj.get("rowsAffected")) error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) - last_insert_rowid = from_union([from_int, from_none], obj.get("lastInsertRowid")) + last_insert_rowid = from_union([from_float, from_none], obj.get("lastInsertRowid")) return SessionFSSqliteQueryResult(columns, rows, rows_affected, error, last_insert_rowid) def to_dict(self) -> dict: @@ -11048,7 +5974,7 @@ def to_dict(self) -> dict: if self.error is not None: result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) if self.last_insert_rowid is not None: - result["lastInsertRowid"] = from_union([from_int, from_none], self.last_insert_rowid) + result["lastInsertRowid"] = from_union([to_float, from_none], self.last_insert_rowid) return result @dataclass @@ -11120,83 +6046,6 @@ def to_dict(self) -> dict: result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AgentGetCurrentResult: - """The currently selected custom agent, or null when using the default agent.""" - - agent: AgentInfo | None = None - """Currently selected custom agent, or null if using the default agent""" - - @staticmethod - def from_dict(obj: Any) -> 'AgentGetCurrentResult': - assert isinstance(obj, dict) - agent = from_union([AgentInfo.from_dict, from_none], obj.get("agent")) - return AgentGetCurrentResult(agent) - - def to_dict(self) -> dict: - result: dict = {} - if self.agent is not None: - result["agent"] = from_union([lambda x: to_class(AgentInfo, x), from_none], self.agent) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AgentList: - """Custom agents available to the session.""" - - agents: list[AgentInfo] - """Available custom agents""" - - @staticmethod - def from_dict(obj: Any) -> 'AgentList': - assert isinstance(obj, dict) - agents = from_list(AgentInfo.from_dict, obj.get("agents")) - return AgentList(agents) - - def to_dict(self) -> dict: - result: dict = {} - result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AgentReloadResult: - """Custom agents available to the session after reloading definitions from disk.""" - - agents: list[AgentInfo] - """Reloaded custom agents""" - - @staticmethod - def from_dict(obj: Any) -> 'AgentReloadResult': - assert isinstance(obj, dict) - agents = from_list(AgentInfo.from_dict, obj.get("agents")) - return AgentReloadResult(agents) - - def to_dict(self) -> dict: - result: dict = {} - result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AgentSelectResult: - """The newly selected custom agent.""" - - agent: AgentInfo - """The newly selected custom agent""" - - @staticmethod - def from_dict(obj: Any) -> 'AgentSelectResult': - assert isinstance(obj, dict) - agent = AgentInfo.from_dict(obj.get("agent")) - return AgentSelectResult(agent) - - def to_dict(self) -> dict: - result: dict = {} - result["agent"] = to_class(AgentInfo, self.agent) - return result - @dataclass class SlashCommandInvocationResult: """Result of invoking the slash command (text output, prompt to send to the agent, or @@ -11275,28 +6124,6 @@ def to_dict(self) -> dict: result["message"] = from_union([from_str, from_none], self.message) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksGetProgressResult: - """Progress information for the task, or null when no task with that ID is tracked.""" - - progress: TaskProgressClass | None = None - """Progress information for the task, discriminated by type. Returns null when no task with - this ID is currently tracked. - """ - - @staticmethod - def from_dict(obj: Any) -> 'TasksGetProgressResult': - assert isinstance(obj, dict) - progress = from_union([TaskProgressClass.from_dict, from_none], obj.get("progress")) - return TasksGetProgressResult(progress) - - def to_dict(self) -> dict: - result: dict = {} - if self.progress is not None: - result["progress"] = from_union([lambda x: to_class(TaskProgressClass, x), from_none], self.progress) - return result - @dataclass class UIElicitationArrayAnyOfField: """Multi-select string field where each option pairs a value with a display label.""" @@ -11313,10 +6140,10 @@ class UIElicitationArrayAnyOfField: description: str | None = None """Help text describing the field.""" - max_items: int | None = None + max_items: float | None = None """Maximum number of items the user may select.""" - min_items: int | None = None + min_items: float | None = None """Minimum number of items the user must select.""" title: str | None = None @@ -11329,8 +6156,8 @@ def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfField': type = UIElicitationArrayAnyOfFieldType(obj.get("type")) default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) description = from_union([from_str, from_none], obj.get("description")) - max_items = from_union([from_int, from_none], obj.get("maxItems")) - min_items = from_union([from_int, from_none], obj.get("minItems")) + max_items = from_union([from_float, from_none], obj.get("maxItems")) + min_items = from_union([from_float, from_none], obj.get("minItems")) title = from_union([from_str, from_none], obj.get("title")) return UIElicitationArrayAnyOfField(items, type, default, description, max_items, min_items, title) @@ -11343,9 +6170,9 @@ def to_dict(self) -> dict: if self.description is not None: result["description"] = from_union([from_str, from_none], self.description) if self.max_items is not None: - result["maxItems"] = from_union([from_int, from_none], self.max_items) + result["maxItems"] = from_union([to_float, from_none], self.max_items) if self.min_items is not None: - result["minItems"] = from_union([from_int, from_none], self.min_items) + result["minItems"] = from_union([to_float, from_none], self.min_items) if self.title is not None: result["title"] = from_union([from_str, from_none], self.title) return result @@ -11366,10 +6193,10 @@ class UIElicitationArrayEnumField: description: str | None = None """Help text describing the field.""" - max_items: int | None = None + max_items: float | None = None """Maximum number of items the user may select.""" - min_items: int | None = None + min_items: float | None = None """Minimum number of items the user must select.""" title: str | None = None @@ -11382,8 +6209,8 @@ def from_dict(obj: Any) -> 'UIElicitationArrayEnumField': type = UIElicitationArrayAnyOfFieldType(obj.get("type")) default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) description = from_union([from_str, from_none], obj.get("description")) - max_items = from_union([from_int, from_none], obj.get("maxItems")) - min_items = from_union([from_int, from_none], obj.get("minItems")) + max_items = from_union([from_float, from_none], obj.get("maxItems")) + min_items = from_union([from_float, from_none], obj.get("minItems")) title = from_union([from_str, from_none], obj.get("title")) return UIElicitationArrayEnumField(items, type, default, description, max_items, min_items, title) @@ -11396,9 +6223,9 @@ def to_dict(self) -> dict: if self.description is not None: result["description"] = from_union([from_str, from_none], self.description) if self.max_items is not None: - result["maxItems"] = from_union([from_int, from_none], self.max_items) + result["maxItems"] = from_union([to_float, from_none], self.max_items) if self.min_items is not None: - result["minItems"] = from_union([from_int, from_none], self.min_items) + result["minItems"] = from_union([to_float, from_none], self.min_items) if self.title is not None: result["title"] = from_union([from_str, from_none], self.title) return result @@ -11455,19 +6282,19 @@ class UIElicitationSchemaProperty: items: UIElicitationArrayFieldItems | None = None """Schema applied to each item in the array.""" - max_items: int | None = None + max_items: float | None = None """Maximum number of items the user may select.""" - min_items: int | None = None + min_items: float | None = None """Minimum number of items the user must select.""" format: UIElicitationSchemaPropertyStringFormat | None = None """Optional format hint that constrains the accepted input.""" - max_length: int | None = None + max_length: float | None = None """Maximum number of characters allowed.""" - min_length: int | None = None + min_length: float | None = None """Minimum number of characters required.""" maximum: float | None = None @@ -11487,11 +6314,11 @@ def from_dict(obj: Any) -> 'UIElicitationSchemaProperty': title = from_union([from_str, from_none], obj.get("title")) one_of = from_union([lambda x: from_list(UIElicitationStringOneOfFieldOneOf.from_dict, x), from_none], obj.get("oneOf")) items = from_union([UIElicitationArrayFieldItems.from_dict, from_none], obj.get("items")) - max_items = from_union([from_int, from_none], obj.get("maxItems")) - min_items = from_union([from_int, from_none], obj.get("minItems")) + max_items = from_union([from_float, from_none], obj.get("maxItems")) + min_items = from_union([from_float, from_none], obj.get("minItems")) format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) - max_length = from_union([from_int, from_none], obj.get("maxLength")) - min_length = from_union([from_int, from_none], obj.get("minLength")) + max_length = from_union([from_float, from_none], obj.get("maxLength")) + min_length = from_union([from_float, from_none], obj.get("minLength")) maximum = from_union([from_float, from_none], obj.get("maximum")) minimum = from_union([from_float, from_none], obj.get("minimum")) return UIElicitationSchemaProperty(type, default, description, enum, enum_names, title, one_of, items, max_items, min_items, format, max_length, min_length, maximum, minimum) @@ -11514,15 +6341,15 @@ def to_dict(self) -> dict: if self.items is not None: result["items"] = from_union([lambda x: to_class(UIElicitationArrayFieldItems, x), from_none], self.items) if self.max_items is not None: - result["maxItems"] = from_union([from_int, from_none], self.max_items) + result["maxItems"] = from_union([to_float, from_none], self.max_items) if self.min_items is not None: - result["minItems"] = from_union([from_int, from_none], self.min_items) + result["minItems"] = from_union([to_float, from_none], self.min_items) if self.format is not None: result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) if self.max_length is not None: - result["maxLength"] = from_union([from_int, from_none], self.max_length) + result["maxLength"] = from_union([to_float, from_none], self.max_length) if self.min_length is not None: - result["minLength"] = from_union([from_int, from_none], self.min_length) + result["minLength"] = from_union([to_float, from_none], self.min_length) if self.maximum is not None: result["maximum"] = from_union([to_float, from_none], self.maximum) if self.minimum is not None: @@ -11553,29 +6380,6 @@ def to_dict(self) -> dict: result["result"] = to_class(UIElicitationResponse, self.result) return result -@dataclass -class UIHandlePendingExitPlanModeRequest: - """Request ID of a pending `exit_plan_mode.requested` event and the user's response.""" - - request_id: str - """The unique request ID from the exit_plan_mode.requested event""" - - response: UIExitPlanModeResponse - """Schema for the `UIExitPlanModeResponse` type.""" - - @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingExitPlanModeRequest': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - response = UIExitPlanModeResponse.from_dict(obj.get("response")) - return UIHandlePendingExitPlanModeRequest(request_id, response) - - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - result["response"] = to_class(UIExitPlanModeResponse, self.response) - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UsageGetMetricsResult: @@ -11594,10 +6398,10 @@ class UsageGetMetricsResult: model_metrics: dict[str, UsageMetricsModelMetric] """Per-model token and request metrics, keyed by model identifier""" - session_start_time: datetime - """ISO 8601 timestamp when the session started""" + session_start_time: int + """Session start timestamp (epoch milliseconds)""" - total_api_duration_ms: int + total_api_duration_ms: float """Total time spent in model API calls (milliseconds)""" total_premium_request_cost: float @@ -11623,8 +6427,8 @@ def from_dict(obj: Any) -> 'UsageGetMetricsResult': last_call_input_tokens = from_int(obj.get("lastCallInputTokens")) last_call_output_tokens = from_int(obj.get("lastCallOutputTokens")) model_metrics = from_dict(UsageMetricsModelMetric.from_dict, obj.get("modelMetrics")) - session_start_time = from_datetime(obj.get("sessionStartTime")) - total_api_duration_ms = from_int(obj.get("totalApiDurationMs")) + session_start_time = from_int(obj.get("sessionStartTime")) + total_api_duration_ms = from_float(obj.get("totalApiDurationMs")) total_premium_request_cost = from_float(obj.get("totalPremiumRequestCost")) total_user_requests = from_int(obj.get("totalUserRequests")) current_model = from_union([from_str, from_none], obj.get("currentModel")) @@ -11638,8 +6442,8 @@ def to_dict(self) -> dict: result["lastCallInputTokens"] = from_int(self.last_call_input_tokens) result["lastCallOutputTokens"] = from_int(self.last_call_output_tokens) result["modelMetrics"] = from_dict(lambda x: to_class(UsageMetricsModelMetric, x), self.model_metrics) - result["sessionStartTime"] = self.session_start_time.isoformat() - result["totalApiDurationMs"] = from_int(self.total_api_duration_ms) + result["sessionStartTime"] = from_int(self.session_start_time) + result["totalApiDurationMs"] = to_float(self.total_api_duration_ms) result["totalPremiumRequestCost"] = to_float(self.total_premium_request_cost) result["totalUserRequests"] = from_int(self.total_user_requests) if self.current_model is not None: @@ -11651,301 +6455,44 @@ def to_dict(self) -> dict: return result @dataclass -class CommandList: - """Slash commands available in the session, after applying any include/exclude filters.""" - - commands: list[SlashCommandInfo] - """Commands available in this session""" - - @staticmethod - def from_dict(obj: Any) -> 'CommandList': - assert isinstance(obj, dict) - commands = from_list(SlashCommandInfo.from_dict, obj.get("commands")) - return CommandList(commands) - - def to_dict(self) -> dict: - result: dict = {} - result["commands"] = from_list(lambda x: to_class(SlashCommandInfo, x), self.commands) - return result - -@dataclass -class APIKeyAuthInfo: - """Schema for the `ApiKeyAuthInfo` type.""" - - api_key: str - """The API key. Treat as a secret.""" - - host: str - """Authentication host.""" - - type: APIKeyAuthInfoType - """API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style).""" - - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - - @staticmethod - def from_dict(obj: Any) -> 'APIKeyAuthInfo': - assert isinstance(obj, dict) - api_key = from_str(obj.get("apiKey")) - host = from_str(obj.get("host")) - type = APIKeyAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - return APIKeyAuthInfo(api_key, host, type, copilot_user) - - def to_dict(self) -> dict: - result: dict = {} - result["apiKey"] = from_str(self.api_key) - result["host"] = from_str(self.host) - result["type"] = to_enum(APIKeyAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - return result - -@dataclass -class CopilotAPITokenAuthInfo: - """Schema for the `CopilotApiTokenAuthInfo` type.""" - - host: Host - """Authentication host (always the public GitHub host).""" - - type: CopilotAPITokenAuthInfoType - """Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` - environment-variable pair. The token itself is read from the environment by the runtime, - not carried in this struct. - """ - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - - @staticmethod - def from_dict(obj: Any) -> 'CopilotAPITokenAuthInfo': - assert isinstance(obj, dict) - host = Host(obj.get("host")) - type = CopilotAPITokenAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - return CopilotAPITokenAuthInfo(host, type, copilot_user) - - def to_dict(self) -> dict: - result: dict = {} - result["host"] = to_enum(Host, self.host) - result["type"] = to_enum(CopilotAPITokenAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - return result - -@dataclass -class EnvAuthInfo: - """Schema for the `EnvAuthInfo` type.""" - - env_var: str - """Name of the environment variable the token was sourced from.""" - - host: str - """Authentication host (e.g. https://github.com or a GHES host).""" - - token: str - """The token value itself. Treat as a secret.""" - - type: EnvAuthInfoType - """Personal access token (PAT) or server-to-server token sourced from an environment - variable. - """ - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - login: str | None = None - """User login associated with the token. Undefined for server-to-server tokens (those - starting with `ghs_`). - """ - - @staticmethod - def from_dict(obj: Any) -> 'EnvAuthInfo': - assert isinstance(obj, dict) - env_var = from_str(obj.get("envVar")) - host = from_str(obj.get("host")) - token = from_str(obj.get("token")) - type = EnvAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - login = from_union([from_str, from_none], obj.get("login")) - return EnvAuthInfo(env_var, host, token, type, copilot_user, login) - - def to_dict(self) -> dict: - result: dict = {} - result["envVar"] = from_str(self.env_var) - result["host"] = from_str(self.host) - result["token"] = from_str(self.token) - result["type"] = to_enum(EnvAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - if self.login is not None: - result["login"] = from_union([from_str, from_none], self.login) - return result - -@dataclass -class GhCLIAuthInfo: - """Schema for the `GhCliAuthInfo` type.""" - - host: str - """Authentication host.""" - - login: str - """User login as reported by `gh auth status`.""" - - token: str - """The token returned by `gh auth token`. Treat as a secret.""" - - type: GhCLIAuthInfoType - """Authentication via the `gh` CLI's saved credentials.""" - - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - - @staticmethod - def from_dict(obj: Any) -> 'GhCLIAuthInfo': - assert isinstance(obj, dict) - host = from_str(obj.get("host")) - login = from_str(obj.get("login")) - token = from_str(obj.get("token")) - type = GhCLIAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - return GhCLIAuthInfo(host, login, token, type, copilot_user) - - def to_dict(self) -> dict: - result: dict = {} - result["host"] = from_str(self.host) - result["login"] = from_str(self.login) - result["token"] = from_str(self.token) - result["type"] = to_enum(GhCLIAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - return result - -@dataclass -class HMACAuthInfo: - """Schema for the `HMACAuthInfo` type.""" - - hmac: str - """HMAC secret used to sign requests.""" - - host: Host - """Authentication host. HMAC auth always targets the public GitHub host.""" - - type: HMACAuthInfoType - """HMAC-based authentication used by GitHub-internal services.""" - - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - - @staticmethod - def from_dict(obj: Any) -> 'HMACAuthInfo': - assert isinstance(obj, dict) - hmac = from_str(obj.get("hmac")) - host = Host(obj.get("host")) - type = HMACAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - return HMACAuthInfo(hmac, host, type, copilot_user) - - def to_dict(self) -> dict: - result: dict = {} - result["hmac"] = from_str(self.hmac) - result["host"] = to_enum(Host, self.host) - result["type"] = to_enum(HMACAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - return result - -@dataclass -class TokenAuthInfo: - """Schema for the `TokenAuthInfo` type.""" - - host: str - """Authentication host.""" - - token: str - """The token value itself. Treat as a secret.""" - - type: TokenAuthInfoType - """SDK-side token authentication; the host configured the token directly via the SDK.""" +class WorkspacesGetWorkspaceResult: + """Current workspace metadata for the session, or null when not available.""" - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ + workspace: Workspace | None = None + """Current workspace metadata, or null if not available""" @staticmethod - def from_dict(obj: Any) -> 'TokenAuthInfo': + def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': assert isinstance(obj, dict) - host = from_str(obj.get("host")) - token = from_str(obj.get("token")) - type = TokenAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - return TokenAuthInfo(host, token, type, copilot_user) + workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) + return WorkspacesGetWorkspaceResult(workspace) def to_dict(self) -> dict: result: dict = {} - result["host"] = from_str(self.host) - result["token"] = from_str(self.token) - result["type"] = to_enum(TokenAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) return result @dataclass -class UserAuthInfo: - """Schema for the `UserAuthInfo` type.""" - - host: str - """Authentication host.""" - - login: str - """OAuth user login.""" +class CommandList: + """Slash commands available in the session, after applying any include/exclude filters.""" - type: UserAuthInfoType - """OAuth user authentication. The token itself is held in the runtime's secret token store - (keyed by host+login) and is NOT carried in this struct. - """ - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ + commands: list[SlashCommandInfo] + """Commands available in this session""" @staticmethod - def from_dict(obj: Any) -> 'UserAuthInfo': + def from_dict(obj: Any) -> 'CommandList': assert isinstance(obj, dict) - host = from_str(obj.get("host")) - login = from_str(obj.get("login")) - type = UserAuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - return UserAuthInfo(host, login, type, copilot_user) + commands = from_list(SlashCommandInfo.from_dict, obj.get("commands")) + return CommandList(commands) def to_dict(self) -> dict: result: dict = {} - result["host"] = from_str(self.host) - result["login"] = from_str(self.login) - result["type"] = to_enum(UserAuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + result["commands"] = from_list(lambda x: to_class(SlashCommandInfo, x), self.commands) return result @dataclass class PermissionDecisionApproveForLocationApproval: - """Approval to persist for this location + """The approval to persist for this location Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type. @@ -12031,7 +6578,7 @@ def to_dict(self) -> dict: @dataclass class PermissionDecisionApproveForIonApproval: - """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) + """The approval to add as a session-scoped rule Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type. @@ -12052,7 +6599,7 @@ class PermissionDecisionApproveForIonApproval: Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` type. - Approval to persist for this location + The approval to persist for this location Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type. @@ -12072,15 +6619,8 @@ class PermissionDecisionApproveForIonApproval: Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` type. - - The approval to add as a session-scoped rule - - The approval to persist for this location """ - command_identifiers: list[str] | None = None - """Command identifiers covered by this approval.""" - - kind: ApprovalKind | None = None + kind: ApprovalKind """Approval scoped to specific command identifiers. Approval covering read-only filesystem operations. @@ -12099,6 +6639,9 @@ class PermissionDecisionApproveForIonApproval: Approval covering an extension's request to access a permission-gated capability. """ + command_identifiers: list[str] | None = None + """Command identifiers covered by this approval.""" + server_name: str | None = None """MCP server name.""" @@ -12114,26 +6657,22 @@ class PermissionDecisionApproveForIonApproval: extension_name: str | None = None """Extension name.""" - external_ref_marker_external_ref_user_tool_session_approval: str | None = None - @staticmethod def from_dict(obj: Any) -> 'PermissionDecisionApproveForIonApproval': assert isinstance(obj, dict) + kind = ApprovalKind(obj.get("kind")) command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) - kind = from_union([ApprovalKind, from_none], obj.get("kind")) server_name = from_union([from_str, from_none], obj.get("serverName")) tool_name = from_union([from_none, from_str], obj.get("toolName")) operation = from_union([from_str, from_none], obj.get("operation")) extension_name = from_union([from_str, from_none], obj.get("extensionName")) - external_ref_marker_external_ref_user_tool_session_approval = from_union([from_str, from_none], obj.get("__externalRefMarker___ExternalRef_UserToolSessionApproval")) - return PermissionDecisionApproveForIonApproval(command_identifiers, kind, server_name, tool_name, operation, extension_name, external_ref_marker_external_ref_user_tool_session_approval) + return PermissionDecisionApproveForIonApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) def to_dict(self) -> dict: result: dict = {} + result["kind"] = to_enum(ApprovalKind, self.kind) if self.command_identifiers is not None: result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) - if self.kind is not None: - result["kind"] = from_union([lambda x: to_enum(ApprovalKind, x), from_none], self.kind) if self.server_name is not None: result["serverName"] = from_union([from_str, from_none], self.server_name) if self.tool_name is not None: @@ -12142,13 +6681,11 @@ def to_dict(self) -> dict: result["operation"] = from_union([from_str, from_none], self.operation) if self.extension_name is not None: result["extensionName"] = from_union([from_str, from_none], self.extension_name) - if self.external_ref_marker_external_ref_user_tool_session_approval is not None: - result["__externalRefMarker___ExternalRef_UserToolSessionApproval"] = from_union([from_str, from_none], self.external_ref_marker_external_ref_user_tool_session_approval) return result @dataclass class PermissionDecisionApproveForSessionApproval: - """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) + """The approval to add as a session-scoped rule Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type. @@ -12180,530 +6717,111 @@ class PermissionDecisionApproveForSessionApproval: Approval covering MCP sampling requests for a server. - Approval covering writes to long-term memory. - - Approval covering a custom tool. - - Approval covering extension lifecycle operations such as enable, disable, or reload. - - Approval covering an extension's request to access a permission-gated capability. - """ - command_identifiers: list[str] | None = None - """Command identifiers covered by this approval.""" - - server_name: str | None = None - """MCP server name.""" - - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server. - - Custom tool name. - """ - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. - """ - extension_name: str | None = None - """Extension name.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApproval': - assert isinstance(obj, dict) - kind = ApprovalKind(obj.get("kind")) - command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) - server_name = from_union([from_str, from_none], obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - operation = from_union([from_str, from_none], obj.get("operation")) - extension_name = from_union([from_str, from_none], obj.get("extensionName")) - return PermissionDecisionApproveForSessionApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(ApprovalKind, self.kind) - if self.command_identifiers is not None: - result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) - if self.server_name is not None: - result["serverName"] = from_union([from_str, from_none], self.server_name) - if self.tool_name is not None: - result["toolName"] = from_union([from_none, from_str], self.tool_name) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) - if self.extension_name is not None: - result["extensionName"] = from_union([from_str, from_none], self.extension_name) - return result - -@dataclass -class ExternalToolTextResultForLlm: - """Expanded external tool result payload""" - - text_result_for_llm: str - """Text result returned to the model""" - - binary_results_for_llm: list[ExternalToolTextResultForLlmBinaryResultsForLlm] | None = None - """Base64-encoded binary results returned to the model""" - - contents: list[ExternalToolTextResultForLlmContent] | None = None - """Structured content blocks from the tool""" - - error: str | None = None - """Optional error message for failed executions""" - - result_type: str | None = None - """Execution outcome classification. Optional for back-compat; normalized to 'success' (or - 'failure' when error is present) when missing or unrecognized. - """ - session_log: str | None = None - """Detailed log content for timeline display""" - - tool_telemetry: dict[str, Any] | None = None - """Optional tool-specific telemetry""" - - @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlm': - assert isinstance(obj, dict) - text_result_for_llm = from_str(obj.get("textResultForLlm")) - binary_results_for_llm = from_union([lambda x: from_list(ExternalToolTextResultForLlmBinaryResultsForLlm.from_dict, x), from_none], obj.get("binaryResultsForLlm")) - contents = from_union([lambda x: from_list(ExternalToolTextResultForLlmContent.from_dict, x), from_none], obj.get("contents")) - error = from_union([from_str, from_none], obj.get("error")) - result_type = from_union([from_str, from_none], obj.get("resultType")) - session_log = from_union([from_str, from_none], obj.get("sessionLog")) - tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry")) - return ExternalToolTextResultForLlm(text_result_for_llm, binary_results_for_llm, contents, error, result_type, session_log, tool_telemetry) - - def to_dict(self) -> dict: - result: dict = {} - result["textResultForLlm"] = from_str(self.text_result_for_llm) - if self.binary_results_for_llm is not None: - result["binaryResultsForLlm"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmBinaryResultsForLlm, x), x), from_none], self.binary_results_for_llm) - if self.contents is not None: - result["contents"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContent, x), x), from_none], self.contents) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result_type is not None: - result["resultType"] = from_union([from_str, from_none], self.result_type) - if self.session_log is not None: - result["sessionLog"] = from_union([from_str, from_none], self.session_log) - if self.tool_telemetry is not None: - result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class InstalledPlugin: - """Schema for the `InstalledPlugin` type.""" - - enabled: bool - """Whether the plugin is currently enabled""" - - installed_at: str - """Installation timestamp""" - - marketplace: str - """Marketplace the plugin came from (empty string for direct repo installs)""" - - name: str - """Plugin name""" - - cache_path: str | None = None - """Path where the plugin is cached locally""" - - source: InstalledPluginSource | str | None = None - """Source for direct repo installs (when marketplace is empty)""" - - version: str | None = None - """Version installed (if available)""" - - @staticmethod - def from_dict(obj: Any) -> 'InstalledPlugin': - assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - installed_at = from_str(obj.get("installed_at")) - marketplace = from_str(obj.get("marketplace")) - name = from_str(obj.get("name")) - cache_path = from_union([from_str, from_none], obj.get("cache_path")) - source = from_union([InstalledPluginSource.from_dict, from_str, from_none], obj.get("source")) - version = from_union([from_str, from_none], obj.get("version")) - return InstalledPlugin(enabled, installed_at, marketplace, name, cache_path, source, version) - - def to_dict(self) -> dict: - result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["installed_at"] = from_str(self.installed_at) - result["marketplace"] = from_str(self.marketplace) - result["name"] = from_str(self.name) - if self.cache_path is not None: - result["cache_path"] = from_union([from_str, from_none], self.cache_path) - if self.source is not None: - result["source"] = from_union([lambda x: to_class(InstalledPluginSource, x), from_str, from_none], self.source) - if self.version is not None: - result["version"] = from_union([from_str, from_none], self.version) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionInstalledPlugin: - """Schema for the `SessionInstalledPlugin` type.""" - - enabled: bool - """Whether the plugin is currently enabled""" - - installed_at: str - """Installation timestamp (ISO-8601)""" - - marketplace: str - """Marketplace the plugin came from (empty string for direct repo installs)""" - - name: str - """Plugin name""" - - cache_path: str | None = None - """Path where the plugin is cached locally""" - - source: SessionInstalledPluginSource | str | None = None - """Source descriptor for direct repo installs (when marketplace is empty)""" - - version: str | None = None - """Installed version, if known""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionInstalledPlugin': - assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - installed_at = from_str(obj.get("installed_at")) - marketplace = from_str(obj.get("marketplace")) - name = from_str(obj.get("name")) - cache_path = from_union([from_str, from_none], obj.get("cache_path")) - source = from_union([SessionInstalledPluginSource.from_dict, from_str, from_none], obj.get("source")) - version = from_union([from_str, from_none], obj.get("version")) - return SessionInstalledPlugin(enabled, installed_at, marketplace, name, cache_path, source, version) - - def to_dict(self) -> dict: - result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["installed_at"] = from_str(self.installed_at) - result["marketplace"] = from_str(self.marketplace) - result["name"] = from_str(self.name) - if self.cache_path is not None: - result["cache_path"] = from_union([from_str, from_none], self.cache_path) - if self.source is not None: - result["source"] = from_union([lambda x: to_class(SessionInstalledPluginSource, x), from_str, from_none], self.source) - if self.version is not None: - result["version"] = from_union([from_str, from_none], self.version) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionEnrichMetadataResult: - """The same metadata records, with summary and context fields backfilled where available.""" - - sessions: list[SessionMetadata] - """Same records, with summary and context backfilled""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionEnrichMetadataResult': - assert isinstance(obj, dict) - sessions = from_list(SessionMetadata.from_dict, obj.get("sessions")) - return SessionEnrichMetadataResult(sessions) - - def to_dict(self) -> dict: - result: dict = {} - result["sessions"] = from_list(lambda x: to_class(SessionMetadata, x), self.sessions) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionList: - """Persisted sessions matching the filter, ordered most-recently-modified first.""" - - sessions: list[SessionMetadata] - """Sessions ordered most-recently-modified first""" - - @staticmethod - def from_dict(obj: Any) -> 'SessionList': - assert isinstance(obj, dict) - sessions = from_list(SessionMetadata.from_dict, obj.get("sessions")) - return SessionList(sessions) - - def to_dict(self) -> dict: - result: dict = {} - result["sessions"] = from_list(lambda x: to_class(SessionMetadata, x), self.sessions) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsEnrichMetadataRequest: - """Session metadata records to enrich with summary and context information.""" - - sessions: list[SessionMetadata] - """Session metadata records to enrich. Records that already have summary and context are - returned unchanged. - """ - - @staticmethod - def from_dict(obj: Any) -> 'SessionsEnrichMetadataRequest': - assert isinstance(obj, dict) - sessions = from_list(SessionMetadata.from_dict, obj.get("sessions")) - return SessionsEnrichMetadataRequest(sessions) - - def to_dict(self) -> dict: - result: dict = {} - result["sessions"] = from_list(lambda x: to_class(SessionMetadata, x), self.sessions) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionMetadataSnapshot: - """Point-in-time snapshot of slow-changing session identifier and state fields""" - - already_in_use: bool - """True when the session was detected to be in use by another process at construction time. - Local consumers may surface a confirmation prompt before fully attaching. Always false - for new sessions. - """ - current_mode: MetadataSnapshotCurrentMode - """The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot')""" - - is_remote: bool - """Whether this is a remote session (i.e., one whose runtime executes elsewhere and is - steered through this process) - """ - modified_time: datetime - """ISO 8601 timestamp of when the session's persisted state was last modified on disk. For - new sessions, equals startTime. For resumed sessions, reflects the previous modification - time at construction. - """ - session_id: str - """The unique identifier of the session""" - - start_time: datetime - """ISO 8601 timestamp of when the session started""" - - working_directory: str - """Absolute path to the session's current working directory""" - - initial_name: str | None = None - """User-provided name supplied at session construction (via `--name`), if any. Immutable - after construction. - """ - remote_metadata: MetadataSnapshotRemoteMetadata | None = None - """Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are - immutable for the lifetime of the session. - """ - selected_model: str | None = None - """Currently selected model identifier, if any""" - - summary: str | None = None - """Short human-readable summary of the session, if known. Omitted when no summary has been - generated. - """ - workspace: WorkspaceSummary | None = None - """Public-facing workspace metadata for this session, or null if the session has no - associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, - internal flags). - """ - workspace_path: str | None = None - """Absolute path to the session's workspace directory on disk, or null if the session has no - associated workspace - """ - - @staticmethod - def from_dict(obj: Any) -> 'SessionMetadataSnapshot': - assert isinstance(obj, dict) - already_in_use = from_bool(obj.get("alreadyInUse")) - current_mode = MetadataSnapshotCurrentMode(obj.get("currentMode")) - is_remote = from_bool(obj.get("isRemote")) - modified_time = from_datetime(obj.get("modifiedTime")) - session_id = from_str(obj.get("sessionId")) - start_time = from_datetime(obj.get("startTime")) - working_directory = from_str(obj.get("workingDirectory")) - initial_name = from_union([from_str, from_none], obj.get("initialName")) - remote_metadata = from_union([MetadataSnapshotRemoteMetadata.from_dict, from_none], obj.get("remoteMetadata")) - selected_model = from_union([from_str, from_none], obj.get("selectedModel")) - summary = from_union([from_str, from_none], obj.get("summary")) - workspace = from_union([WorkspaceSummary.from_dict, from_none], obj.get("workspace")) - workspace_path = from_union([from_none, from_str], obj.get("workspacePath")) - return SessionMetadataSnapshot(already_in_use, current_mode, is_remote, modified_time, session_id, start_time, working_directory, initial_name, remote_metadata, selected_model, summary, workspace, workspace_path) + Approval covering writes to long-term memory. - def to_dict(self) -> dict: - result: dict = {} - result["alreadyInUse"] = from_bool(self.already_in_use) - result["currentMode"] = to_enum(MetadataSnapshotCurrentMode, self.current_mode) - result["isRemote"] = from_bool(self.is_remote) - result["modifiedTime"] = self.modified_time.isoformat() - result["sessionId"] = from_str(self.session_id) - result["startTime"] = self.start_time.isoformat() - result["workingDirectory"] = from_str(self.working_directory) - if self.initial_name is not None: - result["initialName"] = from_union([from_str, from_none], self.initial_name) - if self.remote_metadata is not None: - result["remoteMetadata"] = from_union([lambda x: to_class(MetadataSnapshotRemoteMetadata, x), from_none], self.remote_metadata) - if self.selected_model is not None: - result["selectedModel"] = from_union([from_str, from_none], self.selected_model) - if self.summary is not None: - result["summary"] = from_union([from_str, from_none], self.summary) - if self.workspace is not None: - result["workspace"] = from_union([lambda x: to_class(WorkspaceSummary, x), from_none], self.workspace) - result["workspacePath"] = from_union([from_none, from_str], self.workspace_path) - return result + Approval covering a custom tool. -@dataclass -class PermissionsConfigureParams: - """Patch of permission policy fields to apply (omit a field to leave it unchanged).""" + Approval covering extension lifecycle operations such as enable, disable, or reload. - additional_content_exclusion_policies: list[PermissionsConfigureAdditionalContentExclusionPolicy] | None = None - """If specified, replaces the host-supplied GitHub Content Exclusion policies on the session - (combined with natively-discovered policies when evaluating tool/file access). Omit to - leave the current policies unchanged. - """ - approve_all_read_permission_requests: bool | None = None - """If specified, sets whether path/URL read permission requests are auto-approved. Omit to - leave the current value unchanged. - """ - approve_all_tool_permission_requests: bool | None = None - """If specified, sets whether tool permission requests are auto-approved without prompting. - Omit to leave the current value unchanged. - """ - paths: PermissionPathsConfig | None = None - """If specified, replaces the session's path-permission policy. The runtime constructs the - appropriate PathManager based on these inputs (rooted at the session's working - directory). Omit to leave the current path policy unchanged. + Approval covering an extension's request to access a permission-gated capability. """ - rules: PermissionRulesSet | None = None - """If specified, replaces the session's approved/denied permission rules. Omit to leave the - current rules unchanged. + command_identifiers: list[str] | None = None + """Command identifiers covered by this approval.""" + + server_name: str | None = None + """MCP server name.""" + + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server. + + Custom tool name. """ - urls: PermissionUrlsConfig | None = None - """If specified, replaces the session's URL-permission policy. The runtime constructs a - fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy - unchanged. + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. """ + extension_name: str | None = None + """Extension name.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsConfigureParams': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApproval': assert isinstance(obj, dict) - additional_content_exclusion_policies = from_union([lambda x: from_list(PermissionsConfigureAdditionalContentExclusionPolicy.from_dict, x), from_none], obj.get("additionalContentExclusionPolicies")) - approve_all_read_permission_requests = from_union([from_bool, from_none], obj.get("approveAllReadPermissionRequests")) - approve_all_tool_permission_requests = from_union([from_bool, from_none], obj.get("approveAllToolPermissionRequests")) - paths = from_union([PermissionPathsConfig.from_dict, from_none], obj.get("paths")) - rules = from_union([PermissionRulesSet.from_dict, from_none], obj.get("rules")) - urls = from_union([PermissionUrlsConfig.from_dict, from_none], obj.get("urls")) - return PermissionsConfigureParams(additional_content_exclusion_policies, approve_all_read_permission_requests, approve_all_tool_permission_requests, paths, rules, urls) + kind = ApprovalKind(obj.get("kind")) + command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) + server_name = from_union([from_str, from_none], obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + operation = from_union([from_str, from_none], obj.get("operation")) + extension_name = from_union([from_str, from_none], obj.get("extensionName")) + return PermissionDecisionApproveForSessionApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) def to_dict(self) -> dict: result: dict = {} - if self.additional_content_exclusion_policies is not None: - result["additionalContentExclusionPolicies"] = from_union([lambda x: from_list(lambda x: to_class(PermissionsConfigureAdditionalContentExclusionPolicy, x), x), from_none], self.additional_content_exclusion_policies) - if self.approve_all_read_permission_requests is not None: - result["approveAllReadPermissionRequests"] = from_union([from_bool, from_none], self.approve_all_read_permission_requests) - if self.approve_all_tool_permission_requests is not None: - result["approveAllToolPermissionRequests"] = from_union([from_bool, from_none], self.approve_all_tool_permission_requests) - if self.paths is not None: - result["paths"] = from_union([lambda x: to_class(PermissionPathsConfig, x), from_none], self.paths) - if self.rules is not None: - result["rules"] = from_union([lambda x: to_class(PermissionRulesSet, x), from_none], self.rules) - if self.urls is not None: - result["urls"] = from_union([lambda x: to_class(PermissionUrlsConfig, x), from_none], self.urls) + result["kind"] = to_enum(ApprovalKind, self.kind) + if self.command_identifiers is not None: + result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) + if self.server_name is not None: + result["serverName"] = from_union([from_str, from_none], self.server_name) + if self.tool_name is not None: + result["toolName"] = from_union([from_none, from_str], self.tool_name) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) + if self.extension_name is not None: + result["extensionName"] = from_union([from_str, from_none], self.extension_name) return result @dataclass -class SendRequest: - """Parameters for sending a user message to the session""" - - prompt: str - """The user message text""" +class ExternalToolTextResultForLlm: + """Expanded external tool result payload""" - agent_mode: SendAgentMode | None = None - """The UI mode the agent was in when this message was sent. Defaults to the session's - current mode. - """ - attachments: list[SendAttachment] | None = None - """Optional attachments (files, directories, selections, blobs, GitHub references) to - include with the message - """ - billable: bool | None = None - """If false, this message will not trigger a Premium Request Unit charge. User messages - default to billable. - """ - display_prompt: str | None = None - """If provided, this is shown in the timeline instead of `prompt`""" + text_result_for_llm: str + """Text result returned to the model""" - mode: SendMode | None = None - """How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` - interjects during an in-progress turn. - """ - prepend: bool | None = None - """If true, adds the message to the front of the queue instead of the end""" + binary_results_for_llm: list[ExternalToolTextResultForLlmBinaryResultsForLlm] | None = None + """Base64-encoded binary results returned to the model""" - request_headers: dict[str, str] | None = None - """Custom HTTP headers to include in outbound model requests for this turn. Merged with - session-level provider headers; per-turn headers augment and overwrite session-level - headers with the same key. - """ - required_tool: str | None = None - """If set, the request will fail if the named tool is not available when this message is - among the user messages at the start of the current exchange - """ - source: Any = None - """Optional provenance tag copied to the resulting user.message event. Supported values are - `system`, `command-*`, and `schedule-*`. - """ - traceparent: str | None = None - """W3C Trace Context traceparent header for distributed tracing of this agent turn""" + contents: list[ExternalToolTextResultForLlmContent] | None = None + """Structured content blocks from the tool""" - tracestate: str | None = None - """W3C Trace Context tracestate header for distributed tracing""" + error: str | None = None + """Optional error message for failed executions""" - wait: bool | None = None - """If true, await completion of the agentic loop for this message before returning. Defaults - to false (fire-and-forget). When true, the result still contains the same `messageId`; - the caller can rely on the agent having processed the message before the call resolves. + result_type: str | None = None + """Execution outcome classification. Optional for back-compat; normalized to 'success' (or + 'failure' when error is present) when missing or unrecognized. """ + session_log: str | None = None + """Detailed log content for timeline display""" + + tool_telemetry: dict[str, Any] | None = None + """Optional tool-specific telemetry""" @staticmethod - def from_dict(obj: Any) -> 'SendRequest': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlm': assert isinstance(obj, dict) - prompt = from_str(obj.get("prompt")) - agent_mode = from_union([SendAgentMode, from_none], obj.get("agentMode")) - attachments = from_union([lambda x: from_list(SendAttachment.from_dict, x), from_none], obj.get("attachments")) - billable = from_union([from_bool, from_none], obj.get("billable")) - display_prompt = from_union([from_str, from_none], obj.get("displayPrompt")) - mode = from_union([SendMode, from_none], obj.get("mode")) - prepend = from_union([from_bool, from_none], obj.get("prepend")) - request_headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("requestHeaders")) - required_tool = from_union([from_str, from_none], obj.get("requiredTool")) - source = obj.get("source") - traceparent = from_union([from_str, from_none], obj.get("traceparent")) - tracestate = from_union([from_str, from_none], obj.get("tracestate")) - wait = from_union([from_bool, from_none], obj.get("wait")) - return SendRequest(prompt, agent_mode, attachments, billable, display_prompt, mode, prepend, request_headers, required_tool, source, traceparent, tracestate, wait) + text_result_for_llm = from_str(obj.get("textResultForLlm")) + binary_results_for_llm = from_union([lambda x: from_list(ExternalToolTextResultForLlmBinaryResultsForLlm.from_dict, x), from_none], obj.get("binaryResultsForLlm")) + contents = from_union([lambda x: from_list(ExternalToolTextResultForLlmContent.from_dict, x), from_none], obj.get("contents")) + error = from_union([from_str, from_none], obj.get("error")) + result_type = from_union([from_str, from_none], obj.get("resultType")) + session_log = from_union([from_str, from_none], obj.get("sessionLog")) + tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry")) + return ExternalToolTextResultForLlm(text_result_for_llm, binary_results_for_llm, contents, error, result_type, session_log, tool_telemetry) def to_dict(self) -> dict: result: dict = {} - result["prompt"] = from_str(self.prompt) - if self.agent_mode is not None: - result["agentMode"] = from_union([lambda x: to_enum(SendAgentMode, x), from_none], self.agent_mode) - if self.attachments is not None: - result["attachments"] = from_union([lambda x: from_list(lambda x: to_class(SendAttachment, x), x), from_none], self.attachments) - if self.billable is not None: - result["billable"] = from_union([from_bool, from_none], self.billable) - if self.display_prompt is not None: - result["displayPrompt"] = from_union([from_str, from_none], self.display_prompt) - if self.mode is not None: - result["mode"] = from_union([lambda x: to_enum(SendMode, x), from_none], self.mode) - if self.prepend is not None: - result["prepend"] = from_union([from_bool, from_none], self.prepend) - if self.request_headers is not None: - result["requestHeaders"] = from_union([lambda x: from_dict(from_str, x), from_none], self.request_headers) - if self.required_tool is not None: - result["requiredTool"] = from_union([from_str, from_none], self.required_tool) - if self.source is not None: - result["source"] = self.source - if self.traceparent is not None: - result["traceparent"] = from_union([from_str, from_none], self.traceparent) - if self.tracestate is not None: - result["tracestate"] = from_union([from_str, from_none], self.tracestate) - if self.wait is not None: - result["wait"] = from_union([from_bool, from_none], self.wait) + result["textResultForLlm"] = from_str(self.text_result_for_llm) + if self.binary_results_for_llm is not None: + result["binaryResultsForLlm"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmBinaryResultsForLlm, x), x), from_none], self.binary_results_for_llm) + if self.contents is not None: + result["contents"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContent, x), x), from_none], self.contents) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result_type is not None: + result["resultType"] = from_union([from_str, from_none], self.result_type) + if self.session_log is not None: + result["sessionLog"] = from_union([from_str, from_none], self.session_log) + if self.tool_telemetry is not None: + result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry) return result @dataclass @@ -12735,126 +6853,18 @@ def to_dict(self) -> dict: result["required"] = from_union([lambda x: from_list(from_str, x), from_none], self.required) return result -@dataclass -class AuthInfo: - """The new auth credentials to install on the session. When omitted or `undefined`, the call - is a no-op and the session's existing credentials are preserved. The runtime stores the - value verbatim and uses it for outbound model/API requests; it does NOT re-validate or - re-fetch the associated Copilot user response. Several variants carry secret material; - treat this method's params as containing secrets at rest and in transit. - - Schema for the `HMACAuthInfo` type. - - Schema for the `EnvAuthInfo` type. - - Schema for the `TokenAuthInfo` type. - - Schema for the `CopilotApiTokenAuthInfo` type. - - Schema for the `UserAuthInfo` type. - - Schema for the `GhCliAuthInfo` type. - - Schema for the `ApiKeyAuthInfo` type. - """ - host: str - """Authentication host. HMAC auth always targets the public GitHub host. - - Authentication host (e.g. https://github.com or a GHES host). - - Authentication host. - - Authentication host (always the public GitHub host). - """ - type: AuthInfoType - """HMAC-based authentication used by GitHub-internal services. - - Personal access token (PAT) or server-to-server token sourced from an environment - variable. - - SDK-side token authentication; the host configured the token directly via the SDK. - - Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` - environment-variable pair. The token itself is read from the environment by the runtime, - not carried in this struct. - - OAuth user authentication. The token itself is held in the runtime's secret token store - (keyed by host+login) and is NOT carried in this struct. - - Authentication via the `gh` CLI's saved credentials. - - API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style). - """ - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the - GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this - verbatim and does not re-fetch when set. - """ - hmac: str | None = None - """HMAC secret used to sign requests.""" - - env_var: str | None = None - """Name of the environment variable the token was sourced from.""" - - login: str | None = None - """User login associated with the token. Undefined for server-to-server tokens (those - starting with `ghs_`). - - OAuth user login. - - User login as reported by `gh auth status`. - """ - token: str | None = None - """The token value itself. Treat as a secret. - - The token returned by `gh auth token`. Treat as a secret. - """ - api_key: str | None = None - """The API key. Treat as a secret.""" - - @staticmethod - def from_dict(obj: Any) -> 'AuthInfo': - assert isinstance(obj, dict) - host = from_str(obj.get("host")) - type = AuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - hmac = from_union([from_str, from_none], obj.get("hmac")) - env_var = from_union([from_str, from_none], obj.get("envVar")) - login = from_union([from_str, from_none], obj.get("login")) - token = from_union([from_str, from_none], obj.get("token")) - api_key = from_union([from_str, from_none], obj.get("apiKey")) - return AuthInfo(host, type, copilot_user, hmac, env_var, login, token, api_key) - - def to_dict(self) -> dict: - result: dict = {} - result["host"] = from_str(self.host) - result["type"] = to_enum(AuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - if self.hmac is not None: - result["hmac"] = from_union([from_str, from_none], self.hmac) - if self.env_var is not None: - result["envVar"] = from_union([from_str, from_none], self.env_var) - if self.login is not None: - result["login"] = from_union([from_str, from_none], self.login) - if self.token is not None: - result["token"] = from_union([from_str, from_none], self.token) - if self.api_key is not None: - result["apiKey"] = from_union([from_str, from_none], self.api_key) - return result - @dataclass class PermissionDecisionApproveForLocation: """Schema for the `PermissionDecisionApproveForLocation` type.""" approval: PermissionDecisionApproveForLocationApproval - """Approval to persist for this location""" + """The approval to persist for this location""" kind: PermissionDecisionApproveForLocationKind - """Approve and persist for this project location""" + """Approved and persisted for this project location""" location_key: str - """Location key (git root or cwd) to persist the approval to""" + """The location key (git root or cwd) to persist the approval to""" @staticmethod def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocation': @@ -12869,327 +6879,67 @@ def to_dict(self) -> dict: result["approval"] = to_class(PermissionDecisionApproveForLocationApproval, self.approval) result["kind"] = to_enum(PermissionDecisionApproveForLocationKind, self.kind) result["locationKey"] = from_str(self.location_key) - return result - -@dataclass -class PermissionDecisionApproveForSession: - """Schema for the `PermissionDecisionApproveForSession` type.""" - - kind: PermissionDecisionApproveForSessionKind - """Approve and remember for the rest of the session""" - - approval: PermissionDecisionApproveForSessionApproval | None = None - """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts)""" - - domain: str | None = None - """URL domain to approve for the rest of the session (URL prompts only)""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSession': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForSessionKind(obj.get("kind")) - approval = from_union([PermissionDecisionApproveForSessionApproval.from_dict, from_none], obj.get("approval")) - domain = from_union([from_str, from_none], obj.get("domain")) - return PermissionDecisionApproveForSession(kind, approval, domain) - - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForSessionKind, self.kind) - if self.approval is not None: - result["approval"] = from_union([lambda x: to_class(PermissionDecisionApproveForSessionApproval, x), from_none], self.approval) - if self.domain is not None: - result["domain"] = from_union([from_str, from_none], self.domain) - return result - -@dataclass -class HandlePendingToolCallRequest: - """Pending external tool call request ID, with the tool result or an error describing why it - failed. - """ - request_id: str - """Request ID of the pending tool call""" - - error: str | None = None - """Error message if the tool call failed""" - - result: ExternalToolTextResultForLlm | str | None = None - """Tool call result (string or expanded result object)""" - - @staticmethod - def from_dict(obj: Any) -> 'HandlePendingToolCallRequest': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - error = from_union([from_str, from_none], obj.get("error")) - result = from_union([ExternalToolTextResultForLlm.from_dict, from_str, from_none], obj.get("result")) - return HandlePendingToolCallRequest(request_id, error, result) - - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result is not None: - result["result"] = from_union([lambda x: to_class(ExternalToolTextResultForLlm, x), from_str, from_none], self.result) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionsSetAdditionalPluginsRequest: - """Manager-wide additional plugins to register; replaces any previously-configured set.""" - - plugins: list[InstalledPlugin] - """Manager-wide additional plugins to register. Replaces any previously-configured set. Pass - an empty array to clear. - """ - - @staticmethod - def from_dict(obj: Any) -> 'SessionsSetAdditionalPluginsRequest': - assert isinstance(obj, dict) - plugins = from_list(InstalledPlugin.from_dict, obj.get("plugins")) - return SessionsSetAdditionalPluginsRequest(plugins) - - def to_dict(self) -> dict: - result: dict = {} - result["plugins"] = from_list(lambda x: to_class(InstalledPlugin, x), self.plugins) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class SessionUpdateOptionsParams: - """Patch of mutable session options to apply to the running session.""" - - additional_content_exclusion_policies: list[Any] | None = None - """Additional content-exclusion policies to merge into the session's policy set. Opaque - shape; see `ContentExclusionApiResponse` in the runtime. - """ - agent_context: str | None = None - """Runtime context discriminator (e.g., `cli`, `actions`).""" - - ask_user_disabled: bool | None = None - """Whether to disable the `ask_user` tool (encourages autonomous behavior).""" - - available_tools: list[str] | None = None - """Allowlist of tool names available to this session.""" - - client_name: str | None = None - """Identifier of the client driving the session.""" - - coauthor_enabled: bool | None = None - """Whether to include the `Co-authored-by` trailer in commit messages.""" - - continue_on_auto_mode: bool | None = None - """Whether to allow auto-mode continuation across turns.""" - - copilot_url: str | None = None - """Override URL for the Copilot API endpoint.""" - - custom_agents_local_only: bool | None = None - """Whether to default custom agents to local-only execution.""" - - disabled_instruction_sources: list[str] | None = None - """Instruction source IDs to exclude from the system prompt.""" - - disabled_skills: list[str] | None = None - """Skill IDs that should be excluded from this session.""" - - enable_on_demand_instruction_discovery: bool | None = None - """Whether to discover custom instructions on demand after successful file views (AGENTS.md - / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with - `skipCustomInstructions` and the runtime-side `ON_DEMAND_INSTRUCTIONS` feature flag. - """ - enable_reasoning_summaries: bool | None = None - """Whether to surface reasoning-summary events from the model.""" - - enable_script_safety: bool | None = None - """Whether shell-script safety heuristics are enabled.""" - - enable_streaming: bool | None = None - """Whether to stream model responses.""" - - env_value_mode: MCPSetEnvValueModeDetails | None = None - """How env values are passed to MCP servers (`direct` inlines literal values; `indirect` - resolves at launch). - """ - events_log_directory: str | None = None - """Override directory for the session-events log. When unset, the runtime's default events - log directory is used. - """ - excluded_tools: list[str] | None = None - """Denylist of tool names for this session.""" - - feature_flags: dict[str, bool] | None = None - """Map of feature-flag IDs to their boolean enabled state.""" - - installed_plugins: list[SessionInstalledPlugin] | None = None - """Full set of installed plugins for the session. Replaces the existing list; the runtime - invalidates the skills cache only when the list materially changes. - """ - integration_id: str | None = None - """Stable integration identifier used for analytics and rate-limit attribution.""" - - is_experimental_mode: bool | None = None - """Whether experimental capabilities are enabled.""" - - log_interactive_shells: bool | None = None - """Whether interactive shell sessions are logged.""" - - lsp_client_name: str | None = None - """Identifier sent to LSP-style integrations.""" - - manage_schedule_enabled: bool | None = None - """Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the - per-session schedule registry; this flag only controls tool exposure (typically gated to - staff users). - """ - model: str | None = None - """The model ID to use for assistant turns.""" + return result - provider: Any = None - """Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the - runtime. - """ - reasoning_effort: str | None = None - """Reasoning effort for the selected model (model-defined enum).""" +@dataclass +class PermissionDecisionApproveForSession: + """Schema for the `PermissionDecisionApproveForSession` type.""" - running_in_interactive_mode: bool | None = None - """Whether the session is running in an interactive UI.""" + kind: PermissionDecisionApproveForSessionKind + """Approved and remembered for the rest of the session""" - sandbox_config: Any = None - """Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime.""" + approval: PermissionDecisionApproveForSessionApproval | None = None + """The approval to add as a session-scoped rule""" - shell_init_profile: str | None = None - """Shell init profile (`None` or `NonInteractive`).""" + domain: str | None = None + """The URL domain to approve for this session""" - shell_process_flags: list[str] | None = None - """Per-shell process flags (e.g., `pwsh` arguments).""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSession': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForSessionKind(obj.get("kind")) + approval = from_union([PermissionDecisionApproveForSessionApproval.from_dict, from_none], obj.get("approval")) + domain = from_union([from_str, from_none], obj.get("domain")) + return PermissionDecisionApproveForSession(kind, approval, domain) - skill_directories: list[str] | None = None - """Additional directories to search for skills.""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForSessionKind, self.kind) + if self.approval is not None: + result["approval"] = from_union([lambda x: to_class(PermissionDecisionApproveForSessionApproval, x), from_none], self.approval) + if self.domain is not None: + result["domain"] = from_union([from_str, from_none], self.domain) + return result - skip_custom_instructions: bool | None = None - """Whether to skip loading custom instruction sources.""" +@dataclass +class HandlePendingToolCallRequest: + """Pending external tool call request ID, with the tool result or an error describing why it + failed. + """ + request_id: str + """Request ID of the pending tool call""" - trajectory_file: str | None = None - """Optional path for trajectory output.""" + error: str | None = None + """Error message if the tool call failed""" - working_directory: str | None = None - """Absolute working-directory path for shell tools.""" + result: ExternalToolTextResultForLlm | str | None = None + """Tool call result (string or expanded result object)""" @staticmethod - def from_dict(obj: Any) -> 'SessionUpdateOptionsParams': + def from_dict(obj: Any) -> 'HandlePendingToolCallRequest': assert isinstance(obj, dict) - additional_content_exclusion_policies = from_union([lambda x: from_list(lambda x: x, x), from_none], obj.get("additionalContentExclusionPolicies")) - agent_context = from_union([from_str, from_none], obj.get("agentContext")) - ask_user_disabled = from_union([from_bool, from_none], obj.get("askUserDisabled")) - available_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("availableTools")) - client_name = from_union([from_str, from_none], obj.get("clientName")) - coauthor_enabled = from_union([from_bool, from_none], obj.get("coauthorEnabled")) - continue_on_auto_mode = from_union([from_bool, from_none], obj.get("continueOnAutoMode")) - copilot_url = from_union([from_str, from_none], obj.get("copilotUrl")) - custom_agents_local_only = from_union([from_bool, from_none], obj.get("customAgentsLocalOnly")) - disabled_instruction_sources = from_union([lambda x: from_list(from_str, x), from_none], obj.get("disabledInstructionSources")) - disabled_skills = from_union([lambda x: from_list(from_str, x), from_none], obj.get("disabledSkills")) - enable_on_demand_instruction_discovery = from_union([from_bool, from_none], obj.get("enableOnDemandInstructionDiscovery")) - enable_reasoning_summaries = from_union([from_bool, from_none], obj.get("enableReasoningSummaries")) - enable_script_safety = from_union([from_bool, from_none], obj.get("enableScriptSafety")) - enable_streaming = from_union([from_bool, from_none], obj.get("enableStreaming")) - env_value_mode = from_union([MCPSetEnvValueModeDetails, from_none], obj.get("envValueMode")) - events_log_directory = from_union([from_str, from_none], obj.get("eventsLogDirectory")) - excluded_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludedTools")) - feature_flags = from_union([lambda x: from_dict(from_bool, x), from_none], obj.get("featureFlags")) - installed_plugins = from_union([lambda x: from_list(SessionInstalledPlugin.from_dict, x), from_none], obj.get("installedPlugins")) - integration_id = from_union([from_str, from_none], obj.get("integrationId")) - is_experimental_mode = from_union([from_bool, from_none], obj.get("isExperimentalMode")) - log_interactive_shells = from_union([from_bool, from_none], obj.get("logInteractiveShells")) - lsp_client_name = from_union([from_str, from_none], obj.get("lspClientName")) - manage_schedule_enabled = from_union([from_bool, from_none], obj.get("manageScheduleEnabled")) - model = from_union([from_str, from_none], obj.get("model")) - provider = obj.get("provider") - reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) - running_in_interactive_mode = from_union([from_bool, from_none], obj.get("runningInInteractiveMode")) - sandbox_config = obj.get("sandboxConfig") - shell_init_profile = from_union([from_str, from_none], obj.get("shellInitProfile")) - shell_process_flags = from_union([lambda x: from_list(from_str, x), from_none], obj.get("shellProcessFlags")) - skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) - skip_custom_instructions = from_union([from_bool, from_none], obj.get("skipCustomInstructions")) - trajectory_file = from_union([from_str, from_none], obj.get("trajectoryFile")) - working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) - return SessionUpdateOptionsParams(additional_content_exclusion_policies, agent_context, ask_user_disabled, available_tools, client_name, coauthor_enabled, continue_on_auto_mode, copilot_url, custom_agents_local_only, disabled_instruction_sources, disabled_skills, enable_on_demand_instruction_discovery, enable_reasoning_summaries, enable_script_safety, enable_streaming, env_value_mode, events_log_directory, excluded_tools, feature_flags, installed_plugins, integration_id, is_experimental_mode, log_interactive_shells, lsp_client_name, manage_schedule_enabled, model, provider, reasoning_effort, running_in_interactive_mode, sandbox_config, shell_init_profile, shell_process_flags, skill_directories, skip_custom_instructions, trajectory_file, working_directory) + request_id = from_str(obj.get("requestId")) + error = from_union([from_str, from_none], obj.get("error")) + result = from_union([ExternalToolTextResultForLlm.from_dict, from_str, from_none], obj.get("result")) + return HandlePendingToolCallRequest(request_id, error, result) def to_dict(self) -> dict: result: dict = {} - if self.additional_content_exclusion_policies is not None: - result["additionalContentExclusionPolicies"] = from_union([lambda x: from_list(lambda x: x, x), from_none], self.additional_content_exclusion_policies) - if self.agent_context is not None: - result["agentContext"] = from_union([from_str, from_none], self.agent_context) - if self.ask_user_disabled is not None: - result["askUserDisabled"] = from_union([from_bool, from_none], self.ask_user_disabled) - if self.available_tools is not None: - result["availableTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.available_tools) - if self.client_name is not None: - result["clientName"] = from_union([from_str, from_none], self.client_name) - if self.coauthor_enabled is not None: - result["coauthorEnabled"] = from_union([from_bool, from_none], self.coauthor_enabled) - if self.continue_on_auto_mode is not None: - result["continueOnAutoMode"] = from_union([from_bool, from_none], self.continue_on_auto_mode) - if self.copilot_url is not None: - result["copilotUrl"] = from_union([from_str, from_none], self.copilot_url) - if self.custom_agents_local_only is not None: - result["customAgentsLocalOnly"] = from_union([from_bool, from_none], self.custom_agents_local_only) - if self.disabled_instruction_sources is not None: - result["disabledInstructionSources"] = from_union([lambda x: from_list(from_str, x), from_none], self.disabled_instruction_sources) - if self.disabled_skills is not None: - result["disabledSkills"] = from_union([lambda x: from_list(from_str, x), from_none], self.disabled_skills) - if self.enable_on_demand_instruction_discovery is not None: - result["enableOnDemandInstructionDiscovery"] = from_union([from_bool, from_none], self.enable_on_demand_instruction_discovery) - if self.enable_reasoning_summaries is not None: - result["enableReasoningSummaries"] = from_union([from_bool, from_none], self.enable_reasoning_summaries) - if self.enable_script_safety is not None: - result["enableScriptSafety"] = from_union([from_bool, from_none], self.enable_script_safety) - if self.enable_streaming is not None: - result["enableStreaming"] = from_union([from_bool, from_none], self.enable_streaming) - if self.env_value_mode is not None: - result["envValueMode"] = from_union([lambda x: to_enum(MCPSetEnvValueModeDetails, x), from_none], self.env_value_mode) - if self.events_log_directory is not None: - result["eventsLogDirectory"] = from_union([from_str, from_none], self.events_log_directory) - if self.excluded_tools is not None: - result["excludedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.excluded_tools) - if self.feature_flags is not None: - result["featureFlags"] = from_union([lambda x: from_dict(from_bool, x), from_none], self.feature_flags) - if self.installed_plugins is not None: - result["installedPlugins"] = from_union([lambda x: from_list(lambda x: to_class(SessionInstalledPlugin, x), x), from_none], self.installed_plugins) - if self.integration_id is not None: - result["integrationId"] = from_union([from_str, from_none], self.integration_id) - if self.is_experimental_mode is not None: - result["isExperimentalMode"] = from_union([from_bool, from_none], self.is_experimental_mode) - if self.log_interactive_shells is not None: - result["logInteractiveShells"] = from_union([from_bool, from_none], self.log_interactive_shells) - if self.lsp_client_name is not None: - result["lspClientName"] = from_union([from_str, from_none], self.lsp_client_name) - if self.manage_schedule_enabled is not None: - result["manageScheduleEnabled"] = from_union([from_bool, from_none], self.manage_schedule_enabled) - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) - if self.provider is not None: - result["provider"] = self.provider - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) - if self.running_in_interactive_mode is not None: - result["runningInInteractiveMode"] = from_union([from_bool, from_none], self.running_in_interactive_mode) - if self.sandbox_config is not None: - result["sandboxConfig"] = self.sandbox_config - if self.shell_init_profile is not None: - result["shellInitProfile"] = from_union([from_str, from_none], self.shell_init_profile) - if self.shell_process_flags is not None: - result["shellProcessFlags"] = from_union([lambda x: from_list(from_str, x), from_none], self.shell_process_flags) - if self.skill_directories is not None: - result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) - if self.skip_custom_instructions is not None: - result["skipCustomInstructions"] = from_union([from_bool, from_none], self.skip_custom_instructions) - if self.trajectory_file is not None: - result["trajectoryFile"] = from_union([from_str, from_none], self.trajectory_file) - if self.working_directory is not None: - result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) + result["requestId"] = from_str(self.request_id) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result is not None: + result["result"] = from_union([lambda x: to_class(ExternalToolTextResultForLlm, x), from_str, from_none], self.result) return result @dataclass @@ -13215,33 +6965,9 @@ def to_dict(self) -> dict: result["requestedSchema"] = to_class(UIElicitationSchema, self.requested_schema) return result -@dataclass -class SessionSetCredentialsParams: - """New auth credentials to install on the session. Omit to leave credentials unchanged.""" - - credentials: AuthInfo | None = None - """The new auth credentials to install on the session. When omitted or `undefined`, the call - is a no-op and the session's existing credentials are preserved. The runtime stores the - value verbatim and uses it for outbound model/API requests; it does NOT re-validate or - re-fetch the associated Copilot user response. Several variants carry secret material; - treat this method's params as containing secrets at rest and in transit. - """ - - @staticmethod - def from_dict(obj: Any) -> 'SessionSetCredentialsParams': - assert isinstance(obj, dict) - credentials = from_union([AuthInfo.from_dict, from_none], obj.get("credentials")) - return SessionSetCredentialsParams(credentials) - - def to_dict(self) -> dict: - result: dict = {} - if self.credentials is not None: - result["credentials"] = from_union([lambda x: to_class(AuthInfo, x), from_none], self.credentials) - return result - @dataclass class PermissionDecision: - """The client's response to the pending permission prompt + """Decision to apply to a pending permission request. Schema for the `PermissionDecisionApproveOnce` type. @@ -13254,99 +6980,35 @@ class PermissionDecision: Schema for the `PermissionDecisionReject` type. Schema for the `PermissionDecisionUserNotAvailable` type. - - Schema for the `PermissionDecisionApproved` type. - - Schema for the `PermissionDecisionApprovedForSession` type. - - Schema for the `PermissionDecisionApprovedForLocation` type. - - Schema for the `PermissionDecisionCancelled` type. - - Schema for the `PermissionDecisionDeniedByRules` type. - - Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type. - - Schema for the `PermissionDecisionDeniedInteractivelyByUser` type. - - Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type. - - Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type. """ kind: PermissionDecisionKind - """Approve this single request only - - Approve and remember for the rest of the session - - Approve and persist for this project location - - Approve and persist across sessions (URL prompts only) - - Reject the request - - No user is available to confirm the request - - The permission request was approved + """The permission request was approved for this one instance Approved and remembered for the rest of the session Approved and persisted for this project location - The permission request was cancelled before a response was used - - Denied because approval rules explicitly blocked it - - Denied because no approval rule matched and user confirmation was unavailable + Approved and persisted across sessions Denied by the user during an interactive prompt - Denied by the organization's content exclusion policy - - Denied by a permission request hook registered by an extension or plugin + Denied because user confirmation was unavailable """ approval: PermissionDecisionApproveForIonApproval | None = None - """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) - - Approval to persist for this location - - The approval to add as a session-scoped rule + """The approval to add as a session-scoped rule The approval to persist for this location """ domain: str | None = None - """URL domain to approve for the rest of the session (URL prompts only) + """The URL domain to approve for this session - URL domain to approve permanently + The URL domain to approve permanently """ location_key: str | None = None - """Location key (git root or cwd) to persist the approval to + """The location key (git root or cwd) to persist the approval to""" - The location key (git root or cwd) to persist the approval to - """ feedback: str | None = None - """Optional feedback explaining the rejection - - Optional feedback from the user explaining the denial - """ - reason: str | None = None - """Optional explanation of why the request was cancelled""" - - rules: list[PermissionRule] | None = None - """Rules that denied the request""" - - force_reject: bool | None = None - """Whether to force-reject the current agent turn""" - - message: str | None = None - """Human-readable explanation of why the path was excluded - - Optional message from the hook explaining the denial - """ - path: str | None = None - """File path that triggered the exclusion""" - - interrupt: bool | None = None - """Whether to interrupt the current agent turn""" + """Optional feedback from the user explaining the denial""" @staticmethod def from_dict(obj: Any) -> 'PermissionDecision': @@ -13356,13 +7018,7 @@ def from_dict(obj: Any) -> 'PermissionDecision': domain = from_union([from_str, from_none], obj.get("domain")) location_key = from_union([from_str, from_none], obj.get("locationKey")) feedback = from_union([from_str, from_none], obj.get("feedback")) - reason = from_union([from_str, from_none], obj.get("reason")) - rules = from_union([lambda x: from_list(PermissionRule.from_dict, x), from_none], obj.get("rules")) - force_reject = from_union([from_bool, from_none], obj.get("forceReject")) - message = from_union([from_str, from_none], obj.get("message")) - path = from_union([from_str, from_none], obj.get("path")) - interrupt = from_union([from_bool, from_none], obj.get("interrupt")) - return PermissionDecision(kind, approval, domain, location_key, feedback, reason, rules, force_reject, message, path, interrupt) + return PermissionDecision(kind, approval, domain, location_key, feedback) def to_dict(self) -> dict: result: dict = {} @@ -13375,18 +7031,6 @@ def to_dict(self) -> dict: result["locationKey"] = from_union([from_str, from_none], self.location_key) if self.feedback is not None: result["feedback"] = from_union([from_str, from_none], self.feedback) - if self.reason is not None: - result["reason"] = from_union([from_str, from_none], self.reason) - if self.rules is not None: - result["rules"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRule, x), x), from_none], self.rules) - if self.force_reject is not None: - result["forceReject"] = from_union([from_bool, from_none], self.force_reject) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.interrupt is not None: - result["interrupt"] = from_union([from_bool, from_none], self.interrupt) return result @dataclass @@ -13397,7 +7041,7 @@ class PermissionDecisionRequest: """Request ID of the pending permission request""" result: PermissionDecision - """The client's response to the pending permission prompt""" + """Decision to apply to a pending permission request.""" @staticmethod def from_dict(obj: Any) -> 'PermissionDecisionRequest': @@ -13412,99 +7056,6 @@ def to_dict(self) -> dict: result["result"] = to_class(PermissionDecision, self.result) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPExecuteSamplingParams: - """Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference.""" - - mcp_request_id: float | str - """The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate - the inference with the originating MCP request for telemetry; this is distinct from - `requestId` (which is the schema-level cancellation handle). - """ - request: dict[str, Any] - """Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. - Treated as opaque at the schema layer; the runtime converts the embedded MCP messages - into the OpenAI chat-completion shape internally. - """ - request_id: str - """Caller-provided unique identifier for this sampling execution. Use this same ID with - cancelSamplingExecution to cancel the in-flight call. Must be unique within the session - for the lifetime of the call. - """ - server_name: str - """Name of the MCP server that initiated the sampling request""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPExecuteSamplingParams': - assert isinstance(obj, dict) - mcp_request_id = from_union([from_float, from_str], obj.get("mcpRequestId")) - request = from_dict(lambda x: x, obj.get("request")) - request_id = from_str(obj.get("requestId")) - server_name = from_str(obj.get("serverName")) - return MCPExecuteSamplingParams(mcp_request_id, request, request_id, server_name) - - def to_dict(self) -> dict: - result: dict = {} - result["mcpRequestId"] = from_union([to_float, from_str], self.mcp_request_id) - result["request"] = from_dict(lambda x: x, self.request) - result["requestId"] = from_str(self.request_id) - result["serverName"] = from_str(self.server_name) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataContextInfoRequest: - """Model identifier and token limits used to compute the context-info breakdown.""" - - output_token_limit: int - """Maximum output tokens allowed by the target model. Pass 0 if unknown.""" - - prompt_token_limit: int - """Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default.""" - - selected_model: str | None = None - """Model identifier used for tokenization. Omit to use the session default. Used both for - token counting and to compute display values. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataContextInfoRequest': - assert isinstance(obj, dict) - output_token_limit = from_int(obj.get("outputTokenLimit")) - prompt_token_limit = from_int(obj.get("promptTokenLimit")) - selected_model = from_union([from_str, from_none], obj.get("selectedModel")) - return MetadataContextInfoRequest(output_token_limit, prompt_token_limit, selected_model) - - def to_dict(self) -> dict: - result: dict = {} - result["outputTokenLimit"] = from_int(self.output_token_limit) - result["promptTokenLimit"] = from_int(self.prompt_token_limit) - if self.selected_model is not None: - result["selectedModel"] = from_union([from_str, from_none], self.selected_model) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MetadataRecomputeContextTokensRequest: - """Model identifier to use when re-tokenizing the session's existing messages.""" - - model_id: str - """Model identifier used for tokenization. The runtime token-counts both chat-context and - system-context messages against this model. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MetadataRecomputeContextTokensRequest': - assert isinstance(obj, dict) - model_id = from_str(obj.get("modelId")) - return MetadataRecomputeContextTokensRequest(model_id) - - def to_dict(self) -> dict: - result: dict = {} - result["modelId"] = from_str(self.model_id) - return result - @dataclass class ModelCapabilities: """Model capabilities and limits""" @@ -13656,38 +7207,6 @@ def to_dict(self) -> dict: result["reasoningSummary"] = from_union([lambda x: to_enum(ReasoningSummary, x), from_none], self.reasoning_summary) return result -class PermissionsSetApproveAllSource(Enum): - """Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.""" - - AUTOPILOT_CONFIRMATION = "autopilot_confirmation" - CLI_FLAG = "cli_flag" - RPC = "rpc" - SLASH_COMMAND = "slash_command" - -@dataclass -class PermissionsSetApproveAllRequest: - """Allow-all toggle for tool permission requests, with an optional telemetry source.""" - - enabled: bool - """Whether to auto-approve all tool permission requests""" - - source: PermissionsSetApproveAllSource | None = None - """Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.""" - - @staticmethod - def from_dict(obj: Any) -> 'PermissionsSetApproveAllRequest': - assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - source = from_union([PermissionsSetApproveAllSource, from_none], obj.get("source")) - return PermissionsSetApproveAllRequest(enabled, source) - - def to_dict(self) -> dict: - result: dict = {} - result["enabled"] = from_bool(self.enabled) - if self.source is not None: - result["source"] = from_union([lambda x: to_enum(PermissionsSetApproveAllSource, x), from_none], self.source) - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class TaskAgentInfo: @@ -13809,14 +7328,6 @@ def to_dict(self) -> dict: class TaskInfo: """Schema for the `TaskInfo` type. - The first sync-waiting task (agent first, then shell) that can currently be promoted to - background mode. Omitted if no such task exists. The returned task is guaranteed to have - executionMode='sync' and canPromoteToBackground=true at the time of the call. - - The promoted task as it now exists in background mode, omitted if no promotable task was - waiting. Atomic operation: avoids the race window of getCurrentPromotable + - promoteToBackground. - Schema for the `TaskAgentInfo` type. Schema for the `TaskShellInfo` type. @@ -13833,7 +7344,7 @@ class TaskInfo: status: TaskStatus """Current lifecycle status of the task""" - type: TaskAgentProgressType + type: TaskInfoType """Task kind""" active_started_at: datetime | None = None @@ -13899,7 +7410,7 @@ def from_dict(obj: Any) -> 'TaskInfo': id = from_str(obj.get("id")) started_at = from_datetime(obj.get("startedAt")) status = TaskStatus(obj.get("status")) - type = TaskAgentProgressType(obj.get("type")) + type = TaskInfoType(obj.get("type")) active_started_at = from_union([from_datetime, from_none], obj.get("activeStartedAt")) active_time_ms = from_union([from_int, from_none], obj.get("activeTimeMs")) agent_type = from_union([from_str, from_none], obj.get("agentType")) @@ -13925,7 +7436,7 @@ def to_dict(self) -> dict: result["id"] = from_str(self.id) result["startedAt"] = self.started_at.isoformat() result["status"] = to_enum(TaskStatus, self.status) - result["type"] = to_enum(TaskAgentProgressType, self.type) + result["type"] = to_enum(TaskInfoType, self.type) if self.active_started_at is not None: result["activeStartedAt"] = from_union([lambda x: x.isoformat(), from_none], self.active_started_at) if self.active_time_ms is not None: @@ -13981,69 +7492,17 @@ def to_dict(self) -> dict: result["tasks"] = from_list(lambda x: to_class(TaskInfo, x), self.tasks) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksGetCurrentPromotableResult: - """The first sync-waiting task that can currently be promoted to background mode.""" - - task: TaskInfo | None = None - """The first sync-waiting task (agent first, then shell) that can currently be promoted to - background mode. Omitted if no such task exists. The returned task is guaranteed to have - executionMode='sync' and canPromoteToBackground=true at the time of the call. - """ - - @staticmethod - def from_dict(obj: Any) -> 'TasksGetCurrentPromotableResult': - assert isinstance(obj, dict) - task = from_union([TaskInfo.from_dict, from_none], obj.get("task")) - return TasksGetCurrentPromotableResult(task) - - def to_dict(self) -> dict: - result: dict = {} - if self.task is not None: - result["task"] = from_union([lambda x: to_class(TaskInfo, x), from_none], self.task) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksPromoteCurrentToBackgroundResult: - """The promoted task as it now exists in background mode, omitted if no promotable task was - waiting. - """ - task: TaskInfo | None = None - """The promoted task as it now exists in background mode, omitted if no promotable task was - waiting. Atomic operation: avoids the race window of getCurrentPromotable + - promoteToBackground. - """ - - @staticmethod - def from_dict(obj: Any) -> 'TasksPromoteCurrentToBackgroundResult': - assert isinstance(obj, dict) - task = from_union([TaskInfo.from_dict, from_none], obj.get("task")) - return TasksPromoteCurrentToBackgroundResult(task) - - def to_dict(self) -> dict: - result: dict = {} - if self.task is not None: - result["task"] = from_union([lambda x: to_class(TaskInfo, x), from_none], self.task) - return result - @dataclass class RPC: - abort_request: AbortRequest - abort_result: AbortResult account_get_quota_request: AccountGetQuotaRequest account_get_quota_result: AccountGetQuotaResult account_quota_snapshot: AccountQuotaSnapshot agent_get_current_result: AgentGetCurrentResult agent_info: AgentInfo - agent_info_source: AgentInfoSource agent_list: AgentList agent_reload_result: AgentReloadResult agent_select_request: AgentSelectRequest agent_select_result: AgentSelectResult - api_key_auth_info: APIKeyAuthInfo - auth_info: AuthInfo auth_info_type: AuthInfoType command_list: CommandList commands_handle_pending_command_request: CommandsHandlePendingCommandRequest @@ -14059,28 +7518,9 @@ class RPC: connect_request: ConnectRequest connect_result: ConnectResult content_filter_mode: ContentFilterMode - copilot_api_token_auth_info: CopilotAPITokenAuthInfo - copilot_user_response: CopilotUserResponse - copilot_user_response_endpoints: CopilotUserResponseEndpoints - copilot_user_response_quota_snapshots: dict[str, CopilotUserResponseQuotaSnapshots | None] - copilot_user_response_quota_snapshots_chat: CopilotUserResponseQuotaSnapshotsChat - copilot_user_response_quota_snapshots_completions: CopilotUserResponseQuotaSnapshotsCompletions - copilot_user_response_quota_snapshots_premium_interactions: CopilotUserResponseQuotaSnapshotsPremiumInteractions current_model: CurrentModel discovered_mcp_server: DiscoveredMCPServer discovered_mcp_server_type: DiscoveredMCPServerType - enqueue_command_params: EnqueueCommandParams - enqueue_command_result: EnqueueCommandResult - env_auth_info: EnvAuthInfo - event_log_read_request: EventLogReadRequest - event_log_release_interest_result: EventLogReleaseInterestResult - event_log_tail_result: EventLogTailResult - event_log_types: list[str] | EventLogTypes - events_agent_scope: EventsAgentScope - events_cursor_status: EventsCursorStatus - events_read_result: EventsReadResult - execute_command_params: ExecuteCommandParams - execute_command_result: ExecuteCommandResult extension: Extension extension_list: ExtensionList extensions_disable_request: ExtensionsDisableRequest @@ -14104,31 +7544,18 @@ class RPC: filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode fleet_start_request: FleetStartRequest fleet_start_result: FleetStartResult - gh_cli_auth_info: GhCLIAuthInfo handle_pending_tool_call_request: HandlePendingToolCallRequest handle_pending_tool_call_result: HandlePendingToolCallResult - history_abort_manual_compaction_result: HistoryAbortManualCompactionResult - history_cancel_background_compaction_result: HistoryCancelBackgroundCompactionResult history_compact_context_window: HistoryCompactContextWindow history_compact_result: HistoryCompactResult - history_summarize_for_handoff_result: HistorySummarizeForHandoffResult history_truncate_request: HistoryTruncateRequest history_truncate_result: HistoryTruncateResult - hmac_auth_info: HMACAuthInfo - installed_plugin: InstalledPlugin - installed_plugin_source: InstalledPluginSource | str - installed_plugin_source_github: InstalledPluginSourceGithub - installed_plugin_source_local: InstalledPluginSourceLocal - installed_plugin_source_url: InstalledPluginSourceURL instructions_get_sources_result: InstructionsGetSourcesResult instructions_sources: InstructionsSources instructions_sources_location: InstructionsSourcesLocation instructions_sources_type: InstructionsSourcesType log_request: LogRequest log_result: LogResult - lsp_initialize_request: LspInitializeRequest - mcp_cancel_sampling_execution_params: MCPCancelSamplingExecutionParams - mcp_cancel_sampling_execution_result: MCPCancelSamplingExecutionResult mcp_config_add_request: MCPConfigAddRequest mcp_config_disable_request: MCPConfigDisableRequest mcp_config_enable_request: MCPConfigEnableRequest @@ -14139,14 +7566,8 @@ class RPC: mcp_discover_request: MCPDiscoverRequest mcp_discover_result: MCPDiscoverResult mcp_enable_request: MCPEnableRequest - mcp_execute_sampling_params: MCPExecuteSamplingParams - mcp_execute_sampling_request: dict[str, Any] - mcp_execute_sampling_result: dict[str, Any] mcp_oauth_login_request: MCPOauthLoginRequest mcp_oauth_login_result: MCPOauthLoginResult - mcp_remove_git_hub_result: MCPRemoveGitHubResult - mcp_sampling_execution_action: MCPSamplingExecutionAction - mcp_sampling_execution_result: MCPSamplingExecutionResult mcp_server: MCPServer mcp_server_config: MCPServerConfig mcp_server_config_http: MCPServerConfigHTTP @@ -14155,22 +7576,6 @@ class RPC: mcp_server_config_http_type: MCPServerConfigHTTPType mcp_server_config_stdio: MCPServerConfigStdio mcp_server_list: MCPServerList - mcp_set_env_value_mode_details: MCPSetEnvValueModeDetails - mcp_set_env_value_mode_params: MCPSetEnvValueModeParams - mcp_set_env_value_mode_result: MCPSetEnvValueModeResult - metadata_context_info_request: MetadataContextInfoRequest - metadata_context_info_result: MetadataContextInfoResult - metadata_is_processing_result: MetadataIsProcessingResult - metadata_recompute_context_tokens_request: MetadataRecomputeContextTokensRequest - metadata_recompute_context_tokens_result: MetadataRecomputeContextTokensResult - metadata_record_context_change_request: MetadataRecordContextChangeRequest - metadata_record_context_change_result: MetadataRecordContextChangeResult - metadata_set_working_directory_request: MetadataSetWorkingDirectoryRequest - metadata_set_working_directory_result: MetadataSetWorkingDirectoryResult - metadata_snapshot_current_mode: MetadataSnapshotCurrentMode - metadata_snapshot_remote_metadata: MetadataSnapshotRemoteMetadata - metadata_snapshot_remote_metadata_repository: MetadataSnapshotRemoteMetadataRepository - metadata_snapshot_remote_metadata_task_type: MetadataSnapshotRemoteMetadataTaskType model: Model model_billing: ModelBilling model_billing_token_prices: ModelBillingTokenPrices @@ -14187,23 +7592,13 @@ class RPC: model_picker_price_category: ModelPickerPriceCategory model_policy: ModelPolicy model_policy_state: ModelPolicyState - model_set_reasoning_effort_request: ModelSetReasoningEffortRequest - model_set_reasoning_effort_result: ModelSetReasoningEffortResult models_list_request: ModelsListRequest model_switch_to_request: ModelSwitchToRequest model_switch_to_result: ModelSwitchToResult mode_set_request: ModeSetRequest name_get_result: NameGetResult - name_set_auto_request: NameSetAutoRequest - name_set_auto_result: NameSetAutoResult name_set_request: NameSetRequest - options_update_env_value_mode: MCPSetEnvValueModeDetails - pending_permission_request: PendingPermissionRequest - pending_permission_request_list: PendingPermissionRequestList permission_decision: PermissionDecision - permission_decision_approved: PermissionDecisionApproved - permission_decision_approved_for_location: PermissionDecisionApprovedForLocation - permission_decision_approved_for_session: PermissionDecisionApprovedForSession permission_decision_approve_for_location: PermissionDecisionApproveForLocation permission_decision_approve_for_location_approval: PermissionDecisionApproveForLocationApproval permission_decision_approve_for_location_approval_commands: PermissionDecisionApproveForLocationApprovalCommands @@ -14228,50 +7623,14 @@ class RPC: permission_decision_approve_for_session_approval_write: PermissionDecisionApproveForSessionApprovalWrite permission_decision_approve_once: PermissionDecisionApproveOnce permission_decision_approve_permanently: PermissionDecisionApprovePermanently - permission_decision_cancelled: PermissionDecisionCancelled - permission_decision_denied_by_content_exclusion_policy: PermissionDecisionDeniedByContentExclusionPolicy - permission_decision_denied_by_permission_request_hook: PermissionDecisionDeniedByPermissionRequestHook - permission_decision_denied_by_rules: PermissionDecisionDeniedByRules - permission_decision_denied_interactively_by_user: PermissionDecisionDeniedInteractivelyByUser - permission_decision_denied_no_approval_rule_and_could_not_request_from_user: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser permission_decision_reject: PermissionDecisionReject permission_decision_request: PermissionDecisionRequest permission_decision_user_not_available: PermissionDecisionUserNotAvailable - permission_paths_add_params: PermissionPathsAddParams - permission_paths_allowed_check_params: PermissionPathsAllowedCheckParams - permission_paths_allowed_check_result: PermissionPathsAllowedCheckResult - permission_paths_config: PermissionPathsConfig - permission_paths_list: PermissionPathsList - permission_paths_update_primary_params: PermissionPathsUpdatePrimaryParams - permission_paths_workspace_check_params: PermissionPathsWorkspaceCheckParams - permission_paths_workspace_check_result: PermissionPathsWorkspaceCheckResult - permission_prompt_shown_notification: PermissionPromptShownNotification permission_request_result: PermissionRequestResult - permission_rules_set: PermissionRulesSet - permissions_configure_additional_content_exclusion_policy: PermissionsConfigureAdditionalContentExclusionPolicy - permissions_configure_additional_content_exclusion_policy_rule: PermissionsConfigureAdditionalContentExclusionPolicyRule - permissions_configure_additional_content_exclusion_policy_rule_source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource - permissions_configure_additional_content_exclusion_policy_scope: PermissionsConfigureAdditionalContentExclusionPolicyScope - permissions_configure_params: PermissionsConfigureParams - permissions_configure_result: PermissionsConfigureResult - permissions_modify_rules_params: PermissionsModifyRulesParams - permissions_modify_rules_result: PermissionsModifyRulesResult - permissions_modify_rules_scope: PermissionsModifyRulesScope - permissions_notify_prompt_shown_result: PermissionsNotifyPromptShownResult - permissions_paths_add_result: PermissionsPathsAddResult - permissions_paths_list_request: PermissionsPathsListRequest - permissions_paths_update_primary_result: PermissionsPathsUpdatePrimaryResult - permissions_pending_requests_request: PermissionsPendingRequestsRequest permissions_reset_session_approvals_request: PermissionsResetSessionApprovalsRequest permissions_reset_session_approvals_result: PermissionsResetSessionApprovalsResult permissions_set_approve_all_request: PermissionsSetApproveAllRequest permissions_set_approve_all_result: PermissionsSetApproveAllResult - permissions_set_approve_all_source: PermissionsSetApproveAllSource - permissions_set_required_request: PermissionsSetRequiredRequest - permissions_set_required_result: PermissionsSetRequiredResult - permissions_urls_set_unrestricted_mode_result: PermissionsUrlsSetUnrestrictedModeResult - permission_urls_config: PermissionUrlsConfig - permission_urls_set_unrestricted_mode_params: PermissionUrlsSetUnrestrictedModeParams ping_request: PingRequest ping_result: PingResult plan_read_result: PlanReadResult @@ -14281,45 +7640,13 @@ class RPC: queued_command_handled: QueuedCommandHandled queued_command_not_handled: QueuedCommandNotHandled queued_command_result: QueuedCommandResult - queue_pending_items: QueuePendingItems - queue_pending_items_kind: QueuePendingItemsKind - queue_pending_items_result: QueuePendingItemsResult - queue_remove_most_recent_result: QueueRemoveMostRecentResult - register_event_interest_params: RegisterEventInterestParams - register_event_interest_result: RegisterEventInterestResult - release_event_interest_params: ReleaseEventInterestParams remote_enable_request: RemoteEnableRequest remote_enable_result: RemoteEnableResult - remote_notify_steerable_changed_request: RemoteNotifySteerableChangedRequest - remote_notify_steerable_changed_result: RemoteNotifySteerableChangedResult remote_session_connection_result: RemoteSessionConnectionResult remote_session_mode: RemoteSessionMode - schedule_entry: ScheduleEntry - schedule_list: ScheduleList - schedule_stop_request: ScheduleStopRequest - schedule_stop_result: ScheduleStopResult - send_agent_mode: SendAgentMode - send_attachment: SendAttachment - send_attachment_blob: SendAttachmentBlob - send_attachment_directory: SendAttachmentDirectory - send_attachment_file: SendAttachmentFile - send_attachment_file_line_range: SendAttachmentFileLineRange - send_attachment_github_reference: SendAttachmentGithubReference - send_attachment_github_reference_type: SendAttachmentGithubReferenceTypeEnum - send_attachment_selection: SendAttachmentSelection - send_attachment_selection_details: SendAttachmentSelectionDetails - send_attachment_selection_details_end: SendAttachmentSelectionDetailsEnd - send_attachment_selection_details_start: SendAttachmentSelectionDetailsStart - send_mode: SendMode - send_request: SendRequest - send_result: SendResult server_skill: ServerSkill server_skill_list: ServerSkillList session_auth_status: SessionAuthStatus - session_bulk_delete_result: SessionBulkDeleteResult - session_context: SessionContext - session_context_host_type: SessionContextHostType - session_enrich_metadata_result: SessionEnrichMetadataResult session_fs_append_file_request: SessionFSAppendFileRequest session_fs_error: SessionFSError session_fs_error_code: SessionFSErrorCode @@ -14348,68 +7675,21 @@ class RPC: session_fs_stat_request: SessionFSStatRequest session_fs_stat_result: SessionFSStatResult session_fs_write_file_request: SessionFSWriteFileRequest - session_installed_plugin: SessionInstalledPlugin - session_installed_plugin_source: SessionInstalledPluginSource | str - session_installed_plugin_source_github: SessionInstalledPluginSourceGithub - session_installed_plugin_source_local: SessionInstalledPluginSourceLocal - session_installed_plugin_source_url: SessionInstalledPluginSourceURL - session_list: SessionList - session_load_deferred_repo_hooks_result: SessionLoadDeferredRepoHooksResult session_log_level: SessionLogLevel - session_metadata: SessionMetadata - session_metadata_snapshot: SessionMetadataSnapshot session_mode: SessionMode - session_prune_result: SessionPruneResult - sessions_bulk_delete_request: SessionsBulkDeleteRequest - sessions_check_in_use_request: SessionsCheckInUseRequest - sessions_check_in_use_result: SessionsCheckInUseResult - sessions_close_request: SessionsCloseRequest - sessions_close_result: SessionsCloseResult - sessions_enrich_metadata_request: SessionsEnrichMetadataRequest - session_set_credentials_params: SessionSetCredentialsParams - session_set_credentials_result: SessionSetCredentialsResult - sessions_find_by_prefix_request: SessionsFindByPrefixRequest - sessions_find_by_prefix_result: SessionsFindByPrefixResult - sessions_find_by_task_id_request: SessionsFindByTaskIDRequest - sessions_find_by_task_id_result: SessionsFindByTaskIDResult sessions_fork_request: SessionsForkRequest sessions_fork_result: SessionsForkResult - sessions_get_event_file_path_request: SessionsGetEventFilePathRequest - sessions_get_event_file_path_result: SessionsGetEventFilePathResult - sessions_get_last_for_context_request: SessionsGetLastForContextRequest - sessions_get_last_for_context_result: SessionsGetLastForContextResult - sessions_get_persisted_remote_steerable_request: SessionsGetPersistedRemoteSteerableRequest - sessions_get_persisted_remote_steerable_result: SessionsGetPersistedRemoteSteerableResult - session_sizes: SessionSizes - sessions_list_request: SessionsListRequest - sessions_load_deferred_repo_hooks_request: SessionsLoadDeferredRepoHooksRequest - sessions_prune_old_request: SessionsPruneOldRequest - sessions_release_lock_request: SessionsReleaseLockRequest - sessions_release_lock_result: SessionsReleaseLockResult - sessions_reload_plugin_hooks_request: SessionsReloadPluginHooksRequest - sessions_reload_plugin_hooks_result: SessionsReloadPluginHooksResult - sessions_save_request: SessionsSaveRequest - sessions_save_result: SessionsSaveResult - sessions_set_additional_plugins_request: SessionsSetAdditionalPluginsRequest - sessions_set_additional_plugins_result: SessionsSetAdditionalPluginsResult - session_update_options_params: SessionUpdateOptionsParams - session_update_options_result: SessionUpdateOptionsResult - session_working_directory_context: SessionWorkingDirectoryContext - session_working_directory_context_host_type: SessionContextHostType shell_exec_request: ShellExecRequest shell_exec_result: ShellExecResult shell_kill_request: ShellKillRequest shell_kill_result: ShellKillResult shell_kill_signal: ShellKillSignal - shutdown_request: ShutdownRequest skill: Skill skill_list: SkillList skills_config_set_disabled_skills_request: SkillsConfigSetDisabledSkillsRequest skills_disable_request: SkillsDisableRequest skills_discover_request: SkillsDiscoverRequest skills_enable_request: SkillsEnableRequest - skills_get_invoked_result: SkillsGetInvokedResult - skills_invoked_skill: SkillsInvokedSkill skills_load_diagnostics: SkillsLoadDiagnostics slash_command_agent_prompt_result: SlashCommandAgentPromptResult slash_command_completed_result: SlashCommandCompletedResult @@ -14420,22 +7700,15 @@ class RPC: slash_command_kind: SlashCommandKind slash_command_text_result: SlashCommandTextResult task_agent_info: TaskAgentInfo - task_agent_progress: TaskAgentProgress task_execution_mode: TaskExecutionMode task_info: TaskInfo task_list: TaskList tasks_cancel_request: TasksCancelRequest tasks_cancel_result: TasksCancelResult - tasks_get_current_promotable_result: TasksGetCurrentPromotableResult - tasks_get_progress_request: TasksGetProgressRequest - tasks_get_progress_result: TasksGetProgressResult task_shell_info: TaskShellInfo task_shell_info_attachment_mode: TaskShellInfoAttachmentMode - task_shell_progress: None - tasks_promote_current_to_background_result: TasksPromoteCurrentToBackgroundResult tasks_promote_to_background_request: TasksPromoteToBackgroundRequest tasks_promote_to_background_result: TasksPromoteToBackgroundResult - tasks_refresh_result: TasksRefreshResult tasks_remove_request: TasksRemoveRequest tasks_remove_result: TasksRemoveResult tasks_send_message_request: TasksSendMessageRequest @@ -14443,14 +7716,9 @@ class RPC: tasks_start_agent_request: TasksStartAgentRequest tasks_start_agent_result: TasksStartAgentResult task_status: TaskStatus - tasks_wait_for_pending_result: TasksWaitForPendingResult - telemetry_set_feature_overrides_request: TelemetrySetFeatureOverridesRequest - token_auth_info: TokenAuthInfo tool: Tool tool_list: ToolList - tools_initialize_and_validate_result: ToolsInitializeAndValidateResult tools_list_request: ToolsListRequest - ui_auto_mode_switch_response: UIAutoModeSwitchResponse ui_elicitation_array_any_of_field: UIElicitationArrayAnyOfField ui_elicitation_array_any_of_field_items: UIElicitationArrayAnyOfFieldItems ui_elicitation_array_any_of_field_items_any_of: UIElicitationArrayAnyOfFieldItemsAnyOf @@ -14472,19 +7740,7 @@ class RPC: ui_elicitation_string_enum_field: UIElicitationStringEnumField ui_elicitation_string_one_of_field: UIElicitationStringOneOfField ui_elicitation_string_one_of_field_one_of: UIElicitationStringOneOfFieldOneOf - ui_exit_plan_mode_action: UIExitPlanModeAction - ui_exit_plan_mode_response: UIExitPlanModeResponse - ui_handle_pending_auto_mode_switch_request: UIHandlePendingAutoModeSwitchRequest ui_handle_pending_elicitation_request: UIHandlePendingElicitationRequest - ui_handle_pending_exit_plan_mode_request: UIHandlePendingExitPlanModeRequest - ui_handle_pending_result: UIHandlePendingResult - ui_handle_pending_sampling_request: UIHandlePendingSamplingRequest - ui_handle_pending_sampling_response: dict[str, Any] - ui_handle_pending_user_input_request: UIHandlePendingUserInputRequest - ui_register_direct_auto_mode_switch_handler_result: UIRegisterDirectAutoModeSwitchHandlerResult - ui_unregister_direct_auto_mode_switch_handler_request: UIUnregisterDirectAutoModeSwitchHandlerRequest - ui_unregister_direct_auto_mode_switch_handler_result: UIUnregisterDirectAutoModeSwitchHandlerResult - ui_user_input_response: UIUserInputResponse usage_get_metrics_result: UsageGetMetricsResult usage_metrics_code_changes: UsageMetricsCodeChanges usage_metrics_model_metric: UsageMetricsModelMetric @@ -14492,47 +7748,24 @@ class RPC: usage_metrics_model_metric_token_detail: UsageMetricsModelMetricTokenDetail usage_metrics_model_metric_usage: UsageMetricsModelMetricUsage usage_metrics_token_detail: UsageMetricsTokenDetail - user_auth_info: UserAuthInfo - user_tool_session_approval_commands: UserToolSessionApprovalCommands - user_tool_session_approval_custom_tool: UserToolSessionApprovalCustomTool - user_tool_session_approval_extension_management: UserToolSessionApprovalExtensionManagement - user_tool_session_approval_extension_permission_access: UserToolSessionApprovalExtensionPermissionAccess - user_tool_session_approval_mcp: UserToolSessionApprovalMCP - user_tool_session_approval_memory: UserToolSessionApprovalMemory - user_tool_session_approval_read: UserToolSessionApprovalRead - user_tool_session_approval_write: UserToolSessionApprovalWrite - workspaces_checkpoints: WorkspacesCheckpoints workspaces_create_file_request: WorkspacesCreateFileRequest workspaces_get_workspace_result: WorkspacesGetWorkspaceResult - workspaces_list_checkpoints_result: WorkspacesListCheckpointsResult workspaces_list_files_result: WorkspacesListFilesResult - workspaces_read_checkpoint_request: WorkspacesReadCheckpointRequest - workspaces_read_checkpoint_result: WorkspacesReadCheckpointResult workspaces_read_file_request: WorkspacesReadFileRequest workspaces_read_file_result: WorkspacesReadFileResult - workspaces_save_large_paste_request: WorkspacesSaveLargePasteRequest - workspaces_save_large_paste_result: WorkspacesSaveLargePasteResult - session_context_info: SessionContextInfo | None = None - task_progress: TaskProgressClass | None = None - workspace_summary: WorkspaceSummary | None = None @staticmethod def from_dict(obj: Any) -> 'RPC': assert isinstance(obj, dict) - abort_request = AbortRequest.from_dict(obj.get("AbortRequest")) - abort_result = AbortResult.from_dict(obj.get("AbortResult")) account_get_quota_request = AccountGetQuotaRequest.from_dict(obj.get("AccountGetQuotaRequest")) account_get_quota_result = AccountGetQuotaResult.from_dict(obj.get("AccountGetQuotaResult")) account_quota_snapshot = AccountQuotaSnapshot.from_dict(obj.get("AccountQuotaSnapshot")) agent_get_current_result = AgentGetCurrentResult.from_dict(obj.get("AgentGetCurrentResult")) agent_info = AgentInfo.from_dict(obj.get("AgentInfo")) - agent_info_source = AgentInfoSource(obj.get("AgentInfoSource")) agent_list = AgentList.from_dict(obj.get("AgentList")) agent_reload_result = AgentReloadResult.from_dict(obj.get("AgentReloadResult")) agent_select_request = AgentSelectRequest.from_dict(obj.get("AgentSelectRequest")) agent_select_result = AgentSelectResult.from_dict(obj.get("AgentSelectResult")) - api_key_auth_info = APIKeyAuthInfo.from_dict(obj.get("ApiKeyAuthInfo")) - auth_info = AuthInfo.from_dict(obj.get("AuthInfo")) auth_info_type = AuthInfoType(obj.get("AuthInfoType")) command_list = CommandList.from_dict(obj.get("CommandList")) commands_handle_pending_command_request = CommandsHandlePendingCommandRequest.from_dict(obj.get("CommandsHandlePendingCommandRequest")) @@ -14548,28 +7781,9 @@ def from_dict(obj: Any) -> 'RPC': connect_request = ConnectRequest.from_dict(obj.get("ConnectRequest")) connect_result = ConnectResult.from_dict(obj.get("ConnectResult")) content_filter_mode = ContentFilterMode(obj.get("ContentFilterMode")) - copilot_api_token_auth_info = CopilotAPITokenAuthInfo.from_dict(obj.get("CopilotApiTokenAuthInfo")) - copilot_user_response = CopilotUserResponse.from_dict(obj.get("CopilotUserResponse")) - copilot_user_response_endpoints = CopilotUserResponseEndpoints.from_dict(obj.get("CopilotUserResponseEndpoints")) - copilot_user_response_quota_snapshots = from_dict(lambda x: from_union([CopilotUserResponseQuotaSnapshots.from_dict, from_none], x), obj.get("CopilotUserResponseQuotaSnapshots")) - copilot_user_response_quota_snapshots_chat = CopilotUserResponseQuotaSnapshotsChat.from_dict(obj.get("CopilotUserResponseQuotaSnapshotsChat")) - copilot_user_response_quota_snapshots_completions = CopilotUserResponseQuotaSnapshotsCompletions.from_dict(obj.get("CopilotUserResponseQuotaSnapshotsCompletions")) - copilot_user_response_quota_snapshots_premium_interactions = CopilotUserResponseQuotaSnapshotsPremiumInteractions.from_dict(obj.get("CopilotUserResponseQuotaSnapshotsPremiumInteractions")) current_model = CurrentModel.from_dict(obj.get("CurrentModel")) discovered_mcp_server = DiscoveredMCPServer.from_dict(obj.get("DiscoveredMcpServer")) discovered_mcp_server_type = DiscoveredMCPServerType(obj.get("DiscoveredMcpServerType")) - enqueue_command_params = EnqueueCommandParams.from_dict(obj.get("EnqueueCommandParams")) - enqueue_command_result = EnqueueCommandResult.from_dict(obj.get("EnqueueCommandResult")) - env_auth_info = EnvAuthInfo.from_dict(obj.get("EnvAuthInfo")) - event_log_read_request = EventLogReadRequest.from_dict(obj.get("EventLogReadRequest")) - event_log_release_interest_result = EventLogReleaseInterestResult.from_dict(obj.get("EventLogReleaseInterestResult")) - event_log_tail_result = EventLogTailResult.from_dict(obj.get("EventLogTailResult")) - event_log_types = from_union([lambda x: from_list(from_str, x), EventLogTypes], obj.get("EventLogTypes")) - events_agent_scope = EventsAgentScope(obj.get("EventsAgentScope")) - events_cursor_status = EventsCursorStatus(obj.get("EventsCursorStatus")) - events_read_result = EventsReadResult.from_dict(obj.get("EventsReadResult")) - execute_command_params = ExecuteCommandParams.from_dict(obj.get("ExecuteCommandParams")) - execute_command_result = ExecuteCommandResult.from_dict(obj.get("ExecuteCommandResult")) extension = Extension.from_dict(obj.get("Extension")) extension_list = ExtensionList.from_dict(obj.get("ExtensionList")) extensions_disable_request = ExtensionsDisableRequest.from_dict(obj.get("ExtensionsDisableRequest")) @@ -14593,31 +7807,18 @@ def from_dict(obj: Any) -> 'RPC': filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode], obj.get("FilterMapping")) fleet_start_request = FleetStartRequest.from_dict(obj.get("FleetStartRequest")) fleet_start_result = FleetStartResult.from_dict(obj.get("FleetStartResult")) - gh_cli_auth_info = GhCLIAuthInfo.from_dict(obj.get("GhCliAuthInfo")) handle_pending_tool_call_request = HandlePendingToolCallRequest.from_dict(obj.get("HandlePendingToolCallRequest")) handle_pending_tool_call_result = HandlePendingToolCallResult.from_dict(obj.get("HandlePendingToolCallResult")) - history_abort_manual_compaction_result = HistoryAbortManualCompactionResult.from_dict(obj.get("HistoryAbortManualCompactionResult")) - history_cancel_background_compaction_result = HistoryCancelBackgroundCompactionResult.from_dict(obj.get("HistoryCancelBackgroundCompactionResult")) history_compact_context_window = HistoryCompactContextWindow.from_dict(obj.get("HistoryCompactContextWindow")) history_compact_result = HistoryCompactResult.from_dict(obj.get("HistoryCompactResult")) - history_summarize_for_handoff_result = HistorySummarizeForHandoffResult.from_dict(obj.get("HistorySummarizeForHandoffResult")) history_truncate_request = HistoryTruncateRequest.from_dict(obj.get("HistoryTruncateRequest")) history_truncate_result = HistoryTruncateResult.from_dict(obj.get("HistoryTruncateResult")) - hmac_auth_info = HMACAuthInfo.from_dict(obj.get("HMACAuthInfo")) - installed_plugin = InstalledPlugin.from_dict(obj.get("InstalledPlugin")) - installed_plugin_source = from_union([InstalledPluginSource.from_dict, from_str], obj.get("InstalledPluginSource")) - installed_plugin_source_github = InstalledPluginSourceGithub.from_dict(obj.get("InstalledPluginSourceGithub")) - installed_plugin_source_local = InstalledPluginSourceLocal.from_dict(obj.get("InstalledPluginSourceLocal")) - installed_plugin_source_url = InstalledPluginSourceURL.from_dict(obj.get("InstalledPluginSourceUrl")) instructions_get_sources_result = InstructionsGetSourcesResult.from_dict(obj.get("InstructionsGetSourcesResult")) instructions_sources = InstructionsSources.from_dict(obj.get("InstructionsSources")) instructions_sources_location = InstructionsSourcesLocation(obj.get("InstructionsSourcesLocation")) instructions_sources_type = InstructionsSourcesType(obj.get("InstructionsSourcesType")) log_request = LogRequest.from_dict(obj.get("LogRequest")) log_result = LogResult.from_dict(obj.get("LogResult")) - lsp_initialize_request = LspInitializeRequest.from_dict(obj.get("LspInitializeRequest")) - mcp_cancel_sampling_execution_params = MCPCancelSamplingExecutionParams.from_dict(obj.get("McpCancelSamplingExecutionParams")) - mcp_cancel_sampling_execution_result = MCPCancelSamplingExecutionResult.from_dict(obj.get("McpCancelSamplingExecutionResult")) mcp_config_add_request = MCPConfigAddRequest.from_dict(obj.get("McpConfigAddRequest")) mcp_config_disable_request = MCPConfigDisableRequest.from_dict(obj.get("McpConfigDisableRequest")) mcp_config_enable_request = MCPConfigEnableRequest.from_dict(obj.get("McpConfigEnableRequest")) @@ -14628,14 +7829,8 @@ def from_dict(obj: Any) -> 'RPC': mcp_discover_request = MCPDiscoverRequest.from_dict(obj.get("McpDiscoverRequest")) mcp_discover_result = MCPDiscoverResult.from_dict(obj.get("McpDiscoverResult")) mcp_enable_request = MCPEnableRequest.from_dict(obj.get("McpEnableRequest")) - mcp_execute_sampling_params = MCPExecuteSamplingParams.from_dict(obj.get("McpExecuteSamplingParams")) - mcp_execute_sampling_request = from_dict(lambda x: x, obj.get("McpExecuteSamplingRequest")) - mcp_execute_sampling_result = from_dict(lambda x: x, obj.get("McpExecuteSamplingResult")) mcp_oauth_login_request = MCPOauthLoginRequest.from_dict(obj.get("McpOauthLoginRequest")) mcp_oauth_login_result = MCPOauthLoginResult.from_dict(obj.get("McpOauthLoginResult")) - mcp_remove_git_hub_result = MCPRemoveGitHubResult.from_dict(obj.get("McpRemoveGitHubResult")) - mcp_sampling_execution_action = MCPSamplingExecutionAction(obj.get("McpSamplingExecutionAction")) - mcp_sampling_execution_result = MCPSamplingExecutionResult.from_dict(obj.get("McpSamplingExecutionResult")) mcp_server = MCPServer.from_dict(obj.get("McpServer")) mcp_server_config = MCPServerConfig.from_dict(obj.get("McpServerConfig")) mcp_server_config_http = MCPServerConfigHTTP.from_dict(obj.get("McpServerConfigHttp")) @@ -14644,22 +7839,6 @@ def from_dict(obj: Any) -> 'RPC': mcp_server_config_http_type = MCPServerConfigHTTPType(obj.get("McpServerConfigHttpType")) mcp_server_config_stdio = MCPServerConfigStdio.from_dict(obj.get("McpServerConfigStdio")) mcp_server_list = MCPServerList.from_dict(obj.get("McpServerList")) - mcp_set_env_value_mode_details = MCPSetEnvValueModeDetails(obj.get("McpSetEnvValueModeDetails")) - mcp_set_env_value_mode_params = MCPSetEnvValueModeParams.from_dict(obj.get("McpSetEnvValueModeParams")) - mcp_set_env_value_mode_result = MCPSetEnvValueModeResult.from_dict(obj.get("McpSetEnvValueModeResult")) - metadata_context_info_request = MetadataContextInfoRequest.from_dict(obj.get("MetadataContextInfoRequest")) - metadata_context_info_result = MetadataContextInfoResult.from_dict(obj.get("MetadataContextInfoResult")) - metadata_is_processing_result = MetadataIsProcessingResult.from_dict(obj.get("MetadataIsProcessingResult")) - metadata_recompute_context_tokens_request = MetadataRecomputeContextTokensRequest.from_dict(obj.get("MetadataRecomputeContextTokensRequest")) - metadata_recompute_context_tokens_result = MetadataRecomputeContextTokensResult.from_dict(obj.get("MetadataRecomputeContextTokensResult")) - metadata_record_context_change_request = MetadataRecordContextChangeRequest.from_dict(obj.get("MetadataRecordContextChangeRequest")) - metadata_record_context_change_result = MetadataRecordContextChangeResult.from_dict(obj.get("MetadataRecordContextChangeResult")) - metadata_set_working_directory_request = MetadataSetWorkingDirectoryRequest.from_dict(obj.get("MetadataSetWorkingDirectoryRequest")) - metadata_set_working_directory_result = MetadataSetWorkingDirectoryResult.from_dict(obj.get("MetadataSetWorkingDirectoryResult")) - metadata_snapshot_current_mode = MetadataSnapshotCurrentMode(obj.get("MetadataSnapshotCurrentMode")) - metadata_snapshot_remote_metadata = MetadataSnapshotRemoteMetadata.from_dict(obj.get("MetadataSnapshotRemoteMetadata")) - metadata_snapshot_remote_metadata_repository = MetadataSnapshotRemoteMetadataRepository.from_dict(obj.get("MetadataSnapshotRemoteMetadataRepository")) - metadata_snapshot_remote_metadata_task_type = MetadataSnapshotRemoteMetadataTaskType(obj.get("MetadataSnapshotRemoteMetadataTaskType")) model = Model.from_dict(obj.get("Model")) model_billing = ModelBilling.from_dict(obj.get("ModelBilling")) model_billing_token_prices = ModelBillingTokenPrices.from_dict(obj.get("ModelBillingTokenPrices")) @@ -14676,23 +7855,13 @@ def from_dict(obj: Any) -> 'RPC': model_picker_price_category = ModelPickerPriceCategory(obj.get("ModelPickerPriceCategory")) model_policy = ModelPolicy.from_dict(obj.get("ModelPolicy")) model_policy_state = ModelPolicyState(obj.get("ModelPolicyState")) - model_set_reasoning_effort_request = ModelSetReasoningEffortRequest.from_dict(obj.get("ModelSetReasoningEffortRequest")) - model_set_reasoning_effort_result = ModelSetReasoningEffortResult.from_dict(obj.get("ModelSetReasoningEffortResult")) models_list_request = ModelsListRequest.from_dict(obj.get("ModelsListRequest")) model_switch_to_request = ModelSwitchToRequest.from_dict(obj.get("ModelSwitchToRequest")) model_switch_to_result = ModelSwitchToResult.from_dict(obj.get("ModelSwitchToResult")) mode_set_request = ModeSetRequest.from_dict(obj.get("ModeSetRequest")) name_get_result = NameGetResult.from_dict(obj.get("NameGetResult")) - name_set_auto_request = NameSetAutoRequest.from_dict(obj.get("NameSetAutoRequest")) - name_set_auto_result = NameSetAutoResult.from_dict(obj.get("NameSetAutoResult")) name_set_request = NameSetRequest.from_dict(obj.get("NameSetRequest")) - options_update_env_value_mode = MCPSetEnvValueModeDetails(obj.get("OptionsUpdateEnvValueMode")) - pending_permission_request = PendingPermissionRequest.from_dict(obj.get("PendingPermissionRequest")) - pending_permission_request_list = PendingPermissionRequestList.from_dict(obj.get("PendingPermissionRequestList")) permission_decision = PermissionDecision.from_dict(obj.get("PermissionDecision")) - permission_decision_approved = PermissionDecisionApproved.from_dict(obj.get("PermissionDecisionApproved")) - permission_decision_approved_for_location = PermissionDecisionApprovedForLocation.from_dict(obj.get("PermissionDecisionApprovedForLocation")) - permission_decision_approved_for_session = PermissionDecisionApprovedForSession.from_dict(obj.get("PermissionDecisionApprovedForSession")) permission_decision_approve_for_location = PermissionDecisionApproveForLocation.from_dict(obj.get("PermissionDecisionApproveForLocation")) permission_decision_approve_for_location_approval = PermissionDecisionApproveForLocationApproval.from_dict(obj.get("PermissionDecisionApproveForLocationApproval")) permission_decision_approve_for_location_approval_commands = PermissionDecisionApproveForLocationApprovalCommands.from_dict(obj.get("PermissionDecisionApproveForLocationApprovalCommands")) @@ -14717,50 +7886,14 @@ def from_dict(obj: Any) -> 'RPC': permission_decision_approve_for_session_approval_write = PermissionDecisionApproveForSessionApprovalWrite.from_dict(obj.get("PermissionDecisionApproveForSessionApprovalWrite")) permission_decision_approve_once = PermissionDecisionApproveOnce.from_dict(obj.get("PermissionDecisionApproveOnce")) permission_decision_approve_permanently = PermissionDecisionApprovePermanently.from_dict(obj.get("PermissionDecisionApprovePermanently")) - permission_decision_cancelled = PermissionDecisionCancelled.from_dict(obj.get("PermissionDecisionCancelled")) - permission_decision_denied_by_content_exclusion_policy = PermissionDecisionDeniedByContentExclusionPolicy.from_dict(obj.get("PermissionDecisionDeniedByContentExclusionPolicy")) - permission_decision_denied_by_permission_request_hook = PermissionDecisionDeniedByPermissionRequestHook.from_dict(obj.get("PermissionDecisionDeniedByPermissionRequestHook")) - permission_decision_denied_by_rules = PermissionDecisionDeniedByRules.from_dict(obj.get("PermissionDecisionDeniedByRules")) - permission_decision_denied_interactively_by_user = PermissionDecisionDeniedInteractivelyByUser.from_dict(obj.get("PermissionDecisionDeniedInteractivelyByUser")) - permission_decision_denied_no_approval_rule_and_could_not_request_from_user = PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser.from_dict(obj.get("PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser")) permission_decision_reject = PermissionDecisionReject.from_dict(obj.get("PermissionDecisionReject")) permission_decision_request = PermissionDecisionRequest.from_dict(obj.get("PermissionDecisionRequest")) permission_decision_user_not_available = PermissionDecisionUserNotAvailable.from_dict(obj.get("PermissionDecisionUserNotAvailable")) - permission_paths_add_params = PermissionPathsAddParams.from_dict(obj.get("PermissionPathsAddParams")) - permission_paths_allowed_check_params = PermissionPathsAllowedCheckParams.from_dict(obj.get("PermissionPathsAllowedCheckParams")) - permission_paths_allowed_check_result = PermissionPathsAllowedCheckResult.from_dict(obj.get("PermissionPathsAllowedCheckResult")) - permission_paths_config = PermissionPathsConfig.from_dict(obj.get("PermissionPathsConfig")) - permission_paths_list = PermissionPathsList.from_dict(obj.get("PermissionPathsList")) - permission_paths_update_primary_params = PermissionPathsUpdatePrimaryParams.from_dict(obj.get("PermissionPathsUpdatePrimaryParams")) - permission_paths_workspace_check_params = PermissionPathsWorkspaceCheckParams.from_dict(obj.get("PermissionPathsWorkspaceCheckParams")) - permission_paths_workspace_check_result = PermissionPathsWorkspaceCheckResult.from_dict(obj.get("PermissionPathsWorkspaceCheckResult")) - permission_prompt_shown_notification = PermissionPromptShownNotification.from_dict(obj.get("PermissionPromptShownNotification")) permission_request_result = PermissionRequestResult.from_dict(obj.get("PermissionRequestResult")) - permission_rules_set = PermissionRulesSet.from_dict(obj.get("PermissionRulesSet")) - permissions_configure_additional_content_exclusion_policy = PermissionsConfigureAdditionalContentExclusionPolicy.from_dict(obj.get("PermissionsConfigureAdditionalContentExclusionPolicy")) - permissions_configure_additional_content_exclusion_policy_rule = PermissionsConfigureAdditionalContentExclusionPolicyRule.from_dict(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyRule")) - permissions_configure_additional_content_exclusion_policy_rule_source = PermissionsConfigureAdditionalContentExclusionPolicyRuleSource.from_dict(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyRuleSource")) - permissions_configure_additional_content_exclusion_policy_scope = PermissionsConfigureAdditionalContentExclusionPolicyScope(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyScope")) - permissions_configure_params = PermissionsConfigureParams.from_dict(obj.get("PermissionsConfigureParams")) - permissions_configure_result = PermissionsConfigureResult.from_dict(obj.get("PermissionsConfigureResult")) - permissions_modify_rules_params = PermissionsModifyRulesParams.from_dict(obj.get("PermissionsModifyRulesParams")) - permissions_modify_rules_result = PermissionsModifyRulesResult.from_dict(obj.get("PermissionsModifyRulesResult")) - permissions_modify_rules_scope = PermissionsModifyRulesScope(obj.get("PermissionsModifyRulesScope")) - permissions_notify_prompt_shown_result = PermissionsNotifyPromptShownResult.from_dict(obj.get("PermissionsNotifyPromptShownResult")) - permissions_paths_add_result = PermissionsPathsAddResult.from_dict(obj.get("PermissionsPathsAddResult")) - permissions_paths_list_request = PermissionsPathsListRequest.from_dict(obj.get("PermissionsPathsListRequest")) - permissions_paths_update_primary_result = PermissionsPathsUpdatePrimaryResult.from_dict(obj.get("PermissionsPathsUpdatePrimaryResult")) - permissions_pending_requests_request = PermissionsPendingRequestsRequest.from_dict(obj.get("PermissionsPendingRequestsRequest")) permissions_reset_session_approvals_request = PermissionsResetSessionApprovalsRequest.from_dict(obj.get("PermissionsResetSessionApprovalsRequest")) permissions_reset_session_approvals_result = PermissionsResetSessionApprovalsResult.from_dict(obj.get("PermissionsResetSessionApprovalsResult")) permissions_set_approve_all_request = PermissionsSetApproveAllRequest.from_dict(obj.get("PermissionsSetApproveAllRequest")) permissions_set_approve_all_result = PermissionsSetApproveAllResult.from_dict(obj.get("PermissionsSetApproveAllResult")) - permissions_set_approve_all_source = PermissionsSetApproveAllSource(obj.get("PermissionsSetApproveAllSource")) - permissions_set_required_request = PermissionsSetRequiredRequest.from_dict(obj.get("PermissionsSetRequiredRequest")) - permissions_set_required_result = PermissionsSetRequiredResult.from_dict(obj.get("PermissionsSetRequiredResult")) - permissions_urls_set_unrestricted_mode_result = PermissionsUrlsSetUnrestrictedModeResult.from_dict(obj.get("PermissionsUrlsSetUnrestrictedModeResult")) - permission_urls_config = PermissionUrlsConfig.from_dict(obj.get("PermissionUrlsConfig")) - permission_urls_set_unrestricted_mode_params = PermissionUrlsSetUnrestrictedModeParams.from_dict(obj.get("PermissionUrlsSetUnrestrictedModeParams")) ping_request = PingRequest.from_dict(obj.get("PingRequest")) ping_result = PingResult.from_dict(obj.get("PingResult")) plan_read_result = PlanReadResult.from_dict(obj.get("PlanReadResult")) @@ -14770,45 +7903,13 @@ def from_dict(obj: Any) -> 'RPC': queued_command_handled = QueuedCommandHandled.from_dict(obj.get("QueuedCommandHandled")) queued_command_not_handled = QueuedCommandNotHandled.from_dict(obj.get("QueuedCommandNotHandled")) queued_command_result = QueuedCommandResult.from_dict(obj.get("QueuedCommandResult")) - queue_pending_items = QueuePendingItems.from_dict(obj.get("QueuePendingItems")) - queue_pending_items_kind = QueuePendingItemsKind(obj.get("QueuePendingItemsKind")) - queue_pending_items_result = QueuePendingItemsResult.from_dict(obj.get("QueuePendingItemsResult")) - queue_remove_most_recent_result = QueueRemoveMostRecentResult.from_dict(obj.get("QueueRemoveMostRecentResult")) - register_event_interest_params = RegisterEventInterestParams.from_dict(obj.get("RegisterEventInterestParams")) - register_event_interest_result = RegisterEventInterestResult.from_dict(obj.get("RegisterEventInterestResult")) - release_event_interest_params = ReleaseEventInterestParams.from_dict(obj.get("ReleaseEventInterestParams")) remote_enable_request = RemoteEnableRequest.from_dict(obj.get("RemoteEnableRequest")) remote_enable_result = RemoteEnableResult.from_dict(obj.get("RemoteEnableResult")) - remote_notify_steerable_changed_request = RemoteNotifySteerableChangedRequest.from_dict(obj.get("RemoteNotifySteerableChangedRequest")) - remote_notify_steerable_changed_result = RemoteNotifySteerableChangedResult.from_dict(obj.get("RemoteNotifySteerableChangedResult")) remote_session_connection_result = RemoteSessionConnectionResult.from_dict(obj.get("RemoteSessionConnectionResult")) remote_session_mode = RemoteSessionMode(obj.get("RemoteSessionMode")) - schedule_entry = ScheduleEntry.from_dict(obj.get("ScheduleEntry")) - schedule_list = ScheduleList.from_dict(obj.get("ScheduleList")) - schedule_stop_request = ScheduleStopRequest.from_dict(obj.get("ScheduleStopRequest")) - schedule_stop_result = ScheduleStopResult.from_dict(obj.get("ScheduleStopResult")) - send_agent_mode = SendAgentMode(obj.get("SendAgentMode")) - send_attachment = SendAttachment.from_dict(obj.get("SendAttachment")) - send_attachment_blob = SendAttachmentBlob.from_dict(obj.get("SendAttachmentBlob")) - send_attachment_directory = SendAttachmentDirectory.from_dict(obj.get("SendAttachmentDirectory")) - send_attachment_file = SendAttachmentFile.from_dict(obj.get("SendAttachmentFile")) - send_attachment_file_line_range = SendAttachmentFileLineRange.from_dict(obj.get("SendAttachmentFileLineRange")) - send_attachment_github_reference = SendAttachmentGithubReference.from_dict(obj.get("SendAttachmentGithubReference")) - send_attachment_github_reference_type = SendAttachmentGithubReferenceTypeEnum(obj.get("SendAttachmentGithubReferenceType")) - send_attachment_selection = SendAttachmentSelection.from_dict(obj.get("SendAttachmentSelection")) - send_attachment_selection_details = SendAttachmentSelectionDetails.from_dict(obj.get("SendAttachmentSelectionDetails")) - send_attachment_selection_details_end = SendAttachmentSelectionDetailsEnd.from_dict(obj.get("SendAttachmentSelectionDetailsEnd")) - send_attachment_selection_details_start = SendAttachmentSelectionDetailsStart.from_dict(obj.get("SendAttachmentSelectionDetailsStart")) - send_mode = SendMode(obj.get("SendMode")) - send_request = SendRequest.from_dict(obj.get("SendRequest")) - send_result = SendResult.from_dict(obj.get("SendResult")) server_skill = ServerSkill.from_dict(obj.get("ServerSkill")) server_skill_list = ServerSkillList.from_dict(obj.get("ServerSkillList")) session_auth_status = SessionAuthStatus.from_dict(obj.get("SessionAuthStatus")) - session_bulk_delete_result = SessionBulkDeleteResult.from_dict(obj.get("SessionBulkDeleteResult")) - session_context = SessionContext.from_dict(obj.get("SessionContext")) - session_context_host_type = SessionContextHostType(obj.get("SessionContextHostType")) - session_enrich_metadata_result = SessionEnrichMetadataResult.from_dict(obj.get("SessionEnrichMetadataResult")) session_fs_append_file_request = SessionFSAppendFileRequest.from_dict(obj.get("SessionFsAppendFileRequest")) session_fs_error = SessionFSError.from_dict(obj.get("SessionFsError")) session_fs_error_code = SessionFSErrorCode(obj.get("SessionFsErrorCode")) @@ -14837,68 +7938,21 @@ def from_dict(obj: Any) -> 'RPC': session_fs_stat_request = SessionFSStatRequest.from_dict(obj.get("SessionFsStatRequest")) session_fs_stat_result = SessionFSStatResult.from_dict(obj.get("SessionFsStatResult")) session_fs_write_file_request = SessionFSWriteFileRequest.from_dict(obj.get("SessionFsWriteFileRequest")) - session_installed_plugin = SessionInstalledPlugin.from_dict(obj.get("SessionInstalledPlugin")) - session_installed_plugin_source = from_union([SessionInstalledPluginSource.from_dict, from_str], obj.get("SessionInstalledPluginSource")) - session_installed_plugin_source_github = SessionInstalledPluginSourceGithub.from_dict(obj.get("SessionInstalledPluginSourceGithub")) - session_installed_plugin_source_local = SessionInstalledPluginSourceLocal.from_dict(obj.get("SessionInstalledPluginSourceLocal")) - session_installed_plugin_source_url = SessionInstalledPluginSourceURL.from_dict(obj.get("SessionInstalledPluginSourceUrl")) - session_list = SessionList.from_dict(obj.get("SessionList")) - session_load_deferred_repo_hooks_result = SessionLoadDeferredRepoHooksResult.from_dict(obj.get("SessionLoadDeferredRepoHooksResult")) session_log_level = SessionLogLevel(obj.get("SessionLogLevel")) - session_metadata = SessionMetadata.from_dict(obj.get("SessionMetadata")) - session_metadata_snapshot = SessionMetadataSnapshot.from_dict(obj.get("SessionMetadataSnapshot")) session_mode = SessionMode(obj.get("SessionMode")) - session_prune_result = SessionPruneResult.from_dict(obj.get("SessionPruneResult")) - sessions_bulk_delete_request = SessionsBulkDeleteRequest.from_dict(obj.get("SessionsBulkDeleteRequest")) - sessions_check_in_use_request = SessionsCheckInUseRequest.from_dict(obj.get("SessionsCheckInUseRequest")) - sessions_check_in_use_result = SessionsCheckInUseResult.from_dict(obj.get("SessionsCheckInUseResult")) - sessions_close_request = SessionsCloseRequest.from_dict(obj.get("SessionsCloseRequest")) - sessions_close_result = SessionsCloseResult.from_dict(obj.get("SessionsCloseResult")) - sessions_enrich_metadata_request = SessionsEnrichMetadataRequest.from_dict(obj.get("SessionsEnrichMetadataRequest")) - session_set_credentials_params = SessionSetCredentialsParams.from_dict(obj.get("SessionSetCredentialsParams")) - session_set_credentials_result = SessionSetCredentialsResult.from_dict(obj.get("SessionSetCredentialsResult")) - sessions_find_by_prefix_request = SessionsFindByPrefixRequest.from_dict(obj.get("SessionsFindByPrefixRequest")) - sessions_find_by_prefix_result = SessionsFindByPrefixResult.from_dict(obj.get("SessionsFindByPrefixResult")) - sessions_find_by_task_id_request = SessionsFindByTaskIDRequest.from_dict(obj.get("SessionsFindByTaskIDRequest")) - sessions_find_by_task_id_result = SessionsFindByTaskIDResult.from_dict(obj.get("SessionsFindByTaskIDResult")) sessions_fork_request = SessionsForkRequest.from_dict(obj.get("SessionsForkRequest")) sessions_fork_result = SessionsForkResult.from_dict(obj.get("SessionsForkResult")) - sessions_get_event_file_path_request = SessionsGetEventFilePathRequest.from_dict(obj.get("SessionsGetEventFilePathRequest")) - sessions_get_event_file_path_result = SessionsGetEventFilePathResult.from_dict(obj.get("SessionsGetEventFilePathResult")) - sessions_get_last_for_context_request = SessionsGetLastForContextRequest.from_dict(obj.get("SessionsGetLastForContextRequest")) - sessions_get_last_for_context_result = SessionsGetLastForContextResult.from_dict(obj.get("SessionsGetLastForContextResult")) - sessions_get_persisted_remote_steerable_request = SessionsGetPersistedRemoteSteerableRequest.from_dict(obj.get("SessionsGetPersistedRemoteSteerableRequest")) - sessions_get_persisted_remote_steerable_result = SessionsGetPersistedRemoteSteerableResult.from_dict(obj.get("SessionsGetPersistedRemoteSteerableResult")) - session_sizes = SessionSizes.from_dict(obj.get("SessionSizes")) - sessions_list_request = SessionsListRequest.from_dict(obj.get("SessionsListRequest")) - sessions_load_deferred_repo_hooks_request = SessionsLoadDeferredRepoHooksRequest.from_dict(obj.get("SessionsLoadDeferredRepoHooksRequest")) - sessions_prune_old_request = SessionsPruneOldRequest.from_dict(obj.get("SessionsPruneOldRequest")) - sessions_release_lock_request = SessionsReleaseLockRequest.from_dict(obj.get("SessionsReleaseLockRequest")) - sessions_release_lock_result = SessionsReleaseLockResult.from_dict(obj.get("SessionsReleaseLockResult")) - sessions_reload_plugin_hooks_request = SessionsReloadPluginHooksRequest.from_dict(obj.get("SessionsReloadPluginHooksRequest")) - sessions_reload_plugin_hooks_result = SessionsReloadPluginHooksResult.from_dict(obj.get("SessionsReloadPluginHooksResult")) - sessions_save_request = SessionsSaveRequest.from_dict(obj.get("SessionsSaveRequest")) - sessions_save_result = SessionsSaveResult.from_dict(obj.get("SessionsSaveResult")) - sessions_set_additional_plugins_request = SessionsSetAdditionalPluginsRequest.from_dict(obj.get("SessionsSetAdditionalPluginsRequest")) - sessions_set_additional_plugins_result = SessionsSetAdditionalPluginsResult.from_dict(obj.get("SessionsSetAdditionalPluginsResult")) - session_update_options_params = SessionUpdateOptionsParams.from_dict(obj.get("SessionUpdateOptionsParams")) - session_update_options_result = SessionUpdateOptionsResult.from_dict(obj.get("SessionUpdateOptionsResult")) - session_working_directory_context = SessionWorkingDirectoryContext.from_dict(obj.get("SessionWorkingDirectoryContext")) - session_working_directory_context_host_type = SessionContextHostType(obj.get("SessionWorkingDirectoryContextHostType")) shell_exec_request = ShellExecRequest.from_dict(obj.get("ShellExecRequest")) shell_exec_result = ShellExecResult.from_dict(obj.get("ShellExecResult")) shell_kill_request = ShellKillRequest.from_dict(obj.get("ShellKillRequest")) shell_kill_result = ShellKillResult.from_dict(obj.get("ShellKillResult")) shell_kill_signal = ShellKillSignal(obj.get("ShellKillSignal")) - shutdown_request = ShutdownRequest.from_dict(obj.get("ShutdownRequest")) skill = Skill.from_dict(obj.get("Skill")) skill_list = SkillList.from_dict(obj.get("SkillList")) skills_config_set_disabled_skills_request = SkillsConfigSetDisabledSkillsRequest.from_dict(obj.get("SkillsConfigSetDisabledSkillsRequest")) skills_disable_request = SkillsDisableRequest.from_dict(obj.get("SkillsDisableRequest")) skills_discover_request = SkillsDiscoverRequest.from_dict(obj.get("SkillsDiscoverRequest")) skills_enable_request = SkillsEnableRequest.from_dict(obj.get("SkillsEnableRequest")) - skills_get_invoked_result = SkillsGetInvokedResult.from_dict(obj.get("SkillsGetInvokedResult")) - skills_invoked_skill = SkillsInvokedSkill.from_dict(obj.get("SkillsInvokedSkill")) skills_load_diagnostics = SkillsLoadDiagnostics.from_dict(obj.get("SkillsLoadDiagnostics")) slash_command_agent_prompt_result = SlashCommandAgentPromptResult.from_dict(obj.get("SlashCommandAgentPromptResult")) slash_command_completed_result = SlashCommandCompletedResult.from_dict(obj.get("SlashCommandCompletedResult")) @@ -14909,22 +7963,15 @@ def from_dict(obj: Any) -> 'RPC': slash_command_kind = SlashCommandKind(obj.get("SlashCommandKind")) slash_command_text_result = SlashCommandTextResult.from_dict(obj.get("SlashCommandTextResult")) task_agent_info = TaskAgentInfo.from_dict(obj.get("TaskAgentInfo")) - task_agent_progress = TaskAgentProgress.from_dict(obj.get("TaskAgentProgress")) task_execution_mode = TaskExecutionMode(obj.get("TaskExecutionMode")) task_info = TaskInfo.from_dict(obj.get("TaskInfo")) task_list = TaskList.from_dict(obj.get("TaskList")) tasks_cancel_request = TasksCancelRequest.from_dict(obj.get("TasksCancelRequest")) tasks_cancel_result = TasksCancelResult.from_dict(obj.get("TasksCancelResult")) - tasks_get_current_promotable_result = TasksGetCurrentPromotableResult.from_dict(obj.get("TasksGetCurrentPromotableResult")) - tasks_get_progress_request = TasksGetProgressRequest.from_dict(obj.get("TasksGetProgressRequest")) - tasks_get_progress_result = TasksGetProgressResult.from_dict(obj.get("TasksGetProgressResult")) task_shell_info = TaskShellInfo.from_dict(obj.get("TaskShellInfo")) task_shell_info_attachment_mode = TaskShellInfoAttachmentMode(obj.get("TaskShellInfoAttachmentMode")) - task_shell_progress = from_none(obj.get("TaskShellProgress")) - tasks_promote_current_to_background_result = TasksPromoteCurrentToBackgroundResult.from_dict(obj.get("TasksPromoteCurrentToBackgroundResult")) tasks_promote_to_background_request = TasksPromoteToBackgroundRequest.from_dict(obj.get("TasksPromoteToBackgroundRequest")) tasks_promote_to_background_result = TasksPromoteToBackgroundResult.from_dict(obj.get("TasksPromoteToBackgroundResult")) - tasks_refresh_result = TasksRefreshResult.from_dict(obj.get("TasksRefreshResult")) tasks_remove_request = TasksRemoveRequest.from_dict(obj.get("TasksRemoveRequest")) tasks_remove_result = TasksRemoveResult.from_dict(obj.get("TasksRemoveResult")) tasks_send_message_request = TasksSendMessageRequest.from_dict(obj.get("TasksSendMessageRequest")) @@ -14932,14 +7979,9 @@ def from_dict(obj: Any) -> 'RPC': tasks_start_agent_request = TasksStartAgentRequest.from_dict(obj.get("TasksStartAgentRequest")) tasks_start_agent_result = TasksStartAgentResult.from_dict(obj.get("TasksStartAgentResult")) task_status = TaskStatus(obj.get("TaskStatus")) - tasks_wait_for_pending_result = TasksWaitForPendingResult.from_dict(obj.get("TasksWaitForPendingResult")) - telemetry_set_feature_overrides_request = TelemetrySetFeatureOverridesRequest.from_dict(obj.get("TelemetrySetFeatureOverridesRequest")) - token_auth_info = TokenAuthInfo.from_dict(obj.get("TokenAuthInfo")) tool = Tool.from_dict(obj.get("Tool")) tool_list = ToolList.from_dict(obj.get("ToolList")) - tools_initialize_and_validate_result = ToolsInitializeAndValidateResult.from_dict(obj.get("ToolsInitializeAndValidateResult")) tools_list_request = ToolsListRequest.from_dict(obj.get("ToolsListRequest")) - ui_auto_mode_switch_response = UIAutoModeSwitchResponse(obj.get("UIAutoModeSwitchResponse")) ui_elicitation_array_any_of_field = UIElicitationArrayAnyOfField.from_dict(obj.get("UIElicitationArrayAnyOfField")) ui_elicitation_array_any_of_field_items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("UIElicitationArrayAnyOfFieldItems")) ui_elicitation_array_any_of_field_items_any_of = UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict(obj.get("UIElicitationArrayAnyOfFieldItemsAnyOf")) @@ -14961,19 +8003,7 @@ def from_dict(obj: Any) -> 'RPC': ui_elicitation_string_enum_field = UIElicitationStringEnumField.from_dict(obj.get("UIElicitationStringEnumField")) ui_elicitation_string_one_of_field = UIElicitationStringOneOfField.from_dict(obj.get("UIElicitationStringOneOfField")) ui_elicitation_string_one_of_field_one_of = UIElicitationStringOneOfFieldOneOf.from_dict(obj.get("UIElicitationStringOneOfFieldOneOf")) - ui_exit_plan_mode_action = UIExitPlanModeAction(obj.get("UIExitPlanModeAction")) - ui_exit_plan_mode_response = UIExitPlanModeResponse.from_dict(obj.get("UIExitPlanModeResponse")) - ui_handle_pending_auto_mode_switch_request = UIHandlePendingAutoModeSwitchRequest.from_dict(obj.get("UIHandlePendingAutoModeSwitchRequest")) ui_handle_pending_elicitation_request = UIHandlePendingElicitationRequest.from_dict(obj.get("UIHandlePendingElicitationRequest")) - ui_handle_pending_exit_plan_mode_request = UIHandlePendingExitPlanModeRequest.from_dict(obj.get("UIHandlePendingExitPlanModeRequest")) - ui_handle_pending_result = UIHandlePendingResult.from_dict(obj.get("UIHandlePendingResult")) - ui_handle_pending_sampling_request = UIHandlePendingSamplingRequest.from_dict(obj.get("UIHandlePendingSamplingRequest")) - ui_handle_pending_sampling_response = from_dict(lambda x: x, obj.get("UIHandlePendingSamplingResponse")) - ui_handle_pending_user_input_request = UIHandlePendingUserInputRequest.from_dict(obj.get("UIHandlePendingUserInputRequest")) - ui_register_direct_auto_mode_switch_handler_result = UIRegisterDirectAutoModeSwitchHandlerResult.from_dict(obj.get("UIRegisterDirectAutoModeSwitchHandlerResult")) - ui_unregister_direct_auto_mode_switch_handler_request = UIUnregisterDirectAutoModeSwitchHandlerRequest.from_dict(obj.get("UIUnregisterDirectAutoModeSwitchHandlerRequest")) - ui_unregister_direct_auto_mode_switch_handler_result = UIUnregisterDirectAutoModeSwitchHandlerResult.from_dict(obj.get("UIUnregisterDirectAutoModeSwitchHandlerResult")) - ui_user_input_response = UIUserInputResponse.from_dict(obj.get("UIUserInputResponse")) usage_get_metrics_result = UsageGetMetricsResult.from_dict(obj.get("UsageGetMetricsResult")) usage_metrics_code_changes = UsageMetricsCodeChanges.from_dict(obj.get("UsageMetricsCodeChanges")) usage_metrics_model_metric = UsageMetricsModelMetric.from_dict(obj.get("UsageMetricsModelMetric")) @@ -14981,47 +8011,24 @@ def from_dict(obj: Any) -> 'RPC': usage_metrics_model_metric_token_detail = UsageMetricsModelMetricTokenDetail.from_dict(obj.get("UsageMetricsModelMetricTokenDetail")) usage_metrics_model_metric_usage = UsageMetricsModelMetricUsage.from_dict(obj.get("UsageMetricsModelMetricUsage")) usage_metrics_token_detail = UsageMetricsTokenDetail.from_dict(obj.get("UsageMetricsTokenDetail")) - user_auth_info = UserAuthInfo.from_dict(obj.get("UserAuthInfo")) - user_tool_session_approval_commands = UserToolSessionApprovalCommands.from_dict(obj.get("UserToolSessionApprovalCommands")) - user_tool_session_approval_custom_tool = UserToolSessionApprovalCustomTool.from_dict(obj.get("UserToolSessionApprovalCustomTool")) - user_tool_session_approval_extension_management = UserToolSessionApprovalExtensionManagement.from_dict(obj.get("UserToolSessionApprovalExtensionManagement")) - user_tool_session_approval_extension_permission_access = UserToolSessionApprovalExtensionPermissionAccess.from_dict(obj.get("UserToolSessionApprovalExtensionPermissionAccess")) - user_tool_session_approval_mcp = UserToolSessionApprovalMCP.from_dict(obj.get("UserToolSessionApprovalMcp")) - user_tool_session_approval_memory = UserToolSessionApprovalMemory.from_dict(obj.get("UserToolSessionApprovalMemory")) - user_tool_session_approval_read = UserToolSessionApprovalRead.from_dict(obj.get("UserToolSessionApprovalRead")) - user_tool_session_approval_write = UserToolSessionApprovalWrite.from_dict(obj.get("UserToolSessionApprovalWrite")) - workspaces_checkpoints = WorkspacesCheckpoints.from_dict(obj.get("WorkspacesCheckpoints")) workspaces_create_file_request = WorkspacesCreateFileRequest.from_dict(obj.get("WorkspacesCreateFileRequest")) workspaces_get_workspace_result = WorkspacesGetWorkspaceResult.from_dict(obj.get("WorkspacesGetWorkspaceResult")) - workspaces_list_checkpoints_result = WorkspacesListCheckpointsResult.from_dict(obj.get("WorkspacesListCheckpointsResult")) workspaces_list_files_result = WorkspacesListFilesResult.from_dict(obj.get("WorkspacesListFilesResult")) - workspaces_read_checkpoint_request = WorkspacesReadCheckpointRequest.from_dict(obj.get("WorkspacesReadCheckpointRequest")) - workspaces_read_checkpoint_result = WorkspacesReadCheckpointResult.from_dict(obj.get("WorkspacesReadCheckpointResult")) workspaces_read_file_request = WorkspacesReadFileRequest.from_dict(obj.get("WorkspacesReadFileRequest")) workspaces_read_file_result = WorkspacesReadFileResult.from_dict(obj.get("WorkspacesReadFileResult")) - workspaces_save_large_paste_request = WorkspacesSaveLargePasteRequest.from_dict(obj.get("WorkspacesSaveLargePasteRequest")) - workspaces_save_large_paste_result = WorkspacesSaveLargePasteResult.from_dict(obj.get("WorkspacesSaveLargePasteResult")) - session_context_info = from_union([SessionContextInfo.from_dict, from_none], obj.get("SessionContextInfo")) - task_progress = from_union([TaskProgressClass.from_dict, from_none], obj.get("TaskProgress")) - workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, account_get_quota_request, account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_reload_result, agent_select_request, agent_select_result, api_key_auth_info, auth_info, auth_info_type, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, discovered_mcp_server, discovered_mcp_server_type, enqueue_command_params, enqueue_command_result, env_auth_info, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_result, execute_command_params, execute_command_result, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, gh_cli_auth_info, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_compact_context_window, history_compact_result, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, installed_plugin, installed_plugin_source, installed_plugin_source_github, installed_plugin_source_local, installed_plugin_source_url, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, lsp_initialize_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_oauth_login_request, mcp_oauth_login_result, mcp_remove_git_hub_result, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_auth, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_list, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, model, model_billing, model_billing_token_prices, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_picker_category, model_picker_price_category, model_policy, model_policy_state, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, options_update_env_value_mode, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_cancelled, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, queued_command_handled, queued_command_not_handled, queued_command_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_most_recent_result, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_mode, schedule_entry, schedule_list, schedule_stop_request, schedule_stop_result, send_agent_mode, send_attachment, send_attachment_blob, send_attachment_directory, send_attachment_file, send_attachment_file_line_range, send_attachment_github_reference, send_attachment_github_reference_type, send_attachment_selection, send_attachment_selection_details, send_attachment_selection_details_end, send_attachment_selection_details_start, send_mode, send_request, send_result, server_skill, server_skill_list, session_auth_status, session_bulk_delete_result, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_github, session_installed_plugin_source_local, session_installed_plugin_source_url, session_list, session_load_deferred_repo_hooks_result, session_log_level, session_metadata, session_metadata_snapshot, session_mode, session_prune_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_close_request, sessions_close_result, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_prune_old_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, session_update_options_params, session_update_options_result, session_working_directory_context, session_working_directory_context_host_type, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, shutdown_request, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_text_result, task_agent_info, task_agent_progress, task_execution_mode, task_info, task_list, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, tool, tool_list, tools_initialize_and_validate_result, tools_list_request, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, user_auth_info, user_tool_session_approval_commands, user_tool_session_approval_custom_tool, user_tool_session_approval_extension_management, user_tool_session_approval_extension_permission_access, user_tool_session_approval_mcp, user_tool_session_approval_memory, user_tool_session_approval_read, user_tool_session_approval_write, workspaces_checkpoints, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_save_large_paste_request, workspaces_save_large_paste_result, session_context_info, task_progress, workspace_summary) + return RPC(account_get_quota_request, account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_list, agent_reload_result, agent_select_request, agent_select_result, auth_info_type, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, current_model, discovered_mcp_server, discovered_mcp_server_type, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, handle_pending_tool_call_request, handle_pending_tool_call_result, history_compact_context_window, history_compact_result, history_truncate_request, history_truncate_result, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_oauth_login_request, mcp_oauth_login_result, mcp_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_auth, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_list, model, model_billing, model_billing_token_prices, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_picker_category, model_picker_price_category, model_policy, model_policy_state, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_request, permission_decision, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_request_result, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, queued_command_handled, queued_command_not_handled, queued_command_result, remote_enable_request, remote_enable_result, remote_session_connection_result, remote_session_mode, server_skill, server_skill_list, session_auth_status, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_log_level, session_mode, sessions_fork_request, sessions_fork_result, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_text_result, task_agent_info, task_execution_mode, task_info, task_list, tasks_cancel_request, tasks_cancel_result, task_shell_info, task_shell_info_attachment_mode, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tool, tool_list, tools_list_request, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_handle_pending_elicitation_request, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_files_result, workspaces_read_file_request, workspaces_read_file_result) def to_dict(self) -> dict: result: dict = {} - result["AbortRequest"] = to_class(AbortRequest, self.abort_request) - result["AbortResult"] = to_class(AbortResult, self.abort_result) result["AccountGetQuotaRequest"] = to_class(AccountGetQuotaRequest, self.account_get_quota_request) result["AccountGetQuotaResult"] = to_class(AccountGetQuotaResult, self.account_get_quota_result) result["AccountQuotaSnapshot"] = to_class(AccountQuotaSnapshot, self.account_quota_snapshot) result["AgentGetCurrentResult"] = to_class(AgentGetCurrentResult, self.agent_get_current_result) result["AgentInfo"] = to_class(AgentInfo, self.agent_info) - result["AgentInfoSource"] = to_enum(AgentInfoSource, self.agent_info_source) result["AgentList"] = to_class(AgentList, self.agent_list) result["AgentReloadResult"] = to_class(AgentReloadResult, self.agent_reload_result) result["AgentSelectRequest"] = to_class(AgentSelectRequest, self.agent_select_request) result["AgentSelectResult"] = to_class(AgentSelectResult, self.agent_select_result) - result["ApiKeyAuthInfo"] = to_class(APIKeyAuthInfo, self.api_key_auth_info) - result["AuthInfo"] = to_class(AuthInfo, self.auth_info) result["AuthInfoType"] = to_enum(AuthInfoType, self.auth_info_type) result["CommandList"] = to_class(CommandList, self.command_list) result["CommandsHandlePendingCommandRequest"] = to_class(CommandsHandlePendingCommandRequest, self.commands_handle_pending_command_request) @@ -15037,28 +8044,9 @@ def to_dict(self) -> dict: result["ConnectRequest"] = to_class(ConnectRequest, self.connect_request) result["ConnectResult"] = to_class(ConnectResult, self.connect_result) result["ContentFilterMode"] = to_enum(ContentFilterMode, self.content_filter_mode) - result["CopilotApiTokenAuthInfo"] = to_class(CopilotAPITokenAuthInfo, self.copilot_api_token_auth_info) - result["CopilotUserResponse"] = to_class(CopilotUserResponse, self.copilot_user_response) - result["CopilotUserResponseEndpoints"] = to_class(CopilotUserResponseEndpoints, self.copilot_user_response_endpoints) - result["CopilotUserResponseQuotaSnapshots"] = from_dict(lambda x: from_union([lambda x: to_class(CopilotUserResponseQuotaSnapshots, x), from_none], x), self.copilot_user_response_quota_snapshots) - result["CopilotUserResponseQuotaSnapshotsChat"] = to_class(CopilotUserResponseQuotaSnapshotsChat, self.copilot_user_response_quota_snapshots_chat) - result["CopilotUserResponseQuotaSnapshotsCompletions"] = to_class(CopilotUserResponseQuotaSnapshotsCompletions, self.copilot_user_response_quota_snapshots_completions) - result["CopilotUserResponseQuotaSnapshotsPremiumInteractions"] = to_class(CopilotUserResponseQuotaSnapshotsPremiumInteractions, self.copilot_user_response_quota_snapshots_premium_interactions) result["CurrentModel"] = to_class(CurrentModel, self.current_model) result["DiscoveredMcpServer"] = to_class(DiscoveredMCPServer, self.discovered_mcp_server) result["DiscoveredMcpServerType"] = to_enum(DiscoveredMCPServerType, self.discovered_mcp_server_type) - result["EnqueueCommandParams"] = to_class(EnqueueCommandParams, self.enqueue_command_params) - result["EnqueueCommandResult"] = to_class(EnqueueCommandResult, self.enqueue_command_result) - result["EnvAuthInfo"] = to_class(EnvAuthInfo, self.env_auth_info) - result["EventLogReadRequest"] = to_class(EventLogReadRequest, self.event_log_read_request) - result["EventLogReleaseInterestResult"] = to_class(EventLogReleaseInterestResult, self.event_log_release_interest_result) - result["EventLogTailResult"] = to_class(EventLogTailResult, self.event_log_tail_result) - result["EventLogTypes"] = from_union([lambda x: from_list(from_str, x), lambda x: to_enum(EventLogTypes, x)], self.event_log_types) - result["EventsAgentScope"] = to_enum(EventsAgentScope, self.events_agent_scope) - result["EventsCursorStatus"] = to_enum(EventsCursorStatus, self.events_cursor_status) - result["EventsReadResult"] = to_class(EventsReadResult, self.events_read_result) - result["ExecuteCommandParams"] = to_class(ExecuteCommandParams, self.execute_command_params) - result["ExecuteCommandResult"] = to_class(ExecuteCommandResult, self.execute_command_result) result["Extension"] = to_class(Extension, self.extension) result["ExtensionList"] = to_class(ExtensionList, self.extension_list) result["ExtensionsDisableRequest"] = to_class(ExtensionsDisableRequest, self.extensions_disable_request) @@ -15082,31 +8070,18 @@ def to_dict(self) -> dict: result["FilterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x)], self.filter_mapping) result["FleetStartRequest"] = to_class(FleetStartRequest, self.fleet_start_request) result["FleetStartResult"] = to_class(FleetStartResult, self.fleet_start_result) - result["GhCliAuthInfo"] = to_class(GhCLIAuthInfo, self.gh_cli_auth_info) result["HandlePendingToolCallRequest"] = to_class(HandlePendingToolCallRequest, self.handle_pending_tool_call_request) result["HandlePendingToolCallResult"] = to_class(HandlePendingToolCallResult, self.handle_pending_tool_call_result) - result["HistoryAbortManualCompactionResult"] = to_class(HistoryAbortManualCompactionResult, self.history_abort_manual_compaction_result) - result["HistoryCancelBackgroundCompactionResult"] = to_class(HistoryCancelBackgroundCompactionResult, self.history_cancel_background_compaction_result) result["HistoryCompactContextWindow"] = to_class(HistoryCompactContextWindow, self.history_compact_context_window) result["HistoryCompactResult"] = to_class(HistoryCompactResult, self.history_compact_result) - result["HistorySummarizeForHandoffResult"] = to_class(HistorySummarizeForHandoffResult, self.history_summarize_for_handoff_result) result["HistoryTruncateRequest"] = to_class(HistoryTruncateRequest, self.history_truncate_request) result["HistoryTruncateResult"] = to_class(HistoryTruncateResult, self.history_truncate_result) - result["HMACAuthInfo"] = to_class(HMACAuthInfo, self.hmac_auth_info) - result["InstalledPlugin"] = to_class(InstalledPlugin, self.installed_plugin) - result["InstalledPluginSource"] = from_union([lambda x: to_class(InstalledPluginSource, x), from_str], self.installed_plugin_source) - result["InstalledPluginSourceGithub"] = to_class(InstalledPluginSourceGithub, self.installed_plugin_source_github) - result["InstalledPluginSourceLocal"] = to_class(InstalledPluginSourceLocal, self.installed_plugin_source_local) - result["InstalledPluginSourceUrl"] = to_class(InstalledPluginSourceURL, self.installed_plugin_source_url) result["InstructionsGetSourcesResult"] = to_class(InstructionsGetSourcesResult, self.instructions_get_sources_result) result["InstructionsSources"] = to_class(InstructionsSources, self.instructions_sources) result["InstructionsSourcesLocation"] = to_enum(InstructionsSourcesLocation, self.instructions_sources_location) result["InstructionsSourcesType"] = to_enum(InstructionsSourcesType, self.instructions_sources_type) result["LogRequest"] = to_class(LogRequest, self.log_request) result["LogResult"] = to_class(LogResult, self.log_result) - result["LspInitializeRequest"] = to_class(LspInitializeRequest, self.lsp_initialize_request) - result["McpCancelSamplingExecutionParams"] = to_class(MCPCancelSamplingExecutionParams, self.mcp_cancel_sampling_execution_params) - result["McpCancelSamplingExecutionResult"] = to_class(MCPCancelSamplingExecutionResult, self.mcp_cancel_sampling_execution_result) result["McpConfigAddRequest"] = to_class(MCPConfigAddRequest, self.mcp_config_add_request) result["McpConfigDisableRequest"] = to_class(MCPConfigDisableRequest, self.mcp_config_disable_request) result["McpConfigEnableRequest"] = to_class(MCPConfigEnableRequest, self.mcp_config_enable_request) @@ -15117,14 +8092,8 @@ def to_dict(self) -> dict: result["McpDiscoverRequest"] = to_class(MCPDiscoverRequest, self.mcp_discover_request) result["McpDiscoverResult"] = to_class(MCPDiscoverResult, self.mcp_discover_result) result["McpEnableRequest"] = to_class(MCPEnableRequest, self.mcp_enable_request) - result["McpExecuteSamplingParams"] = to_class(MCPExecuteSamplingParams, self.mcp_execute_sampling_params) - result["McpExecuteSamplingRequest"] = from_dict(lambda x: x, self.mcp_execute_sampling_request) - result["McpExecuteSamplingResult"] = from_dict(lambda x: x, self.mcp_execute_sampling_result) result["McpOauthLoginRequest"] = to_class(MCPOauthLoginRequest, self.mcp_oauth_login_request) result["McpOauthLoginResult"] = to_class(MCPOauthLoginResult, self.mcp_oauth_login_result) - result["McpRemoveGitHubResult"] = to_class(MCPRemoveGitHubResult, self.mcp_remove_git_hub_result) - result["McpSamplingExecutionAction"] = to_enum(MCPSamplingExecutionAction, self.mcp_sampling_execution_action) - result["McpSamplingExecutionResult"] = to_class(MCPSamplingExecutionResult, self.mcp_sampling_execution_result) result["McpServer"] = to_class(MCPServer, self.mcp_server) result["McpServerConfig"] = to_class(MCPServerConfig, self.mcp_server_config) result["McpServerConfigHttp"] = to_class(MCPServerConfigHTTP, self.mcp_server_config_http) @@ -15133,22 +8102,6 @@ def to_dict(self) -> dict: result["McpServerConfigHttpType"] = to_enum(MCPServerConfigHTTPType, self.mcp_server_config_http_type) result["McpServerConfigStdio"] = to_class(MCPServerConfigStdio, self.mcp_server_config_stdio) result["McpServerList"] = to_class(MCPServerList, self.mcp_server_list) - result["McpSetEnvValueModeDetails"] = to_enum(MCPSetEnvValueModeDetails, self.mcp_set_env_value_mode_details) - result["McpSetEnvValueModeParams"] = to_class(MCPSetEnvValueModeParams, self.mcp_set_env_value_mode_params) - result["McpSetEnvValueModeResult"] = to_class(MCPSetEnvValueModeResult, self.mcp_set_env_value_mode_result) - result["MetadataContextInfoRequest"] = to_class(MetadataContextInfoRequest, self.metadata_context_info_request) - result["MetadataContextInfoResult"] = to_class(MetadataContextInfoResult, self.metadata_context_info_result) - result["MetadataIsProcessingResult"] = to_class(MetadataIsProcessingResult, self.metadata_is_processing_result) - result["MetadataRecomputeContextTokensRequest"] = to_class(MetadataRecomputeContextTokensRequest, self.metadata_recompute_context_tokens_request) - result["MetadataRecomputeContextTokensResult"] = to_class(MetadataRecomputeContextTokensResult, self.metadata_recompute_context_tokens_result) - result["MetadataRecordContextChangeRequest"] = to_class(MetadataRecordContextChangeRequest, self.metadata_record_context_change_request) - result["MetadataRecordContextChangeResult"] = to_class(MetadataRecordContextChangeResult, self.metadata_record_context_change_result) - result["MetadataSetWorkingDirectoryRequest"] = to_class(MetadataSetWorkingDirectoryRequest, self.metadata_set_working_directory_request) - result["MetadataSetWorkingDirectoryResult"] = to_class(MetadataSetWorkingDirectoryResult, self.metadata_set_working_directory_result) - result["MetadataSnapshotCurrentMode"] = to_enum(MetadataSnapshotCurrentMode, self.metadata_snapshot_current_mode) - result["MetadataSnapshotRemoteMetadata"] = to_class(MetadataSnapshotRemoteMetadata, self.metadata_snapshot_remote_metadata) - result["MetadataSnapshotRemoteMetadataRepository"] = to_class(MetadataSnapshotRemoteMetadataRepository, self.metadata_snapshot_remote_metadata_repository) - result["MetadataSnapshotRemoteMetadataTaskType"] = to_enum(MetadataSnapshotRemoteMetadataTaskType, self.metadata_snapshot_remote_metadata_task_type) result["Model"] = to_class(Model, self.model) result["ModelBilling"] = to_class(ModelBilling, self.model_billing) result["ModelBillingTokenPrices"] = to_class(ModelBillingTokenPrices, self.model_billing_token_prices) @@ -15165,23 +8118,13 @@ def to_dict(self) -> dict: result["ModelPickerPriceCategory"] = to_enum(ModelPickerPriceCategory, self.model_picker_price_category) result["ModelPolicy"] = to_class(ModelPolicy, self.model_policy) result["ModelPolicyState"] = to_enum(ModelPolicyState, self.model_policy_state) - result["ModelSetReasoningEffortRequest"] = to_class(ModelSetReasoningEffortRequest, self.model_set_reasoning_effort_request) - result["ModelSetReasoningEffortResult"] = to_class(ModelSetReasoningEffortResult, self.model_set_reasoning_effort_result) result["ModelsListRequest"] = to_class(ModelsListRequest, self.models_list_request) result["ModelSwitchToRequest"] = to_class(ModelSwitchToRequest, self.model_switch_to_request) result["ModelSwitchToResult"] = to_class(ModelSwitchToResult, self.model_switch_to_result) result["ModeSetRequest"] = to_class(ModeSetRequest, self.mode_set_request) result["NameGetResult"] = to_class(NameGetResult, self.name_get_result) - result["NameSetAutoRequest"] = to_class(NameSetAutoRequest, self.name_set_auto_request) - result["NameSetAutoResult"] = to_class(NameSetAutoResult, self.name_set_auto_result) result["NameSetRequest"] = to_class(NameSetRequest, self.name_set_request) - result["OptionsUpdateEnvValueMode"] = to_enum(MCPSetEnvValueModeDetails, self.options_update_env_value_mode) - result["PendingPermissionRequest"] = to_class(PendingPermissionRequest, self.pending_permission_request) - result["PendingPermissionRequestList"] = to_class(PendingPermissionRequestList, self.pending_permission_request_list) result["PermissionDecision"] = to_class(PermissionDecision, self.permission_decision) - result["PermissionDecisionApproved"] = to_class(PermissionDecisionApproved, self.permission_decision_approved) - result["PermissionDecisionApprovedForLocation"] = to_class(PermissionDecisionApprovedForLocation, self.permission_decision_approved_for_location) - result["PermissionDecisionApprovedForSession"] = to_class(PermissionDecisionApprovedForSession, self.permission_decision_approved_for_session) result["PermissionDecisionApproveForLocation"] = to_class(PermissionDecisionApproveForLocation, self.permission_decision_approve_for_location) result["PermissionDecisionApproveForLocationApproval"] = to_class(PermissionDecisionApproveForLocationApproval, self.permission_decision_approve_for_location_approval) result["PermissionDecisionApproveForLocationApprovalCommands"] = to_class(PermissionDecisionApproveForLocationApprovalCommands, self.permission_decision_approve_for_location_approval_commands) @@ -15206,50 +8149,14 @@ def to_dict(self) -> dict: result["PermissionDecisionApproveForSessionApprovalWrite"] = to_class(PermissionDecisionApproveForSessionApprovalWrite, self.permission_decision_approve_for_session_approval_write) result["PermissionDecisionApproveOnce"] = to_class(PermissionDecisionApproveOnce, self.permission_decision_approve_once) result["PermissionDecisionApprovePermanently"] = to_class(PermissionDecisionApprovePermanently, self.permission_decision_approve_permanently) - result["PermissionDecisionCancelled"] = to_class(PermissionDecisionCancelled, self.permission_decision_cancelled) - result["PermissionDecisionDeniedByContentExclusionPolicy"] = to_class(PermissionDecisionDeniedByContentExclusionPolicy, self.permission_decision_denied_by_content_exclusion_policy) - result["PermissionDecisionDeniedByPermissionRequestHook"] = to_class(PermissionDecisionDeniedByPermissionRequestHook, self.permission_decision_denied_by_permission_request_hook) - result["PermissionDecisionDeniedByRules"] = to_class(PermissionDecisionDeniedByRules, self.permission_decision_denied_by_rules) - result["PermissionDecisionDeniedInteractivelyByUser"] = to_class(PermissionDecisionDeniedInteractivelyByUser, self.permission_decision_denied_interactively_by_user) - result["PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser"] = to_class(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser, self.permission_decision_denied_no_approval_rule_and_could_not_request_from_user) result["PermissionDecisionReject"] = to_class(PermissionDecisionReject, self.permission_decision_reject) result["PermissionDecisionRequest"] = to_class(PermissionDecisionRequest, self.permission_decision_request) result["PermissionDecisionUserNotAvailable"] = to_class(PermissionDecisionUserNotAvailable, self.permission_decision_user_not_available) - result["PermissionPathsAddParams"] = to_class(PermissionPathsAddParams, self.permission_paths_add_params) - result["PermissionPathsAllowedCheckParams"] = to_class(PermissionPathsAllowedCheckParams, self.permission_paths_allowed_check_params) - result["PermissionPathsAllowedCheckResult"] = to_class(PermissionPathsAllowedCheckResult, self.permission_paths_allowed_check_result) - result["PermissionPathsConfig"] = to_class(PermissionPathsConfig, self.permission_paths_config) - result["PermissionPathsList"] = to_class(PermissionPathsList, self.permission_paths_list) - result["PermissionPathsUpdatePrimaryParams"] = to_class(PermissionPathsUpdatePrimaryParams, self.permission_paths_update_primary_params) - result["PermissionPathsWorkspaceCheckParams"] = to_class(PermissionPathsWorkspaceCheckParams, self.permission_paths_workspace_check_params) - result["PermissionPathsWorkspaceCheckResult"] = to_class(PermissionPathsWorkspaceCheckResult, self.permission_paths_workspace_check_result) - result["PermissionPromptShownNotification"] = to_class(PermissionPromptShownNotification, self.permission_prompt_shown_notification) result["PermissionRequestResult"] = to_class(PermissionRequestResult, self.permission_request_result) - result["PermissionRulesSet"] = to_class(PermissionRulesSet, self.permission_rules_set) - result["PermissionsConfigureAdditionalContentExclusionPolicy"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicy, self.permissions_configure_additional_content_exclusion_policy) - result["PermissionsConfigureAdditionalContentExclusionPolicyRule"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicyRule, self.permissions_configure_additional_content_exclusion_policy_rule) - result["PermissionsConfigureAdditionalContentExclusionPolicyRuleSource"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicyRuleSource, self.permissions_configure_additional_content_exclusion_policy_rule_source) - result["PermissionsConfigureAdditionalContentExclusionPolicyScope"] = to_enum(PermissionsConfigureAdditionalContentExclusionPolicyScope, self.permissions_configure_additional_content_exclusion_policy_scope) - result["PermissionsConfigureParams"] = to_class(PermissionsConfigureParams, self.permissions_configure_params) - result["PermissionsConfigureResult"] = to_class(PermissionsConfigureResult, self.permissions_configure_result) - result["PermissionsModifyRulesParams"] = to_class(PermissionsModifyRulesParams, self.permissions_modify_rules_params) - result["PermissionsModifyRulesResult"] = to_class(PermissionsModifyRulesResult, self.permissions_modify_rules_result) - result["PermissionsModifyRulesScope"] = to_enum(PermissionsModifyRulesScope, self.permissions_modify_rules_scope) - result["PermissionsNotifyPromptShownResult"] = to_class(PermissionsNotifyPromptShownResult, self.permissions_notify_prompt_shown_result) - result["PermissionsPathsAddResult"] = to_class(PermissionsPathsAddResult, self.permissions_paths_add_result) - result["PermissionsPathsListRequest"] = to_class(PermissionsPathsListRequest, self.permissions_paths_list_request) - result["PermissionsPathsUpdatePrimaryResult"] = to_class(PermissionsPathsUpdatePrimaryResult, self.permissions_paths_update_primary_result) - result["PermissionsPendingRequestsRequest"] = to_class(PermissionsPendingRequestsRequest, self.permissions_pending_requests_request) result["PermissionsResetSessionApprovalsRequest"] = to_class(PermissionsResetSessionApprovalsRequest, self.permissions_reset_session_approvals_request) result["PermissionsResetSessionApprovalsResult"] = to_class(PermissionsResetSessionApprovalsResult, self.permissions_reset_session_approvals_result) result["PermissionsSetApproveAllRequest"] = to_class(PermissionsSetApproveAllRequest, self.permissions_set_approve_all_request) result["PermissionsSetApproveAllResult"] = to_class(PermissionsSetApproveAllResult, self.permissions_set_approve_all_result) - result["PermissionsSetApproveAllSource"] = to_enum(PermissionsSetApproveAllSource, self.permissions_set_approve_all_source) - result["PermissionsSetRequiredRequest"] = to_class(PermissionsSetRequiredRequest, self.permissions_set_required_request) - result["PermissionsSetRequiredResult"] = to_class(PermissionsSetRequiredResult, self.permissions_set_required_result) - result["PermissionsUrlsSetUnrestrictedModeResult"] = to_class(PermissionsUrlsSetUnrestrictedModeResult, self.permissions_urls_set_unrestricted_mode_result) - result["PermissionUrlsConfig"] = to_class(PermissionUrlsConfig, self.permission_urls_config) - result["PermissionUrlsSetUnrestrictedModeParams"] = to_class(PermissionUrlsSetUnrestrictedModeParams, self.permission_urls_set_unrestricted_mode_params) result["PingRequest"] = to_class(PingRequest, self.ping_request) result["PingResult"] = to_class(PingResult, self.ping_result) result["PlanReadResult"] = to_class(PlanReadResult, self.plan_read_result) @@ -15259,45 +8166,13 @@ def to_dict(self) -> dict: result["QueuedCommandHandled"] = to_class(QueuedCommandHandled, self.queued_command_handled) result["QueuedCommandNotHandled"] = to_class(QueuedCommandNotHandled, self.queued_command_not_handled) result["QueuedCommandResult"] = to_class(QueuedCommandResult, self.queued_command_result) - result["QueuePendingItems"] = to_class(QueuePendingItems, self.queue_pending_items) - result["QueuePendingItemsKind"] = to_enum(QueuePendingItemsKind, self.queue_pending_items_kind) - result["QueuePendingItemsResult"] = to_class(QueuePendingItemsResult, self.queue_pending_items_result) - result["QueueRemoveMostRecentResult"] = to_class(QueueRemoveMostRecentResult, self.queue_remove_most_recent_result) - result["RegisterEventInterestParams"] = to_class(RegisterEventInterestParams, self.register_event_interest_params) - result["RegisterEventInterestResult"] = to_class(RegisterEventInterestResult, self.register_event_interest_result) - result["ReleaseEventInterestParams"] = to_class(ReleaseEventInterestParams, self.release_event_interest_params) result["RemoteEnableRequest"] = to_class(RemoteEnableRequest, self.remote_enable_request) result["RemoteEnableResult"] = to_class(RemoteEnableResult, self.remote_enable_result) - result["RemoteNotifySteerableChangedRequest"] = to_class(RemoteNotifySteerableChangedRequest, self.remote_notify_steerable_changed_request) - result["RemoteNotifySteerableChangedResult"] = to_class(RemoteNotifySteerableChangedResult, self.remote_notify_steerable_changed_result) result["RemoteSessionConnectionResult"] = to_class(RemoteSessionConnectionResult, self.remote_session_connection_result) result["RemoteSessionMode"] = to_enum(RemoteSessionMode, self.remote_session_mode) - result["ScheduleEntry"] = to_class(ScheduleEntry, self.schedule_entry) - result["ScheduleList"] = to_class(ScheduleList, self.schedule_list) - result["ScheduleStopRequest"] = to_class(ScheduleStopRequest, self.schedule_stop_request) - result["ScheduleStopResult"] = to_class(ScheduleStopResult, self.schedule_stop_result) - result["SendAgentMode"] = to_enum(SendAgentMode, self.send_agent_mode) - result["SendAttachment"] = to_class(SendAttachment, self.send_attachment) - result["SendAttachmentBlob"] = to_class(SendAttachmentBlob, self.send_attachment_blob) - result["SendAttachmentDirectory"] = to_class(SendAttachmentDirectory, self.send_attachment_directory) - result["SendAttachmentFile"] = to_class(SendAttachmentFile, self.send_attachment_file) - result["SendAttachmentFileLineRange"] = to_class(SendAttachmentFileLineRange, self.send_attachment_file_line_range) - result["SendAttachmentGithubReference"] = to_class(SendAttachmentGithubReference, self.send_attachment_github_reference) - result["SendAttachmentGithubReferenceType"] = to_enum(SendAttachmentGithubReferenceTypeEnum, self.send_attachment_github_reference_type) - result["SendAttachmentSelection"] = to_class(SendAttachmentSelection, self.send_attachment_selection) - result["SendAttachmentSelectionDetails"] = to_class(SendAttachmentSelectionDetails, self.send_attachment_selection_details) - result["SendAttachmentSelectionDetailsEnd"] = to_class(SendAttachmentSelectionDetailsEnd, self.send_attachment_selection_details_end) - result["SendAttachmentSelectionDetailsStart"] = to_class(SendAttachmentSelectionDetailsStart, self.send_attachment_selection_details_start) - result["SendMode"] = to_enum(SendMode, self.send_mode) - result["SendRequest"] = to_class(SendRequest, self.send_request) - result["SendResult"] = to_class(SendResult, self.send_result) result["ServerSkill"] = to_class(ServerSkill, self.server_skill) result["ServerSkillList"] = to_class(ServerSkillList, self.server_skill_list) result["SessionAuthStatus"] = to_class(SessionAuthStatus, self.session_auth_status) - result["SessionBulkDeleteResult"] = to_class(SessionBulkDeleteResult, self.session_bulk_delete_result) - result["SessionContext"] = to_class(SessionContext, self.session_context) - result["SessionContextHostType"] = to_enum(SessionContextHostType, self.session_context_host_type) - result["SessionEnrichMetadataResult"] = to_class(SessionEnrichMetadataResult, self.session_enrich_metadata_result) result["SessionFsAppendFileRequest"] = to_class(SessionFSAppendFileRequest, self.session_fs_append_file_request) result["SessionFsError"] = to_class(SessionFSError, self.session_fs_error) result["SessionFsErrorCode"] = to_enum(SessionFSErrorCode, self.session_fs_error_code) @@ -15326,68 +8201,21 @@ def to_dict(self) -> dict: result["SessionFsStatRequest"] = to_class(SessionFSStatRequest, self.session_fs_stat_request) result["SessionFsStatResult"] = to_class(SessionFSStatResult, self.session_fs_stat_result) result["SessionFsWriteFileRequest"] = to_class(SessionFSWriteFileRequest, self.session_fs_write_file_request) - result["SessionInstalledPlugin"] = to_class(SessionInstalledPlugin, self.session_installed_plugin) - result["SessionInstalledPluginSource"] = from_union([lambda x: to_class(SessionInstalledPluginSource, x), from_str], self.session_installed_plugin_source) - result["SessionInstalledPluginSourceGithub"] = to_class(SessionInstalledPluginSourceGithub, self.session_installed_plugin_source_github) - result["SessionInstalledPluginSourceLocal"] = to_class(SessionInstalledPluginSourceLocal, self.session_installed_plugin_source_local) - result["SessionInstalledPluginSourceUrl"] = to_class(SessionInstalledPluginSourceURL, self.session_installed_plugin_source_url) - result["SessionList"] = to_class(SessionList, self.session_list) - result["SessionLoadDeferredRepoHooksResult"] = to_class(SessionLoadDeferredRepoHooksResult, self.session_load_deferred_repo_hooks_result) result["SessionLogLevel"] = to_enum(SessionLogLevel, self.session_log_level) - result["SessionMetadata"] = to_class(SessionMetadata, self.session_metadata) - result["SessionMetadataSnapshot"] = to_class(SessionMetadataSnapshot, self.session_metadata_snapshot) result["SessionMode"] = to_enum(SessionMode, self.session_mode) - result["SessionPruneResult"] = to_class(SessionPruneResult, self.session_prune_result) - result["SessionsBulkDeleteRequest"] = to_class(SessionsBulkDeleteRequest, self.sessions_bulk_delete_request) - result["SessionsCheckInUseRequest"] = to_class(SessionsCheckInUseRequest, self.sessions_check_in_use_request) - result["SessionsCheckInUseResult"] = to_class(SessionsCheckInUseResult, self.sessions_check_in_use_result) - result["SessionsCloseRequest"] = to_class(SessionsCloseRequest, self.sessions_close_request) - result["SessionsCloseResult"] = to_class(SessionsCloseResult, self.sessions_close_result) - result["SessionsEnrichMetadataRequest"] = to_class(SessionsEnrichMetadataRequest, self.sessions_enrich_metadata_request) - result["SessionSetCredentialsParams"] = to_class(SessionSetCredentialsParams, self.session_set_credentials_params) - result["SessionSetCredentialsResult"] = to_class(SessionSetCredentialsResult, self.session_set_credentials_result) - result["SessionsFindByPrefixRequest"] = to_class(SessionsFindByPrefixRequest, self.sessions_find_by_prefix_request) - result["SessionsFindByPrefixResult"] = to_class(SessionsFindByPrefixResult, self.sessions_find_by_prefix_result) - result["SessionsFindByTaskIDRequest"] = to_class(SessionsFindByTaskIDRequest, self.sessions_find_by_task_id_request) - result["SessionsFindByTaskIDResult"] = to_class(SessionsFindByTaskIDResult, self.sessions_find_by_task_id_result) result["SessionsForkRequest"] = to_class(SessionsForkRequest, self.sessions_fork_request) result["SessionsForkResult"] = to_class(SessionsForkResult, self.sessions_fork_result) - result["SessionsGetEventFilePathRequest"] = to_class(SessionsGetEventFilePathRequest, self.sessions_get_event_file_path_request) - result["SessionsGetEventFilePathResult"] = to_class(SessionsGetEventFilePathResult, self.sessions_get_event_file_path_result) - result["SessionsGetLastForContextRequest"] = to_class(SessionsGetLastForContextRequest, self.sessions_get_last_for_context_request) - result["SessionsGetLastForContextResult"] = to_class(SessionsGetLastForContextResult, self.sessions_get_last_for_context_result) - result["SessionsGetPersistedRemoteSteerableRequest"] = to_class(SessionsGetPersistedRemoteSteerableRequest, self.sessions_get_persisted_remote_steerable_request) - result["SessionsGetPersistedRemoteSteerableResult"] = to_class(SessionsGetPersistedRemoteSteerableResult, self.sessions_get_persisted_remote_steerable_result) - result["SessionSizes"] = to_class(SessionSizes, self.session_sizes) - result["SessionsListRequest"] = to_class(SessionsListRequest, self.sessions_list_request) - result["SessionsLoadDeferredRepoHooksRequest"] = to_class(SessionsLoadDeferredRepoHooksRequest, self.sessions_load_deferred_repo_hooks_request) - result["SessionsPruneOldRequest"] = to_class(SessionsPruneOldRequest, self.sessions_prune_old_request) - result["SessionsReleaseLockRequest"] = to_class(SessionsReleaseLockRequest, self.sessions_release_lock_request) - result["SessionsReleaseLockResult"] = to_class(SessionsReleaseLockResult, self.sessions_release_lock_result) - result["SessionsReloadPluginHooksRequest"] = to_class(SessionsReloadPluginHooksRequest, self.sessions_reload_plugin_hooks_request) - result["SessionsReloadPluginHooksResult"] = to_class(SessionsReloadPluginHooksResult, self.sessions_reload_plugin_hooks_result) - result["SessionsSaveRequest"] = to_class(SessionsSaveRequest, self.sessions_save_request) - result["SessionsSaveResult"] = to_class(SessionsSaveResult, self.sessions_save_result) - result["SessionsSetAdditionalPluginsRequest"] = to_class(SessionsSetAdditionalPluginsRequest, self.sessions_set_additional_plugins_request) - result["SessionsSetAdditionalPluginsResult"] = to_class(SessionsSetAdditionalPluginsResult, self.sessions_set_additional_plugins_result) - result["SessionUpdateOptionsParams"] = to_class(SessionUpdateOptionsParams, self.session_update_options_params) - result["SessionUpdateOptionsResult"] = to_class(SessionUpdateOptionsResult, self.session_update_options_result) - result["SessionWorkingDirectoryContext"] = to_class(SessionWorkingDirectoryContext, self.session_working_directory_context) - result["SessionWorkingDirectoryContextHostType"] = to_enum(SessionContextHostType, self.session_working_directory_context_host_type) result["ShellExecRequest"] = to_class(ShellExecRequest, self.shell_exec_request) result["ShellExecResult"] = to_class(ShellExecResult, self.shell_exec_result) result["ShellKillRequest"] = to_class(ShellKillRequest, self.shell_kill_request) result["ShellKillResult"] = to_class(ShellKillResult, self.shell_kill_result) result["ShellKillSignal"] = to_enum(ShellKillSignal, self.shell_kill_signal) - result["ShutdownRequest"] = to_class(ShutdownRequest, self.shutdown_request) result["Skill"] = to_class(Skill, self.skill) result["SkillList"] = to_class(SkillList, self.skill_list) result["SkillsConfigSetDisabledSkillsRequest"] = to_class(SkillsConfigSetDisabledSkillsRequest, self.skills_config_set_disabled_skills_request) result["SkillsDisableRequest"] = to_class(SkillsDisableRequest, self.skills_disable_request) result["SkillsDiscoverRequest"] = to_class(SkillsDiscoverRequest, self.skills_discover_request) result["SkillsEnableRequest"] = to_class(SkillsEnableRequest, self.skills_enable_request) - result["SkillsGetInvokedResult"] = to_class(SkillsGetInvokedResult, self.skills_get_invoked_result) - result["SkillsInvokedSkill"] = to_class(SkillsInvokedSkill, self.skills_invoked_skill) result["SkillsLoadDiagnostics"] = to_class(SkillsLoadDiagnostics, self.skills_load_diagnostics) result["SlashCommandAgentPromptResult"] = to_class(SlashCommandAgentPromptResult, self.slash_command_agent_prompt_result) result["SlashCommandCompletedResult"] = to_class(SlashCommandCompletedResult, self.slash_command_completed_result) @@ -15398,22 +8226,15 @@ def to_dict(self) -> dict: result["SlashCommandKind"] = to_enum(SlashCommandKind, self.slash_command_kind) result["SlashCommandTextResult"] = to_class(SlashCommandTextResult, self.slash_command_text_result) result["TaskAgentInfo"] = to_class(TaskAgentInfo, self.task_agent_info) - result["TaskAgentProgress"] = to_class(TaskAgentProgress, self.task_agent_progress) result["TaskExecutionMode"] = to_enum(TaskExecutionMode, self.task_execution_mode) result["TaskInfo"] = to_class(TaskInfo, self.task_info) result["TaskList"] = to_class(TaskList, self.task_list) result["TasksCancelRequest"] = to_class(TasksCancelRequest, self.tasks_cancel_request) result["TasksCancelResult"] = to_class(TasksCancelResult, self.tasks_cancel_result) - result["TasksGetCurrentPromotableResult"] = to_class(TasksGetCurrentPromotableResult, self.tasks_get_current_promotable_result) - result["TasksGetProgressRequest"] = to_class(TasksGetProgressRequest, self.tasks_get_progress_request) - result["TasksGetProgressResult"] = to_class(TasksGetProgressResult, self.tasks_get_progress_result) result["TaskShellInfo"] = to_class(TaskShellInfo, self.task_shell_info) result["TaskShellInfoAttachmentMode"] = to_enum(TaskShellInfoAttachmentMode, self.task_shell_info_attachment_mode) - result["TaskShellProgress"] = from_none(self.task_shell_progress) - result["TasksPromoteCurrentToBackgroundResult"] = to_class(TasksPromoteCurrentToBackgroundResult, self.tasks_promote_current_to_background_result) result["TasksPromoteToBackgroundRequest"] = to_class(TasksPromoteToBackgroundRequest, self.tasks_promote_to_background_request) result["TasksPromoteToBackgroundResult"] = to_class(TasksPromoteToBackgroundResult, self.tasks_promote_to_background_result) - result["TasksRefreshResult"] = to_class(TasksRefreshResult, self.tasks_refresh_result) result["TasksRemoveRequest"] = to_class(TasksRemoveRequest, self.tasks_remove_request) result["TasksRemoveResult"] = to_class(TasksRemoveResult, self.tasks_remove_result) result["TasksSendMessageRequest"] = to_class(TasksSendMessageRequest, self.tasks_send_message_request) @@ -15421,14 +8242,9 @@ def to_dict(self) -> dict: result["TasksStartAgentRequest"] = to_class(TasksStartAgentRequest, self.tasks_start_agent_request) result["TasksStartAgentResult"] = to_class(TasksStartAgentResult, self.tasks_start_agent_result) result["TaskStatus"] = to_enum(TaskStatus, self.task_status) - result["TasksWaitForPendingResult"] = to_class(TasksWaitForPendingResult, self.tasks_wait_for_pending_result) - result["TelemetrySetFeatureOverridesRequest"] = to_class(TelemetrySetFeatureOverridesRequest, self.telemetry_set_feature_overrides_request) - result["TokenAuthInfo"] = to_class(TokenAuthInfo, self.token_auth_info) result["Tool"] = to_class(Tool, self.tool) result["ToolList"] = to_class(ToolList, self.tool_list) - result["ToolsInitializeAndValidateResult"] = to_class(ToolsInitializeAndValidateResult, self.tools_initialize_and_validate_result) result["ToolsListRequest"] = to_class(ToolsListRequest, self.tools_list_request) - result["UIAutoModeSwitchResponse"] = to_enum(UIAutoModeSwitchResponse, self.ui_auto_mode_switch_response) result["UIElicitationArrayAnyOfField"] = to_class(UIElicitationArrayAnyOfField, self.ui_elicitation_array_any_of_field) result["UIElicitationArrayAnyOfFieldItems"] = to_class(UIElicitationArrayAnyOfFieldItems, self.ui_elicitation_array_any_of_field_items) result["UIElicitationArrayAnyOfFieldItemsAnyOf"] = to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, self.ui_elicitation_array_any_of_field_items_any_of) @@ -15450,19 +8266,7 @@ def to_dict(self) -> dict: result["UIElicitationStringEnumField"] = to_class(UIElicitationStringEnumField, self.ui_elicitation_string_enum_field) result["UIElicitationStringOneOfField"] = to_class(UIElicitationStringOneOfField, self.ui_elicitation_string_one_of_field) result["UIElicitationStringOneOfFieldOneOf"] = to_class(UIElicitationStringOneOfFieldOneOf, self.ui_elicitation_string_one_of_field_one_of) - result["UIExitPlanModeAction"] = to_enum(UIExitPlanModeAction, self.ui_exit_plan_mode_action) - result["UIExitPlanModeResponse"] = to_class(UIExitPlanModeResponse, self.ui_exit_plan_mode_response) - result["UIHandlePendingAutoModeSwitchRequest"] = to_class(UIHandlePendingAutoModeSwitchRequest, self.ui_handle_pending_auto_mode_switch_request) result["UIHandlePendingElicitationRequest"] = to_class(UIHandlePendingElicitationRequest, self.ui_handle_pending_elicitation_request) - result["UIHandlePendingExitPlanModeRequest"] = to_class(UIHandlePendingExitPlanModeRequest, self.ui_handle_pending_exit_plan_mode_request) - result["UIHandlePendingResult"] = to_class(UIHandlePendingResult, self.ui_handle_pending_result) - result["UIHandlePendingSamplingRequest"] = to_class(UIHandlePendingSamplingRequest, self.ui_handle_pending_sampling_request) - result["UIHandlePendingSamplingResponse"] = from_dict(lambda x: x, self.ui_handle_pending_sampling_response) - result["UIHandlePendingUserInputRequest"] = to_class(UIHandlePendingUserInputRequest, self.ui_handle_pending_user_input_request) - result["UIRegisterDirectAutoModeSwitchHandlerResult"] = to_class(UIRegisterDirectAutoModeSwitchHandlerResult, self.ui_register_direct_auto_mode_switch_handler_result) - result["UIUnregisterDirectAutoModeSwitchHandlerRequest"] = to_class(UIUnregisterDirectAutoModeSwitchHandlerRequest, self.ui_unregister_direct_auto_mode_switch_handler_request) - result["UIUnregisterDirectAutoModeSwitchHandlerResult"] = to_class(UIUnregisterDirectAutoModeSwitchHandlerResult, self.ui_unregister_direct_auto_mode_switch_handler_result) - result["UIUserInputResponse"] = to_class(UIUserInputResponse, self.ui_user_input_response) result["UsageGetMetricsResult"] = to_class(UsageGetMetricsResult, self.usage_get_metrics_result) result["UsageMetricsCodeChanges"] = to_class(UsageMetricsCodeChanges, self.usage_metrics_code_changes) result["UsageMetricsModelMetric"] = to_class(UsageMetricsModelMetric, self.usage_metrics_model_metric) @@ -15470,29 +8274,11 @@ def to_dict(self) -> dict: result["UsageMetricsModelMetricTokenDetail"] = to_class(UsageMetricsModelMetricTokenDetail, self.usage_metrics_model_metric_token_detail) result["UsageMetricsModelMetricUsage"] = to_class(UsageMetricsModelMetricUsage, self.usage_metrics_model_metric_usage) result["UsageMetricsTokenDetail"] = to_class(UsageMetricsTokenDetail, self.usage_metrics_token_detail) - result["UserAuthInfo"] = to_class(UserAuthInfo, self.user_auth_info) - result["UserToolSessionApprovalCommands"] = to_class(UserToolSessionApprovalCommands, self.user_tool_session_approval_commands) - result["UserToolSessionApprovalCustomTool"] = to_class(UserToolSessionApprovalCustomTool, self.user_tool_session_approval_custom_tool) - result["UserToolSessionApprovalExtensionManagement"] = to_class(UserToolSessionApprovalExtensionManagement, self.user_tool_session_approval_extension_management) - result["UserToolSessionApprovalExtensionPermissionAccess"] = to_class(UserToolSessionApprovalExtensionPermissionAccess, self.user_tool_session_approval_extension_permission_access) - result["UserToolSessionApprovalMcp"] = to_class(UserToolSessionApprovalMCP, self.user_tool_session_approval_mcp) - result["UserToolSessionApprovalMemory"] = to_class(UserToolSessionApprovalMemory, self.user_tool_session_approval_memory) - result["UserToolSessionApprovalRead"] = to_class(UserToolSessionApprovalRead, self.user_tool_session_approval_read) - result["UserToolSessionApprovalWrite"] = to_class(UserToolSessionApprovalWrite, self.user_tool_session_approval_write) - result["WorkspacesCheckpoints"] = to_class(WorkspacesCheckpoints, self.workspaces_checkpoints) result["WorkspacesCreateFileRequest"] = to_class(WorkspacesCreateFileRequest, self.workspaces_create_file_request) result["WorkspacesGetWorkspaceResult"] = to_class(WorkspacesGetWorkspaceResult, self.workspaces_get_workspace_result) - result["WorkspacesListCheckpointsResult"] = to_class(WorkspacesListCheckpointsResult, self.workspaces_list_checkpoints_result) result["WorkspacesListFilesResult"] = to_class(WorkspacesListFilesResult, self.workspaces_list_files_result) - result["WorkspacesReadCheckpointRequest"] = to_class(WorkspacesReadCheckpointRequest, self.workspaces_read_checkpoint_request) - result["WorkspacesReadCheckpointResult"] = to_class(WorkspacesReadCheckpointResult, self.workspaces_read_checkpoint_result) result["WorkspacesReadFileRequest"] = to_class(WorkspacesReadFileRequest, self.workspaces_read_file_request) result["WorkspacesReadFileResult"] = to_class(WorkspacesReadFileResult, self.workspaces_read_file_result) - result["WorkspacesSaveLargePasteRequest"] = to_class(WorkspacesSaveLargePasteRequest, self.workspaces_save_large_paste_request) - result["WorkspacesSaveLargePasteResult"] = to_class(WorkspacesSaveLargePasteResult, self.workspaces_save_large_paste_result) - result["SessionContextInfo"] = from_union([lambda x: to_class(SessionContextInfo, x), from_none], self.session_context_info) - result["TaskProgress"] = from_union([lambda x: to_class(TaskProgressClass, x), from_none], self.task_progress) - result["WorkspaceSummary"] = from_union([lambda x: to_class(WorkspaceSummary, x), from_none], self.workspace_summary) return result def rpc_from_dict(s: Any) -> RPC: @@ -15504,15 +8290,8 @@ def rpc_to_dict(x: RPC) -> Any: ExternalToolResult = ExternalToolTextResultForLlm FilterMapping = dict -McpExecuteSamplingRequest = dict -McpExecuteSamplingResult = dict -OptionsUpdateEnvValueMode = MCPSetEnvValueModeDetails -SessionWorkingDirectoryContextHostType = SessionContextHostType TaskInfoExecutionMode = TaskExecutionMode TaskInfoStatus = TaskStatus -TaskInfoType = TaskAgentProgressType -TaskProgress = TaskProgressClass -TaskShellProgress = None def _timeout_kwargs(timeout: float | None) -> dict: """Build keyword arguments for optional timeout forwarding.""" @@ -15548,6 +8327,9 @@ def __init__(self, client: "JsonRpcClient"): async def list(self, params: ModelsListRequest, *, timeout: float | None = None) -> ModelList: "Lists Copilot models available to the authenticated user.\n\nArgs:\n params: Optional GitHub token used to list models for a specific user instead of the global auth context.\n\nReturns:\n List of Copilot models available to the resolved user, including capabilities and billing metadata." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return ModelList.from_dict(_patch_model_capabilities(await self._client.request("models.list", params_dict, **_timeout_kwargs(timeout)))) @@ -15558,6 +8340,9 @@ def __init__(self, client: "JsonRpcClient"): async def list(self, params: ToolsListRequest, *, timeout: float | None = None) -> ToolList: "Lists built-in tools available for a model.\n\nArgs:\n params: Optional model identifier whose tool overrides should be applied to the listing.\n\nReturns:\n Built-in tools available for the requested model, with their parameters and instructions." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return ToolList.from_dict(await self._client.request("tools.list", params_dict, **_timeout_kwargs(timeout))) @@ -15568,6 +8353,9 @@ def __init__(self, client: "JsonRpcClient"): async def get_quota(self, params: AccountGetQuotaRequest, *, timeout: float | None = None) -> AccountGetQuotaResult: "Gets Copilot quota usage for the authenticated user or supplied GitHub token.\n\nArgs:\n params: Optional GitHub token used to look up quota for a specific user instead of the global auth context.\n\nReturns:\n Quota usage snapshots for the resolved user, keyed by quota type." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return AccountGetQuotaResult.from_dict(await self._client.request("account.getQuota", params_dict, **_timeout_kwargs(timeout))) @@ -15582,26 +8370,41 @@ async def list(self, *, timeout: float | None = None) -> MCPConfigList: async def add(self, params: MCPConfigAddRequest, *, timeout: float | None = None) -> None: "Adds an MCP server to user configuration.\n\nArgs:\n params: MCP server name and configuration to add to user configuration." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("mcp.config.add", params_dict, **_timeout_kwargs(timeout)) async def update(self, params: MCPConfigUpdateRequest, *, timeout: float | None = None) -> None: "Updates an MCP server in user configuration.\n\nArgs:\n params: MCP server name and replacement configuration to write to user configuration." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("mcp.config.update", params_dict, **_timeout_kwargs(timeout)) async def remove(self, params: MCPConfigRemoveRequest, *, timeout: float | None = None) -> None: "Removes an MCP server from user configuration.\n\nArgs:\n params: MCP server name to remove from user configuration." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("mcp.config.remove", params_dict, **_timeout_kwargs(timeout)) async def enable(self, params: MCPConfigEnableRequest, *, timeout: float | None = None) -> None: "Enables MCP servers in user configuration for new sessions.\n\nArgs:\n params: MCP server names to enable for new sessions." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("mcp.config.enable", params_dict, **_timeout_kwargs(timeout)) async def disable(self, params: MCPConfigDisableRequest, *, timeout: float | None = None) -> None: "Disables MCP servers in user configuration for new sessions.\n\nArgs:\n params: MCP server names to disable for new sessions." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("mcp.config.disable", params_dict, **_timeout_kwargs(timeout)) @@ -15613,6 +8416,9 @@ def __init__(self, client: "JsonRpcClient"): async def discover(self, params: MCPDiscoverRequest, *, timeout: float | None = None) -> MCPDiscoverResult: "Discovers MCP servers from user, workspace, plugin, and builtin sources.\n\nArgs:\n params: Optional working directory used as context for MCP server discovery.\n\nReturns:\n MCP servers discovered from user, workspace, plugin, and built-in sources." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return MCPDiscoverResult.from_dict(await self._client.request("mcp.discover", params_dict, **_timeout_kwargs(timeout))) @@ -15623,6 +8429,9 @@ def __init__(self, client: "JsonRpcClient"): async def set_disabled_skills(self, params: SkillsConfigSetDisabledSkillsRequest, *, timeout: float | None = None) -> None: "Replaces the global list of disabled skills.\n\nArgs:\n params: Skill names to mark as disabled in global configuration, replacing any previous list." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("skills.config.setDisabledSkills", params_dict, **_timeout_kwargs(timeout)) @@ -15634,6 +8443,9 @@ def __init__(self, client: "JsonRpcClient"): async def discover(self, params: SkillsDiscoverRequest, *, timeout: float | None = None) -> ServerSkillList: "Discovers skills across global and project sources.\n\nArgs:\n params: Optional project paths and additional skill directories to include in discovery.\n\nReturns:\n Skills discovered across global and project sources." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return ServerSkillList.from_dict(await self._client.request("skills.discover", params_dict, **_timeout_kwargs(timeout))) @@ -15644,6 +8456,9 @@ def __init__(self, client: "JsonRpcClient"): async def set_provider(self, params: SessionFSSetProviderRequest, *, timeout: float | None = None) -> SessionFSSetProviderResult: "Registers an SDK client as the session filesystem provider.\n\nArgs:\n params: Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider.\n\nReturns:\n Indicates whether the calling client was registered as the session filesystem provider." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return SessionFSSetProviderResult.from_dict(await self._client.request("sessionFs.setProvider", params_dict, **_timeout_kwargs(timeout))) @@ -15651,101 +8466,23 @@ async def set_provider(self, params: SessionFSSetProviderRequest, *, timeout: fl # Experimental: this API group is experimental and may change or be removed. class ServerSessionsApi: def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def fork(self, params: SessionsForkRequest, *, timeout: float | None = None) -> SessionsForkResult: - "Creates a new session by forking persisted history from an existing session.\n\nArgs:\n params: Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session.\n\nReturns:\n Identifier and optional friendly name assigned to the newly forked session." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsForkResult.from_dict(await self._client.request("sessions.fork", params_dict, **_timeout_kwargs(timeout))) - - async def connect(self, params: ConnectRemoteSessionParams, *, timeout: float | None = None) -> RemoteSessionConnectionResult: - "Connects to an existing remote session and exposes it as an SDK session.\n\nArgs:\n params: Remote session connection parameters.\n\nReturns:\n Remote session connection result." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return RemoteSessionConnectionResult.from_dict(await self._client.request("sessions.connect", params_dict, **_timeout_kwargs(timeout))) - - async def list(self, params: SessionsListRequest, *, timeout: float | None = None) -> SessionList: - "Lists persisted sessions, optionally filtered by working-directory context.\n\nArgs:\n params: Optional metadata-load limit and context filter applied to the returned sessions.\n\nReturns:\n Persisted sessions matching the filter, ordered most-recently-modified first." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionList.from_dict(await self._client.request("sessions.list", params_dict, **_timeout_kwargs(timeout))) - - async def find_by_task_id(self, params: SessionsFindByTaskIDRequest, *, timeout: float | None = None) -> SessionsFindByTaskIDResult: - "Finds the local session bound to a GitHub task ID, if any.\n\nArgs:\n params: GitHub task ID to look up.\n\nReturns:\n ID of the local session bound to the given GitHub task, or omitted when none." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsFindByTaskIDResult.from_dict(await self._client.request("sessions.findByTaskId", params_dict, **_timeout_kwargs(timeout))) - - async def find_by_prefix(self, params: SessionsFindByPrefixRequest, *, timeout: float | None = None) -> SessionsFindByPrefixResult: - "Resolves a UUID prefix to a unique session ID, if exactly one session matches.\n\nArgs:\n params: UUID prefix to resolve to a unique session ID.\n\nReturns:\n Session ID matching the prefix, omitted when no unique match exists." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsFindByPrefixResult.from_dict(await self._client.request("sessions.findByPrefix", params_dict, **_timeout_kwargs(timeout))) - - async def get_last_for_context(self, params: SessionsGetLastForContextRequest, *, timeout: float | None = None) -> SessionsGetLastForContextResult: - "Returns the most-relevant prior session for a given working-directory context.\n\nArgs:\n params: Optional working-directory context used to score session relevance.\n\nReturns:\n Most-relevant session ID for the supplied context, or omitted when no sessions exist." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsGetLastForContextResult.from_dict(await self._client.request("sessions.getLastForContext", params_dict, **_timeout_kwargs(timeout))) - - async def get_event_file_path(self, params: SessionsGetEventFilePathRequest, *, timeout: float | None = None) -> SessionsGetEventFilePathResult: - "Computes the absolute path to a session's persisted events.jsonl file.\n\nArgs:\n params: Session ID whose event-log file path to compute.\n\nReturns:\n Absolute path to the session's events.jsonl file on disk." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsGetEventFilePathResult.from_dict(await self._client.request("sessions.getEventFilePath", params_dict, **_timeout_kwargs(timeout))) - - async def get_sizes(self, *, timeout: float | None = None) -> SessionSizes: - "Returns the on-disk byte size of each session's workspace directory.\n\nReturns:\n Map of sessionId -> on-disk size in bytes for each session's workspace directory." - return SessionSizes.from_dict(await self._client.request("sessions.getSizes", {}, **_timeout_kwargs(timeout))) - - async def check_in_use(self, params: SessionsCheckInUseRequest, *, timeout: float | None = None) -> SessionsCheckInUseResult: - "Returns the subset of the supplied session IDs that are currently held by another running process.\n\nArgs:\n params: Session IDs to test for live in-use locks.\n\nReturns:\n Session IDs from the input set that are currently in use by another process." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsCheckInUseResult.from_dict(await self._client.request("sessions.checkInUse", params_dict, **_timeout_kwargs(timeout))) - - async def get_persisted_remote_steerable(self, params: SessionsGetPersistedRemoteSteerableRequest, *, timeout: float | None = None) -> SessionsGetPersistedRemoteSteerableResult: - "Returns a session's persisted remote-steerable flag, if any has been recorded.\n\nArgs:\n params: Session ID to look up the persisted remote-steerable flag for.\n\nReturns:\n The session's persisted remote-steerable flag, or omitted when no value has been persisted." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsGetPersistedRemoteSteerableResult.from_dict(await self._client.request("sessions.getPersistedRemoteSteerable", params_dict, **_timeout_kwargs(timeout))) - - async def close(self, params: SessionsCloseRequest, *, timeout: float | None = None) -> SessionsCloseResult: - "Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session.\n\nArgs:\n params: Session ID to close.\n\nReturns:\n Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsCloseResult.from_dict(await self._client.request("sessions.close", params_dict, **_timeout_kwargs(timeout))) - - async def bulk_delete(self, params: SessionsBulkDeleteRequest, *, timeout: float | None = None) -> SessionBulkDeleteResult: - "Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session.\n\nArgs:\n params: Session IDs to close, deactivate, and delete from disk.\n\nReturns:\n Map of sessionId -> bytes freed by removing the session's workspace directory." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionBulkDeleteResult.from_dict(await self._client.request("sessions.bulkDelete", params_dict, **_timeout_kwargs(timeout))) - - async def prune_old(self, params: SessionsPruneOldRequest, *, timeout: float | None = None) -> SessionPruneResult: - "Deletes sessions older than the given threshold, with optional dry-run and exclusion list.\n\nArgs:\n params: Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true).\n\nReturns:\n Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionPruneResult.from_dict(await self._client.request("sessions.pruneOld", params_dict, **_timeout_kwargs(timeout))) - - async def save(self, params: SessionsSaveRequest, *, timeout: float | None = None) -> SessionsSaveResult: - "Flushes a session's pending events to disk.\n\nArgs:\n params: Session ID whose pending events should be flushed to disk.\n\nReturns:\n Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed)." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsSaveResult.from_dict(await self._client.request("sessions.save", params_dict, **_timeout_kwargs(timeout))) - - async def release_lock(self, params: SessionsReleaseLockRequest, *, timeout: float | None = None) -> SessionsReleaseLockResult: - "Releases the in-use lock held by this process for a session.\n\nArgs:\n params: Session ID whose in-use lock should be released.\n\nReturns:\n Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsReleaseLockResult.from_dict(await self._client.request("sessions.releaseLock", params_dict, **_timeout_kwargs(timeout))) + self._client = client - async def enrich_metadata(self, params: SessionsEnrichMetadataRequest, *, timeout: float | None = None) -> SessionEnrichMetadataResult: - "Backfills missing summary and context fields on the supplied session metadata records.\n\nArgs:\n params: Session metadata records to enrich with summary and context information.\n\nReturns:\n The same metadata records, with summary and context fields backfilled where available." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionEnrichMetadataResult.from_dict(await self._client.request("sessions.enrichMetadata", params_dict, **_timeout_kwargs(timeout))) + async def fork(self, params: SessionsForkRequest, *, timeout: float | None = None) -> SessionsForkResult: + "Creates a new session by forking persisted history from an existing session.\n\nArgs:\n params: Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session.\n\nReturns:\n Identifier and optional friendly name assigned to the newly forked session." + if params is None: + raise TypeError("params is required") - async def reload_plugin_hooks(self, params: SessionsReloadPluginHooksRequest, *, timeout: float | None = None) -> SessionsReloadPluginHooksResult: - "Reloads user, plugin, and (optionally) repo hooks on the active session.\n\nArgs:\n params: Active session ID and an optional flag for deferring repo-level hooks until folder trust.\n\nReturns:\n Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId." params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsReloadPluginHooksResult.from_dict(await self._client.request("sessions.reloadPluginHooks", params_dict, **_timeout_kwargs(timeout))) + return SessionsForkResult.from_dict(await self._client.request("sessions.fork", params_dict, **_timeout_kwargs(timeout))) - async def load_deferred_repo_hooks(self, params: SessionsLoadDeferredRepoHooksRequest, *, timeout: float | None = None) -> SessionLoadDeferredRepoHooksResult: - "Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts.\n\nArgs:\n params: Active session ID whose deferred repo-level hooks should be loaded.\n\nReturns:\n Queued repo-level startup prompts and the total hook command count after loading." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionLoadDeferredRepoHooksResult.from_dict(await self._client.request("sessions.loadDeferredRepoHooks", params_dict, **_timeout_kwargs(timeout))) + async def connect(self, params: ConnectRemoteSessionParams, *, timeout: float | None = None) -> RemoteSessionConnectionResult: + "Connects to an existing remote session and exposes it as an SDK session.\n\nArgs:\n params: Remote session connection parameters.\n\nReturns:\n Remote session connection result." + if params is None: + raise TypeError("params is required") - async def set_additional_plugins(self, params: SessionsSetAdditionalPluginsRequest, *, timeout: float | None = None) -> SessionsSetAdditionalPluginsResult: - "Replaces the manager-wide additional plugins registered with the session manager.\n\nArgs:\n params: Manager-wide additional plugins to register; replaces any previously-configured set.\n\nReturns:\n Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload." params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionsSetAdditionalPluginsResult.from_dict(await self._client.request("sessions.setAdditionalPlugins", params_dict, **_timeout_kwargs(timeout))) + return RemoteSessionConnectionResult.from_dict(await self._client.request("sessions.connect", params_dict, **_timeout_kwargs(timeout))) class ServerRpc: @@ -15761,7 +8498,10 @@ def __init__(self, client: "JsonRpcClient"): self.sessions = ServerSessionsApi(client) async def ping(self, params: PingRequest, *, timeout: float | None = None) -> PingResult: - "Checks server responsiveness and returns protocol information.\n\nArgs:\n params: Optional message to echo back to the caller.\n\nReturns:\n Server liveness response, including the echoed message, current server timestamp, and protocol version." + "Checks server responsiveness and returns protocol information.\n\nArgs:\n params: Optional message to echo back to the caller.\n\nReturns:\n Server liveness response, including the echoed message, current timestamp, and protocol version." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return PingResult.from_dict(await self._client.request("ping", params_dict, **_timeout_kwargs(timeout))) @@ -15773,166 +8513,205 @@ def __init__(self, client: "JsonRpcClient"): async def connect(self, params: ConnectRequest, *, timeout: float | None = None) -> ConnectResult: "Performs the SDK server connection handshake and validates the optional connection token.\n\nArgs:\n params: Optional connection token presented by the SDK client during the handshake.\n\nReturns:\n Handshake result reporting the server's protocol version and package version on success.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + if params is None: + raise TypeError("params is required") + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} return ConnectResult.from_dict(await self._client.request("connect", params_dict, **_timeout_kwargs(timeout))) class AuthApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get_status(self, *, timeout: float | None = None) -> SessionAuthStatus: "Gets authentication status and account metadata for the session.\n\nReturns:\n Authentication status and account metadata for the session." - return SessionAuthStatus.from_dict(await self._client.request("session.auth.getStatus", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def set_credentials(self, params: SessionSetCredentialsParams, *, timeout: float | None = None) -> SessionSetCredentialsResult: - "Updates the session's auth credentials used for outbound model and API requests.\n\nArgs:\n params: New auth credentials to install on the session. Omit to leave credentials unchanged.\n\nReturns:\n Indicates whether the credential update succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return SessionSetCredentialsResult.from_dict(await self._client.request("session.auth.setCredentials", params_dict, **_timeout_kwargs(timeout))) + return SessionAuthStatus.from_dict(await self._client.request("session.auth.getStatus", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) class ModelApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get_current(self, *, timeout: float | None = None) -> CurrentModel: - "Gets the currently selected model for the session.\n\nReturns:\n The currently selected model and reasoning effort for the session." + "Gets the currently selected model for the session.\n\nReturns:\n The currently selected model for the session." + if self._assert_active is not None: + self._assert_active() + return CurrentModel.from_dict(await self._client.request("session.model.getCurrent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def switch_to(self, params: ModelSwitchToRequest, *, timeout: float | None = None) -> ModelSwitchToResult: "Switches the session to a model and optional reasoning configuration.\n\nArgs:\n params: Target model identifier and optional reasoning effort, summary, and capability overrides.\n\nReturns:\n The model identifier active on the session after the switch." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return ModelSwitchToResult.from_dict(await self._client.request("session.model.switchTo", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def set_reasoning_effort(self, params: ModelSetReasoningEffortRequest, *, timeout: float | None = None) -> ModelSetReasoningEffortResult: - "Updates the session's reasoning effort without changing the selected model.\n\nArgs:\n params: Reasoning effort level to apply to the currently selected model.\n\nReturns:\n Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return ModelSetReasoningEffortResult.from_dict(await self._client.request("session.model.setReasoningEffort", params_dict, **_timeout_kwargs(timeout))) + return ModelSwitchToResult.from_dict(await self._client.request("session.model.switchTo", params_dict, **_timeout_kwargs(timeout))) class ModeApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get(self, *, timeout: float | None = None) -> SessionMode: "Gets the current agent interaction mode.\n\nReturns:\n The session mode the agent is operating in" + if self._assert_active is not None: + self._assert_active() + return SessionMode(await self._client.request("session.mode.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def set(self, params: ModeSetRequest, *, timeout: float | None = None) -> None: "Sets the current agent interaction mode.\n\nArgs:\n params: Agent interaction mode to apply to the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.mode.set", params_dict, **_timeout_kwargs(timeout)) class NameApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get(self, *, timeout: float | None = None) -> NameGetResult: "Gets the session's friendly name.\n\nReturns:\n The session's friendly name, or null when not yet set." + if self._assert_active is not None: + self._assert_active() + return NameGetResult.from_dict(await self._client.request("session.name.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def set(self, params: NameSetRequest, *, timeout: float | None = None) -> None: "Sets the session's friendly name.\n\nArgs:\n params: New friendly name to apply to the session." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - await self._client.request("session.name.set", params_dict, **_timeout_kwargs(timeout)) + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def set_auto(self, params: NameSetAutoRequest, *, timeout: float | None = None) -> NameSetAutoResult: - "Persists an auto-generated session summary as the session's name when no user-set name exists.\n\nArgs:\n params: Auto-generated session summary to apply as the session's name when no user-set name exists.\n\nReturns:\n Indicates whether the auto-generated summary was applied as the session's name." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return NameSetAutoResult.from_dict(await self._client.request("session.name.setAuto", params_dict, **_timeout_kwargs(timeout))) + await self._client.request("session.name.set", params_dict, **_timeout_kwargs(timeout)) class PlanApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def read(self, *, timeout: float | None = None) -> PlanReadResult: "Reads the session plan file from the workspace.\n\nReturns:\n Existence, contents, and resolved path of the session plan file." + if self._assert_active is not None: + self._assert_active() + return PlanReadResult.from_dict(await self._client.request("session.plan.read", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def update(self, params: PlanUpdateRequest, *, timeout: float | None = None) -> None: "Writes new content to the session plan file.\n\nArgs:\n params: Replacement contents to write to the session plan file." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.plan.update", params_dict, **_timeout_kwargs(timeout)) async def delete(self, *, timeout: float | None = None) -> None: "Deletes the session plan file from the workspace." + if self._assert_active is not None: + self._assert_active() + await self._client.request("session.plan.delete", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) class WorkspacesApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get_workspace(self, *, timeout: float | None = None) -> WorkspacesGetWorkspaceResult: - "Gets current workspace metadata for the session.\n\nReturns:\n Current workspace metadata for the session, including its absolute filesystem path when available." + "Gets current workspace metadata for the session.\n\nReturns:\n Current workspace metadata for the session, or null when not available." + if self._assert_active is not None: + self._assert_active() + return WorkspacesGetWorkspaceResult.from_dict(await self._client.request("session.workspaces.getWorkspace", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def list_files(self, *, timeout: float | None = None) -> WorkspacesListFilesResult: "Lists files stored in the session workspace files directory.\n\nReturns:\n Relative paths of files stored in the session workspace files directory." + if self._assert_active is not None: + self._assert_active() + return WorkspacesListFilesResult.from_dict(await self._client.request("session.workspaces.listFiles", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def read_file(self, params: WorkspacesReadFileRequest, *, timeout: float | None = None) -> WorkspacesReadFileResult: "Reads a file from the session workspace files directory.\n\nArgs:\n params: Relative path of the workspace file to read.\n\nReturns:\n Contents of the requested workspace file as a UTF-8 string." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return WorkspacesReadFileResult.from_dict(await self._client.request("session.workspaces.readFile", params_dict, **_timeout_kwargs(timeout))) async def create_file(self, params: WorkspacesCreateFileRequest, *, timeout: float | None = None) -> None: "Creates or overwrites a file in the session workspace files directory.\n\nArgs:\n params: Relative path and UTF-8 content for the workspace file to create or overwrite." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - await self._client.request("session.workspaces.createFile", params_dict, **_timeout_kwargs(timeout)) - - async def list_checkpoints(self, *, timeout: float | None = None) -> WorkspacesListCheckpointsResult: - "Lists workspace checkpoints in chronological order.\n\nReturns:\n Workspace checkpoints in chronological order; empty when the workspace is not enabled." - return WorkspacesListCheckpointsResult.from_dict(await self._client.request("session.workspaces.listCheckpoints", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def read_checkpoint(self, params: WorkspacesReadCheckpointRequest, *, timeout: float | None = None) -> WorkspacesReadCheckpointResult: - "Reads the content of a workspace checkpoint by number.\n\nArgs:\n params: Checkpoint number to read.\n\nReturns:\n Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return WorkspacesReadCheckpointResult.from_dict(await self._client.request("session.workspaces.readCheckpoint", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def save_large_paste(self, params: WorkspacesSaveLargePasteRequest, *, timeout: float | None = None) -> WorkspacesSaveLargePasteResult: - "Saves pasted content as a UTF-8 file in the session workspace.\n\nArgs:\n params: Pasted content to save as a UTF-8 file in the session workspace.\n\nReturns:\n Descriptor for the saved paste file, or null when the workspace is unavailable." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return WorkspacesSaveLargePasteResult.from_dict(await self._client.request("session.workspaces.saveLargePaste", params_dict, **_timeout_kwargs(timeout))) + await self._client.request("session.workspaces.createFile", params_dict, **_timeout_kwargs(timeout)) class InstructionsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get_sources(self, *, timeout: float | None = None) -> InstructionsGetSourcesResult: "Gets instruction sources loaded for the session.\n\nReturns:\n Instruction sources loaded for the session, in merge order." + if self._assert_active is not None: + self._assert_active() + return InstructionsGetSourcesResult.from_dict(await self._client.request("session.instructions.getSources", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. class FleetApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def start(self, params: FleetStartRequest, *, timeout: float | None = None) -> FleetStartResult: "Starts fleet mode by submitting the fleet orchestration prompt to the session.\n\nArgs:\n params: Optional user prompt to combine with the fleet orchestration instructions.\n\nReturns:\n Indicates whether fleet mode was successfully activated." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return FleetStartResult.from_dict(await self._client.request("session.fleet.start", params_dict, **_timeout_kwargs(timeout))) @@ -15940,91 +8719,116 @@ async def start(self, params: FleetStartRequest, *, timeout: float | None = None # Experimental: this API group is experimental and may change or be removed. class AgentApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def list(self, *, timeout: float | None = None) -> AgentList: "Lists custom agents available to the session.\n\nReturns:\n Custom agents available to the session." + if self._assert_active is not None: + self._assert_active() + return AgentList.from_dict(await self._client.request("session.agent.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def get_current(self, *, timeout: float | None = None) -> AgentGetCurrentResult: "Gets the currently selected custom agent for the session.\n\nReturns:\n The currently selected custom agent, or null when using the default agent." + if self._assert_active is not None: + self._assert_active() + return AgentGetCurrentResult.from_dict(await self._client.request("session.agent.getCurrent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def select(self, params: AgentSelectRequest, *, timeout: float | None = None) -> AgentSelectResult: "Selects a custom agent for subsequent turns in the session.\n\nArgs:\n params: Name of the custom agent to select for subsequent turns.\n\nReturns:\n The newly selected custom agent." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return AgentSelectResult.from_dict(await self._client.request("session.agent.select", params_dict, **_timeout_kwargs(timeout))) async def deselect(self, *, timeout: float | None = None) -> None: "Clears the selected custom agent and returns the session to the default agent." + if self._assert_active is not None: + self._assert_active() + await self._client.request("session.agent.deselect", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) async def reload(self, *, timeout: float | None = None) -> AgentReloadResult: "Reloads custom agent definitions and returns the refreshed list.\n\nReturns:\n Custom agents available to the session after reloading definitions from disk." + if self._assert_active is not None: + self._assert_active() + return AgentReloadResult.from_dict(await self._client.request("session.agent.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. class TasksApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def start_agent(self, params: TasksStartAgentRequest, *, timeout: float | None = None) -> TasksStartAgentResult: "Starts a background agent task in the session.\n\nArgs:\n params: Agent type, prompt, name, and optional description and model override for the new task.\n\nReturns:\n Identifier assigned to the newly started background agent task." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return TasksStartAgentResult.from_dict(await self._client.request("session.tasks.startAgent", params_dict, **_timeout_kwargs(timeout))) async def list(self, *, timeout: float | None = None) -> TaskList: "Lists background tasks tracked by the session.\n\nReturns:\n Background tasks currently tracked by the session." - return TaskList.from_dict(await self._client.request("session.tasks.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def refresh(self, *, timeout: float | None = None) -> TasksRefreshResult: - "Refreshes metadata for any detached background shells the runtime knows about.\n\nReturns:\n Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop." - return TasksRefreshResult.from_dict(await self._client.request("session.tasks.refresh", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def wait_for_pending(self, *, timeout: float | None = None) -> TasksWaitForPendingResult: - "Waits for all in-flight background tasks and any follow-up turns to settle.\n\nReturns:\n Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS)." - return TasksWaitForPendingResult.from_dict(await self._client.request("session.tasks.waitForPending", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def get_progress(self, params: TasksGetProgressRequest, *, timeout: float | None = None) -> TasksGetProgressResult: - "Returns progress information for a background task by ID.\n\nArgs:\n params: Identifier of the background task to fetch progress for.\n\nReturns:\n Progress information for the task, or null when no task with that ID is tracked." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return TasksGetProgressResult.from_dict(await self._client.request("session.tasks.getProgress", params_dict, **_timeout_kwargs(timeout))) - - async def get_current_promotable(self, *, timeout: float | None = None) -> TasksGetCurrentPromotableResult: - "Returns the first sync-waiting task that can currently be promoted to background mode.\n\nReturns:\n The first sync-waiting task that can currently be promoted to background mode." - return TasksGetCurrentPromotableResult.from_dict(await self._client.request("session.tasks.getCurrentPromotable", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return TaskList.from_dict(await self._client.request("session.tasks.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def promote_to_background(self, params: TasksPromoteToBackgroundRequest, *, timeout: float | None = None) -> TasksPromoteToBackgroundResult: "Promotes an eligible synchronously-waited task so it continues running in the background.\n\nArgs:\n params: Identifier of the task to promote to background mode.\n\nReturns:\n Indicates whether the task was successfully promoted to background mode." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return TasksPromoteToBackgroundResult.from_dict(await self._client.request("session.tasks.promoteToBackground", params_dict, **_timeout_kwargs(timeout))) - async def promote_current_to_background(self, *, timeout: float | None = None) -> TasksPromoteCurrentToBackgroundResult: - "Atomically promotes the first promotable sync-waiting task to background mode and returns it.\n\nReturns:\n The promoted task as it now exists in background mode, omitted if no promotable task was waiting." - return TasksPromoteCurrentToBackgroundResult.from_dict(await self._client.request("session.tasks.promoteCurrentToBackground", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def cancel(self, params: TasksCancelRequest, *, timeout: float | None = None) -> TasksCancelResult: "Cancels a background task.\n\nArgs:\n params: Identifier of the background task to cancel.\n\nReturns:\n Indicates whether the background task was successfully cancelled." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return TasksCancelResult.from_dict(await self._client.request("session.tasks.cancel", params_dict, **_timeout_kwargs(timeout))) async def remove(self, params: TasksRemoveRequest, *, timeout: float | None = None) -> TasksRemoveResult: "Removes a completed or cancelled background task from tracking.\n\nArgs:\n params: Identifier of the completed or cancelled task to remove from tracking.\n\nReturns:\n Indicates whether the task was removed. False when the task does not exist or is still running/idle." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return TasksRemoveResult.from_dict(await self._client.request("session.tasks.remove", params_dict, **_timeout_kwargs(timeout))) async def send_message(self, params: TasksSendMessageRequest, *, timeout: float | None = None) -> TasksSendMessageResult: "Sends a message to a background agent task.\n\nArgs:\n params: Identifier of the target agent task, message content, and optional sender agent ID.\n\nReturns:\n Indicates whether the message was delivered, with an error message when delivery failed." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return TasksSendMessageResult.from_dict(await self._client.request("session.tasks.sendMessage", params_dict, **_timeout_kwargs(timeout))) @@ -16032,47 +8836,62 @@ async def send_message(self, params: TasksSendMessageRequest, *, timeout: float # Experimental: this API group is experimental and may change or be removed. class SkillsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def list(self, *, timeout: float | None = None) -> SkillList: "Lists skills available to the session.\n\nReturns:\n Skills available to the session, with their enabled state." - return SkillList.from_dict(await self._client.request("session.skills.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def get_invoked(self, *, timeout: float | None = None) -> SkillsGetInvokedResult: - "Returns the skills that have been invoked during this session.\n\nReturns:\n Skills invoked during this session, ordered by invocation time (most recent last)." - return SkillsGetInvokedResult.from_dict(await self._client.request("session.skills.getInvoked", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return SkillList.from_dict(await self._client.request("session.skills.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def enable(self, params: SkillsEnableRequest, *, timeout: float | None = None) -> None: "Enables a skill for the session.\n\nArgs:\n params: Name of the skill to enable for the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.skills.enable", params_dict, **_timeout_kwargs(timeout)) async def disable(self, params: SkillsDisableRequest, *, timeout: float | None = None) -> None: "Disables a skill for the session.\n\nArgs:\n params: Name of the skill to disable for the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.skills.disable", params_dict, **_timeout_kwargs(timeout)) async def reload(self, *, timeout: float | None = None) -> SkillsLoadDiagnostics: "Reloads skill definitions for the session.\n\nReturns:\n Diagnostics from reloading skill definitions, with warnings and errors as separate lists." - return SkillsLoadDiagnostics.from_dict(await self._client.request("session.skills.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def ensure_loaded(self, *, timeout: float | None = None) -> None: - "Ensures the session's skill definitions have been loaded from disk." - await self._client.request("session.skills.ensureLoaded", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + return SkillsLoadDiagnostics.from_dict(await self._client.request("session.skills.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. class McpOauthApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def login(self, params: MCPOauthLoginRequest, *, timeout: float | None = None) -> MCPOauthLoginResult: "Starts OAuth authentication for a remote MCP server.\n\nArgs:\n params: Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, and the callback success-page copy.\n\nReturns:\n OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return MCPOauthLoginResult.from_dict(await self._client.request("session.mcp.oauth.login", params_dict, **_timeout_kwargs(timeout))) @@ -16080,391 +8899,264 @@ async def login(self, params: MCPOauthLoginRequest, *, timeout: float | None = N # Experimental: this API group is experimental and may change or be removed. class McpApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id - self.oauth = McpOauthApi(client, session_id) + self._assert_active = assert_active + self.oauth = McpOauthApi(client, session_id, assert_active) async def list(self, *, timeout: float | None = None) -> MCPServerList: "Lists MCP servers configured for the session and their connection status.\n\nReturns:\n MCP servers configured for the session, with their connection status." + if self._assert_active is not None: + self._assert_active() + return MCPServerList.from_dict(await self._client.request("session.mcp.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def enable(self, params: MCPEnableRequest, *, timeout: float | None = None) -> None: "Enables an MCP server for the session.\n\nArgs:\n params: Name of the MCP server to enable for the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.mcp.enable", params_dict, **_timeout_kwargs(timeout)) async def disable(self, params: MCPDisableRequest, *, timeout: float | None = None) -> None: "Disables an MCP server for the session.\n\nArgs:\n params: Name of the MCP server to disable for the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.mcp.disable", params_dict, **_timeout_kwargs(timeout)) async def reload(self, *, timeout: float | None = None) -> None: "Reloads MCP server connections for the session." - await self._client.request("session.mcp.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - - async def execute_sampling(self, params: MCPExecuteSamplingParams, *, timeout: float | None = None) -> MCPSamplingExecutionResult: - "Runs an MCP sampling inference on behalf of an MCP server.\n\nArgs:\n params: Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference.\n\nReturns:\n Outcome of an MCP sampling execution: success result, failure error, or cancellation." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MCPSamplingExecutionResult.from_dict(await self._client.request("session.mcp.executeSampling", params_dict, **_timeout_kwargs(timeout))) - - async def cancel_sampling_execution(self, params: MCPCancelSamplingExecutionParams, *, timeout: float | None = None) -> MCPCancelSamplingExecutionResult: - "Cancels an in-flight MCP sampling execution by request ID.\n\nArgs:\n params: The requestId previously passed to executeSampling that should be cancelled.\n\nReturns:\n Indicates whether an in-flight sampling execution with the given requestId was found and cancelled." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MCPCancelSamplingExecutionResult.from_dict(await self._client.request("session.mcp.cancelSamplingExecution", params_dict, **_timeout_kwargs(timeout))) - - async def set_env_value_mode(self, params: MCPSetEnvValueModeParams, *, timeout: float | None = None) -> MCPSetEnvValueModeResult: - "Sets how environment-variable values supplied to MCP servers are resolved (direct or indirect).\n\nArgs:\n params: Mode controlling how MCP server env values are resolved (`direct` or `indirect`).\n\nReturns:\n Env-value mode recorded on the session after the update." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MCPSetEnvValueModeResult.from_dict(await self._client.request("session.mcp.setEnvValueMode", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def remove_git_hub(self, *, timeout: float | None = None) -> MCPRemoveGitHubResult: - "Removes the auto-managed `github` MCP server when present.\n\nReturns:\n Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove)." - return MCPRemoveGitHubResult.from_dict(await self._client.request("session.mcp.removeGitHub", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + await self._client.request("session.mcp.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) # Experimental: this API group is experimental and may change or be removed. class PluginsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def list(self, *, timeout: float | None = None) -> PluginList: "Lists plugins installed for the session.\n\nReturns:\n Plugins installed for the session, with their enabled state and version metadata." - return PluginList.from_dict(await self._client.request("session.plugins.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class OptionsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def update(self, params: SessionUpdateOptionsParams, *, timeout: float | None = None) -> SessionUpdateOptionsResult: - "Patches the genuinely-mutable subset of session options.\n\nArgs:\n params: Patch of mutable session options to apply to the running session.\n\nReturns:\n Indicates whether the session options patch was applied successfully." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return SessionUpdateOptionsResult.from_dict(await self._client.request("session.options.update", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class LspApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id + if self._assert_active is not None: + self._assert_active() - async def initialize(self, params: LspInitializeRequest, *, timeout: float | None = None) -> None: - "Loads the merged LSP configuration set for the session's working directory.\n\nArgs:\n params: Parameters for (re)loading the merged LSP configuration set." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - await self._client.request("session.lsp.initialize", params_dict, **_timeout_kwargs(timeout)) + return PluginList.from_dict(await self._client.request("session.plugins.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. class ExtensionsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def list(self, *, timeout: float | None = None) -> ExtensionList: "Lists extensions discovered for the session and their current status.\n\nReturns:\n Extensions discovered for the session, with their current status." + if self._assert_active is not None: + self._assert_active() + return ExtensionList.from_dict(await self._client.request("session.extensions.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def enable(self, params: ExtensionsEnableRequest, *, timeout: float | None = None) -> None: "Enables an extension for the session.\n\nArgs:\n params: Source-qualified extension identifier to enable for the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.extensions.enable", params_dict, **_timeout_kwargs(timeout)) async def disable(self, params: ExtensionsDisableRequest, *, timeout: float | None = None) -> None: "Disables an extension for the session.\n\nArgs:\n params: Source-qualified extension identifier to disable for the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.extensions.disable", params_dict, **_timeout_kwargs(timeout)) async def reload(self, *, timeout: float | None = None) -> None: "Reloads extension definitions and processes for the session." + if self._assert_active is not None: + self._assert_active() + await self._client.request("session.extensions.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) class ToolsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def handle_pending_tool_call(self, params: HandlePendingToolCallRequest, *, timeout: float | None = None) -> HandlePendingToolCallResult: "Provides the result for a pending external tool call.\n\nArgs:\n params: Pending external tool call request ID, with the tool result or an error describing why it failed.\n\nReturns:\n Indicates whether the external tool call result was handled successfully." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return HandlePendingToolCallResult.from_dict(await self._client.request("session.tools.handlePendingToolCall", params_dict, **_timeout_kwargs(timeout))) - async def initialize_and_validate(self, *, timeout: float | None = None) -> ToolsInitializeAndValidateResult: - "Resolves, builds, and validates the runtime tool list for the session.\n\nReturns:\n Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation." - return ToolsInitializeAndValidateResult.from_dict(await self._client.request("session.tools.initializeAndValidate", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - class CommandsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def list(self, params: CommandsListRequest | None = None, *, timeout: float | None = None) -> CommandList: "Lists slash commands available in the session.\n\nArgs:\n params: Optional filters controlling which command sources to include in the listing.\n\nReturns:\n Slash commands available in the session, after applying any include/exclude filters." + if self._assert_active is not None: + self._assert_active() + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} params_dict["sessionId"] = self._session_id return CommandList.from_dict(await self._client.request("session.commands.list", params_dict, **_timeout_kwargs(timeout))) async def invoke(self, params: CommandsInvokeRequest, *, timeout: float | None = None) -> SlashCommandInvocationResult: "Invokes a slash command in the session.\n\nArgs:\n params: Slash command name and optional raw input string to invoke.\n\nReturns:\n Result of invoking the slash command (text output, prompt to send to the agent, or completion)." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return SlashCommandInvocationResult.from_dict(await self._client.request("session.commands.invoke", params_dict, **_timeout_kwargs(timeout))) async def handle_pending_command(self, params: CommandsHandlePendingCommandRequest, *, timeout: float | None = None) -> CommandsHandlePendingCommandResult: "Reports completion of a pending client-handled slash command.\n\nArgs:\n params: Pending command request ID and an optional error if the client handler failed.\n\nReturns:\n Indicates whether the pending client-handled command was completed successfully." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return CommandsHandlePendingCommandResult.from_dict(await self._client.request("session.commands.handlePendingCommand", params_dict, **_timeout_kwargs(timeout))) - - async def execute(self, params: ExecuteCommandParams, *, timeout: float | None = None) -> ExecuteCommandResult: - "Executes a slash command synchronously and returns any error.\n\nArgs:\n params: Slash command name and argument string to execute synchronously.\n\nReturns:\n Error message produced while executing the command, if any." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return ExecuteCommandResult.from_dict(await self._client.request("session.commands.execute", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def enqueue(self, params: EnqueueCommandParams, *, timeout: float | None = None) -> EnqueueCommandResult: - "Enqueues a slash command for FIFO processing on the local session.\n\nArgs:\n params: Slash-prefixed command string to enqueue for FIFO processing.\n\nReturns:\n Indicates whether the command was accepted into the local execution queue." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return EnqueueCommandResult.from_dict(await self._client.request("session.commands.enqueue", params_dict, **_timeout_kwargs(timeout))) + return CommandsHandlePendingCommandResult.from_dict(await self._client.request("session.commands.handlePendingCommand", params_dict, **_timeout_kwargs(timeout))) async def respond_to_queued_command(self, params: CommandsRespondToQueuedCommandRequest, *, timeout: float | None = None) -> CommandsRespondToQueuedCommandResult: - "Reports whether the host actually executed a queued command and whether to continue processing.\n\nArgs:\n params: Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands).\n\nReturns:\n Indicates whether the queued-command response was matched to a pending request." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return CommandsRespondToQueuedCommandResult.from_dict(await self._client.request("session.commands.respondToQueuedCommand", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class TelemetryApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id + "Responds to a queued command request from the session.\n\nArgs:\n params: Queued command request ID and the result indicating whether the client handled it.\n\nReturns:\n Indicates whether the queued-command response was accepted by the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def set_feature_overrides(self, params: TelemetrySetFeatureOverridesRequest, *, timeout: float | None = None) -> None: - "Sets feature override key/value pairs to attach to subsequent telemetry events for the session.\n\nArgs:\n params: Feature override key/value pairs to attach to subsequent telemetry events from this session." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.telemetry.setFeatureOverrides", params_dict, **_timeout_kwargs(timeout)) + return CommandsRespondToQueuedCommandResult.from_dict(await self._client.request("session.commands.respondToQueuedCommand", params_dict, **_timeout_kwargs(timeout))) class UiApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def elicitation(self, params: UIElicitationRequest, *, timeout: float | None = None) -> UIElicitationResponse: "Requests structured input from a UI-capable client.\n\nArgs:\n params: Prompt message and JSON schema describing the form fields to elicit from the user.\n\nReturns:\n The elicitation response (accept with form values, decline, or cancel)" + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return UIElicitationResponse.from_dict(await self._client.request("session.ui.elicitation", params_dict, **_timeout_kwargs(timeout))) async def handle_pending_elicitation(self, params: UIHandlePendingElicitationRequest, *, timeout: float | None = None) -> UIElicitationResult: "Provides the user response for a pending elicitation request.\n\nArgs:\n params: Pending elicitation request ID and the user's response (accept/decline/cancel + form values).\n\nReturns:\n Indicates whether the elicitation response was accepted; false if it was already resolved by another client." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return UIElicitationResult.from_dict(await self._client.request("session.ui.handlePendingElicitation", params_dict, **_timeout_kwargs(timeout))) - - async def handle_pending_user_input(self, params: UIHandlePendingUserInputRequest, *, timeout: float | None = None) -> UIHandlePendingResult: - "Resolves a pending `user_input.requested` event with the user's response.\n\nArgs:\n params: Request ID of a pending `user_input.requested` event and the user's response.\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingUserInput", params_dict, **_timeout_kwargs(timeout))) - - async def handle_pending_sampling(self, params: UIHandlePendingSamplingRequest, *, timeout: float | None = None) -> UIHandlePendingResult: - "Resolves a pending `sampling.requested` event with a sampling result, or rejects it.\n\nArgs:\n params: Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject).\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingSampling", params_dict, **_timeout_kwargs(timeout))) - - async def handle_pending_auto_mode_switch(self, params: UIHandlePendingAutoModeSwitchRequest, *, timeout: float | None = None) -> UIHandlePendingResult: - "Resolves a pending `auto_mode_switch.requested` event with the user's accept/decline decision.\n\nArgs:\n params: Request ID of a pending `auto_mode_switch.requested` event and the user's response.\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingAutoModeSwitch", params_dict, **_timeout_kwargs(timeout))) - - async def handle_pending_exit_plan_mode(self, params: UIHandlePendingExitPlanModeRequest, *, timeout: float | None = None) -> UIHandlePendingResult: - "Resolves a pending `exit_plan_mode.requested` event with the user's response.\n\nArgs:\n params: Request ID of a pending `exit_plan_mode.requested` event and the user's response.\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingExitPlanMode", params_dict, **_timeout_kwargs(timeout))) - - async def register_direct_auto_mode_switch_handler(self, *, timeout: float | None = None) -> UIRegisterDirectAutoModeSwitchHandlerResult: - "Registers an in-process handler for auto-mode-switch requests so the server bridge skips dispatch.\n\nReturns:\n Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId)." - return UIRegisterDirectAutoModeSwitchHandlerResult.from_dict(await self._client.request("session.ui.registerDirectAutoModeSwitchHandler", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def unregister_direct_auto_mode_switch_handler(self, params: UIUnregisterDirectAutoModeSwitchHandlerRequest, *, timeout: float | None = None) -> UIUnregisterDirectAutoModeSwitchHandlerResult: - "Unregisters a previously-registered in-process auto-mode-switch handler by its opaque handle.\n\nArgs:\n params: Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release.\n\nReturns:\n Indicates whether the handle was active and the registration count was decremented." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return UIUnregisterDirectAutoModeSwitchHandlerResult.from_dict(await self._client.request("session.ui.unregisterDirectAutoModeSwitchHandler", params_dict, **_timeout_kwargs(timeout))) - - -class PermissionsPathsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def list(self, *, timeout: float | None = None) -> PermissionPathsList: - "Returns the session's allowed directories and primary working directory.\n\nReturns:\n Snapshot of the session's allow-listed directories and primary working directory." - return PermissionPathsList.from_dict(await self._client.request("session.permissions.paths.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def add(self, params: PermissionPathsAddParams, *, timeout: float | None = None) -> PermissionsPathsAddResult: - "Adds a directory to the session's allow-list.\n\nArgs:\n params: Directory path to add to the session's allowed directories.\n\nReturns:\n Indicates whether the operation succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionsPathsAddResult.from_dict(await self._client.request("session.permissions.paths.add", params_dict, **_timeout_kwargs(timeout))) - - async def update_primary(self, params: PermissionPathsUpdatePrimaryParams, *, timeout: float | None = None) -> PermissionsPathsUpdatePrimaryResult: - "Updates the session's primary working directory used by the permission policy.\n\nArgs:\n params: Directory path to set as the session's new primary working directory.\n\nReturns:\n Indicates whether the operation succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionsPathsUpdatePrimaryResult.from_dict(await self._client.request("session.permissions.paths.updatePrimary", params_dict, **_timeout_kwargs(timeout))) - - async def is_path_within_allowed_directories(self, params: PermissionPathsAllowedCheckParams, *, timeout: float | None = None) -> PermissionPathsAllowedCheckResult: - "Reports whether a path falls within any of the session's allowed directories.\n\nArgs:\n params: Path to evaluate against the session's allowed directories.\n\nReturns:\n Indicates whether the supplied path is within the session's allowed directories." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionPathsAllowedCheckResult.from_dict(await self._client.request("session.permissions.paths.isPathWithinAllowedDirectories", params_dict, **_timeout_kwargs(timeout))) - - async def is_path_within_workspace(self, params: PermissionPathsWorkspaceCheckParams, *, timeout: float | None = None) -> PermissionPathsWorkspaceCheckResult: - "Reports whether a path falls within the session's workspace (primary) directory.\n\nArgs:\n params: Path to evaluate against the session's workspace (primary) directory.\n\nReturns:\n Indicates whether the supplied path is within the session's workspace directory." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionPathsWorkspaceCheckResult.from_dict(await self._client.request("session.permissions.paths.isPathWithinWorkspace", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - -class PermissionsUrlsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def set_unrestricted_mode(self, params: PermissionUrlsSetUnrestrictedModeParams, *, timeout: float | None = None) -> PermissionsUrlsSetUnrestrictedModeResult: - "Toggles the runtime's URL-permission policy between unrestricted and restricted modes.\n\nArgs:\n params: Whether the URL-permission policy should run in unrestricted mode.\n\nReturns:\n Indicates whether the operation succeeded." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return PermissionsUrlsSetUnrestrictedModeResult.from_dict(await self._client.request("session.permissions.urls.setUnrestrictedMode", params_dict, **_timeout_kwargs(timeout))) + return UIElicitationResult.from_dict(await self._client.request("session.ui.handlePendingElicitation", params_dict, **_timeout_kwargs(timeout))) class PermissionsApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id - self.paths = PermissionsPathsApi(client, session_id) - self.urls = PermissionsUrlsApi(client, session_id) - - async def configure(self, params: PermissionsConfigureParams, *, timeout: float | None = None) -> PermissionsConfigureResult: - "Replaces selected permission policy fields (rules, paths, URLs, exclusions, allow-all flags) on the session.\n\nArgs:\n params: Patch of permission policy fields to apply (omit a field to leave it unchanged).\n\nReturns:\n Indicates whether the operation succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionsConfigureResult.from_dict(await self._client.request("session.permissions.configure", params_dict, **_timeout_kwargs(timeout))) + self._assert_active = assert_active async def handle_pending_permission_request(self, params: PermissionDecisionRequest, *, timeout: float | None = None) -> PermissionRequestResult: "Provides a decision for a pending tool permission request.\n\nArgs:\n params: Pending permission request ID and the decision to apply (approve/reject and scope).\n\nReturns:\n Indicates whether the permission decision was applied; false when the request was already resolved." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return PermissionRequestResult.from_dict(await self._client.request("session.permissions.handlePendingPermissionRequest", params_dict, **_timeout_kwargs(timeout))) - async def pending_requests(self, *, timeout: float | None = None) -> PendingPermissionRequestList: - "Reconstructs the set of pending tool permission requests from the session's event history.\n\nReturns:\n List of pending permission requests reconstructed from event history." - return PendingPermissionRequestList.from_dict(await self._client.request("session.permissions.pendingRequests", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def set_approve_all(self, params: PermissionsSetApproveAllRequest, *, timeout: float | None = None) -> PermissionsSetApproveAllResult: - "Enables or disables automatic approval of tool permission requests for the session.\n\nArgs:\n params: Allow-all toggle for tool permission requests, with an optional telemetry source.\n\nReturns:\n Indicates whether the operation succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionsSetApproveAllResult.from_dict(await self._client.request("session.permissions.setApproveAll", params_dict, **_timeout_kwargs(timeout))) - - async def modify_rules(self, params: PermissionsModifyRulesParams, *, timeout: float | None = None) -> PermissionsModifyRulesResult: - "Adds or removes session-scoped or location-scoped permission rules.\n\nArgs:\n params: Scope and add/remove instructions for modifying session- or location-scoped permission rules.\n\nReturns:\n Indicates whether the operation succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionsModifyRulesResult.from_dict(await self._client.request("session.permissions.modifyRules", params_dict, **_timeout_kwargs(timeout))) + "Enables or disables automatic approval of tool permission requests for the session.\n\nArgs:\n params: Whether to auto-approve all tool permission requests for the rest of the session.\n\nReturns:\n Indicates whether the operation succeeded." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def set_required(self, params: PermissionsSetRequiredRequest, *, timeout: float | None = None) -> PermissionsSetRequiredResult: - "Sets whether the client wants permission prompts bridged into session events.\n\nArgs:\n params: Toggles whether permission prompts should be bridged into session events for this client.\n\nReturns:\n Indicates whether the operation succeeded." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return PermissionsSetRequiredResult.from_dict(await self._client.request("session.permissions.setRequired", params_dict, **_timeout_kwargs(timeout))) + return PermissionsSetApproveAllResult.from_dict(await self._client.request("session.permissions.setApproveAll", params_dict, **_timeout_kwargs(timeout))) async def reset_session_approvals(self, *, timeout: float | None = None) -> PermissionsResetSessionApprovalsResult: "Clears session-scoped tool permission approvals.\n\nReturns:\n Indicates whether the operation succeeded." - return PermissionsResetSessionApprovalsResult.from_dict(await self._client.request("session.permissions.resetSessionApprovals", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def notify_prompt_shown(self, params: PermissionPromptShownNotification, *, timeout: float | None = None) -> PermissionsNotifyPromptShownResult: - "Notifies the runtime that a permission prompt UI has been shown to the user.\n\nArgs:\n params: Notification payload describing the permission prompt that the client just rendered.\n\nReturns:\n Indicates whether the operation succeeded." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return PermissionsNotifyPromptShownResult.from_dict(await self._client.request("session.permissions.notifyPromptShown", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class MetadataApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def snapshot(self, *, timeout: float | None = None) -> SessionMetadataSnapshot: - "Returns a snapshot of the session's identifying metadata, mode, agent, and remote info.\n\nReturns:\n Point-in-time snapshot of slow-changing session identifier and state fields" - return SessionMetadataSnapshot.from_dict(await self._client.request("session.metadata.snapshot", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def is_processing(self, *, timeout: float | None = None) -> MetadataIsProcessingResult: - "Reports whether the local session is currently processing user/agent messages.\n\nReturns:\n Indicates whether the local session is currently processing a turn or background continuation." - return MetadataIsProcessingResult.from_dict(await self._client.request("session.metadata.isProcessing", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def context_info(self, params: MetadataContextInfoRequest, *, timeout: float | None = None) -> MetadataContextInfoResult: - "Returns the token breakdown for the session's current context window for a given model.\n\nArgs:\n params: Model identifier and token limits used to compute the context-info breakdown.\n\nReturns:\n Token breakdown for the session's current context window, or null if uninitialized." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MetadataContextInfoResult.from_dict(await self._client.request("session.metadata.contextInfo", params_dict, **_timeout_kwargs(timeout))) - - async def record_context_change(self, params: MetadataRecordContextChangeRequest, *, timeout: float | None = None) -> MetadataRecordContextChangeResult: - "Records a working-directory/git context change and emits a `session.context_changed` event.\n\nArgs:\n params: Updated working-directory/git context to record on the session.\n\nReturns:\n Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode)." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MetadataRecordContextChangeResult.from_dict(await self._client.request("session.metadata.recordContextChange", params_dict, **_timeout_kwargs(timeout))) - - async def set_working_directory(self, params: MetadataSetWorkingDirectoryRequest, *, timeout: float | None = None) -> MetadataSetWorkingDirectoryResult: - "Updates the session's recorded working directory.\n\nArgs:\n params: Absolute path to set as the session's new working directory.\n\nReturns:\n Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any related side-effects (file index, etc.); this method only updates the session's own recorded path." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MetadataSetWorkingDirectoryResult.from_dict(await self._client.request("session.metadata.setWorkingDirectory", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def recompute_context_tokens(self, params: MetadataRecomputeContextTokensRequest, *, timeout: float | None = None) -> MetadataRecomputeContextTokensResult: - "Re-tokenizes the session's existing messages against a model and returns aggregate token totals.\n\nArgs:\n params: Model identifier to use when re-tokenizing the session's existing messages.\n\nReturns:\n Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MetadataRecomputeContextTokensResult.from_dict(await self._client.request("session.metadata.recomputeContextTokens", params_dict, **_timeout_kwargs(timeout))) + return PermissionsResetSessionApprovalsResult.from_dict(await self._client.request("session.permissions.resetSessionApprovals", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) class ShellApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def exec(self, params: ShellExecRequest, *, timeout: float | None = None) -> ShellExecResult: "Starts a shell command and streams output through session notifications.\n\nArgs:\n params: Shell command to run, with optional working directory and timeout in milliseconds.\n\nReturns:\n Identifier of the spawned process, used to correlate streamed output and exit notifications." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return ShellExecResult.from_dict(await self._client.request("session.shell.exec", params_dict, **_timeout_kwargs(timeout))) async def kill(self, params: ShellKillRequest, *, timeout: float | None = None) -> ShellKillResult: "Sends a signal to a shell process previously started via \"shell.exec\".\n\nArgs:\n params: Identifier of a process previously returned by \"shell.exec\" and the signal to send.\n\nReturns:\n Indicates whether the signal was delivered; false if the process was unknown or already exited." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return ShellKillResult.from_dict(await self._client.request("session.shell.kill", params_dict, **_timeout_kwargs(timeout))) @@ -16472,191 +9164,114 @@ async def kill(self, params: ShellKillRequest, *, timeout: float | None = None) # Experimental: this API group is experimental and may change or be removed. class HistoryApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def compact(self, *, timeout: float | None = None) -> HistoryCompactResult: - "Compacts the session history to reduce context usage.\n\nReturns:\n Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown." + "Compacts the session history to reduce context usage.\n\nReturns:\n Compaction outcome with the number of tokens and messages removed and the resulting context window breakdown." + if self._assert_active is not None: + self._assert_active() + return HistoryCompactResult.from_dict(await self._client.request("session.history.compact", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) async def truncate(self, params: HistoryTruncateRequest, *, timeout: float | None = None) -> HistoryTruncateResult: "Truncates persisted session history to a specific event.\n\nArgs:\n params: Identifier of the event to truncate to; this event and all later events are removed.\n\nReturns:\n Number of events that were removed by the truncation." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return HistoryTruncateResult.from_dict(await self._client.request("session.history.truncate", params_dict, **_timeout_kwargs(timeout))) - - async def cancel_background_compaction(self, *, timeout: float | None = None) -> HistoryCancelBackgroundCompactionResult: - "Cancels any in-progress background compaction on a local session.\n\nReturns:\n Indicates whether an in-progress background compaction was cancelled." - return HistoryCancelBackgroundCompactionResult.from_dict(await self._client.request("session.history.cancelBackgroundCompaction", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def abort_manual_compaction(self, *, timeout: float | None = None) -> HistoryAbortManualCompactionResult: - "Aborts any in-progress manual compaction on a local session.\n\nReturns:\n Indicates whether an in-progress manual compaction was aborted." - return HistoryAbortManualCompactionResult.from_dict(await self._client.request("session.history.abortManualCompaction", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def summarize_for_handoff(self, *, timeout: float | None = None) -> HistorySummarizeForHandoffResult: - "Produces a markdown summary of the session's conversation context for hand-off scenarios.\n\nReturns:\n Markdown summary of the conversation context (empty when not available)." - return HistorySummarizeForHandoffResult.from_dict(await self._client.request("session.history.summarizeForHandoff", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class QueueApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def pending_items(self, *, timeout: float | None = None) -> QueuePendingItemsResult: - "Returns the local session's pending user-facing queued items and steering messages.\n\nReturns:\n Snapshot of the session's pending queued items and immediate-steering messages." - return QueuePendingItemsResult.from_dict(await self._client.request("session.queue.pendingItems", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def remove_most_recent(self, *, timeout: float | None = None) -> QueueRemoveMostRecentResult: - "Removes the most recently queued user-facing item (LIFO).\n\nReturns:\n Indicates whether a user-facing pending item was removed." - return QueueRemoveMostRecentResult.from_dict(await self._client.request("session.queue.removeMostRecent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def clear(self, *, timeout: float | None = None) -> None: - "Clears all pending queued items on the local session." - await self._client.request("session.queue.clear", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - - -# Experimental: this API group is experimental and may change or be removed. -class EventLogApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def read(self, params: EventLogReadRequest, *, timeout: float | None = None) -> EventsReadResult: - "Reads a batch of session events from a cursor, optionally waiting for new events.\n\nArgs:\n params: Cursor, batch size, and optional long-poll/filter parameters for reading session events.\n\nReturns:\n Batch of session events returned by a read, with cursor and continuation metadata." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return EventsReadResult.from_dict(await self._client.request("session.eventLog.read", params_dict, **_timeout_kwargs(timeout))) - - async def tail(self, *, timeout: float | None = None) -> EventLogTailResult: - "Returns a snapshot of the current tail cursor without consuming events.\n\nReturns:\n Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session)." - return EventLogTailResult.from_dict(await self._client.request("session.eventLog.tail", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def register_interest(self, params: RegisterEventInterestParams, *, timeout: float | None = None) -> RegisterEventInterestResult: - "Registers consumer interest in an event type for runtime gating purposes.\n\nArgs:\n params: Event type to register consumer interest for, used by runtime gating logic.\n\nReturns:\n Opaque handle representing an event-type interest registration." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return RegisterEventInterestResult.from_dict(await self._client.request("session.eventLog.registerInterest", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def release_interest(self, params: ReleaseEventInterestParams, *, timeout: float | None = None) -> EventLogReleaseInterestResult: - "Releases a consumer's previously-registered interest in an event type.\n\nArgs:\n params: Opaque handle previously returned by `registerInterest` to release.\n\nReturns:\n Indicates whether the operation succeeded." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return EventLogReleaseInterestResult.from_dict(await self._client.request("session.eventLog.releaseInterest", params_dict, **_timeout_kwargs(timeout))) + return HistoryTruncateResult.from_dict(await self._client.request("session.history.truncate", params_dict, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. class UsageApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def get_metrics(self, *, timeout: float | None = None) -> UsageGetMetricsResult: "Gets accumulated usage metrics for the session.\n\nReturns:\n Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals." + if self._assert_active is not None: + self._assert_active() + return UsageGetMetricsResult.from_dict(await self._client.request("session.usage.getMetrics", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. class RemoteApi: - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id + self._assert_active = assert_active async def enable(self, params: RemoteEnableRequest, *, timeout: float | None = None) -> RemoteEnableResult: "Enables remote session export or steering.\n\nArgs:\n params: Optional remote session mode (\"off\", \"export\", or \"on\"); defaults to enabling both export and remote steering.\n\nReturns:\n GitHub URL for the session and a flag indicating whether remote steering is enabled." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return RemoteEnableResult.from_dict(await self._client.request("session.remote.enable", params_dict, **_timeout_kwargs(timeout))) async def disable(self, *, timeout: float | None = None) -> None: "Disables remote session export and steering." - await self._client.request("session.remote.disable", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - - async def notify_steerable_changed(self, params: RemoteNotifySteerableChangedRequest, *, timeout: float | None = None) -> RemoteNotifySteerableChangedResult: - "Persists a remote-steerability change emitted by the host as a session event.\n\nArgs:\n params: New remote-steerability state to persist as a `session.remote_steerable_changed` event.\n\nReturns:\n Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return RemoteNotifySteerableChangedResult.from_dict(await self._client.request("session.remote.notifySteerableChanged", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class ScheduleApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def list(self, *, timeout: float | None = None) -> ScheduleList: - "Lists the session's currently active scheduled prompts.\n\nReturns:\n Snapshot of the currently active recurring prompts for this session." - return ScheduleList.from_dict(await self._client.request("session.schedule.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def stop(self, params: ScheduleStopRequest, *, timeout: float | None = None) -> ScheduleStopResult: - "Removes a scheduled prompt by id.\n\nArgs:\n params: Identifier of the scheduled prompt to remove.\n\nReturns:\n Remove a scheduled prompt by id. The result entry is omitted if the id was unknown." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return ScheduleStopResult.from_dict(await self._client.request("session.schedule.stop", params_dict, **_timeout_kwargs(timeout))) + await self._client.request("session.remote.disable", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) class SessionRpc: """Typed session-scoped RPC methods.""" - def __init__(self, client: "JsonRpcClient", session_id: str): + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id - self.auth = AuthApi(client, session_id) - self.model = ModelApi(client, session_id) - self.mode = ModeApi(client, session_id) - self.name = NameApi(client, session_id) - self.plan = PlanApi(client, session_id) - self.workspaces = WorkspacesApi(client, session_id) - self.instructions = InstructionsApi(client, session_id) - self.fleet = FleetApi(client, session_id) - self.agent = AgentApi(client, session_id) - self.tasks = TasksApi(client, session_id) - self.skills = SkillsApi(client, session_id) - self.mcp = McpApi(client, session_id) - self.plugins = PluginsApi(client, session_id) - self.options = OptionsApi(client, session_id) - self.lsp = LspApi(client, session_id) - self.extensions = ExtensionsApi(client, session_id) - self.tools = ToolsApi(client, session_id) - self.commands = CommandsApi(client, session_id) - self.telemetry = TelemetryApi(client, session_id) - self.ui = UiApi(client, session_id) - self.permissions = PermissionsApi(client, session_id) - self.metadata = MetadataApi(client, session_id) - self.shell = ShellApi(client, session_id) - self.history = HistoryApi(client, session_id) - self.queue = QueueApi(client, session_id) - self.event_log = EventLogApi(client, session_id) - self.usage = UsageApi(client, session_id) - self.remote = RemoteApi(client, session_id) - self.schedule = ScheduleApi(client, session_id) + self._assert_active = assert_active + self.auth = AuthApi(client, session_id, assert_active) + self.model = ModelApi(client, session_id, assert_active) + self.mode = ModeApi(client, session_id, assert_active) + self.name = NameApi(client, session_id, assert_active) + self.plan = PlanApi(client, session_id, assert_active) + self.workspaces = WorkspacesApi(client, session_id, assert_active) + self.instructions = InstructionsApi(client, session_id, assert_active) + self.fleet = FleetApi(client, session_id, assert_active) + self.agent = AgentApi(client, session_id, assert_active) + self.tasks = TasksApi(client, session_id, assert_active) + self.skills = SkillsApi(client, session_id, assert_active) + self.mcp = McpApi(client, session_id, assert_active) + self.plugins = PluginsApi(client, session_id, assert_active) + self.extensions = ExtensionsApi(client, session_id, assert_active) + self.tools = ToolsApi(client, session_id, assert_active) + self.commands = CommandsApi(client, session_id, assert_active) + self.ui = UiApi(client, session_id, assert_active) + self.permissions = PermissionsApi(client, session_id, assert_active) + self.shell = ShellApi(client, session_id, assert_active) + self.history = HistoryApi(client, session_id, assert_active) + self.usage = UsageApi(client, session_id, assert_active) + self.remote = RemoteApi(client, session_id, assert_active) async def suspend(self, *, timeout: float | None = None) -> None: "Suspends the session while preserving persisted state for later resume." - await self._client.request("session.suspend", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - - async def send(self, params: SendRequest, *, timeout: float | None = None) -> SendResult: - "Sends a user message to the session and returns its message ID.\n\nArgs:\n params: Parameters for sending a user message to the session\n\nReturns:\n Result of sending a user message" - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return SendResult.from_dict(await self._client.request("session.send", params_dict, **_timeout_kwargs(timeout))) - - async def abort(self, params: AbortRequest, *, timeout: float | None = None) -> AbortResult: - "Aborts the current agent turn.\n\nArgs:\n params: Parameters for aborting the current turn\n\nReturns:\n Result of aborting the current turn" - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return AbortResult.from_dict(await self._client.request("session.abort", params_dict, **_timeout_kwargs(timeout))) + if self._assert_active is not None: + self._assert_active() - async def shutdown(self, params: ShutdownRequest, *, timeout: float | None = None) -> None: - "Shuts down the session and persists its final state. Awaits any deferred sessionEnd hooks before resolving so user-supplied hook scripts complete before the runtime tears down.\n\nArgs:\n params: Parameters for shutting down the session" - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - await self._client.request("session.shutdown", params_dict, **_timeout_kwargs(timeout)) + await self._client.request("session.suspend", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) async def log(self, params: LogRequest, *, timeout: float | None = None) -> LogResult: - "Emits a user-visible session log event.\n\nArgs:\n params: Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip.\n\nReturns:\n Identifier of the session event that was emitted for the log message." + "Emits a user-visible session log event.\n\nArgs:\n params: Message text, optional severity level, persistence flag, and optional follow-up URL.\n\nReturns:\n Identifier of the session event that was emitted for the log message." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return LogResult.from_dict(await self._client.request("session.log", params_dict, **_timeout_kwargs(timeout))) diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index f344650cd..4f1b0bc03 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -325,7 +325,7 @@ class AssistantMessageData: encrypted_content: str | None = None interaction_id: str | None = None model: str | None = None - output_tokens: int | None = None + output_tokens: float | None = None # Deprecated: this field is deprecated. parent_tool_call_id: str | None = None phase: str | None = None @@ -345,7 +345,7 @@ def from_dict(obj: Any) -> "AssistantMessageData": encrypted_content = from_union([from_none, from_str], obj.get("encryptedContent")) interaction_id = from_union([from_none, from_str], obj.get("interactionId")) model = from_union([from_none, from_str], obj.get("model")) - output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) + output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) phase = from_union([from_none, from_str], obj.get("phase")) reasoning_opaque = from_union([from_none, from_str], obj.get("reasoningOpaque")) @@ -386,7 +386,7 @@ def to_dict(self) -> dict: if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) + result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) if self.parent_tool_call_id is not None: result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) if self.phase is not None: @@ -559,19 +559,19 @@ def to_dict(self) -> dict: @dataclass class AssistantStreamingDeltaData: "Streaming response progress with cumulative byte count" - total_response_size_bytes: int + total_response_size_bytes: float @staticmethod def from_dict(obj: Any) -> "AssistantStreamingDeltaData": assert isinstance(obj, dict) - total_response_size_bytes = from_int(obj.get("totalResponseSizeBytes")) + total_response_size_bytes = from_float(obj.get("totalResponseSizeBytes")) return AssistantStreamingDeltaData( total_response_size_bytes=total_response_size_bytes, ) def to_dict(self) -> dict: result: dict = {} - result["totalResponseSizeBytes"] = to_int(self.total_response_size_bytes) + result["totalResponseSizeBytes"] = to_float(self.total_response_size_bytes) return result @@ -622,13 +622,13 @@ def to_dict(self) -> dict: class AssistantUsageCopilotUsage: "Per-request cost and usage data from the CAPI copilot_usage response field" token_details: list[AssistantUsageCopilotUsageTokenDetail] - total_nano_aiu: int + total_nano_aiu: float @staticmethod def from_dict(obj: Any) -> "AssistantUsageCopilotUsage": assert isinstance(obj, dict) token_details = from_list(AssistantUsageCopilotUsageTokenDetail.from_dict, obj.get("tokenDetails")) - total_nano_aiu = from_int(obj.get("totalNanoAiu")) + total_nano_aiu = from_float(obj.get("totalNanoAiu")) return AssistantUsageCopilotUsage( token_details=token_details, total_nano_aiu=total_nano_aiu, @@ -637,24 +637,24 @@ def from_dict(obj: Any) -> "AssistantUsageCopilotUsage": def to_dict(self) -> dict: result: dict = {} result["tokenDetails"] = from_list(lambda x: to_class(AssistantUsageCopilotUsageTokenDetail, x), self.token_details) - result["totalNanoAiu"] = to_int(self.total_nano_aiu) + result["totalNanoAiu"] = to_float(self.total_nano_aiu) return result @dataclass class AssistantUsageCopilotUsageTokenDetail: "Token usage detail for a single billing category" - batch_size: int - cost_per_batch: int - token_count: int + batch_size: float + cost_per_batch: float + token_count: float token_type: str @staticmethod def from_dict(obj: Any) -> "AssistantUsageCopilotUsageTokenDetail": assert isinstance(obj, dict) - batch_size = from_int(obj.get("batchSize")) - cost_per_batch = from_int(obj.get("costPerBatch")) - token_count = from_int(obj.get("tokenCount")) + batch_size = from_float(obj.get("batchSize")) + cost_per_batch = from_float(obj.get("costPerBatch")) + token_count = from_float(obj.get("tokenCount")) token_type = from_str(obj.get("tokenType")) return AssistantUsageCopilotUsageTokenDetail( batch_size=batch_size, @@ -665,9 +665,9 @@ def from_dict(obj: Any) -> "AssistantUsageCopilotUsageTokenDetail": def to_dict(self) -> dict: result: dict = {} - result["batchSize"] = to_int(self.batch_size) - result["costPerBatch"] = to_int(self.cost_per_batch) - result["tokenCount"] = to_int(self.token_count) + result["batchSize"] = to_float(self.batch_size) + result["costPerBatch"] = to_float(self.cost_per_batch) + result["tokenCount"] = to_float(self.token_count) result["tokenType"] = from_str(self.token_type) return result @@ -678,21 +678,21 @@ class AssistantUsageData: model: str api_call_id: str | None = None api_endpoint: AssistantUsageApiEndpoint | None = None - cache_read_tokens: int | None = None - cache_write_tokens: int | None = None + cache_read_tokens: float | None = None + cache_write_tokens: float | None = None copilot_usage: AssistantUsageCopilotUsage | None = None cost: float | None = None duration: timedelta | None = None initiator: str | None = None - input_tokens: int | None = None + input_tokens: float | None = None inter_token_latency: timedelta | None = None - output_tokens: int | None = None + output_tokens: float | None = None # Deprecated: this field is deprecated. parent_tool_call_id: str | None = None provider_call_id: str | None = None quota_snapshots: dict[str, AssistantUsageQuotaSnapshot] | None = None reasoning_effort: str | None = None - reasoning_tokens: int | None = None + reasoning_tokens: float | None = None ttft: timedelta | None = None @staticmethod @@ -701,20 +701,20 @@ def from_dict(obj: Any) -> "AssistantUsageData": model = from_str(obj.get("model")) api_call_id = from_union([from_none, from_str], obj.get("apiCallId")) api_endpoint = from_union([from_none, lambda x: parse_enum(AssistantUsageApiEndpoint, x)], obj.get("apiEndpoint")) - cache_read_tokens = from_union([from_none, from_int], obj.get("cacheReadTokens")) - cache_write_tokens = from_union([from_none, from_int], obj.get("cacheWriteTokens")) + cache_read_tokens = from_union([from_none, from_float], obj.get("cacheReadTokens")) + cache_write_tokens = from_union([from_none, from_float], obj.get("cacheWriteTokens")) copilot_usage = from_union([from_none, AssistantUsageCopilotUsage.from_dict], obj.get("copilotUsage")) cost = from_union([from_none, from_float], obj.get("cost")) duration = from_union([from_none, from_timedelta], obj.get("duration")) initiator = from_union([from_none, from_str], obj.get("initiator")) - input_tokens = from_union([from_none, from_int], obj.get("inputTokens")) + input_tokens = from_union([from_none, from_float], obj.get("inputTokens")) inter_token_latency = from_union([from_none, from_timedelta], obj.get("interTokenLatencyMs")) - output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) + output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) quota_snapshots = from_union([from_none, lambda x: from_dict(AssistantUsageQuotaSnapshot.from_dict, x)], obj.get("quotaSnapshots")) reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) - reasoning_tokens = from_union([from_none, from_int], obj.get("reasoningTokens")) + reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) ttft = from_union([from_none, from_timedelta], obj.get("ttftMs")) return AssistantUsageData( model=model, @@ -745,23 +745,23 @@ def to_dict(self) -> dict: if self.api_endpoint is not None: result["apiEndpoint"] = from_union([from_none, lambda x: to_enum(AssistantUsageApiEndpoint, x)], self.api_endpoint) if self.cache_read_tokens is not None: - result["cacheReadTokens"] = from_union([from_none, to_int], self.cache_read_tokens) + result["cacheReadTokens"] = from_union([from_none, to_float], self.cache_read_tokens) if self.cache_write_tokens is not None: - result["cacheWriteTokens"] = from_union([from_none, to_int], self.cache_write_tokens) + result["cacheWriteTokens"] = from_union([from_none, to_float], self.cache_write_tokens) if self.copilot_usage is not None: result["copilotUsage"] = from_union([from_none, lambda x: to_class(AssistantUsageCopilotUsage, x)], self.copilot_usage) if self.cost is not None: result["cost"] = from_union([from_none, to_float], self.cost) if self.duration is not None: - result["duration"] = from_union([from_none, to_timedelta_int], self.duration) + result["duration"] = from_union([from_none, to_timedelta], self.duration) if self.initiator is not None: result["initiator"] = from_union([from_none, from_str], self.initiator) if self.input_tokens is not None: - result["inputTokens"] = from_union([from_none, to_int], self.input_tokens) + result["inputTokens"] = from_union([from_none, to_float], self.input_tokens) if self.inter_token_latency is not None: result["interTokenLatencyMs"] = from_union([from_none, to_timedelta], self.inter_token_latency) if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) + result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) if self.parent_tool_call_id is not None: result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) if self.provider_call_id is not None: @@ -771,34 +771,34 @@ def to_dict(self) -> dict: if self.reasoning_effort is not None: result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_none, to_int], self.reasoning_tokens) + result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) if self.ttft is not None: - result["ttftMs"] = from_union([from_none, to_timedelta_int], self.ttft) + result["ttftMs"] = from_union([from_none, to_timedelta], self.ttft) return result @dataclass class AssistantUsageQuotaSnapshot: "Schema for the `AssistantUsageQuotaSnapshot` type." - entitlement_requests: int + entitlement_requests: float is_unlimited_entitlement: bool overage: float overage_allowed_with_exhausted_quota: bool remaining_percentage: float usage_allowed_with_exhausted_quota: bool - used_requests: int + used_requests: float reset_date: datetime | None = None @staticmethod def from_dict(obj: Any) -> "AssistantUsageQuotaSnapshot": assert isinstance(obj, dict) - entitlement_requests = from_int(obj.get("entitlementRequests")) + entitlement_requests = from_float(obj.get("entitlementRequests")) is_unlimited_entitlement = from_bool(obj.get("isUnlimitedEntitlement")) overage = from_float(obj.get("overage")) overage_allowed_with_exhausted_quota = from_bool(obj.get("overageAllowedWithExhaustedQuota")) remaining_percentage = from_float(obj.get("remainingPercentage")) usage_allowed_with_exhausted_quota = from_bool(obj.get("usageAllowedWithExhaustedQuota")) - used_requests = from_int(obj.get("usedRequests")) + used_requests = from_float(obj.get("usedRequests")) reset_date = from_union([from_none, from_datetime], obj.get("resetDate")) return AssistantUsageQuotaSnapshot( entitlement_requests=entitlement_requests, @@ -813,13 +813,13 @@ def from_dict(obj: Any) -> "AssistantUsageQuotaSnapshot": def to_dict(self) -> dict: result: dict = {} - result["entitlementRequests"] = to_int(self.entitlement_requests) + result["entitlementRequests"] = to_float(self.entitlement_requests) result["isUnlimitedEntitlement"] = from_bool(self.is_unlimited_entitlement) result["overage"] = to_float(self.overage) result["overageAllowedWithExhaustedQuota"] = from_bool(self.overage_allowed_with_exhausted_quota) result["remainingPercentage"] = to_float(self.remaining_percentage) result["usageAllowedWithExhaustedQuota"] = from_bool(self.usage_allowed_with_exhausted_quota) - result["usedRequests"] = to_int(self.used_requests) + result["usedRequests"] = to_float(self.used_requests) if self.reset_date is not None: result["resetDate"] = from_union([from_none, to_datetime], self.reset_date) return result @@ -853,14 +853,14 @@ class AutoModeSwitchRequestedData: "Auto mode switch request notification requiring user approval" request_id: str error_code: str | None = None - retry_after_seconds: int | None = None + retry_after_seconds: float | None = None @staticmethod def from_dict(obj: Any) -> "AutoModeSwitchRequestedData": assert isinstance(obj, dict) request_id = from_str(obj.get("requestId")) error_code = from_union([from_none, from_str], obj.get("errorCode")) - retry_after_seconds = from_union([from_none, from_int], obj.get("retryAfterSeconds")) + retry_after_seconds = from_union([from_none, from_float], obj.get("retryAfterSeconds")) return AutoModeSwitchRequestedData( request_id=request_id, error_code=error_code, @@ -873,7 +873,7 @@ def to_dict(self) -> dict: if self.error_code is not None: result["errorCode"] = from_union([from_none, from_str], self.error_code) if self.retry_after_seconds is not None: - result["retryAfterSeconds"] = from_union([from_none, to_int], self.retry_after_seconds) + result["retryAfterSeconds"] = from_union([from_none, to_float], self.retry_after_seconds) return result @@ -1036,24 +1036,24 @@ def to_dict(self) -> dict: @dataclass class CompactionCompleteCompactionTokensUsed: "Token usage breakdown for the compaction LLM call (aligned with assistant.usage format)" - cache_read_tokens: int | None = None - cache_write_tokens: int | None = None + cache_read_tokens: float | None = None + cache_write_tokens: float | None = None copilot_usage: CompactionCompleteCompactionTokensUsedCopilotUsage | None = None duration: timedelta | None = None - input_tokens: int | None = None + input_tokens: float | None = None model: str | None = None - output_tokens: int | None = None + output_tokens: float | None = None @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": assert isinstance(obj, dict) - cache_read_tokens = from_union([from_none, from_int], obj.get("cacheReadTokens")) - cache_write_tokens = from_union([from_none, from_int], obj.get("cacheWriteTokens")) + cache_read_tokens = from_union([from_none, from_float], obj.get("cacheReadTokens")) + cache_write_tokens = from_union([from_none, from_float], obj.get("cacheWriteTokens")) copilot_usage = from_union([from_none, CompactionCompleteCompactionTokensUsedCopilotUsage.from_dict], obj.get("copilotUsage")) duration = from_union([from_none, from_timedelta], obj.get("duration")) - input_tokens = from_union([from_none, from_int], obj.get("inputTokens")) + input_tokens = from_union([from_none, from_float], obj.get("inputTokens")) model = from_union([from_none, from_str], obj.get("model")) - output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) + output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) return CompactionCompleteCompactionTokensUsed( cache_read_tokens=cache_read_tokens, cache_write_tokens=cache_write_tokens, @@ -1067,19 +1067,19 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": def to_dict(self) -> dict: result: dict = {} if self.cache_read_tokens is not None: - result["cacheReadTokens"] = from_union([from_none, to_int], self.cache_read_tokens) + result["cacheReadTokens"] = from_union([from_none, to_float], self.cache_read_tokens) if self.cache_write_tokens is not None: - result["cacheWriteTokens"] = from_union([from_none, to_int], self.cache_write_tokens) + result["cacheWriteTokens"] = from_union([from_none, to_float], self.cache_write_tokens) if self.copilot_usage is not None: result["copilotUsage"] = from_union([from_none, lambda x: to_class(CompactionCompleteCompactionTokensUsedCopilotUsage, x)], self.copilot_usage) if self.duration is not None: - result["duration"] = from_union([from_none, to_timedelta_int], self.duration) + result["duration"] = from_union([from_none, to_timedelta], self.duration) if self.input_tokens is not None: - result["inputTokens"] = from_union([from_none, to_int], self.input_tokens) + result["inputTokens"] = from_union([from_none, to_float], self.input_tokens) if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) + result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) return result @@ -1087,13 +1087,13 @@ def to_dict(self) -> dict: class CompactionCompleteCompactionTokensUsedCopilotUsage: "Per-request cost and usage data from the CAPI copilot_usage response field" token_details: list[CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail] - total_nano_aiu: int + total_nano_aiu: float @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsage": assert isinstance(obj, dict) token_details = from_list(CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail.from_dict, obj.get("tokenDetails")) - total_nano_aiu = from_int(obj.get("totalNanoAiu")) + total_nano_aiu = from_float(obj.get("totalNanoAiu")) return CompactionCompleteCompactionTokensUsedCopilotUsage( token_details=token_details, total_nano_aiu=total_nano_aiu, @@ -1102,24 +1102,24 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsage": def to_dict(self) -> dict: result: dict = {} result["tokenDetails"] = from_list(lambda x: to_class(CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail, x), self.token_details) - result["totalNanoAiu"] = to_int(self.total_nano_aiu) + result["totalNanoAiu"] = to_float(self.total_nano_aiu) return result @dataclass class CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail: "Token usage detail for a single billing category" - batch_size: int - cost_per_batch: int - token_count: int + batch_size: float + cost_per_batch: float + token_count: float token_type: str @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail": assert isinstance(obj, dict) - batch_size = from_int(obj.get("batchSize")) - cost_per_batch = from_int(obj.get("costPerBatch")) - token_count = from_int(obj.get("tokenCount")) + batch_size = from_float(obj.get("batchSize")) + cost_per_batch = from_float(obj.get("costPerBatch")) + token_count = from_float(obj.get("tokenCount")) token_type = from_str(obj.get("tokenType")) return CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail( batch_size=batch_size, @@ -1130,9 +1130,9 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsageTo def to_dict(self) -> dict: result: dict = {} - result["batchSize"] = to_int(self.batch_size) - result["costPerBatch"] = to_int(self.cost_per_batch) - result["tokenCount"] = to_int(self.token_count) + result["batchSize"] = to_float(self.batch_size) + result["costPerBatch"] = to_float(self.cost_per_batch) + result["tokenCount"] = to_float(self.token_count) result["tokenType"] = from_str(self.token_type) return result @@ -1786,7 +1786,7 @@ def to_dict(self) -> dict: if self.api_call_id is not None: result["apiCallId"] = from_union([from_none, from_str], self.api_call_id) if self.duration is not None: - result["durationMs"] = from_union([from_none, to_timedelta_int], self.duration) + result["durationMs"] = from_union([from_none, to_timedelta], self.duration) if self.error_message is not None: result["errorMessage"] = from_union([from_none, from_str], self.error_message) if self.initiator is not None: @@ -2402,39 +2402,39 @@ def to_dict(self) -> dict: class SessionCompactionCompleteData: "Conversation compaction results including success status, metrics, and optional error details" success: bool - checkpoint_number: int | None = None + checkpoint_number: float | None = None checkpoint_path: str | None = None compaction_tokens_used: CompactionCompleteCompactionTokensUsed | None = None - conversation_tokens: int | None = None + conversation_tokens: float | None = None error: str | None = None - messages_removed: int | None = None - post_compaction_tokens: int | None = None - pre_compaction_messages_length: int | None = None - pre_compaction_tokens: int | None = None + messages_removed: float | None = None + post_compaction_tokens: float | None = None + pre_compaction_messages_length: float | None = None + pre_compaction_tokens: float | None = None request_id: str | None = None summary_content: str | None = None - system_tokens: int | None = None - tokens_removed: int | None = None - tool_definitions_tokens: int | None = None + system_tokens: float | None = None + tokens_removed: float | None = None + tool_definitions_tokens: float | None = None @staticmethod def from_dict(obj: Any) -> "SessionCompactionCompleteData": assert isinstance(obj, dict) success = from_bool(obj.get("success")) - checkpoint_number = from_union([from_none, from_int], obj.get("checkpointNumber")) + checkpoint_number = from_union([from_none, from_float], obj.get("checkpointNumber")) checkpoint_path = from_union([from_none, from_str], obj.get("checkpointPath")) compaction_tokens_used = from_union([from_none, CompactionCompleteCompactionTokensUsed.from_dict], obj.get("compactionTokensUsed")) - conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) error = from_union([from_none, from_str], obj.get("error")) - messages_removed = from_union([from_none, from_int], obj.get("messagesRemoved")) - post_compaction_tokens = from_union([from_none, from_int], obj.get("postCompactionTokens")) - pre_compaction_messages_length = from_union([from_none, from_int], obj.get("preCompactionMessagesLength")) - pre_compaction_tokens = from_union([from_none, from_int], obj.get("preCompactionTokens")) + messages_removed = from_union([from_none, from_float], obj.get("messagesRemoved")) + post_compaction_tokens = from_union([from_none, from_float], obj.get("postCompactionTokens")) + pre_compaction_messages_length = from_union([from_none, from_float], obj.get("preCompactionMessagesLength")) + pre_compaction_tokens = from_union([from_none, from_float], obj.get("preCompactionTokens")) request_id = from_union([from_none, from_str], obj.get("requestId")) summary_content = from_union([from_none, from_str], obj.get("summaryContent")) - system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) - tokens_removed = from_union([from_none, from_int], obj.get("tokensRemoved")) - tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tokens_removed = from_union([from_none, from_float], obj.get("tokensRemoved")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) return SessionCompactionCompleteData( success=success, checkpoint_number=checkpoint_number, @@ -2457,49 +2457,49 @@ def to_dict(self) -> dict: result: dict = {} result["success"] = from_bool(self.success) if self.checkpoint_number is not None: - result["checkpointNumber"] = from_union([from_none, to_int], self.checkpoint_number) + result["checkpointNumber"] = from_union([from_none, to_float], self.checkpoint_number) if self.checkpoint_path is not None: result["checkpointPath"] = from_union([from_none, from_str], self.checkpoint_path) if self.compaction_tokens_used is not None: result["compactionTokensUsed"] = from_union([from_none, lambda x: to_class(CompactionCompleteCompactionTokensUsed, x)], self.compaction_tokens_used) if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) if self.error is not None: result["error"] = from_union([from_none, from_str], self.error) if self.messages_removed is not None: - result["messagesRemoved"] = from_union([from_none, to_int], self.messages_removed) + result["messagesRemoved"] = from_union([from_none, to_float], self.messages_removed) if self.post_compaction_tokens is not None: - result["postCompactionTokens"] = from_union([from_none, to_int], self.post_compaction_tokens) + result["postCompactionTokens"] = from_union([from_none, to_float], self.post_compaction_tokens) if self.pre_compaction_messages_length is not None: - result["preCompactionMessagesLength"] = from_union([from_none, to_int], self.pre_compaction_messages_length) + result["preCompactionMessagesLength"] = from_union([from_none, to_float], self.pre_compaction_messages_length) if self.pre_compaction_tokens is not None: - result["preCompactionTokens"] = from_union([from_none, to_int], self.pre_compaction_tokens) + result["preCompactionTokens"] = from_union([from_none, to_float], self.pre_compaction_tokens) if self.request_id is not None: result["requestId"] = from_union([from_none, from_str], self.request_id) if self.summary_content is not None: result["summaryContent"] = from_union([from_none, from_str], self.summary_content) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) if self.tokens_removed is not None: - result["tokensRemoved"] = from_union([from_none, to_int], self.tokens_removed) + result["tokensRemoved"] = from_union([from_none, to_float], self.tokens_removed) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) return result @dataclass class SessionCompactionStartData: "Context window breakdown at the start of LLM-powered conversation compaction" - conversation_tokens: int | None = None - system_tokens: int | None = None - tool_definitions_tokens: int | None = None + conversation_tokens: float | None = None + system_tokens: float | None = None + tool_definitions_tokens: float | None = None @staticmethod def from_dict(obj: Any) -> "SessionCompactionStartData": assert isinstance(obj, dict) - conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) - system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) - tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) return SessionCompactionStartData( conversation_tokens=conversation_tokens, system_tokens=system_tokens, @@ -2509,11 +2509,11 @@ def from_dict(obj: Any) -> "SessionCompactionStartData": def to_dict(self) -> dict: result: dict = {} if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) return result @@ -2963,7 +2963,7 @@ def to_dict(self) -> dict: @dataclass class SessionResumeData: "Session resume metadata including current context and event count" - event_count: int + event_count: float resume_time: datetime already_in_use: bool | None = None context: WorkingDirectoryContext | None = None @@ -2977,7 +2977,7 @@ class SessionResumeData: @staticmethod def from_dict(obj: Any) -> "SessionResumeData": assert isinstance(obj, dict) - event_count = from_int(obj.get("eventCount")) + event_count = from_float(obj.get("eventCount")) resume_time = from_datetime(obj.get("resumeTime")) already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) @@ -3002,7 +3002,7 @@ def from_dict(obj: Any) -> "SessionResumeData": def to_dict(self) -> dict: result: dict = {} - result["eventCount"] = to_int(self.event_count) + result["eventCount"] = to_float(self.event_count) result["resumeTime"] = to_datetime(self.resume_time) if self.already_in_use is not None: result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) @@ -3084,36 +3084,36 @@ class SessionShutdownData: "Session termination metrics including usage statistics, code changes, and shutdown reason" code_changes: ShutdownCodeChanges model_metrics: dict[str, ShutdownModelMetric] - session_start_time: int + session_start_time: float shutdown_type: ShutdownType total_api_duration: timedelta - total_premium_requests: int - conversation_tokens: int | None = None + total_premium_requests: float + conversation_tokens: float | None = None current_model: str | None = None - current_tokens: int | None = None + current_tokens: float | None = None error_reason: str | None = None - system_tokens: int | None = None + system_tokens: float | None = None token_details: dict[str, ShutdownTokenDetail] | None = None - tool_definitions_tokens: int | None = None - total_nano_aiu: int | None = None + tool_definitions_tokens: float | None = None + total_nano_aiu: float | None = None @staticmethod def from_dict(obj: Any) -> "SessionShutdownData": assert isinstance(obj, dict) code_changes = ShutdownCodeChanges.from_dict(obj.get("codeChanges")) model_metrics = from_dict(ShutdownModelMetric.from_dict, obj.get("modelMetrics")) - session_start_time = from_int(obj.get("sessionStartTime")) + session_start_time = from_float(obj.get("sessionStartTime")) shutdown_type = parse_enum(ShutdownType, obj.get("shutdownType")) total_api_duration = from_timedelta(obj.get("totalApiDurationMs")) - total_premium_requests = from_int(obj.get("totalPremiumRequests")) - conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) + total_premium_requests = from_float(obj.get("totalPremiumRequests")) + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) current_model = from_union([from_none, from_str], obj.get("currentModel")) - current_tokens = from_union([from_none, from_int], obj.get("currentTokens")) + current_tokens = from_union([from_none, from_float], obj.get("currentTokens")) error_reason = from_union([from_none, from_str], obj.get("errorReason")) - system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) token_details = from_union([from_none, lambda x: from_dict(ShutdownTokenDetail.from_dict, x)], obj.get("tokenDetails")) - tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) - total_nano_aiu = from_union([from_none, from_int], obj.get("totalNanoAiu")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + total_nano_aiu = from_union([from_none, from_float], obj.get("totalNanoAiu")) return SessionShutdownData( code_changes=code_changes, model_metrics=model_metrics, @@ -3135,26 +3135,26 @@ def to_dict(self) -> dict: result: dict = {} result["codeChanges"] = to_class(ShutdownCodeChanges, self.code_changes) result["modelMetrics"] = from_dict(lambda x: to_class(ShutdownModelMetric, x), self.model_metrics) - result["sessionStartTime"] = to_int(self.session_start_time) + result["sessionStartTime"] = to_float(self.session_start_time) result["shutdownType"] = to_enum(ShutdownType, self.shutdown_type) - result["totalApiDurationMs"] = to_timedelta_int(self.total_api_duration) - result["totalPremiumRequests"] = to_int(self.total_premium_requests) + result["totalApiDurationMs"] = to_timedelta(self.total_api_duration) + result["totalPremiumRequests"] = to_float(self.total_premium_requests) if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) if self.current_model is not None: result["currentModel"] = from_union([from_none, from_str], self.current_model) if self.current_tokens is not None: - result["currentTokens"] = from_union([from_none, to_int], self.current_tokens) + result["currentTokens"] = from_union([from_none, to_float], self.current_tokens) if self.error_reason is not None: result["errorReason"] = from_union([from_none, from_str], self.error_reason) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) if self.token_details is not None: result["tokenDetails"] = from_union([from_none, lambda x: from_dict(lambda x: to_class(ShutdownTokenDetail, x), x)], self.token_details) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_none, to_int], self.total_nano_aiu) + result["totalNanoAiu"] = from_union([from_none, to_float], self.total_nano_aiu) return result @@ -3180,13 +3180,13 @@ def to_dict(self) -> dict: @dataclass class SessionSnapshotRewindData: "Session rewind details including target event and count of removed events" - events_removed: int + events_removed: float up_to_event_id: str @staticmethod def from_dict(obj: Any) -> "SessionSnapshotRewindData": assert isinstance(obj, dict) - events_removed = from_int(obj.get("eventsRemoved")) + events_removed = from_float(obj.get("eventsRemoved")) up_to_event_id = from_str(obj.get("upToEventId")) return SessionSnapshotRewindData( events_removed=events_removed, @@ -3195,7 +3195,7 @@ def from_dict(obj: Any) -> "SessionSnapshotRewindData": def to_dict(self) -> dict: result: dict = {} - result["eventsRemoved"] = to_int(self.events_removed) + result["eventsRemoved"] = to_float(self.events_removed) result["upToEventId"] = from_str(self.up_to_event_id) return result @@ -3207,7 +3207,7 @@ class SessionStartData: producer: str session_id: str start_time: datetime - version: int + version: float already_in_use: bool | None = None context: WorkingDirectoryContext | None = None detached_from_spawning_parent_session_id: str | None = None @@ -3223,7 +3223,7 @@ def from_dict(obj: Any) -> "SessionStartData": producer = from_str(obj.get("producer")) session_id = from_str(obj.get("sessionId")) start_time = from_datetime(obj.get("startTime")) - version = from_int(obj.get("version")) + version = from_float(obj.get("version")) already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) detached_from_spawning_parent_session_id = from_union([from_none, from_str], obj.get("detachedFromSpawningParentSessionId")) @@ -3252,7 +3252,7 @@ def to_dict(self) -> dict: result["producer"] = from_str(self.producer) result["sessionId"] = from_str(self.session_id) result["startTime"] = to_datetime(self.start_time) - result["version"] = to_int(self.version) + result["version"] = to_float(self.version) if self.already_in_use is not None: result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) if self.context is not None: @@ -3336,26 +3336,26 @@ def to_dict(self) -> dict: @dataclass class SessionTruncationData: "Conversation truncation statistics including token counts and removed content metrics" - messages_removed_during_truncation: int + messages_removed_during_truncation: float performed_by: str - post_truncation_messages_length: int - post_truncation_tokens_in_messages: int - pre_truncation_messages_length: int - pre_truncation_tokens_in_messages: int - token_limit: int - tokens_removed_during_truncation: int + post_truncation_messages_length: float + post_truncation_tokens_in_messages: float + pre_truncation_messages_length: float + pre_truncation_tokens_in_messages: float + token_limit: float + tokens_removed_during_truncation: float @staticmethod def from_dict(obj: Any) -> "SessionTruncationData": assert isinstance(obj, dict) - messages_removed_during_truncation = from_int(obj.get("messagesRemovedDuringTruncation")) + messages_removed_during_truncation = from_float(obj.get("messagesRemovedDuringTruncation")) performed_by = from_str(obj.get("performedBy")) - post_truncation_messages_length = from_int(obj.get("postTruncationMessagesLength")) - post_truncation_tokens_in_messages = from_int(obj.get("postTruncationTokensInMessages")) - pre_truncation_messages_length = from_int(obj.get("preTruncationMessagesLength")) - pre_truncation_tokens_in_messages = from_int(obj.get("preTruncationTokensInMessages")) - token_limit = from_int(obj.get("tokenLimit")) - tokens_removed_during_truncation = from_int(obj.get("tokensRemovedDuringTruncation")) + post_truncation_messages_length = from_float(obj.get("postTruncationMessagesLength")) + post_truncation_tokens_in_messages = from_float(obj.get("postTruncationTokensInMessages")) + pre_truncation_messages_length = from_float(obj.get("preTruncationMessagesLength")) + pre_truncation_tokens_in_messages = from_float(obj.get("preTruncationTokensInMessages")) + token_limit = from_float(obj.get("tokenLimit")) + tokens_removed_during_truncation = from_float(obj.get("tokensRemovedDuringTruncation")) return SessionTruncationData( messages_removed_during_truncation=messages_removed_during_truncation, performed_by=performed_by, @@ -3369,38 +3369,38 @@ def from_dict(obj: Any) -> "SessionTruncationData": def to_dict(self) -> dict: result: dict = {} - result["messagesRemovedDuringTruncation"] = to_int(self.messages_removed_during_truncation) + result["messagesRemovedDuringTruncation"] = to_float(self.messages_removed_during_truncation) result["performedBy"] = from_str(self.performed_by) - result["postTruncationMessagesLength"] = to_int(self.post_truncation_messages_length) - result["postTruncationTokensInMessages"] = to_int(self.post_truncation_tokens_in_messages) - result["preTruncationMessagesLength"] = to_int(self.pre_truncation_messages_length) - result["preTruncationTokensInMessages"] = to_int(self.pre_truncation_tokens_in_messages) - result["tokenLimit"] = to_int(self.token_limit) - result["tokensRemovedDuringTruncation"] = to_int(self.tokens_removed_during_truncation) + result["postTruncationMessagesLength"] = to_float(self.post_truncation_messages_length) + result["postTruncationTokensInMessages"] = to_float(self.post_truncation_tokens_in_messages) + result["preTruncationMessagesLength"] = to_float(self.pre_truncation_messages_length) + result["preTruncationTokensInMessages"] = to_float(self.pre_truncation_tokens_in_messages) + result["tokenLimit"] = to_float(self.token_limit) + result["tokensRemovedDuringTruncation"] = to_float(self.tokens_removed_during_truncation) return result @dataclass class SessionUsageInfoData: "Current context window usage statistics including token and message counts" - current_tokens: int - messages_length: int - token_limit: int - conversation_tokens: int | None = None + current_tokens: float + messages_length: float + token_limit: float + conversation_tokens: float | None = None is_initial: bool | None = None - system_tokens: int | None = None - tool_definitions_tokens: int | None = None + system_tokens: float | None = None + tool_definitions_tokens: float | None = None @staticmethod def from_dict(obj: Any) -> "SessionUsageInfoData": assert isinstance(obj, dict) - current_tokens = from_int(obj.get("currentTokens")) - messages_length = from_int(obj.get("messagesLength")) - token_limit = from_int(obj.get("tokenLimit")) - conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) + current_tokens = from_float(obj.get("currentTokens")) + messages_length = from_float(obj.get("messagesLength")) + token_limit = from_float(obj.get("tokenLimit")) + conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) is_initial = from_union([from_none, from_bool], obj.get("isInitial")) - system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) - tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) + system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) return SessionUsageInfoData( current_tokens=current_tokens, messages_length=messages_length, @@ -3413,17 +3413,17 @@ def from_dict(obj: Any) -> "SessionUsageInfoData": def to_dict(self) -> dict: result: dict = {} - result["currentTokens"] = to_int(self.current_tokens) - result["messagesLength"] = to_int(self.messages_length) - result["tokenLimit"] = to_int(self.token_limit) + result["currentTokens"] = to_float(self.current_tokens) + result["messagesLength"] = to_float(self.messages_length) + result["tokenLimit"] = to_float(self.token_limit) if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) if self.is_initial is not None: result["isInitial"] = from_union([from_none, from_bool], self.is_initial) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) return result @@ -3482,15 +3482,15 @@ def to_dict(self) -> dict: class ShutdownCodeChanges: "Aggregate code change metrics for the session" files_modified: list[str] - lines_added: int - lines_removed: int + lines_added: float + lines_removed: float @staticmethod def from_dict(obj: Any) -> "ShutdownCodeChanges": assert isinstance(obj, dict) files_modified = from_list(from_str, obj.get("filesModified")) - lines_added = from_int(obj.get("linesAdded")) - lines_removed = from_int(obj.get("linesRemoved")) + lines_added = from_float(obj.get("linesAdded")) + lines_removed = from_float(obj.get("linesRemoved")) return ShutdownCodeChanges( files_modified=files_modified, lines_added=lines_added, @@ -3500,8 +3500,8 @@ def from_dict(obj: Any) -> "ShutdownCodeChanges": def to_dict(self) -> dict: result: dict = {} result["filesModified"] = from_list(from_str, self.files_modified) - result["linesAdded"] = to_int(self.lines_added) - result["linesRemoved"] = to_int(self.lines_removed) + result["linesAdded"] = to_float(self.lines_added) + result["linesRemoved"] = to_float(self.lines_removed) return result @@ -3511,7 +3511,7 @@ class ShutdownModelMetric: requests: ShutdownModelMetricRequests usage: ShutdownModelMetricUsage token_details: dict[str, ShutdownModelMetricTokenDetail] | None = None - total_nano_aiu: int | None = None + total_nano_aiu: float | None = None @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetric": @@ -3519,7 +3519,7 @@ def from_dict(obj: Any) -> "ShutdownModelMetric": requests = ShutdownModelMetricRequests.from_dict(obj.get("requests")) usage = ShutdownModelMetricUsage.from_dict(obj.get("usage")) token_details = from_union([from_none, lambda x: from_dict(ShutdownModelMetricTokenDetail.from_dict, x)], obj.get("tokenDetails")) - total_nano_aiu = from_union([from_none, from_int], obj.get("totalNanoAiu")) + total_nano_aiu = from_union([from_none, from_float], obj.get("totalNanoAiu")) return ShutdownModelMetric( requests=requests, usage=usage, @@ -3534,7 +3534,7 @@ def to_dict(self) -> dict: if self.token_details is not None: result["tokenDetails"] = from_union([from_none, lambda x: from_dict(lambda x: to_class(ShutdownModelMetricTokenDetail, x), x)], self.token_details) if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_none, to_int], self.total_nano_aiu) + result["totalNanoAiu"] = from_union([from_none, to_float], self.total_nano_aiu) return result @@ -3542,13 +3542,13 @@ def to_dict(self) -> dict: class ShutdownModelMetricRequests: "Request count and cost metrics" cost: float - count: int + count: float @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricRequests": assert isinstance(obj, dict) cost = from_float(obj.get("cost")) - count = from_int(obj.get("count")) + count = from_float(obj.get("count")) return ShutdownModelMetricRequests( cost=cost, count=count, @@ -3557,46 +3557,46 @@ def from_dict(obj: Any) -> "ShutdownModelMetricRequests": def to_dict(self) -> dict: result: dict = {} result["cost"] = to_float(self.cost) - result["count"] = to_int(self.count) + result["count"] = to_float(self.count) return result @dataclass class ShutdownModelMetricTokenDetail: "Schema for the `ShutdownModelMetricTokenDetail` type." - token_count: int + token_count: float @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricTokenDetail": assert isinstance(obj, dict) - token_count = from_int(obj.get("tokenCount")) + token_count = from_float(obj.get("tokenCount")) return ShutdownModelMetricTokenDetail( token_count=token_count, ) def to_dict(self) -> dict: result: dict = {} - result["tokenCount"] = to_int(self.token_count) + result["tokenCount"] = to_float(self.token_count) return result @dataclass class ShutdownModelMetricUsage: "Token usage breakdown" - cache_read_tokens: int - cache_write_tokens: int - input_tokens: int - output_tokens: int - reasoning_tokens: int | None = None + cache_read_tokens: float + cache_write_tokens: float + input_tokens: float + output_tokens: float + reasoning_tokens: float | None = None @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricUsage": assert isinstance(obj, dict) - cache_read_tokens = from_int(obj.get("cacheReadTokens")) - cache_write_tokens = from_int(obj.get("cacheWriteTokens")) - input_tokens = from_int(obj.get("inputTokens")) - output_tokens = from_int(obj.get("outputTokens")) - reasoning_tokens = from_union([from_none, from_int], obj.get("reasoningTokens")) + cache_read_tokens = from_float(obj.get("cacheReadTokens")) + cache_write_tokens = from_float(obj.get("cacheWriteTokens")) + input_tokens = from_float(obj.get("inputTokens")) + output_tokens = from_float(obj.get("outputTokens")) + reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) return ShutdownModelMetricUsage( cache_read_tokens=cache_read_tokens, cache_write_tokens=cache_write_tokens, @@ -3607,31 +3607,31 @@ def from_dict(obj: Any) -> "ShutdownModelMetricUsage": def to_dict(self) -> dict: result: dict = {} - result["cacheReadTokens"] = to_int(self.cache_read_tokens) - result["cacheWriteTokens"] = to_int(self.cache_write_tokens) - result["inputTokens"] = to_int(self.input_tokens) - result["outputTokens"] = to_int(self.output_tokens) + result["cacheReadTokens"] = to_float(self.cache_read_tokens) + result["cacheWriteTokens"] = to_float(self.cache_write_tokens) + result["inputTokens"] = to_float(self.input_tokens) + result["outputTokens"] = to_float(self.output_tokens) if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_none, to_int], self.reasoning_tokens) + result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) return result @dataclass class ShutdownTokenDetail: "Schema for the `ShutdownTokenDetail` type." - token_count: int + token_count: float @staticmethod def from_dict(obj: Any) -> "ShutdownTokenDetail": assert isinstance(obj, dict) - token_count = from_int(obj.get("tokenCount")) + token_count = from_float(obj.get("tokenCount")) return ShutdownTokenDetail( token_count=token_count, ) def to_dict(self) -> dict: result: dict = {} - result["tokenCount"] = to_int(self.token_count) + result["tokenCount"] = to_float(self.token_count) return result @@ -3730,8 +3730,8 @@ class SubagentCompletedData: tool_call_id: str duration: timedelta | None = None model: str | None = None - total_tokens: int | None = None - total_tool_calls: int | None = None + total_tokens: float | None = None + total_tool_calls: float | None = None @staticmethod def from_dict(obj: Any) -> "SubagentCompletedData": @@ -3741,8 +3741,8 @@ def from_dict(obj: Any) -> "SubagentCompletedData": tool_call_id = from_str(obj.get("toolCallId")) duration = from_union([from_none, from_timedelta], obj.get("durationMs")) model = from_union([from_none, from_str], obj.get("model")) - total_tokens = from_union([from_none, from_int], obj.get("totalTokens")) - total_tool_calls = from_union([from_none, from_int], obj.get("totalToolCalls")) + total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) + total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) return SubagentCompletedData( agent_display_name=agent_display_name, agent_name=agent_name, @@ -3759,13 +3759,13 @@ def to_dict(self) -> dict: result["agentName"] = from_str(self.agent_name) result["toolCallId"] = from_str(self.tool_call_id) if self.duration is not None: - result["durationMs"] = from_union([from_none, to_timedelta_int], self.duration) + result["durationMs"] = from_union([from_none, to_timedelta], self.duration) if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.total_tokens is not None: - result["totalTokens"] = from_union([from_none, to_int], self.total_tokens) + result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) if self.total_tool_calls is not None: - result["totalToolCalls"] = from_union([from_none, to_int], self.total_tool_calls) + result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) return result @@ -3790,8 +3790,8 @@ class SubagentFailedData: tool_call_id: str duration: timedelta | None = None model: str | None = None - total_tokens: int | None = None - total_tool_calls: int | None = None + total_tokens: float | None = None + total_tool_calls: float | None = None @staticmethod def from_dict(obj: Any) -> "SubagentFailedData": @@ -3802,8 +3802,8 @@ def from_dict(obj: Any) -> "SubagentFailedData": tool_call_id = from_str(obj.get("toolCallId")) duration = from_union([from_none, from_timedelta], obj.get("durationMs")) model = from_union([from_none, from_str], obj.get("model")) - total_tokens = from_union([from_none, from_int], obj.get("totalTokens")) - total_tool_calls = from_union([from_none, from_int], obj.get("totalToolCalls")) + total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) + total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) return SubagentFailedData( agent_display_name=agent_display_name, agent_name=agent_name, @@ -3822,13 +3822,13 @@ def to_dict(self) -> dict: result["error"] = from_str(self.error) result["toolCallId"] = from_str(self.tool_call_id) if self.duration is not None: - result["durationMs"] = from_union([from_none, to_timedelta_int], self.duration) + result["durationMs"] = from_union([from_none, to_timedelta], self.duration) if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.total_tokens is not None: - result["totalTokens"] = from_union([from_none, to_int], self.total_tokens) + result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) if self.total_tool_calls is not None: - result["totalToolCalls"] = from_union([from_none, to_int], self.total_tool_calls) + result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) return result @@ -3961,7 +3961,7 @@ class SystemNotification: agent_type: str | None = None description: str | None = None entry_id: str | None = None - exit_code: int | None = None + exit_code: float | None = None prompt: str | None = None sender_name: str | None = None sender_type: str | None = None @@ -3980,7 +3980,7 @@ def from_dict(obj: Any) -> "SystemNotification": agent_type = from_union([from_none, from_str], obj.get("agentType")) description = from_union([from_none, from_str], obj.get("description")) entry_id = from_union([from_none, from_str], obj.get("entryId")) - exit_code = from_union([from_none, from_int], obj.get("exitCode")) + exit_code = from_union([from_none, from_float], obj.get("exitCode")) prompt = from_union([from_none, from_str], obj.get("prompt")) sender_name = from_union([from_none, from_str], obj.get("senderName")) sender_type = from_union([from_none, from_str], obj.get("senderType")) @@ -4020,7 +4020,7 @@ def to_dict(self) -> dict: if self.entry_id is not None: result["entryId"] = from_union([from_none, from_str], self.entry_id) if self.exit_code is not None: - result["exitCode"] = from_union([from_none, to_int], self.exit_code) + result["exitCode"] = from_union([from_none, to_float], self.exit_code) if self.prompt is not None: result["prompt"] = from_union([from_none, from_str], self.prompt) if self.sender_name is not None: @@ -4072,12 +4072,12 @@ class ToolExecutionCompleteContent: cwd: str | None = None data: str | None = None description: str | None = None - exit_code: int | None = None + exit_code: float | None = None icons: list[ToolExecutionCompleteContentResourceLinkIcon] | None = None mime_type: str | None = None name: str | None = None resource: ToolExecutionCompleteContentResourceDetails | None = None - size: int | None = None + size: float | None = None text: str | None = None title: str | None = None uri: str | None = None @@ -4089,12 +4089,12 @@ def from_dict(obj: Any) -> "ToolExecutionCompleteContent": cwd = from_union([from_none, from_str], obj.get("cwd")) data = from_union([from_none, from_str], obj.get("data")) description = from_union([from_none, from_str], obj.get("description")) - exit_code = from_union([from_none, from_int], obj.get("exitCode")) + exit_code = from_union([from_none, from_float], obj.get("exitCode")) icons = from_union([from_none, lambda x: from_list(ToolExecutionCompleteContentResourceLinkIcon.from_dict, x)], obj.get("icons")) mime_type = from_union([from_none, from_str], obj.get("mimeType")) name = from_union([from_none, from_str], obj.get("name")) resource = from_union([from_none, lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x)], obj.get("resource")) - size = from_union([from_none, from_int], obj.get("size")) + size = from_union([from_none, from_float], obj.get("size")) text = from_union([from_none, from_str], obj.get("text")) title = from_union([from_none, from_str], obj.get("title")) uri = from_union([from_none, from_str], obj.get("uri")) @@ -4124,7 +4124,7 @@ def to_dict(self) -> dict: if self.description is not None: result["description"] = from_union([from_none, from_str], self.description) if self.exit_code is not None: - result["exitCode"] = from_union([from_none, to_int], self.exit_code) + result["exitCode"] = from_union([from_none, to_float], self.exit_code) if self.icons is not None: result["icons"] = from_union([from_none, lambda x: from_list(lambda x: to_class(ToolExecutionCompleteContentResourceLinkIcon, x), x)], self.icons) if self.mime_type is not None: @@ -4134,7 +4134,7 @@ def to_dict(self) -> dict: if self.resource is not None: result["resource"] = from_union([from_none, lambda x: from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], x)], self.resource) if self.size is not None: - result["size"] = from_union([from_none, to_int], self.size) + result["size"] = from_union([from_none, to_float], self.size) if self.text is not None: result["text"] = from_union([from_none, from_str], self.text) if self.title is not None: @@ -4494,7 +4494,7 @@ class UserMessageAttachment: file_path: str | None = None line_range: UserMessageAttachmentFileLineRange | None = None mime_type: str | None = None - number: int | None = None + number: float | None = None path: str | None = None reference_type: UserMessageAttachmentGithubReferenceType | None = None selection: UserMessageAttachmentSelectionDetails | None = None @@ -4512,7 +4512,7 @@ def from_dict(obj: Any) -> "UserMessageAttachment": file_path = from_union([from_none, from_str], obj.get("filePath")) line_range = from_union([from_none, UserMessageAttachmentFileLineRange.from_dict], obj.get("lineRange")) mime_type = from_union([from_none, from_str], obj.get("mimeType")) - number = from_union([from_none, from_int], obj.get("number")) + number = from_union([from_none, from_float], obj.get("number")) path = from_union([from_none, from_str], obj.get("path")) reference_type = from_union([from_none, lambda x: parse_enum(UserMessageAttachmentGithubReferenceType, x)], obj.get("referenceType")) selection = from_union([from_none, UserMessageAttachmentSelectionDetails.from_dict], obj.get("selection")) @@ -4551,7 +4551,7 @@ def to_dict(self) -> dict: if self.mime_type is not None: result["mimeType"] = from_union([from_none, from_str], self.mime_type) if self.number is not None: - result["number"] = from_union([from_none, to_int], self.number) + result["number"] = from_union([from_none, to_float], self.number) if self.path is not None: result["path"] = from_union([from_none, from_str], self.path) if self.reference_type is not None: @@ -4572,14 +4572,14 @@ def to_dict(self) -> dict: @dataclass class UserMessageAttachmentFileLineRange: "Optional line range to scope the attachment to a specific section of the file" - end: int - start: int + end: float + start: float @staticmethod def from_dict(obj: Any) -> "UserMessageAttachmentFileLineRange": assert isinstance(obj, dict) - end = from_int(obj.get("end")) - start = from_int(obj.get("start")) + end = from_float(obj.get("end")) + start = from_float(obj.get("start")) return UserMessageAttachmentFileLineRange( end=end, start=start, @@ -4587,8 +4587,8 @@ def from_dict(obj: Any) -> "UserMessageAttachmentFileLineRange": def to_dict(self) -> dict: result: dict = {} - result["end"] = to_int(self.end) - result["start"] = to_int(self.start) + result["end"] = to_float(self.end) + result["start"] = to_float(self.start) return result @@ -4618,14 +4618,14 @@ def to_dict(self) -> dict: @dataclass class UserMessageAttachmentSelectionDetailsEnd: "End position of the selection" - character: int - line: int + character: float + line: float @staticmethod def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsEnd": assert isinstance(obj, dict) - character = from_int(obj.get("character")) - line = from_int(obj.get("line")) + character = from_float(obj.get("character")) + line = from_float(obj.get("line")) return UserMessageAttachmentSelectionDetailsEnd( character=character, line=line, @@ -4633,22 +4633,22 @@ def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsEnd": def to_dict(self) -> dict: result: dict = {} - result["character"] = to_int(self.character) - result["line"] = to_int(self.line) + result["character"] = to_float(self.character) + result["line"] = to_float(self.line) return result @dataclass class UserMessageAttachmentSelectionDetailsStart: "Start position of the selection" - character: int - line: int + character: float + line: float @staticmethod def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsStart": assert isinstance(obj, dict) - character = from_int(obj.get("character")) - line = from_int(obj.get("line")) + character = from_float(obj.get("character")) + line = from_float(obj.get("line")) return UserMessageAttachmentSelectionDetailsStart( character=character, line=line, @@ -4656,8 +4656,8 @@ def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsStart": def to_dict(self) -> dict: result: dict = {} - result["character"] = to_int(self.character) - result["line"] = to_int(self.line) + result["character"] = to_float(self.character) + result["line"] = to_float(self.line) return result diff --git a/python/copilot/session.py b/python/copilot/session.py index 4789724fb..e1b27cfe1 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -1116,7 +1116,11 @@ class CopilotSession: """ def __init__( - self, session_id: str, client: Any, workspace_path: os.PathLike[str] | str | None = None + self, + session_id: str, + client: Any, + workspace_path: os.PathLike[str] | str | None = None, + on_disconnected: Callable[[CopilotSession], None] | None = None, ): """ Initialize a new CopilotSession. @@ -1158,12 +1162,16 @@ def __init__( self._client_session_apis = ClientSessionApiHandlers() self._rpc: SessionRpc | None = None self._destroyed = False + self._disconnect_task: asyncio.Task[None] | None = None + self._disconnect_lock = threading.Lock() + self._on_disconnected = on_disconnected @property def rpc(self) -> SessionRpc: """Typed session-scoped RPC methods.""" + self._assert_not_destroyed() if self._rpc is None: - self._rpc = SessionRpc(self._client, self.session_id) + self._rpc = SessionRpc(self._client, self.session_id, self._assert_not_destroyed) return self._rpc @property @@ -1186,6 +1194,7 @@ def ui(self) -> SessionUiApi: >>> if ui_caps.get("elicitation"): ... ok = await session.ui.confirm("Deploy to production?") """ + self._assert_not_destroyed() return SessionUiApi(self) @functools.cached_property @@ -1235,6 +1244,7 @@ async def send( ... attachments=[{"type": "file", "path": "./src/main.py"}], ... ) """ + self._assert_not_destroyed() params: dict[str, Any] = { "sessionId": self.session_id, "prompt": prompt, @@ -1301,6 +1311,7 @@ async def send_and_wait( ... case AssistantMessageData() as data: ... print(data.content) """ + self._assert_not_destroyed() total_start = time.perf_counter() idle_event = asyncio.Event() error_event: Exception | None = None @@ -1403,6 +1414,7 @@ def on(self, handler: Callable[[SessionEvent], None]) -> Callable[[], None]: >>> # Later, to stop receiving events: >>> unsubscribe() """ + self._assert_not_destroyed() with self._event_handlers_lock: self._event_handlers.add(handler) @@ -1838,6 +1850,7 @@ async def _handle_elicitation_request( def _assert_elicitation(self) -> None: """Raises if the host does not support elicitation.""" + self._assert_not_destroyed() ui_caps = self._capabilities.get("ui", {}) if not ui_caps.get("elicitation"): raise RuntimeError( @@ -2235,6 +2248,7 @@ async def get_messages(self) -> list[SessionEvent]: ... case AssistantMessageData() as data: ... print(f"Assistant: {data.content}") """ + self._assert_not_destroyed() response = await self._client.request("session.getMessages", {"sessionId": self.session_id}) # Convert dict events to SessionEvent objects events_dicts = response["events"] @@ -2263,31 +2277,54 @@ async def disconnect(self) -> None: >>> # Clean up when done — session can still be resumed later >>> await session.disconnect() """ - # Ensure that the check and update of _destroyed are atomic so that - # only the first caller proceeds to send the destroy RPC. - with self._event_handlers_lock: + with self._disconnect_lock: if self._destroyed: return - self._destroyed = True + if self._disconnect_task is None: + self._disconnect_task = asyncio.create_task(self._disconnect_core()) + disconnect_task = self._disconnect_task + await asyncio.shield(disconnect_task) + + async def _disconnect_core(self) -> None: try: await self._client.request("session.destroy", {"sessionId": self.session_id}) finally: - # Clear handlers even if the request fails. - with self._event_handlers_lock: - self._event_handlers.clear() - with self._tool_handlers_lock: - self._tool_handlers.clear() - with self._permission_handler_lock: - self._permission_handler = None - with self._command_handlers_lock: - self._command_handlers.clear() - with self._elicitation_handler_lock: - self._elicitation_handler = None - with self._exit_plan_mode_handler_lock: - self._exit_plan_mode_handler = None - with self._auto_mode_switch_handler_lock: - self._auto_mode_switch_handler = None + self._mark_disconnected() + + def _assert_not_destroyed(self) -> None: + if self._destroyed: + raise RuntimeError("Session has been disconnected.") + + def _mark_disconnected(self) -> None: + with self._disconnect_lock: + if self._destroyed: + return + self._destroyed = True + + self._rpc = None + with self._event_handlers_lock: + self._event_handlers.clear() + with self._tool_handlers_lock: + self._tool_handlers.clear() + with self._permission_handler_lock: + self._permission_handler = None + with self._user_input_handler_lock: + self._user_input_handler = None + with self._command_handlers_lock: + self._command_handlers.clear() + with self._elicitation_handler_lock: + self._elicitation_handler = None + with self._exit_plan_mode_handler_lock: + self._exit_plan_mode_handler = None + with self._auto_mode_switch_handler_lock: + self._auto_mode_switch_handler = None + with self._hooks_lock: + self._hooks = None + with self._transform_callbacks_lock: + self._transform_callbacks = None + if self._on_disconnected is not None: + self._on_disconnected(self) async def destroy(self) -> None: """ @@ -2346,6 +2383,7 @@ async def abort(self) -> None: >>> await asyncio.sleep(5) >>> await session.abort() """ + self._assert_not_destroyed() await self._client.request("session.abort", {"sessionId": self.session_id}) async def set_model( @@ -2374,6 +2412,7 @@ async def set_model( >>> await session.set_model("gpt-4.1") >>> await session.set_model("claude-sonnet-4.6", reasoning_effort="high") """ + self._assert_not_destroyed() rpc_caps = None if model_capabilities is not None: from .client import _capabilities_to_dict @@ -2416,6 +2455,7 @@ async def log( >>> await session.log("Operation failed", level="error") >>> await session.log("Temporary status update", ephemeral=True) """ + self._assert_not_destroyed() params = LogRequest( message=message, level=SessionLogLevel(level) if level is not None else None, diff --git a/python/test_client.py b/python/test_client.py index c03968c55..0a6830974 100644 --- a/python/test_client.py +++ b/python/test_client.py @@ -19,7 +19,7 @@ ModelSupports, SubprocessConfig, ) -from copilot.session import PermissionHandler, PermissionRequestResult +from copilot.session import CopilotSession, PermissionHandler, PermissionRequestResult from e2e.testharness import CLI_PATH @@ -72,6 +72,7 @@ async def test_resume_session_allows_none_permission_handler(self): session = await client.create_session( on_permission_request=PermissionHandler.approve_all ) + session._mark_disconnected() resumed = await client.resume_session(session.session_id, on_permission_request=None) assert resumed.session_id == session.session_id finally: @@ -115,6 +116,204 @@ async def mock_request(method, params): await client.force_stop() +class TestSessionLifecycle: + @pytest.mark.asyncio + async def test_direct_disconnect_unregisters_after_destroy_request(self): + sessions = {} + + async def request(method, params): + if method == "session.destroy": + assert sessions["session-1"] is session + return {} + + rpc_client = AsyncMock() + rpc_client.request = AsyncMock(side_effect=request) + + def unregister(candidate): + if sessions.get(candidate.session_id) is candidate: + del sessions[candidate.session_id] + + session = CopilotSession( + "session-1", + rpc_client, + on_disconnected=unregister, + ) + sessions[session.session_id] = session + + await session.disconnect() + + rpc_client.request.assert_awaited_with("session.destroy", {"sessionId": "session-1"}) + assert "session-1" not in sessions + with pytest.raises(RuntimeError, match="disconnected"): + await session.send("hello") + + def test_stale_session_disconnect_does_not_unregister_replacement(self): + sessions = {} + + def unregister(candidate): + if sessions.get(candidate.session_id) is candidate: + del sessions[candidate.session_id] + + rpc_client = AsyncMock() + stale = CopilotSession("session-1", rpc_client, on_disconnected=unregister) + replacement = CopilotSession("session-1", rpc_client, on_disconnected=unregister) + sessions["session-1"] = replacement + + stale._mark_disconnected() + + assert sessions["session-1"] is replacement + replacement._mark_disconnected() + + def test_rejects_duplicate_active_session_registration(self): + client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH, log_level="error")) + rpc_client = AsyncMock() + first = CopilotSession("session-1", rpc_client) + second = CopilotSession("session-1", rpc_client) + + client._register_session(first) + + with pytest.raises(RuntimeError, match="already active"): + client._register_session(second) + + first._mark_disconnected() + + @pytest.mark.asyncio + async def test_failed_create_session_fs_setup_marks_session_disconnected(self): + client = CopilotClient( + SubprocessConfig( + cli_path=CLI_PATH, + log_level="error", + session_fs={ + "initial_cwd": "/", + "session_state_path": "/session-state", + "conventions": "posix", + }, + ) + ) + rpc_client = AsyncMock() + rpc_client.request = AsyncMock() + client._client = rpc_client + captured = {} + + def failing_handler(session): + captured["session"] = session + raise RuntimeError("boom") + + with pytest.raises(RuntimeError, match="boom"): + await client.create_session(create_session_fs_handler=failing_handler) + + session = captured["session"] + assert session.session_id not in client._sessions + with pytest.raises(RuntimeError, match="disconnected"): + await session.send("hello") + rpc_client.request.assert_not_called() + + @pytest.mark.asyncio + async def test_failed_resume_session_fs_setup_marks_session_disconnected(self): + client = CopilotClient( + SubprocessConfig( + cli_path=CLI_PATH, + log_level="error", + session_fs={ + "initial_cwd": "/", + "session_state_path": "/session-state", + "conventions": "posix", + }, + ) + ) + rpc_client = AsyncMock() + rpc_client.request = AsyncMock() + client._client = rpc_client + captured = {} + + def failing_handler(session): + captured["session"] = session + raise RuntimeError("boom") + + with pytest.raises(RuntimeError, match="boom"): + await client.resume_session( + "session-1", create_session_fs_handler=failing_handler + ) + + session = captured["session"] + assert session.session_id not in client._sessions + with pytest.raises(RuntimeError, match="disconnected"): + await session.send("hello") + rpc_client.request.assert_not_called() + + @pytest.mark.asyncio + async def test_duplicate_create_marks_captured_session_disconnected(self): + client = CopilotClient( + SubprocessConfig( + cli_path=CLI_PATH, + log_level="error", + session_fs={ + "initial_cwd": "/", + "session_state_path": "/session-state", + "conventions": "posix", + }, + ) + ) + rpc_client = AsyncMock() + rpc_client.request = AsyncMock() + client._client = rpc_client + existing = CopilotSession("session-1", rpc_client) + client._register_session(existing) + captured = {} + + def create_provider(session): + captured["session"] = session + return object() + + with pytest.raises(RuntimeError, match="already active"): + await client.create_session( + session_id="session-1", create_session_fs_handler=create_provider + ) + + session = captured["session"] + assert client._sessions["session-1"] is existing + with pytest.raises(RuntimeError, match="disconnected"): + await session.send("hello") + rpc_client.request.assert_not_called() + existing._mark_disconnected() + + @pytest.mark.asyncio + async def test_duplicate_resume_marks_captured_session_disconnected(self): + client = CopilotClient( + SubprocessConfig( + cli_path=CLI_PATH, + log_level="error", + session_fs={ + "initial_cwd": "/", + "session_state_path": "/session-state", + "conventions": "posix", + }, + ) + ) + rpc_client = AsyncMock() + rpc_client.request = AsyncMock() + client._client = rpc_client + existing = CopilotSession("session-1", rpc_client) + client._register_session(existing) + captured = {} + + def create_provider(session): + captured["session"] = session + return object() + + with pytest.raises(RuntimeError, match="already active"): + await client.resume_session( + "session-1", create_session_fs_handler=create_provider + ) + + session = captured["session"] + assert client._sessions["session-1"] is existing + with pytest.raises(RuntimeError, match="disconnected"): + await session.send("hello") + rpc_client.request.assert_not_called() + existing._mark_disconnected() + + class TestURLParsing: def test_parse_port_only_url(self): client = CopilotClient(ExternalServerConfig(url="8080")) @@ -338,6 +537,7 @@ async def mock_request(method, params): def grep(params) -> str: return "ok" + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -573,6 +773,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -624,6 +825,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -691,6 +893,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -789,6 +992,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -864,6 +1068,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -894,6 +1099,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -923,6 +1129,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -952,6 +1159,7 @@ async def mock_request(method, params): return await original_request(method, params) client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, diff --git a/python/test_rpc_generated.py b/python/test_rpc_generated.py index 5f484add0..b4425bab7 100644 --- a/python/test_rpc_generated.py +++ b/python/test_rpc_generated.py @@ -22,3 +22,29 @@ async def test_commands_invoke_deserializes_slash_command_result(): assert result.kind is SlashCommandInvocationResultKind.TEXT assert result.text == "hello" assert result.markdown is True + + +@pytest.mark.asyncio +async def test_generated_rpc_rejects_missing_required_params(): + client = AsyncMock() + api = CommandsApi(client, "sess-1") + + with pytest.raises(TypeError, match="params is required"): + await api.invoke(None) # type: ignore[arg-type] + + client.request.assert_not_called() + + +@pytest.mark.asyncio +async def test_generated_session_rpc_checks_active_callback_before_request(): + client = AsyncMock() + api = CommandsApi( + client, + "sess-1", + lambda: (_ for _ in ()).throw(RuntimeError("session inactive")), + ) + + with pytest.raises(RuntimeError, match="session inactive"): + await api.invoke(CommandsInvokeRequest(name="help")) + + client.request.assert_not_called() diff --git a/scripts/codegen/go.ts b/scripts/codegen/go.ts index 03a8da8e8..8f4266eff 100644 --- a/scripts/codegen/go.ts +++ b/scripts/codegen/go.ts @@ -3720,7 +3720,10 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio // Emit the common service struct (unexported, shared by all API groups via type cast) lines.push(`type ${serviceName} struct {`); lines.push(`\tclient *jsonrpc2.Client`); - if (isSession) lines.push(`\tsessionID string`); + if (isSession) { + lines.push(`\tsessionID string`); + lines.push(`\tassertActive func() error`); + } lines.push(`}`); lines.push(``); @@ -3764,11 +3767,15 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio } // Constructor - const ctorParams = isSession ? "client *jsonrpc2.Client, sessionID string" : "client *jsonrpc2.Client"; + const ctorParams = isSession ? "client *jsonrpc2.Client, sessionID string, assertActive ...func() error" : "client *jsonrpc2.Client"; lines.push(`func New${wrapperName}(${ctorParams}) *${wrapperName} {`); lines.push(`\tr := &${wrapperName}{}`); if (isSession) { - lines.push(`\tr.common = ${serviceName}{client: client, sessionID: sessionID}`); + lines.push(`\tvar assertActiveFn func() error`); + lines.push(`\tif len(assertActive) > 0 {`); + lines.push(`\t\tassertActiveFn = assertActive[0]`); + lines.push(`\t}`); + lines.push(`\tr.common = ${serviceName}{client: client, sessionID: sessionID, assertActive: assertActiveFn}`); } else { lines.push(`\tr.common = ${serviceName}{client: client}`); } @@ -3805,6 +3812,7 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc // For wrapper-level methods, access fields through a.common; for service type aliases, use a directly const clientRef = isWrapper ? "a.common.client" : "a.client"; const sessionIDRef = isWrapper ? "a.common.sessionID" : "a.sessionID"; + const assertActiveRef = isWrapper ? "a.common.assertActive" : "a.assertActive"; pushGoRpcMethodComment( lines, @@ -3834,6 +3842,18 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc lines.push(`\t\trequestParams = params[0]`); lines.push(`\t}`); } + if (isSession) { + lines.push(`\tif ${assertActiveRef} != nil {`); + lines.push(`\t\tif err := ${assertActiveRef}(); err != nil {`); + lines.push(`\t\t\treturn nil, err`); + lines.push(`\t\t}`); + lines.push(`\t}`); + } + if (hasParams && !paramsAreOptional && hasRequiredNonSessionParams) { + lines.push(`\tif ${paramsRef} == nil {`); + lines.push(`\t\treturn nil, errors.New("params is required")`); + lines.push(`\t}`); + } if (isSession) { lines.push(`\treq := map[string]any{"sessionId": ${sessionIDRef}}`); diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index 52b11ed59..841348f75 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -2514,12 +2514,13 @@ function emitPyApiGroup( } lines.push(`class ${apiName}:`); if (isSession) { - lines.push(` def __init__(self, client: "JsonRpcClient", session_id: str):`); + lines.push(` def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None):`); lines.push(` self._client = client`); lines.push(` self._session_id = session_id`); + lines.push(` self._assert_active = assert_active`); for (const [subGroupName] of subGroups) { const subApiName = apiName.replace(/Api$/, "") + toPascalCase(subGroupName) + "Api"; - lines.push(` self.${toSnakeCase(subGroupName)} = ${subApiName}(client, session_id)`); + lines.push(` self.${toSnakeCase(subGroupName)} = ${subApiName}(client, session_id, assert_active)`); } } else { lines.push(` def __init__(self, client: "JsonRpcClient"):`); @@ -2559,11 +2560,12 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio lines.push(classPrefix === "_Internal" ? ` """Internal SDK session-scoped RPC methods. Not part of the public API."""` : ` """Typed session-scoped RPC methods."""`); - lines.push(` def __init__(self, client: "JsonRpcClient", session_id: str):`); + lines.push(` def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None):`); lines.push(` self._client = client`); lines.push(` self._session_id = session_id`); + lines.push(` self._assert_active = assert_active`); for (const [groupName] of groups) { - lines.push(` self.${toSnakeCase(groupName)} = ${classPrefix}${toPascalCase(groupName)}Api(client, session_id)`); + lines.push(` self.${toSnakeCase(groupName)} = ${classPrefix}${toPascalCase(groupName)}Api(client, session_id, assert_active)`); } } else { lines.push(`class ${wrapperName}:`); @@ -2630,6 +2632,18 @@ function emitMethod(lines: string[], name: string, method: RpcMethod, isSession: internal: method.visibility === "internal", }); + if (isSession) { + lines.push(` if self._assert_active is not None:`); + lines.push(` self._assert_active()`); + } + if (hasParams && !paramsOptional) { + lines.push(` if params is None:`); + lines.push(` raise TypeError("params is required")`); + } + if (isSession || (hasParams && !paramsOptional)) { + lines.push(``); + } + // Deserialize helper const innerTypeName = hasNullableResult ? resolveType(pythonResultTypeName(method, nullableInner)) : resultType; const deserialize = (expr: string) => { diff --git a/scripts/codegen/typescript.ts b/scripts/codegen/typescript.ts index 3afaec395..0cbbe69d6 100644 --- a/scripts/codegen/typescript.ts +++ b/scripts/codegen/typescript.ts @@ -656,7 +656,7 @@ function hasInternalMethods(node: Record): boolean { if (schema.session) { lines.push(`/** Create typed session-scoped RPC methods. */`); - lines.push(`export function createSessionRpc(connection: MessageConnection, sessionId: string) {`); + lines.push(`export function createSessionRpc(connection: MessageConnection, sessionId: string, assertActive?: () => void) {`); lines.push(` return {`); lines.push(...emitGroup(schema.session, " ", true, false, false, "public")); lines.push(` };`); @@ -669,7 +669,7 @@ function hasInternalMethods(node: Record): boolean { lines.push(` * surface. Not exported on the public client API.`); lines.push(` * @internal`); lines.push(` */`); - lines.push(`export function createInternalSessionRpc(connection: MessageConnection, sessionId: string) {`); + lines.push(`export function createInternalSessionRpc(connection: MessageConnection, sessionId: string, assertActive?: () => void) {`); lines.push(` return {`); lines.push(...emitGroup(schema.session, " ", true, false, false, "internal")); lines.push(` };`); @@ -711,13 +711,14 @@ function emitGroup( : []; const hasParams = hasSchemaPayload(effectiveParams); const hasNonSessionParams = paramEntries.length > 0; + const paramsOptional = isParamsOptional(value); const sigParams: string[] = []; let bodyArg: string; if (isSession) { if (hasNonSessionParams) { - const optMark = isParamsOptional(value) ? "?" : ""; + const optMark = paramsOptional ? "?" : ""; // sessionId is already stripped from the generated type definition, // so no need for Omit<..., "sessionId"> sigParams.push(`params${optMark}: ${paramsType}`); @@ -727,7 +728,7 @@ function emitGroup( } } else { if (hasParams) { - const optMark = isParamsOptional(value) ? "?" : ""; + const optMark = paramsOptional ? "?" : ""; sigParams.push(`params${optMark}: ${paramsType}`); bodyArg = "params"; } else { @@ -741,8 +742,17 @@ function emitGroup( includeDeprecated: (value as RpcMethod).deprecated && !parentDeprecated, includeExperimental: (value as RpcMethod).stability === "experimental" && !parentExperimental, }); - lines.push(`${indent}${key}: async (${sigParams.join(", ")}): Promise<${resultType}> =>`); - lines.push(`${indent} connection.sendRequest("${rpcMethod}", ${bodyArg}),`); + lines.push(`${indent}${key}: async (${sigParams.join(", ")}): Promise<${resultType}> => {`); + if (isSession) { + lines.push(`${indent} assertActive?.();`); + } + if (sigParams.length > 0 && !paramsOptional) { + lines.push(`${indent} if (params == null) {`); + lines.push(`${indent} throw new TypeError("params is required");`); + lines.push(`${indent} }`); + } + lines.push(`${indent} return connection.sendRequest("${rpcMethod}", ${bodyArg});`); + lines.push(`${indent}},`); } else if (typeof value === "object" && value !== null) { const groupExperimental = isNodeFullyExperimental(value as Record); const groupDeprecated = isNodeFullyDeprecated(value as Record); From 30147cc5e903dc838e7f43330e2fa5212048b9fe Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 23:09:45 -0400 Subject: [PATCH 2/6] Format Python lifecycle tests Apply ruff formatting to the new Python lifecycle regression tests so CI format checks pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- python/test_client.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/python/test_client.py b/python/test_client.py index 0a6830974..e42dbf02f 100644 --- a/python/test_client.py +++ b/python/test_client.py @@ -231,9 +231,7 @@ def failing_handler(session): raise RuntimeError("boom") with pytest.raises(RuntimeError, match="boom"): - await client.resume_session( - "session-1", create_session_fs_handler=failing_handler - ) + await client.resume_session("session-1", create_session_fs_handler=failing_handler) session = captured["session"] assert session.session_id not in client._sessions @@ -302,9 +300,7 @@ def create_provider(session): return object() with pytest.raises(RuntimeError, match="already active"): - await client.resume_session( - "session-1", create_session_fs_handler=create_provider - ) + await client.resume_session("session-1", create_session_fs_handler=create_provider) session = captured["session"] assert client._sessions["session-1"] is existing From ce8aa9eecbd76b5ccf953429224fdfa302b440da Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 09:25:11 -0400 Subject: [PATCH 3/6] Fix merge blockers after rebase Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- go/internal/e2e/permissions_e2e_test.go | 2 +- go/session.go | 24 ++++--- nodejs/src/generated/rpc.ts | 73 ++++++--------------- nodejs/src/session.ts | 18 ++++++ nodejs/test/client.test.ts | 16 +++++ nodejs/test/e2e/commands.e2e.test.ts | 1 + nodejs/test/e2e/mcp_and_agents.e2e.test.ts | 3 + nodejs/test/e2e/permissions.e2e.test.ts | 2 + nodejs/test/e2e/session.e2e.test.ts | 6 +- nodejs/test/e2e/session_config.e2e.test.ts | 5 ++ nodejs/test/e2e/skills.e2e.test.ts | 1 + python/copilot/generated/rpc.py | 75 +++++++--------------- python/copilot/session.py | 2 + python/test_rpc_generated.py | 14 ++++ scripts/codegen/python.ts | 4 +- scripts/codegen/typescript.ts | 6 +- 16 files changed, 131 insertions(+), 121 deletions(-) diff --git a/go/internal/e2e/permissions_e2e_test.go b/go/internal/e2e/permissions_e2e_test.go index d77e206e9..c2644c807 100644 --- a/go/internal/e2e/permissions_e2e_test.go +++ b/go/internal/e2e/permissions_e2e_test.go @@ -228,7 +228,7 @@ func TestPermissionsE2E(t *testing.T) { } }) - t.Run("should accept explicit deny handler when joining an active session", func(t *testing.T) { + t.Run("should accept user-not-available handler when joining an active session", func(t *testing.T) { ctx.ConfigureForTest(t) session1, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ diff --git a/go/session.go b/go/session.go index 682fc55f5..626929632 100644 --- a/go/session.go +++ b/go/session.go @@ -82,7 +82,8 @@ type Session struct { // eventCh serializes user event handler dispatch. dispatchEvent enqueues; // a single goroutine (processEvents) dequeues and invokes handlers in FIFO order. eventCh chan SessionEvent - closeOnce sync.Once // guards eventCh close so Disconnect is safe to call more than once + eventMu sync.RWMutex // coordinates sends with closing eventCh + closeOnce sync.Once // guards eventCh close so Disconnect is safe to call more than once stateMu sync.Mutex closed bool closing chan struct{} @@ -948,14 +949,17 @@ func fromRPCContent(value rpc.UIElicitationFieldValue) any { func (s *Session) dispatchEvent(event SessionEvent) { go s.handleBroadcastEvent(event) - // Send to the event channel in a closure with a recover guard. - // Disconnect closes eventCh, and in Go sending on a closed channel - // panics — there is no non-panicking send primitive. We only want - // to suppress that specific panic; other panics are not expected here. - func() { - defer func() { recover() }() - s.eventCh <- event - }() + s.eventMu.RLock() + defer s.eventMu.RUnlock() + + s.stateMu.Lock() + closed := s.closed + s.stateMu.Unlock() + if closed { + return + } + + s.eventCh <- event } // processEvents is the single consumer goroutine for the event channel. @@ -1273,7 +1277,9 @@ func (s *Session) markDisconnected() { s.closed = true s.stateMu.Unlock() + s.eventMu.Lock() s.closeOnce.Do(func() { close(s.eventCh) }) + s.eventMu.Unlock() s.handlerMutex.Lock() s.handlers = nil diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 32bda8a35..9ffac5da5 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -4219,11 +4219,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Server liveness response, including the echoed message, current timestamp, and protocol version. */ - ping: async (params: PingRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("ping", params); + ping: async (params?: PingRequest): Promise => { + return connection.sendRequest("ping", (params ?? {})); }, models: { /** @@ -4233,11 +4230,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns List of Copilot models available to the resolved user, including capabilities and billing metadata. */ - list: async (params: ModelsListRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("models.list", params); + list: async (params?: ModelsListRequest): Promise => { + return connection.sendRequest("models.list", (params ?? {})); }, }, tools: { @@ -4248,11 +4242,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Built-in tools available for the requested model, with their parameters and instructions. */ - list: async (params: ToolsListRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("tools.list", params); + list: async (params?: ToolsListRequest): Promise => { + return connection.sendRequest("tools.list", (params ?? {})); }, }, account: { @@ -4263,11 +4254,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Quota usage snapshots for the resolved user, keyed by quota type. */ - getQuota: async (params: AccountGetQuotaRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("account.getQuota", params); + getQuota: async (params?: AccountGetQuotaRequest): Promise => { + return connection.sendRequest("account.getQuota", (params ?? {})); }, }, mcp: { @@ -4343,11 +4331,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns MCP servers discovered from user, workspace, plugin, and built-in sources. */ - discover: async (params: McpDiscoverRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("mcp.discover", params); + discover: async (params?: McpDiscoverRequest): Promise => { + return connection.sendRequest("mcp.discover", (params ?? {})); }, }, skills: { @@ -4371,11 +4356,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Skills discovered across global and project sources. */ - discover: async (params: SkillsDiscoverRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("skills.discover", params); + discover: async (params?: SkillsDiscoverRequest): Promise => { + return connection.sendRequest("skills.discover", (params ?? {})); }, }, sessionFs: { @@ -4402,11 +4384,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Identifier and optional friendly name assigned to the newly forked session. */ - fork: async (params: SessionsForkRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("sessions.fork", params); + fork: async (params?: SessionsForkRequest): Promise => { + return connection.sendRequest("sessions.fork", (params ?? {})); }, /** * Connects to an existing remote session and exposes it as an SDK session. @@ -4415,11 +4394,8 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Remote session connection result. */ - connect: async (params: ConnectRemoteSessionParams): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("sessions.connect", params); + connect: async (params?: ConnectRemoteSessionParams): Promise => { + return connection.sendRequest("sessions.connect", (params ?? {})); }, }, }; @@ -4439,11 +4415,8 @@ export function createInternalServerRpc(connection: MessageConnection) { * * @returns Handshake result reporting the server's protocol version and package version on success. */ - connect: async (params: ConnectRequest): Promise => { - if (params == null) { - throw new TypeError("params is required"); - } - return connection.sendRequest("connect", params); + connect: async (params?: ConnectRequest): Promise => { + return connection.sendRequest("connect", (params ?? {})); }, }; } @@ -4636,11 +4609,8 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Indicates whether fleet mode was successfully activated. */ - start: async (params: FleetStartRequest): Promise => { + start: async (params?: FleetStartRequest): Promise => { assertActive?.(); - if (params == null) { - throw new TypeError("params is required"); - } return connection.sendRequest("session.fleet.start", { sessionId, ...params }); }, }, @@ -5168,11 +5138,8 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns GitHub URL for the session and a flag indicating whether remote steering is enabled. */ - enable: async (params: RemoteEnableRequest): Promise => { + enable: async (params?: RemoteEnableRequest): Promise => { assertActive?.(); - if (params == null) { - throw new TypeError("params is required"); - } return connection.sendRequest("session.remote.enable", { sessionId, ...params }); }, /** diff --git a/nodejs/src/session.ts b/nodejs/src/session.ts index 0a5f714d2..2bcb6c4a2 100644 --- a/nodejs/src/session.ts +++ b/nodejs/src/session.ts @@ -502,8 +502,14 @@ export class CopilotSession { } else { result = JSON.stringify(rawResult); } + if (this.disconnected) { + return; + } await this.rpc.tools.handlePendingToolCall({ requestId, result }); } catch (error) { + if (this.disconnected) { + return; + } const message = error instanceof Error ? error.message : String(error); try { await this.rpc.tools.handlePendingToolCall({ requestId, error: message }); @@ -531,8 +537,14 @@ export class CopilotSession { if (result.kind === "no-result") { return; } + if (this.disconnected) { + return; + } await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result }); } catch (_error) { + if (this.disconnected) { + return; + } try { await this.rpc.permissions.handlePendingPermissionRequest({ requestId, @@ -576,8 +588,14 @@ export class CopilotSession { try { await handler({ sessionId: this.sessionId, command, commandName, args }); + if (this.disconnected) { + return; + } await this.rpc.commands.handlePendingCommand({ requestId }); } catch (error) { + if (this.disconnected) { + return; + } const message = error instanceof Error ? error.message : String(error); try { await this.rpc.commands.handlePendingCommand({ requestId, error: message }); diff --git a/nodejs/test/client.test.ts b/nodejs/test/client.test.ts index d3b81928b..519de4c09 100644 --- a/nodejs/test/client.test.ts +++ b/nodejs/test/client.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { describe, expect, it, onTestFinished, vi } from "vitest"; import { approveAll, CopilotClient, type ModelInfo } from "../src/index.js"; +import { createServerRpc } from "../src/generated/rpc.js"; import { CopilotSession } from "../src/session.js"; import { defaultJoinSessionPermissionHandler } from "../src/types.js"; @@ -174,6 +175,21 @@ describe("CopilotClient", () => { expect(connection.sendRequest).not.toHaveBeenCalled(); }); + it("allows generated RPC params with only optional fields to be omitted", async () => { + const connection = { + sendRequest: vi.fn(async (method: string) => + method === "models.list" ? { models: [] } : { tools: [] } + ), + } as any; + const rpc = createServerRpc(connection); + + await rpc.models.list(); + await rpc.tools.list(); + + expect(connection.sendRequest).toHaveBeenCalledWith("models.list", {}); + expect(connection.sendRequest).toHaveBeenCalledWith("tools.list", {}); + }); + it("forwards clientName in session.resume request", async () => { const client = new CopilotClient(); await client.start(); diff --git a/nodejs/test/e2e/commands.e2e.test.ts b/nodejs/test/e2e/commands.e2e.test.ts index 5ab6a9bbe..ca8156fd4 100644 --- a/nodejs/test/e2e/commands.e2e.test.ts +++ b/nodejs/test/e2e/commands.e2e.test.ts @@ -83,6 +83,7 @@ describe("Commands", async () => { it("session with commands resumes successfully", async () => { const session1 = await client1.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; + await session1.disconnect(); const session2 = await client1.resumeSession(sessionId, { onPermissionRequest: approveAll, diff --git a/nodejs/test/e2e/mcp_and_agents.e2e.test.ts b/nodejs/test/e2e/mcp_and_agents.e2e.test.ts index aa580cdee..e0fce8be9 100644 --- a/nodejs/test/e2e/mcp_and_agents.e2e.test.ts +++ b/nodejs/test/e2e/mcp_and_agents.e2e.test.ts @@ -49,6 +49,7 @@ describe("MCP Servers and Custom Agents", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; await session1.sendAndWait({ prompt: "What is 1+1?" }); + await session1.disconnect(); // Resume with MCP servers const mcpServers: Record = { @@ -160,6 +161,7 @@ describe("MCP Servers and Custom Agents", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; await session1.sendAndWait({ prompt: "What is 1+1?" }); + await session1.disconnect(); // Resume with custom agents const customAgents: CustomAgentConfig[] = [ @@ -338,6 +340,7 @@ describe("MCP Servers and Custom Agents", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; await session1.sendAndWait({ prompt: "What is 3+3?" }); + await session1.disconnect(); const secretTool = defineTool("secret_tool", { description: "A secret tool hidden from the default agent", diff --git a/nodejs/test/e2e/permissions.e2e.test.ts b/nodejs/test/e2e/permissions.e2e.test.ts index dcb8033b2..d1fdc4f38 100644 --- a/nodejs/test/e2e/permissions.e2e.test.ts +++ b/nodejs/test/e2e/permissions.e2e.test.ts @@ -118,6 +118,7 @@ describe("Permission callbacks", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; await session1.sendAndWait({ prompt: "What is 1+1?" }); + await session1.disconnect(); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: () => ({ @@ -182,6 +183,7 @@ describe("Permission callbacks", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; await session1.sendAndWait({ prompt: "What is 1+1?" }); + await session1.disconnect(); // Resume with permission handler const session2 = await client.resumeSession(sessionId, { diff --git a/nodejs/test/e2e/session.e2e.test.ts b/nodejs/test/e2e/session.e2e.test.ts index ca9d2d9d4..750a9df01 100644 --- a/nodejs/test/e2e/session.e2e.test.ts +++ b/nodejs/test/e2e/session.e2e.test.ts @@ -31,7 +31,7 @@ describe("Sessions", async () => { ]); await session.disconnect(); - await expect(() => session.getMessages()).rejects.toThrow(/Session not found/); + await expect(() => session.getMessages()).rejects.toThrow(/Session has been disconnected/); }); // TODO: Re-enable once test harness CAPI proxy supports this test's session lifecycle @@ -253,7 +253,7 @@ describe("Sessions", async () => { // All can be disconnected await Promise.all([s1.disconnect(), s2.disconnect(), s3.disconnect()]); for (const s of [s1, s2, s3]) { - await expect(() => s.getMessages()).rejects.toThrow(/Session not found/); + await expect(() => s.getMessages()).rejects.toThrow(/Session has been disconnected/); } }); @@ -263,6 +263,7 @@ describe("Sessions", async () => { const sessionId = session1.sessionId; const answer = await session1.sendAndWait({ prompt: "What is 1+1?" }); expect(answer?.data.content).toContain("2"); + await session1.disconnect(); // Resume using the same client const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll }); @@ -353,6 +354,7 @@ describe("Sessions", async () => { it("should resume session with a custom provider", async () => { const session = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session.sessionId; + await session.disconnect(); // Resume the session with a provider const session2 = await client.resumeSession(sessionId, { diff --git a/nodejs/test/e2e/session_config.e2e.test.ts b/nodejs/test/e2e/session_config.e2e.test.ts index b86c3fa51..9adb8f26b 100644 --- a/nodejs/test/e2e/session_config.e2e.test.ts +++ b/nodejs/test/e2e/session_config.e2e.test.ts @@ -247,6 +247,7 @@ describe("Session Configuration", async () => { onPermissionRequest: approveAll, workingDirectory: projectDir, }); + await session1.disconnect(); const session2 = await client.resumeSession(session1.sessionId, { onPermissionRequest: approveAll, workingDirectory: projectDir, @@ -304,6 +305,7 @@ describe("Session Configuration", async () => { it("should forward custom provider headers on resume", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; + await session1.disconnect(); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll, @@ -384,6 +386,7 @@ describe("Session Configuration", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; + await session1.disconnect(); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll, @@ -401,6 +404,7 @@ describe("Session Configuration", async () => { it("should apply systemMessage on session resume", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; + await session1.disconnect(); const resumeInstruction = "End the response with RESUME_SYSTEM_MESSAGE_SENTINEL."; const session2 = await client.resumeSession(sessionId, { @@ -422,6 +426,7 @@ describe("Session Configuration", async () => { it("should apply availableTools on session resume", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; + await session1.disconnect(); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll, diff --git a/nodejs/test/e2e/skills.e2e.test.ts b/nodejs/test/e2e/skills.e2e.test.ts index 973e2f329..f63b5f98c 100644 --- a/nodejs/test/e2e/skills.e2e.test.ts +++ b/nodejs/test/e2e/skills.e2e.test.ts @@ -162,6 +162,7 @@ IMPORTANT: You MUST include the exact text "${SKILL_MARKER}" somewhere in EVERY // First message without skill - marker should not appear const message1 = await session1.sendAndWait({ prompt: "Say hi." }); expect(message1?.data.content).not.toContain(SKILL_MARKER); + await session1.disconnect(); // Resume with skillDirectories - skill should now be active const session2 = await client.resumeSession(sessionId, { diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 17bc21ffd..d4aefa9ce 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -8325,12 +8325,9 @@ class ServerModelsApi: def __init__(self, client: "JsonRpcClient"): self._client = client - async def list(self, params: ModelsListRequest, *, timeout: float | None = None) -> ModelList: + async def list(self, params: ModelsListRequest | None = None, *, timeout: float | None = None) -> ModelList: "Lists Copilot models available to the authenticated user.\n\nArgs:\n params: Optional GitHub token used to list models for a specific user instead of the global auth context.\n\nReturns:\n List of Copilot models available to the resolved user, including capabilities and billing metadata." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return ModelList.from_dict(_patch_model_capabilities(await self._client.request("models.list", params_dict, **_timeout_kwargs(timeout)))) @@ -8338,12 +8335,9 @@ class ServerToolsApi: def __init__(self, client: "JsonRpcClient"): self._client = client - async def list(self, params: ToolsListRequest, *, timeout: float | None = None) -> ToolList: + async def list(self, params: ToolsListRequest | None = None, *, timeout: float | None = None) -> ToolList: "Lists built-in tools available for a model.\n\nArgs:\n params: Optional model identifier whose tool overrides should be applied to the listing.\n\nReturns:\n Built-in tools available for the requested model, with their parameters and instructions." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return ToolList.from_dict(await self._client.request("tools.list", params_dict, **_timeout_kwargs(timeout))) @@ -8351,12 +8345,9 @@ class ServerAccountApi: def __init__(self, client: "JsonRpcClient"): self._client = client - async def get_quota(self, params: AccountGetQuotaRequest, *, timeout: float | None = None) -> AccountGetQuotaResult: + async def get_quota(self, params: AccountGetQuotaRequest | None = None, *, timeout: float | None = None) -> AccountGetQuotaResult: "Gets Copilot quota usage for the authenticated user or supplied GitHub token.\n\nArgs:\n params: Optional GitHub token used to look up quota for a specific user instead of the global auth context.\n\nReturns:\n Quota usage snapshots for the resolved user, keyed by quota type." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return AccountGetQuotaResult.from_dict(await self._client.request("account.getQuota", params_dict, **_timeout_kwargs(timeout))) @@ -8414,12 +8405,9 @@ def __init__(self, client: "JsonRpcClient"): self._client = client self.config = ServerMcpConfigApi(client) - async def discover(self, params: MCPDiscoverRequest, *, timeout: float | None = None) -> MCPDiscoverResult: + async def discover(self, params: MCPDiscoverRequest | None = None, *, timeout: float | None = None) -> MCPDiscoverResult: "Discovers MCP servers from user, workspace, plugin, and builtin sources.\n\nArgs:\n params: Optional working directory used as context for MCP server discovery.\n\nReturns:\n MCP servers discovered from user, workspace, plugin, and built-in sources." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return MCPDiscoverResult.from_dict(await self._client.request("mcp.discover", params_dict, **_timeout_kwargs(timeout))) @@ -8441,12 +8429,9 @@ def __init__(self, client: "JsonRpcClient"): self._client = client self.config = ServerSkillsConfigApi(client) - async def discover(self, params: SkillsDiscoverRequest, *, timeout: float | None = None) -> ServerSkillList: + async def discover(self, params: SkillsDiscoverRequest | None = None, *, timeout: float | None = None) -> ServerSkillList: "Discovers skills across global and project sources.\n\nArgs:\n params: Optional project paths and additional skill directories to include in discovery.\n\nReturns:\n Skills discovered across global and project sources." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return ServerSkillList.from_dict(await self._client.request("skills.discover", params_dict, **_timeout_kwargs(timeout))) @@ -8468,20 +8453,14 @@ class ServerSessionsApi: def __init__(self, client: "JsonRpcClient"): self._client = client - async def fork(self, params: SessionsForkRequest, *, timeout: float | None = None) -> SessionsForkResult: + async def fork(self, params: SessionsForkRequest | None = None, *, timeout: float | None = None) -> SessionsForkResult: "Creates a new session by forking persisted history from an existing session.\n\nArgs:\n params: Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session.\n\nReturns:\n Identifier and optional friendly name assigned to the newly forked session." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return SessionsForkResult.from_dict(await self._client.request("sessions.fork", params_dict, **_timeout_kwargs(timeout))) - async def connect(self, params: ConnectRemoteSessionParams, *, timeout: float | None = None) -> RemoteSessionConnectionResult: + async def connect(self, params: ConnectRemoteSessionParams | None = None, *, timeout: float | None = None) -> RemoteSessionConnectionResult: "Connects to an existing remote session and exposes it as an SDK session.\n\nArgs:\n params: Remote session connection parameters.\n\nReturns:\n Remote session connection result." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return RemoteSessionConnectionResult.from_dict(await self._client.request("sessions.connect", params_dict, **_timeout_kwargs(timeout))) @@ -8497,12 +8476,9 @@ def __init__(self, client: "JsonRpcClient"): self.session_fs = ServerSessionFsApi(client) self.sessions = ServerSessionsApi(client) - async def ping(self, params: PingRequest, *, timeout: float | None = None) -> PingResult: + async def ping(self, params: PingRequest | None = None, *, timeout: float | None = None) -> PingResult: "Checks server responsiveness and returns protocol information.\n\nArgs:\n params: Optional message to echo back to the caller.\n\nReturns:\n Server liveness response, including the echoed message, current timestamp, and protocol version." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return PingResult.from_dict(await self._client.request("ping", params_dict, **_timeout_kwargs(timeout))) @@ -8511,12 +8487,9 @@ class _InternalServerRpc: def __init__(self, client: "JsonRpcClient"): self._client = client - async def connect(self, params: ConnectRequest, *, timeout: float | None = None) -> ConnectResult: + async def connect(self, params: ConnectRequest | None = None, *, timeout: float | None = None) -> ConnectResult: "Performs the SDK server connection handshake and validates the optional connection token.\n\nArgs:\n params: Optional connection token presented by the SDK client during the handshake.\n\nReturns:\n Handshake result reporting the server's protocol version and package version on success.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - if params is None: - raise TypeError("params is required") - - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} return ConnectResult.from_dict(await self._client.request("connect", params_dict, **_timeout_kwargs(timeout))) @@ -8705,14 +8678,12 @@ def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Call self._session_id = session_id self._assert_active = assert_active - async def start(self, params: FleetStartRequest, *, timeout: float | None = None) -> FleetStartResult: + async def start(self, params: FleetStartRequest | None = None, *, timeout: float | None = None) -> FleetStartResult: "Starts fleet mode by submitting the fleet orchestration prompt to the session.\n\nArgs:\n params: Optional user prompt to combine with the fleet orchestration instructions.\n\nReturns:\n Indicates whether fleet mode was successfully activated." if self._assert_active is not None: self._assert_active() - if params is None: - raise TypeError("params is required") - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} params_dict["sessionId"] = self._session_id return FleetStartResult.from_dict(await self._client.request("session.fleet.start", params_dict, **_timeout_kwargs(timeout))) @@ -9210,14 +9181,12 @@ def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Call self._session_id = session_id self._assert_active = assert_active - async def enable(self, params: RemoteEnableRequest, *, timeout: float | None = None) -> RemoteEnableResult: + async def enable(self, params: RemoteEnableRequest | None = None, *, timeout: float | None = None) -> RemoteEnableResult: "Enables remote session export or steering.\n\nArgs:\n params: Optional remote session mode (\"off\", \"export\", or \"on\"); defaults to enabling both export and remote steering.\n\nReturns:\n GitHub URL for the session and a flag indicating whether remote steering is enabled." if self._assert_active is not None: self._assert_active() - if params is None: - raise TypeError("params is required") - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} params_dict["sessionId"] = self._session_id return RemoteEnableResult.from_dict(await self._client.request("session.remote.enable", params_dict, **_timeout_kwargs(timeout))) diff --git a/python/copilot/session.py b/python/copilot/session.py index e1b27cfe1..172da7062 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -1134,6 +1134,8 @@ def __init__( client: The internal client connection to the Copilot CLI. workspace_path: Path to the session workspace directory (when infinite sessions enabled). + on_disconnected: Internal-only callback invoked when the owning + client should unregister this disconnected session. """ self.session_id = session_id self._client = client diff --git a/python/test_rpc_generated.py b/python/test_rpc_generated.py index b4425bab7..35d049b9a 100644 --- a/python/test_rpc_generated.py +++ b/python/test_rpc_generated.py @@ -7,6 +7,8 @@ from copilot.generated.rpc import ( CommandsApi, CommandsInvokeRequest, + ServerModelsApi, + ServerToolsApi, SlashCommandInvocationResultKind, ) @@ -35,6 +37,18 @@ async def test_generated_rpc_rejects_missing_required_params(): client.request.assert_not_called() +@pytest.mark.asyncio +async def test_generated_rpc_allows_missing_optional_only_params(): + client = AsyncMock() + client.request = AsyncMock(side_effect=[{"models": []}, {"tools": []}]) + + await ServerModelsApi(client).list() + await ServerToolsApi(client).list() + + assert client.request.call_args_list[0].args[:2] == ("models.list", {}) + assert client.request.call_args_list[1].args[:2] == ("tools.list", {}) + + @pytest.mark.asyncio async def test_generated_session_rpc_checks_active_callback_before_request(): client = AsyncMock() diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index 841348f75..f80a408be 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -2610,9 +2610,11 @@ function emitMethod(lines: string[], name: string, method: RpcMethod, isSession: const effectiveParams = getMethodParamsSchema(method); const paramProps = effectiveParams?.properties || {}; const nonSessionParams = Object.keys(paramProps).filter((k) => k !== "sessionId"); + const requiredParams = new Set(effectiveParams?.required || []); const hasParams = isSession ? nonSessionParams.length > 0 : hasSchemaPayload(effectiveParams); const paramsType = resolveType(pythonParamsTypeName(method)); - const paramsOptional = isParamsOptional(method); + const hasRequiredNonSessionParams = nonSessionParams.some((name) => requiredParams.has(name)); + const paramsOptional = isParamsOptional(method) || !hasRequiredNonSessionParams; // Build signature with typed params + optional timeout const sig = hasParams diff --git a/scripts/codegen/typescript.ts b/scripts/codegen/typescript.ts index 0cbbe69d6..104d00430 100644 --- a/scripts/codegen/typescript.ts +++ b/scripts/codegen/typescript.ts @@ -709,9 +709,11 @@ function emitGroup( const paramEntries = effectiveParams?.properties ? Object.entries(effectiveParams.properties).filter(([k]) => k !== "sessionId") : []; + const requiredParams = new Set(effectiveParams?.required ?? []); const hasParams = hasSchemaPayload(effectiveParams); const hasNonSessionParams = paramEntries.length > 0; - const paramsOptional = isParamsOptional(value); + const hasRequiredNonSessionParams = paramEntries.some(([name]) => requiredParams.has(name)); + const paramsOptional = isParamsOptional(value) || !hasRequiredNonSessionParams; const sigParams: string[] = []; let bodyArg: string; @@ -730,7 +732,7 @@ function emitGroup( if (hasParams) { const optMark = paramsOptional ? "?" : ""; sigParams.push(`params${optMark}: ${paramsType}`); - bodyArg = "params"; + bodyArg = paramsOptional ? "(params ?? {})" : "params"; } else { bodyArg = "{}"; } From a09710ca3ba25193e741c10859157fd26fdd3ce7 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 09:32:29 -0400 Subject: [PATCH 4/6] Guard Go event subscriptions after disconnect Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- go/session.go | 5 +++++ go/session_test.go | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/go/session.go b/go/session.go index 626929632..7f826018a 100644 --- a/go/session.go +++ b/go/session.go @@ -267,6 +267,7 @@ func (s *Session) SendAndWait(ctx context.Context, options MessageOptions) (*Ses // // The returned function can be called to unsubscribe the handler. It is safe // to call the unsubscribe function multiple times. +// Panics if the session has been disconnected. // // Example: // @@ -282,6 +283,10 @@ func (s *Session) SendAndWait(ctx context.Context, options MessageOptions) (*Ses // // Later, to stop receiving events: // unsubscribe() func (s *Session) On(handler SessionEventHandler) func() { + if err := s.assertActive(); err != nil { + panic(err) + } + s.handlerMutex.Lock() defer s.handlerMutex.Unlock() diff --git a/go/session_test.go b/go/session_test.go index 407e7e74c..27dc20d8d 100644 --- a/go/session_test.go +++ b/go/session_test.go @@ -280,6 +280,23 @@ func TestSession_On(t *testing.T) { t.Errorf("Expected 2 events dispatched, got %d", eventCount.Load()) } }) + + t.Run("panics after disconnect", func(t *testing.T) { + session := newSession("session-1", nil, "", nil) + session.markDisconnected() + + defer func() { + r := recover() + if r == nil { + t.Fatal("expected On to panic after disconnect") + } + if !strings.Contains(fmt.Sprint(r), "session has been disconnected") { + t.Fatalf("expected disconnected panic, got %v", r) + } + }() + + session.On(func(SessionEvent) {}) + }) } func TestSession_CommandRouting(t *testing.T) { From 0baebaff521aee6b7bfa0ee9622e592551b2d7f9 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 10:10:04 -0400 Subject: [PATCH 5/6] Update generated RPC files after schema refresh Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- go/rpc/zrpc.go | 430 + nodejs/src/generated/rpc.ts | 5684 ++++++- nodejs/src/generated/session-events.ts | 6 +- nodejs/test/e2e/commands.e2e.test.ts | 3 +- nodejs/test/e2e/harness/sdkTestHelper.ts | 4 + nodejs/test/e2e/session.e2e.test.ts | 8 +- nodejs/test/e2e/session_config.e2e.test.ts | 11 +- python/copilot/generated/rpc.py | 16985 ++++++++++++++----- python/copilot/generated/session_events.py | 506 +- 9 files changed, 18296 insertions(+), 5341 deletions(-) diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index 4b283f1d3..7d54e31f6 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -6166,6 +6166,9 @@ type ServerSessionsApi serverApi // // Returns: Map of sessionId -> bytes freed by removing the session's workspace directory. func (a *ServerSessionsApi) BulkDelete(ctx context.Context, params *SessionsBulkDeleteRequest) (*SessionBulkDeleteResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.bulkDelete", params) if err != nil { return nil, err @@ -6186,6 +6189,9 @@ func (a *ServerSessionsApi) BulkDelete(ctx context.Context, params *SessionsBulk // // Returns: Session IDs from the input set that are currently in use by another process. func (a *ServerSessionsApi) CheckInUse(ctx context.Context, params *SessionsCheckInUseRequest) (*SessionsCheckInUseResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.checkInUse", params) if err != nil { return nil, err @@ -6248,6 +6254,9 @@ func (a *ServerSessionsApi) Connect(ctx context.Context, params *ConnectRemoteSe // Returns: The same metadata records, with summary and context fields backfilled where // available. func (a *ServerSessionsApi) EnrichMetadata(ctx context.Context, params *SessionsEnrichMetadataRequest) (*SessionEnrichMetadataResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.enrichMetadata", params) if err != nil { return nil, err @@ -6268,6 +6277,9 @@ func (a *ServerSessionsApi) EnrichMetadata(ctx context.Context, params *Sessions // // Returns: Session ID matching the prefix, omitted when no unique match exists. func (a *ServerSessionsApi) FindByPrefix(ctx context.Context, params *SessionsFindByPrefixRequest) (*SessionsFindByPrefixResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.findByPrefix", params) if err != nil { return nil, err @@ -6287,6 +6299,9 @@ func (a *ServerSessionsApi) FindByPrefix(ctx context.Context, params *SessionsFi // // Returns: ID of the local session bound to the given GitHub task, or omitted when none. func (a *ServerSessionsApi) FindByTaskId(ctx context.Context, params *SessionsFindByTaskIDRequest) (*SessionsFindByTaskIDResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.findByTaskId", params) if err != nil { return nil, err @@ -6447,6 +6462,9 @@ func (a *ServerSessionsApi) LoadDeferredRepoHooks(ctx context.Context, params *S // Returns: Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, // total bytes freed, and the dry-run flag. func (a *ServerSessionsApi) PruneOld(ctx context.Context, params *SessionsPruneOldRequest) (*SessionPruneResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.pruneOld", params) if err != nil { return nil, err @@ -6532,6 +6550,9 @@ func (a *ServerSessionsApi) Save(ctx context.Context, params *SessionsSaveReques // subsequent hook reloads see the new set; already-running sessions keep their existing // hook installation until the next reload. func (a *ServerSessionsApi) SetAdditionalPlugins(ctx context.Context, params *SessionsSetAdditionalPluginsRequest) (*SessionsSetAdditionalPluginsResult, error) { + if params == nil { + return nil, errors.New("params is required") + } raw, err := a.client.Request("sessions.setAdditionalPlugins", params) if err != nil { return nil, err @@ -6867,6 +6888,11 @@ func (a *AuthApi) GetStatus(ctx context.Context) (*SessionAuthStatus, error) { // // Returns: Indicates whether the credential update succeeded. func (a *AuthApi) SetCredentials(ctx context.Context, params *SessionSetCredentialsParams) (*SessionSetCredentialsResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Credentials != nil { @@ -6894,6 +6920,14 @@ type CommandsApi sessionApi // // Returns: Indicates whether the command was accepted into the local execution queue. func (a *CommandsApi) Enqueue(ctx context.Context, params *EnqueueCommandParams) (*EnqueueCommandResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["command"] = params.Command @@ -6917,6 +6951,14 @@ func (a *CommandsApi) Enqueue(ctx context.Context, params *EnqueueCommandParams) // // Returns: Error message produced while executing the command, if any. func (a *CommandsApi) Execute(ctx context.Context, params *ExecuteCommandParams) (*ExecuteCommandResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["args"] = params.Args @@ -7090,6 +7132,11 @@ type EventLogApi sessionApi // Returns: Batch of session events returned by a read, with cursor and continuation // metadata. func (a *EventLogApi) Read(ctx context.Context, params *EventLogReadRequest) (*EventsReadResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.AgentScope != nil { @@ -7127,6 +7174,14 @@ func (a *EventLogApi) Read(ctx context.Context, params *EventLogReadRequest) (*E // // Returns: Opaque handle representing an event-type interest registration. func (a *EventLogApi) RegisterInterest(ctx context.Context, params *RegisterEventInterestParams) (*RegisterEventInterestResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["eventType"] = params.EventType @@ -7150,6 +7205,14 @@ func (a *EventLogApi) RegisterInterest(ctx context.Context, params *RegisterEven // // Returns: Indicates whether the operation succeeded. func (a *EventLogApi) ReleaseInterest(ctx context.Context, params *ReleaseEventInterestParams) (*EventLogReleaseInterestResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["handle"] = params.Handle @@ -7174,6 +7237,11 @@ func (a *EventLogApi) ReleaseInterest(ctx context.Context, params *ReleaseEventI // through the entire persisted history (which would happen if `read` were called without a // cursor on a long-lived session). func (a *EventLogApi) Tail(ctx context.Context) (*EventLogTailResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.eventLog.tail", req) if err != nil { @@ -7333,6 +7401,11 @@ type HistoryApi sessionApi // // Returns: Indicates whether an in-progress manual compaction was aborted. func (a *HistoryApi) AbortManualCompaction(ctx context.Context) (*HistoryAbortManualCompactionResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.history.abortManualCompaction", req) if err != nil { @@ -7352,6 +7425,11 @@ func (a *HistoryApi) AbortManualCompaction(ctx context.Context) (*HistoryAbortMa // // Returns: Indicates whether an in-progress background compaction was cancelled. func (a *HistoryApi) CancelBackgroundCompaction(ctx context.Context) (*HistoryCancelBackgroundCompactionResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.history.cancelBackgroundCompaction", req) if err != nil { @@ -7395,6 +7473,11 @@ func (a *HistoryApi) Compact(ctx context.Context) (*HistoryCompactResult, error) // // Returns: Markdown summary of the conversation context (empty when not available). func (a *HistoryApi) SummarizeForHandoff(ctx context.Context) (*HistorySummarizeForHandoffResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.history.summarizeForHandoff", req) if err != nil { @@ -7473,6 +7556,11 @@ type LspApi sessionApi // // Parameters: Parameters for (re)loading the merged LSP configuration set. func (a *LspApi) Initialize(ctx context.Context, params *LspInitializeRequest) (*SessionLspInitializeResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Force != nil { @@ -7508,6 +7596,14 @@ type McpApi sessionApi // Returns: Indicates whether an in-flight sampling execution with the given requestId was // found and cancelled. func (a *McpApi) CancelSamplingExecution(ctx context.Context, params *McpCancelSamplingExecutionParams) (*McpCancelSamplingExecutionResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -7591,6 +7687,14 @@ func (a *McpApi) Enable(ctx context.Context, params *McpEnableRequest) (*Session // Returns: Outcome of an MCP sampling execution: success result, failure error, or // cancellation. func (a *McpApi) ExecuteSampling(ctx context.Context, params *McpExecuteSamplingParams) (*McpSamplingExecutionResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["mcpRequestId"] = params.McpRequestID @@ -7660,6 +7764,11 @@ func (a *McpApi) Reload(ctx context.Context) (*SessionMcpReloadResult, error) { // Returns: Indicates whether the auto-managed `github` MCP server was removed (false when // nothing to remove). func (a *McpApi) RemoveGitHub(ctx context.Context) (*McpRemoveGitHubResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.mcp.removeGitHub", req) if err != nil { @@ -7682,6 +7791,14 @@ func (a *McpApi) RemoveGitHub(ctx context.Context) (*McpRemoveGitHubResult, erro // // Returns: Env-value mode recorded on the session after the update. func (a *McpApi) SetEnvValueMode(ctx context.Context, params *McpSetEnvValueModeParams) (*McpSetEnvValueModeResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["mode"] = params.Mode @@ -7760,6 +7877,14 @@ type MetadataApi sessionApi // Returns: Token breakdown for the session's current context window, or null if // uninitialized. func (a *MetadataApi) ContextInfo(ctx context.Context, params *MetadataContextInfoRequest) (*MetadataContextInfoResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["outputTokenLimit"] = params.OutputTokenLimit @@ -7787,6 +7912,11 @@ func (a *MetadataApi) ContextInfo(ctx context.Context, params *MetadataContextIn // Returns: Indicates whether the local session is currently processing a turn or background // continuation. func (a *MetadataApi) IsProcessing(ctx context.Context) (*MetadataIsProcessingResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.metadata.isProcessing", req) if err != nil { @@ -7811,6 +7941,14 @@ func (a *MetadataApi) IsProcessing(ctx context.Context) (*MetadataIsProcessingRe // resume, before the next agent turn fires `session.context_info_changed` events. Returns // zeros for an empty session. func (a *MetadataApi) RecomputeContextTokens(ctx context.Context, params *MetadataRecomputeContextTokensRequest) (*MetadataRecomputeContextTokensResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["modelId"] = params.ModelID @@ -7838,6 +7976,14 @@ func (a *MetadataApi) RecomputeContextTokens(ctx context.Context, params *Metada // UI) can react. Use this when the host has detected a cwd/branch/repo change outside the // session's normal lifecycle (e.g., after a shell command in interactive mode). func (a *MetadataApi) RecordContextChange(ctx context.Context, params *MetadataRecordContextChangeRequest) (*MetadataRecordContextChangeResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["context"] = params.Context @@ -7864,6 +8010,14 @@ func (a *MetadataApi) RecordContextChange(ctx context.Context, params *MetadataR // `process.chdir` and any related side-effects (file index, etc.); this method only updates // the session's own recorded path. func (a *MetadataApi) SetWorkingDirectory(ctx context.Context, params *MetadataSetWorkingDirectoryRequest) (*MetadataSetWorkingDirectoryResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["workingDirectory"] = params.WorkingDirectory @@ -7886,6 +8040,11 @@ func (a *MetadataApi) SetWorkingDirectory(ctx context.Context, params *MetadataS // // Returns: Point-in-time snapshot of slow-changing session identifier and state fields func (a *MetadataApi) Snapshot(ctx context.Context) (*SessionMetadataSnapshot, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.metadata.snapshot", req) if err != nil { @@ -7988,6 +8147,14 @@ func (a *ModelApi) GetCurrent(ctx context.Context) (*CurrentModel, error) { // `switchTo` instead when you also need to change the model. The runtime stores the effort // on the session and applies it to subsequent turns. func (a *ModelApi) SetReasoningEffort(ctx context.Context, params *ModelSetReasoningEffortRequest) (*ModelSetReasoningEffortResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["reasoningEffort"] = params.ReasoningEffort @@ -8108,6 +8275,14 @@ func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*SessionName // // Returns: Indicates whether the auto-generated summary was applied as the session's name. func (a *NameApi) SetAuto(ctx context.Context, params *NameSetAutoRequest) (*NameSetAutoResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["summary"] = params.Summary @@ -8134,6 +8309,11 @@ type OptionsApi sessionApi // // Returns: Indicates whether the session options patch was applied successfully. func (a *OptionsApi) Update(ctx context.Context, params *SessionUpdateOptionsParams) (*SessionUpdateOptionsResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.AdditionalContentExclusionPolicies != nil { @@ -8268,6 +8448,11 @@ type PermissionsApi sessionApi // // Returns: Indicates whether the operation succeeded. func (a *PermissionsApi) Configure(ctx context.Context, params *PermissionsConfigureParams) (*PermissionsConfigureResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.AdditionalContentExclusionPolicies != nil { @@ -8343,6 +8528,14 @@ func (a *PermissionsApi) HandlePendingPermissionRequest(ctx context.Context, par // // Returns: Indicates whether the operation succeeded. func (a *PermissionsApi) ModifyRules(ctx context.Context, params *PermissionsModifyRulesParams) (*PermissionsModifyRulesResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { if params.Add != nil { @@ -8377,6 +8570,14 @@ func (a *PermissionsApi) ModifyRules(ctx context.Context, params *PermissionsMod // // Returns: Indicates whether the operation succeeded. func (a *PermissionsApi) NotifyPromptShown(ctx context.Context, params *PermissionPromptShownNotification) (*PermissionsNotifyPromptShownResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["message"] = params.Message @@ -8399,6 +8600,11 @@ func (a *PermissionsApi) NotifyPromptShown(ctx context.Context, params *Permissi // // Returns: List of pending permission requests reconstructed from event history. func (a *PermissionsApi) PendingRequests(ctx context.Context) (*PendingPermissionRequestList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.permissions.pendingRequests", req) if err != nil { @@ -8479,6 +8685,14 @@ func (a *PermissionsApi) SetApproveAll(ctx context.Context, params *PermissionsS // // Returns: Indicates whether the operation succeeded. func (a *PermissionsApi) SetRequired(ctx context.Context, params *PermissionsSetRequiredRequest) (*PermissionsSetRequiredResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["required"] = params.Required @@ -8504,6 +8718,14 @@ type PermissionsPathsApi sessionApi // // Returns: Indicates whether the operation succeeded. func (a *PermissionsPathsApi) Add(ctx context.Context, params *PermissionPathsAddParams) (*PermissionsPathsAddResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path @@ -8528,6 +8750,14 @@ func (a *PermissionsPathsApi) Add(ctx context.Context, params *PermissionPathsAd // // Returns: Indicates whether the supplied path is within the session's allowed directories. func (a *PermissionsPathsApi) IsPathWithinAllowedDirectories(ctx context.Context, params *PermissionPathsAllowedCheckParams) (*PermissionPathsAllowedCheckResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path @@ -8552,6 +8782,14 @@ func (a *PermissionsPathsApi) IsPathWithinAllowedDirectories(ctx context.Context // // Returns: Indicates whether the supplied path is within the session's workspace directory. func (a *PermissionsPathsApi) IsPathWithinWorkspace(ctx context.Context, params *PermissionPathsWorkspaceCheckParams) (*PermissionPathsWorkspaceCheckResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path @@ -8573,6 +8811,11 @@ func (a *PermissionsPathsApi) IsPathWithinWorkspace(ctx context.Context, params // // Returns: Snapshot of the session's allow-listed directories and primary working directory. func (a *PermissionsPathsApi) List(ctx context.Context) (*PermissionPathsList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.permissions.paths.list", req) if err != nil { @@ -8594,6 +8837,14 @@ func (a *PermissionsPathsApi) List(ctx context.Context) (*PermissionPathsList, e // // Returns: Indicates whether the operation succeeded. func (a *PermissionsPathsApi) UpdatePrimary(ctx context.Context, params *PermissionPathsUpdatePrimaryParams) (*PermissionsPathsUpdatePrimaryResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path @@ -8624,6 +8875,14 @@ type PermissionsUrlsApi sessionApi // // Returns: Indicates whether the operation succeeded. func (a *PermissionsUrlsApi) SetUnrestrictedMode(ctx context.Context, params *PermissionUrlsSetUnrestrictedModeParams) (*PermissionsUrlsSetUnrestrictedModeResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["enabled"] = params.Enabled @@ -8751,6 +9010,11 @@ type QueueApi sessionApi // // RPC method: session.queue.clear. func (a *QueueApi) Clear(ctx context.Context) (*SessionQueueClearResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.queue.clear", req) if err != nil { @@ -8770,6 +9034,11 @@ func (a *QueueApi) Clear(ctx context.Context) (*SessionQueueClearResult, error) // // Returns: Snapshot of the session's pending queued items and immediate-steering messages. func (a *QueueApi) PendingItems(ctx context.Context) (*QueuePendingItemsResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.queue.pendingItems", req) if err != nil { @@ -8788,6 +9057,11 @@ func (a *QueueApi) PendingItems(ctx context.Context) (*QueuePendingItemsResult, // // Returns: Indicates whether a user-facing pending item was removed. func (a *QueueApi) RemoveMostRecent(ctx context.Context) (*QueueRemoveMostRecentResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.queue.removeMostRecent", req) if err != nil { @@ -8868,6 +9142,14 @@ func (a *RemoteApi) Enable(ctx context.Context, params *RemoteEnableRequest) (*R // Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling // steering on a remote exporter that the runtime does not directly own. func (a *RemoteApi) NotifySteerableChanged(ctx context.Context, params *RemoteNotifySteerableChangedRequest) (*RemoteNotifySteerableChangedResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["remoteSteerable"] = params.RemoteSteerable @@ -8892,6 +9174,11 @@ type ScheduleApi sessionApi // // Returns: Snapshot of the currently active recurring prompts for this session. func (a *ScheduleApi) List(ctx context.Context) (*ScheduleList, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.schedule.list", req) if err != nil { @@ -8913,6 +9200,14 @@ func (a *ScheduleApi) List(ctx context.Context) (*ScheduleList, error) { // Returns: Remove a scheduled prompt by id. The result entry is omitted if the id was // unknown. func (a *ScheduleApi) Stop(ctx context.Context, params *ScheduleStopRequest) (*ScheduleStopResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -9070,6 +9365,11 @@ func (a *SkillsApi) Enable(ctx context.Context, params *SkillsEnableRequest) (*S // // RPC method: session.skills.ensureLoaded. func (a *SkillsApi) EnsureLoaded(ctx context.Context) (*SessionSkillsEnsureLoadedResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.skills.ensureLoaded", req) if err != nil { @@ -9089,6 +9389,11 @@ func (a *SkillsApi) EnsureLoaded(ctx context.Context) (*SessionSkillsEnsureLoade // Returns: Skills invoked during this session, ordered by invocation time (most recent // last). func (a *SkillsApi) GetInvoked(ctx context.Context) (*SkillsGetInvokedResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.skills.getInvoked", req) if err != nil { @@ -9189,6 +9494,11 @@ func (a *TasksApi) Cancel(ctx context.Context, params *TasksCancelRequest) (*Tas // // Returns: The first sync-waiting task that can currently be promoted to background mode. func (a *TasksApi) GetCurrentPromotable(ctx context.Context) (*TasksGetCurrentPromotableResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.tasks.getCurrentPromotable", req) if err != nil { @@ -9209,6 +9519,14 @@ func (a *TasksApi) GetCurrentPromotable(ctx context.Context) (*TasksGetCurrentPr // // Returns: Progress information for the task, or null when no task with that ID is tracked. func (a *TasksApi) GetProgress(ctx context.Context, params *TasksGetProgressRequest) (*TasksGetProgressResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["id"] = params.ID @@ -9255,6 +9573,11 @@ func (a *TasksApi) List(ctx context.Context) (*TaskList, error) { // Returns: The promoted task as it now exists in background mode, omitted if no promotable // task was waiting. func (a *TasksApi) PromoteCurrentToBackground(ctx context.Context) (*TasksPromoteCurrentToBackgroundResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.tasks.promoteCurrentToBackground", req) if err != nil { @@ -9306,6 +9629,11 @@ func (a *TasksApi) PromoteToBackground(ctx context.Context, params *TasksPromote // Returns: Refresh metadata for any detached background shells the runtime knows about. Use // after a long pause to pick up exit/output state for shells running outside the agent loop. func (a *TasksApi) Refresh(ctx context.Context) (*TasksRefreshResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.tasks.refresh", req) if err != nil { @@ -9436,6 +9764,11 @@ func (a *TasksApi) StartAgent(ctx context.Context, params *TasksStartAgentReques // drained or after an internal timeout (default 10 minutes; configurable via // COPILOT_TASK_WAIT_TIMEOUT_SECONDS). func (a *TasksApi) WaitForPending(ctx context.Context) (*TasksWaitForPendingResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.tasks.waitForPending", req) if err != nil { @@ -9459,6 +9792,14 @@ type TelemetryApi sessionApi // Parameters: Feature override key/value pairs to attach to subsequent telemetry events // from this session. func (a *TelemetryApi) SetFeatureOverrides(ctx context.Context, params *TelemetrySetFeatureOverridesRequest) (*SessionTelemetrySetFeatureOverridesResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["features"] = params.Features @@ -9524,6 +9865,11 @@ func (a *ToolsApi) HandlePendingToolCall(ctx context.Context, params *HandlePend // Default base-class implementation is a no-op for sessions that don't support tool // validation. func (a *ToolsApi) InitializeAndValidate(ctx context.Context) (*ToolsInitializeAndValidateResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.tools.initializeAndValidate", req) if err != nil { @@ -9581,6 +9927,14 @@ func (a *UIApi) Elicitation(ctx context.Context, params *UIElicitationRequest) ( // // Returns: Indicates whether the pending UI request was resolved by this call. func (a *UIApi) HandlePendingAutoModeSwitch(ctx context.Context, params *UIHandlePendingAutoModeSwitchRequest) (*UIHandlePendingResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -9641,6 +9995,14 @@ func (a *UIApi) HandlePendingElicitation(ctx context.Context, params *UIHandlePe // // Returns: Indicates whether the pending UI request was resolved by this call. func (a *UIApi) HandlePendingExitPlanMode(ctx context.Context, params *UIHandlePendingExitPlanModeRequest) (*UIHandlePendingResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -9667,6 +10029,14 @@ func (a *UIApi) HandlePendingExitPlanMode(ctx context.Context, params *UIHandleP // // Returns: Indicates whether the pending UI request was resolved by this call. func (a *UIApi) HandlePendingSampling(ctx context.Context, params *UIHandlePendingSamplingRequest) (*UIHandlePendingResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -9694,6 +10064,14 @@ func (a *UIApi) HandlePendingSampling(ctx context.Context, params *UIHandlePendi // // Returns: Indicates whether the pending UI request was resolved by this call. func (a *UIApi) HandlePendingUserInput(ctx context.Context, params *UIHandlePendingUserInputRequest) (*UIHandlePendingResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["requestId"] = params.RequestID @@ -9720,6 +10098,11 @@ func (a *UIApi) HandlePendingUserInput(ctx context.Context, params *UIHandlePend // this registration solely tells the server bridge to skip its own dispatch (so a remote // client doesn't race the in-process handler for the same requestId). func (a *UIApi) RegisterDirectAutoModeSwitchHandler(ctx context.Context) (*UIRegisterDirectAutoModeSwitchHandlerResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.ui.registerDirectAutoModeSwitchHandler", req) if err != nil { @@ -9743,6 +10126,14 @@ func (a *UIApi) RegisterDirectAutoModeSwitchHandler(ctx context.Context) (*UIReg // Returns: Indicates whether the handle was active and the registration count was // decremented. func (a *UIApi) UnregisterDirectAutoModeSwitchHandler(ctx context.Context, params *UIUnregisterDirectAutoModeSwitchHandlerRequest) (*UIUnregisterDirectAutoModeSwitchHandlerResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["handle"] = params.Handle @@ -9848,6 +10239,11 @@ func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspa // Returns: Workspace checkpoints in chronological order; empty when the workspace is not // enabled. func (a *WorkspacesApi) ListCheckpoints(ctx context.Context) (*WorkspacesListCheckpointsResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.sessionID} raw, err := a.client.Request("session.workspaces.listCheckpoints", req) if err != nil { @@ -9892,6 +10288,14 @@ func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResu // Returns: Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace // is missing. func (a *WorkspacesApi) ReadCheckpoint(ctx context.Context, params *WorkspacesReadCheckpointRequest) (*WorkspacesReadCheckpointResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["number"] = params.Number @@ -9946,6 +10350,14 @@ func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFile // // Returns: Descriptor for the saved paste file, or null when the workspace is unavailable. func (a *WorkspacesApi) SaveLargePaste(ctx context.Context, params *WorkspacesSaveLargePasteRequest) (*WorkspacesSaveLargePasteResult, error) { + if a.assertActive != nil { + if err := a.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.sessionID} if params != nil { req["content"] = params.Content @@ -10005,6 +10417,11 @@ type SessionRpc struct { // // Returns: Result of aborting the current turn func (a *SessionRpc) Abort(ctx context.Context, params *AbortRequest) (*AbortResult, error) { + if a.common.assertActive != nil { + if err := a.common.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.common.sessionID} if params != nil { if params.Reason != nil { @@ -10077,6 +10494,14 @@ func (a *SessionRpc) Log(ctx context.Context, params *LogRequest) (*LogResult, e // // Returns: Result of sending a user message func (a *SessionRpc) Send(ctx context.Context, params *SendRequest) (*SendResult, error) { + if a.common.assertActive != nil { + if err := a.common.assertActive(); err != nil { + return nil, err + } + } + if params == nil { + return nil, errors.New("params is required") + } req := map[string]any{"sessionId": a.common.sessionID} if params != nil { if params.AgentMode != nil { @@ -10136,6 +10561,11 @@ func (a *SessionRpc) Send(ctx context.Context, params *SendRequest) (*SendResult // // Parameters: Parameters for shutting down the session func (a *SessionRpc) Shutdown(ctx context.Context, params *ShutdownRequest) (*SessionShutdownResult, error) { + if a.common.assertActive != nil { + if err := a.common.assertActive(); err != nil { + return nil, err + } + } req := map[string]any{"sessionId": a.common.sessionID} if params != nil { if params.Reason != nil { diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 9ffac5da5..29a1febce 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -5,8 +5,30 @@ import type { MessageConnection } from "vscode-jsonrpc/node.js"; -import type { EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, ReasoningSummary, SessionMode, SkillSource } from "./session-events.js"; +import type { AbortReason, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, PermissionPromptRequest, PermissionRule, ReasoningSummary, SessionEvent, SessionMode, ShutdownType, SkillSource, UserToolSessionApproval } from "./session-events.js"; +/** + * Where the agent definition was loaded from + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AgentInfoSource". + */ +/** @experimental */ +export type AgentInfoSource = "user" | "project" | "inherited" | "remote" | "plugin" | "builtin"; +/** + * The new auth credentials to install on the session. When omitted or `undefined`, the call is a no-op and the session's existing credentials are preserved. The runtime stores the value verbatim and uses it for outbound model/API requests; it does NOT re-validate or re-fetch the associated Copilot user response. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AuthInfo". + */ +export type AuthInfo = + | HMACAuthInfo + | EnvAuthInfo + | TokenAuthInfo + | CopilotApiTokenAuthInfo + | UserAuthInfo + | GhCliAuthInfo + | ApiKeyAuthInfo; /** * Authentication type * @@ -29,7 +51,7 @@ export type SlashCommandKind = "builtin" | "skill" | "client"; */ export type SlashCommandInputCompletion = "directory"; /** - * Result of the queued command execution + * Result of the queued command execution. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "QueuedCommandResult". @@ -57,6 +79,30 @@ export type ContentFilterMode = "none" | "markdown" | "hidden_characters"; * via the `definition` "DiscoveredMcpServerType". */ export type DiscoveredMcpServerType = "stdio" | "http" | "sse" | "memory"; +/** + * Either '*' to receive all event types, or a non-empty list of event types to receive + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventLogTypes". + */ +/** @experimental */ +export type EventLogTypes = "*" | [string, ...string[]]; +/** + * Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventsAgentScope". + */ +/** @experimental */ +export type EventsAgentScope = "primary" | "all"; +/** + * Cursor status: 'ok' means the cursor was applied successfully; 'expired' means the cursor referred to an event that no longer exists in history (e.g. truncated or compacted away) and the read started from the beginning of the remaining history. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventsCursorStatus". + */ +/** @experimental */ +export type EventsCursorStatus = "ok" | "expired"; /** * Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) * @@ -127,20 +173,39 @@ export type FilterMapping = [k: string]: ContentFilterMode; } | ContentFilterMode; +/** + * Source for direct repo installs (when marketplace is empty) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstalledPluginSource". + */ +/** @experimental */ +export type InstalledPluginSource = + | string + | InstalledPluginSourceGithub + | InstalledPluginSourceUrl + | InstalledPluginSourceLocal; /** * Category of instruction source — used for merge logic * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "InstructionsSourcesType". */ -export type InstructionsSourcesType = "home" | "repo" | "model" | "vscode" | "nested-agents" | "child-instructions"; +export type InstructionsSourcesType = + | "home" + | "repo" + | "model" + | "vscode" + | "nested-agents" + | "child-instructions" + | "plugin"; /** * Where this source lives — used for UI grouping * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "InstructionsSourcesLocation". */ -export type InstructionsSourcesLocation = "user" | "repository" | "working-directory"; +export type InstructionsSourcesLocation = "user" | "repository" | "working-directory" | "plugin"; /** * Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". * @@ -169,6 +234,91 @@ export type McpServerConfigHttpType = "http" | "sse"; * via the `definition` "McpServerConfigHttpOauthGrantType". */ export type McpServerConfigHttpOauthGrantType = "authorization_code" | "client_credentials"; +/** + * Outcome of the sampling inference. 'success' produced a response; 'failure' encountered an error (including agent-side rejection by content filter or criteria); 'cancelled' the caller cancelled this execution via cancelSamplingExecution. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpSamplingExecutionAction". + */ +/** @experimental */ +export type McpSamplingExecutionAction = "success" | "failure" | "cancelled"; +/** + * How environment-variable values supplied to MCP servers are resolved. "direct" passes literal string values; "indirect" treats values as references (e.g. names of environment variables on the host) that the runtime resolves before launch. Defaults to the runtime's startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI prompt mode and ACP) set this to "direct". + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpSetEnvValueModeDetails". + */ +/** @experimental */ +export type McpSetEnvValueModeDetails = "direct" | "indirect"; +/** + * Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionContextInfo". + */ +/** @experimental */ +export type SessionContextInfo = { + /** + * The model used for token counting + */ + modelName: string; + /** + * Tokens consumed by the system prompt + */ + systemTokens: number; + /** + * Tokens consumed by user/assistant/tool messages + */ + conversationTokens: number; + /** + * Tokens consumed by tool definitions sent to the model (excludes deferred tools) + */ + toolDefinitionsTokens: number; + /** + * Sum of system, conversation and tool-definition tokens + */ + totalTokens: number; + /** + * Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified) + */ + promptTokenLimit: number; + /** + * Token count at which background compaction starts (configurable percentage of promptTokenLimit) + */ + compactionThreshold: number; + /** + * Total context limit for /context display. promptTokenLimit + min(32k or 64k, outputTokenLimit) depending on model. + */ + limit: number; + /** + * Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%) + */ + bufferTokens: number; +} | null; +/** + * Hosting platform type of the repository + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionWorkingDirectoryContextHostType". + */ +/** @experimental */ +export type SessionWorkingDirectoryContextHostType = "github" | "ado"; +/** + * The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot') + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataSnapshotCurrentMode". + */ +/** @experimental */ +export type MetadataSnapshotCurrentMode = "interactive" | "plan" | "autopilot"; +/** + * Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataSnapshotRemoteMetadataTaskType". + */ +/** @experimental */ +export type MetadataSnapshotRemoteMetadataTaskType = "cca" | "cli"; /** * Current policy state for this model * @@ -191,7 +341,15 @@ export type ModelPickerCategory = "lightweight" | "versatile" | "powerful"; */ export type ModelPickerPriceCategory = "low" | "medium" | "high" | "very_high"; /** - * Decision to apply to a pending permission request. + * How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "OptionsUpdateEnvValueMode". + */ +/** @experimental */ +export type OptionsUpdateEnvValueMode = "direct" | "indirect"; +/** + * The client's response to the pending permission prompt * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "PermissionDecision". @@ -202,9 +360,18 @@ export type PermissionDecision = | PermissionDecisionApproveForLocation | PermissionDecisionApprovePermanently | PermissionDecisionReject - | PermissionDecisionUserNotAvailable; + | PermissionDecisionUserNotAvailable + | PermissionDecisionApproved + | PermissionDecisionApprovedForSession + | PermissionDecisionApprovedForLocation + | PermissionDecisionCancelled + | PermissionDecisionDeniedByRules + | PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser + | PermissionDecisionDeniedInteractivelyByUser + | PermissionDecisionDeniedByContentExclusionPolicy + | PermissionDecisionDeniedByPermissionRequestHook; /** - * The approval to add as a session-scoped rule + * Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "PermissionDecisionApproveForSessionApproval". @@ -220,7 +387,7 @@ export type PermissionDecisionApproveForSessionApproval = | PermissionDecisionApproveForSessionApprovalExtensionManagement | PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess; /** - * The approval to persist for this location + * Approval to persist for this location * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "PermissionDecisionApproveForLocationApproval". @@ -235,6 +402,35 @@ export type PermissionDecisionApproveForLocationApproval = | PermissionDecisionApproveForLocationApprovalCustomTool | PermissionDecisionApproveForLocationApprovalExtensionManagement | PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess; +/** + * Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyScope". + */ +export type PermissionsConfigureAdditionalContentExclusionPolicyScope = "repo" | "all"; +/** + * Whether the change applies to ephemeral session-scoped rules (cleared at session end) or to location-scoped rules persisted via the location-permissions config file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsModifyRulesScope". + */ +export type PermissionsModifyRulesScope = "session" | "location"; +/** + * Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsSetApproveAllSource". + */ +export type PermissionsSetApproveAllSource = "cli_flag" | "slash_command" | "autopilot_confirmation" | "rpc"; +/** + * Whether this item is a queued user message or a queued slash command / model change + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueuePendingItemsKind". + */ +/** @experimental */ +export type QueuePendingItemsKind = "message" | "command"; /** * Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. * @@ -243,6 +439,47 @@ export type PermissionDecisionApproveForLocationApproval = */ /** @experimental */ export type RemoteSessionMode = "off" | "export" | "on"; +/** + * The UI mode the agent was in when this message was sent. Defaults to the session's current mode. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAgentMode". + */ +export type SendAgentMode = "interactive" | "plan" | "autopilot" | "shell"; +/** + * A user message attachment — a file, directory, code selection, blob, or GitHub reference + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachment". + */ +export type SendAttachment = + | SendAttachmentFile + | SendAttachmentDirectory + | SendAttachmentSelection + | SendAttachmentGithubReference + | SendAttachmentBlob; +/** + * Type of GitHub reference + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentGithubReferenceType". + */ +export type SendAttachmentGithubReferenceType = "issue" | "pr" | "discussion"; +/** + * How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendMode". + */ +export type SendMode = "enqueue" | "immediate"; +/** + * Repository host type + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionContextHostType". + */ +/** @experimental */ +export type SessionContextHostType = "github" | "ado"; /** * Error classification * @@ -271,6 +508,63 @@ export type SessionFsSetProviderConventions = "windows" | "posix"; * via the `definition` "SessionFsSqliteQueryType". */ export type SessionFsSqliteQueryType = "exec" | "query" | "run"; +/** + * Source descriptor for direct repo installs (when marketplace is empty) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPluginSource". + */ +/** @experimental */ +export type SessionInstalledPluginSource = + | string + | SessionInstalledPluginSourceGithub + | SessionInstalledPluginSourceUrl + | SessionInstalledPluginSourceLocal; +/** + * Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspaceSummary". + */ +/** @experimental */ +export type WorkspaceSummary = { + /** + * Workspace identifier (1:1 with sessionId) + */ + id: string; + /** + * Current working directory at session start + */ + cwd?: string; + /** + * Resolved git root for cwd, if any + */ + git_root?: string; + /** + * Repository identifier in 'owner/repo' or 'org/project/repo' format, if any + */ + repository?: string; + /** + * Repository host type, if known + */ + host_type?: "github" | "ado"; + /** + * Branch checked out at session start, if any + */ + branch?: string; + /** + * Display name for the session, if set + */ + name?: string; + /** + * ISO 8601 timestamp when the workspace was created + */ + created_at?: string; + /** + * ISO 8601 timestamp when the workspace was last updated + */ + updated_at?: string; +} | null; /** * Signal to send (default: SIGTERM) * @@ -304,6 +598,51 @@ export type TaskStatus = "running" | "idle" | "completed" | "failed" | "cancelle */ /** @experimental */ export type TaskExecutionMode = "sync" | "background"; +/** + * Schema for the `TaskAgentProgress` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TaskAgentProgress". + */ +/** @experimental */ +export type TaskAgentProgress = + | { + /** + * Progress kind + */ + type: "agent"; + /** + * Recent tool execution events converted to display lines + */ + recentActivity: { + /** + * Display message, e.g., "▸ bash", "✓ edit src/foo.ts" + */ + message: string; + /** + * ISO 8601 timestamp when this event occurred + */ + timestamp: string; + }[]; + /** + * The most recent intent reported by the agent + */ + latestIntent?: string; + } + | { + /** + * Progress kind + */ + type: "shell"; + /** + * Recent stdout/stderr lines from the running shell command + */ + recentOutput: string; + /** + * Process ID when available + */ + pid?: number; + }; /** * Schema for the `TaskInfo` type. * @@ -320,6 +659,29 @@ export type TaskInfo = TaskAgentInfo | TaskShellInfo; */ /** @experimental */ export type TaskShellInfoAttachmentMode = "attached" | "detached"; +/** + * Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TaskProgress". + */ +/** @experimental */ +export type TaskProgress = TaskAgentProgress | TaskShellProgress; +/** + * Schema for the `TaskShellProgress` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TaskShellProgress". + */ +/** @experimental */ +export type TaskShellProgress = null; +/** + * User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIAutoModeSwitchResponse". + */ +export type UIAutoModeSwitchResponse = "yes" | "yes_always" | "no"; /** * Schema for the `UIElicitationFieldValue` type. * @@ -365,6 +727,39 @@ export type UIElicitationSchemaPropertyNumberType = "number" | "integer"; * via the `definition` "UIElicitationResponseAction". */ export type UIElicitationResponseAction = "accept" | "decline" | "cancel"; +/** + * The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIExitPlanModeAction". + */ +export type UIExitPlanModeAction = "exit_only" | "interactive" | "autopilot" | "autopilot_fleet"; + +/** + * Parameters for aborting the current turn + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AbortRequest". + */ +export interface AbortRequest { + reason?: AbortReason; +} +/** + * Result of aborting the current turn + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AbortResult". + */ +export interface AbortResult { + /** + * Whether the abort completed successfully + */ + success: boolean; + /** + * Error message if the abort failed + */ + error?: string; +} export interface AccountGetQuotaRequest { /** @@ -463,6 +858,33 @@ export interface AgentInfo { * Absolute local file path of the agent definition. Only set for file-based agents loaded from disk; remote agents do not have a path. */ path?: string; + /** + * Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. + */ + id: string; + source?: AgentInfoSource; + /** + * Whether the agent can be selected directly by the user. Agents marked `false` are subagent-only. + */ + userInvocable?: boolean; + /** + * Allowed tool names for this agent. Empty array means none; omitted means inherit defaults. + */ + tools?: string[]; + /** + * Preferred model id for this agent. When omitted, inherits the outer agent's model. + */ + model?: string; + /** + * MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. + */ + mcpServers?: { + [k: string]: unknown | undefined; + }; + /** + * Skill names preloaded into this agent's context. Omitted means none. + */ + skills?: string[]; } /** * Custom agents available to the session. @@ -514,60 +936,387 @@ export interface AgentSelectResult { agent: AgentInfo; } /** - * Slash commands available in the session, after applying any include/exclude filters. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "CommandList". - */ -export interface CommandList { - /** - * Commands available in this session - */ - commands: SlashCommandInfo[]; -} -/** - * Schema for the `SlashCommandInfo` type. + * Schema for the `ApiKeyAuthInfo` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandInfo". + * via the `definition` "ApiKeyAuthInfo". */ -export interface SlashCommandInfo { - /** - * Canonical command name without a leading slash - */ - name: string; - /** - * Canonical aliases without leading slashes - */ - aliases?: string[]; +export interface ApiKeyAuthInfo { /** - * Human-readable command description + * API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style). */ - description: string; - kind: SlashCommandKind; - input?: SlashCommandInput; + type: "api-key"; /** - * Whether the command may run while an agent turn is active + * The API key. Treat as a secret. */ - allowDuringAgentExecution: boolean; + apiKey: string; /** - * Whether the command is experimental + * Authentication host. */ - experimental?: boolean; + host: string; + copilotUser?: CopilotUserResponse; } /** - * Optional unstructured input hint + * Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandInput". + * via the `definition` "CopilotUserResponse". */ -export interface SlashCommandInput { - /** - * Hint to display when command input has not been provided - */ - hint: string; - /** - * When true, the command requires non-empty input; clients should render the input hint as required +export interface CopilotUserResponse { + login?: string; + access_type_sku?: string; + analytics_tracking_id?: string; + assigned_date?: + | ( + | { + [k: string]: unknown | undefined; + } + | string + ) + | null; + can_signup_for_limited?: boolean; + chat_enabled?: boolean; + copilot_plan?: string; + copilotignore_enabled?: boolean; + endpoints?: CopilotUserResponseEndpoints; + organization_login_list?: string[]; + organization_list?: + | ( + | { + [k: string]: unknown | undefined; + } + | ({ + login?: + | ( + | { + [k: string]: unknown | undefined; + } + | string + ) + | null; + name?: + | ( + | { + [k: string]: unknown | undefined; + } + | string + ) + | null; + } | null)[] + ) + | null; + codex_agent_enabled?: boolean; + is_mcp_enabled?: + | ( + | { + [k: string]: unknown | undefined; + } + | boolean + ) + | null; + quota_reset_date?: string; + quota_snapshots?: CopilotUserResponseQuotaSnapshots; + restricted_telemetry?: boolean; + token_based_billing?: boolean; + quota_reset_date_utc?: string; + limited_user_quotas?: { + [k: string]: number | undefined; + }; + limited_user_reset_date?: string; + monthly_quotas?: { + [k: string]: number | undefined; + }; + cloud_session_storage_enabled?: boolean; + cli_remote_control_enabled?: boolean; +} +/** + * Schema for the `CopilotUserResponseEndpoints` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CopilotUserResponseEndpoints". + */ +export interface CopilotUserResponseEndpoints { + api?: string; + "origin-tracker"?: string; + proxy?: string; + telemetry?: string; +} +/** + * Schema for the `CopilotUserResponseQuotaSnapshots` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CopilotUserResponseQuotaSnapshots". + */ +export interface CopilotUserResponseQuotaSnapshots { + chat?: CopilotUserResponseQuotaSnapshotsChat; + completions?: CopilotUserResponseQuotaSnapshotsCompletions; + premium_interactions?: CopilotUserResponseQuotaSnapshotsPremiumInteractions; + [k: string]: + | ({ + entitlement?: number; + overage_count?: number; + overage_permitted?: boolean; + percent_remaining?: number; + quota_id?: string; + quota_remaining?: number; + remaining?: number; + unlimited?: boolean; + timestamp_utc?: string; + has_quota?: boolean; + quota_reset_at?: number; + token_based_billing?: boolean; + } | null) + | undefined; +} +/** + * Schema for the `CopilotUserResponseQuotaSnapshotsChat` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CopilotUserResponseQuotaSnapshotsChat". + */ +export interface CopilotUserResponseQuotaSnapshotsChat { + entitlement?: number; + overage_count?: number; + overage_permitted?: boolean; + percent_remaining?: number; + quota_id?: string; + quota_remaining?: number; + remaining?: number; + unlimited?: boolean; + timestamp_utc?: string; + has_quota?: boolean; + quota_reset_at?: number; + token_based_billing?: boolean; +} +/** + * Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CopilotUserResponseQuotaSnapshotsCompletions". + */ +export interface CopilotUserResponseQuotaSnapshotsCompletions { + entitlement?: number; + overage_count?: number; + overage_permitted?: boolean; + percent_remaining?: number; + quota_id?: string; + quota_remaining?: number; + remaining?: number; + unlimited?: boolean; + timestamp_utc?: string; + has_quota?: boolean; + quota_reset_at?: number; + token_based_billing?: boolean; +} +/** + * Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CopilotUserResponseQuotaSnapshotsPremiumInteractions". + */ +export interface CopilotUserResponseQuotaSnapshotsPremiumInteractions { + entitlement?: number; + overage_count?: number; + overage_permitted?: boolean; + percent_remaining?: number; + quota_id?: string; + quota_remaining?: number; + remaining?: number; + unlimited?: boolean; + timestamp_utc?: string; + has_quota?: boolean; + quota_reset_at?: number; + token_based_billing?: boolean; +} +/** + * Schema for the `HMACAuthInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HMACAuthInfo". + */ +export interface HMACAuthInfo { + /** + * HMAC-based authentication used by GitHub-internal services. + */ + type: "hmac"; + /** + * Authentication host. HMAC auth always targets the public GitHub host. + */ + host: "https://github.com"; + /** + * HMAC secret used to sign requests. + */ + hmac: string; + copilotUser?: CopilotUserResponse; +} +/** + * Schema for the `EnvAuthInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EnvAuthInfo". + */ +export interface EnvAuthInfo { + /** + * Personal access token (PAT) or server-to-server token sourced from an environment variable. + */ + type: "env"; + /** + * Authentication host (e.g. https://github.com or a GHES host). + */ + host: string; + /** + * User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). + */ + login?: string; + /** + * The token value itself. Treat as a secret. + */ + token: string; + /** + * Name of the environment variable the token was sourced from. + */ + envVar: string; + copilotUser?: CopilotUserResponse; +} +/** + * Schema for the `TokenAuthInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TokenAuthInfo". + */ +export interface TokenAuthInfo { + /** + * SDK-side token authentication; the host configured the token directly via the SDK. + */ + type: "token"; + /** + * Authentication host. + */ + host: string; + /** + * The token value itself. Treat as a secret. + */ + token: string; + copilotUser?: CopilotUserResponse; +} +/** + * Schema for the `CopilotApiTokenAuthInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CopilotApiTokenAuthInfo". + */ +export interface CopilotApiTokenAuthInfo { + /** + * Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` environment-variable pair. The token itself is read from the environment by the runtime, not carried in this struct. + */ + type: "copilot-api-token"; + /** + * Authentication host (always the public GitHub host). + */ + host: "https://github.com"; + copilotUser?: CopilotUserResponse; +} +/** + * Schema for the `UserAuthInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserAuthInfo". + */ +export interface UserAuthInfo { + /** + * OAuth user authentication. The token itself is held in the runtime's secret token store (keyed by host+login) and is NOT carried in this struct. + */ + type: "user"; + /** + * Authentication host. + */ + host: string; + /** + * OAuth user login. + */ + login: string; + copilotUser?: CopilotUserResponse; +} +/** + * Schema for the `GhCliAuthInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "GhCliAuthInfo". + */ +export interface GhCliAuthInfo { + /** + * Authentication via the `gh` CLI's saved credentials. + */ + type: "gh-cli"; + /** + * Authentication host. + */ + host: string; + /** + * User login as reported by `gh auth status`. + */ + login: string; + /** + * The token returned by `gh auth token`. Treat as a secret. + */ + token: string; + copilotUser?: CopilotUserResponse; +} +/** + * Slash commands available in the session, after applying any include/exclude filters. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "CommandList". + */ +export interface CommandList { + /** + * Commands available in this session + */ + commands: SlashCommandInfo[]; +} +/** + * Schema for the `SlashCommandInfo` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SlashCommandInfo". + */ +export interface SlashCommandInfo { + /** + * Canonical command name without a leading slash + */ + name: string; + /** + * Canonical aliases without leading slashes + */ + aliases?: string[]; + /** + * Human-readable command description + */ + description: string; + kind: SlashCommandKind; + input?: SlashCommandInput; + /** + * Whether the command may run while an agent turn is active + */ + allowDuringAgentExecution: boolean; + /** + * Whether the command is experimental + */ + experimental?: boolean; +} +/** + * Optional unstructured input hint + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SlashCommandInput". + */ +export interface SlashCommandInput { + /** + * Hint to display when command input has not been provided + */ + hint: string; + /** + * When true, the command requires non-empty input; clients should render the input hint as required */ required?: boolean; completion?: SlashCommandInputCompletion; @@ -641,14 +1390,14 @@ export interface CommandsListRequest { includeClientCommands?: boolean; } /** - * Queued command request ID and the result indicating whether the client handled it. + * Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "CommandsRespondToQueuedCommandRequest". */ export interface CommandsRespondToQueuedCommandRequest { /** - * Request ID from the queued command event + * Request ID from the `command.queued` event the host is responding to. */ requestId: string; result: QueuedCommandResult; @@ -661,11 +1410,11 @@ export interface CommandsRespondToQueuedCommandRequest { */ export interface QueuedCommandHandled { /** - * The command was handled + * The host actually executed the queued command. */ handled: true; /** - * If true, stop processing remaining queued items + * When true, the runtime will not process subsequent queued commands until a new request comes in. */ stopProcessingQueue?: boolean; } @@ -677,19 +1426,19 @@ export interface QueuedCommandHandled { */ export interface QueuedCommandNotHandled { /** - * The command was not handled + * The host did not execute the queued command. Unblocks the queue without claiming the command was processed (e.g. when the handler threw before completing). */ handled: false; } /** - * Indicates whether the queued-command response was accepted by the session. + * Indicates whether the queued-command response was matched to a pending request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "CommandsRespondToQueuedCommandResult". */ export interface CommandsRespondToQueuedCommandResult { /** - * Whether the response was accepted (false if the requestId was not found or already resolved) + * Whether a pending queued command with the given request ID was found and resolved. False when the request was already resolved, cancelled, or unknown. */ success: boolean; } @@ -809,7 +1558,7 @@ export interface ConnectResult { version: string; } /** - * The currently selected model for the session. + * The currently selected model and reasoning effort for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "CurrentModel". @@ -819,6 +1568,10 @@ export interface CurrentModel { * Currently active model identifier */ modelId?: string; + /** + * Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. + */ + reasoningEffort?: string; } /** * Schema for the `DiscoveredMcpServer` type. @@ -838,6 +1591,129 @@ export interface DiscoveredMcpServer { */ enabled: boolean; } +/** + * Slash-prefixed command string to enqueue for FIFO processing. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EnqueueCommandParams". + */ +export interface EnqueueCommandParams { + /** + * Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO with any in-flight items; if the session is idle, processing kicks off immediately. + */ + command: string; +} +/** + * Indicates whether the command was accepted into the local execution queue. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EnqueueCommandResult". + */ +export interface EnqueueCommandResult { + /** + * True when the command was accepted into the local execution queue. False when the call targets a session that does not support local command queueing (e.g. remote sessions). + */ + queued: boolean; +} +/** + * Cursor, batch size, and optional long-poll/filter parameters for reading session events. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventLogReadRequest". + */ +/** @experimental */ +export interface EventLogReadRequest { + /** + * Opaque cursor returned by a previous read. Omit on the first call to start from the beginning of the session's persisted history. + */ + cursor?: string; + /** + * Maximum number of events to return in this batch (1–1000, default 200). + */ + max?: number; + /** + * Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). + */ + waitMs?: number; + types?: EventLogTypes; + agentScope?: EventsAgentScope; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventLogReleaseInterestResult". + */ +/** @experimental */ +export interface EventLogReleaseInterestResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventLogTailResult". + */ +/** @experimental */ +export interface EventLogTailResult { + /** + * Opaque cursor pointing at the current tail of the session's persisted-events history. Pass back to `read` to receive only events that arrive AFTER this snapshot. When the session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent to omitting the cursor on a first read). + */ + cursor: string; +} +/** + * Batch of session events returned by a read, with cursor and continuation metadata. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "EventsReadResult". + */ +/** @experimental */ +export interface EventsReadResult { + /** + * Events are delivered in two batches per read: persisted events first (in append order), then ephemeral events (in seq order). When `waitMs > 0` and the catch-up batches were empty, post-wait events follow the same two-batch ordering. Persisted and ephemeral events do not interleave within a single read. + */ + events: SessionEvent[]; + /** + * Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. + */ + cursor: string; + /** + * True when the read returned `max` events and more events are available immediately. When false, the next read with a non-zero `waitMs` will block until a new event arrives or the wait expires. + */ + hasMore: boolean; + cursorStatus: EventsCursorStatus; +} +/** + * Slash command name and argument string to execute synchronously. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ExecuteCommandParams". + */ +export interface ExecuteCommandParams { + /** + * Name of the slash command to invoke (without the leading '/'). + */ + commandName: string; + /** + * Argument string to pass to the command (empty string if none). + */ + args: string; +} +/** + * Error message produced while executing the command, if any. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ExecuteCommandResult". + */ +export interface ExecuteCommandResult { + /** + * Error message produced while executing the command, if any. Omitted when the handler succeeded. + */ + error?: string; +} /** * Schema for the `Extension` type. * @@ -1169,6 +2045,32 @@ export interface HandlePendingToolCallResult { */ success: boolean; } +/** + * Indicates whether an in-progress manual compaction was aborted. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HistoryAbortManualCompactionResult". + */ +/** @experimental */ +export interface HistoryAbortManualCompactionResult { + /** + * Whether an in-progress manual compaction was aborted. False when no manual compaction was running, when its abort controller was already aborted, or when the session is remote. + */ + aborted: boolean; +} +/** + * Indicates whether an in-progress background compaction was cancelled. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HistoryCancelBackgroundCompactionResult". + */ +/** @experimental */ +export interface HistoryCancelBackgroundCompactionResult { + /** + * Whether an in-progress background compaction was cancelled. False when no compaction was running, when the session is remote, or when the underlying processor was unavailable. + */ + cancelled: boolean; +} /** * Post-compaction context window usage breakdown * @@ -1203,7 +2105,7 @@ export interface HistoryCompactContextWindow { toolDefinitionsTokens?: number; } /** - * Compaction outcome with the number of tokens and messages removed and the resulting context window breakdown. + * Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "HistoryCompactResult". @@ -1222,13 +2124,30 @@ export interface HistoryCompactResult { * Number of messages removed during compaction */ messagesRemoved: number; + /** + * Summary text produced by compaction. Omitted when compaction did not produce a summary (e.g. failure path). + */ + summaryContent?: string; contextWindow?: HistoryCompactContextWindow; } /** - * Identifier of the event to truncate to; this event and all later events are removed. + * Markdown summary of the conversation context (empty when not available). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HistoryTruncateRequest". + * via the `definition` "HistorySummarizeForHandoffResult". + */ +/** @experimental */ +export interface HistorySummarizeForHandoffResult { + /** + * Markdown summary of the conversation context produced by an LLM. Empty string when there are no messages or when the session does not support local summarization. + */ + summary: string; +} +/** + * Identifier of the event to truncate to; this event and all later events are removed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HistoryTruncateRequest". */ /** @experimental */ export interface HistoryTruncateRequest { @@ -1250,6 +2169,86 @@ export interface HistoryTruncateResult { */ eventsRemoved: number; } +/** + * Schema for the `InstalledPlugin` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstalledPlugin". + */ +/** @experimental */ +export interface InstalledPlugin { + /** + * Plugin name + */ + name: string; + /** + * Marketplace the plugin came from (empty string for direct repo installs) + */ + marketplace: string; + /** + * Version installed (if available) + */ + version?: string; + /** + * Installation timestamp + */ + installed_at: string; + /** + * Whether the plugin is currently enabled + */ + enabled: boolean; + /** + * Path where the plugin is cached locally + */ + cache_path?: string; + source?: InstalledPluginSource; +} +/** + * Schema for the `InstalledPluginSourceGithub` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstalledPluginSourceGithub". + */ +/** @experimental */ +export interface InstalledPluginSourceGithub { + /** + * Constant value. Always "github". + */ + source: "github"; + repo: string; + ref?: string; + path?: string; +} +/** + * Schema for the `InstalledPluginSourceUrl` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstalledPluginSourceUrl". + */ +/** @experimental */ +export interface InstalledPluginSourceUrl { + /** + * Constant value. Always "url". + */ + source: "url"; + url: string; + ref?: string; + path?: string; +} +/** + * Schema for the `InstalledPluginSourceLocal` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstalledPluginSourceLocal". + */ +/** @experimental */ +export interface InstalledPluginSourceLocal { + /** + * Constant value. Always "local". + */ + source: "local"; + path: string; +} /** * Instruction sources loaded for the session, in merge order. * @@ -1288,16 +2287,20 @@ export interface InstructionsSources { type: InstructionsSourcesType; location: InstructionsSourcesLocation; /** - * Glob pattern from frontmatter — when set, this instruction applies only to matching files + * Glob pattern(s) from frontmatter — when set, this instruction applies only to matching files */ - applyTo?: string; + applyTo?: string[]; /** * Short description (body after frontmatter) for use in instruction tables */ description?: string; + /** + * When true, this source starts disabled and must be toggled on by the user + */ + defaultDisabled?: boolean; } /** - * Message text, optional severity level, persistence flag, and optional follow-up URL. + * Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "LogRequest". @@ -1308,6 +2311,10 @@ export interface LogRequest { */ message: string; level?: SessionLogLevel; + /** + * Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". + */ + type?: string; /** * When true, the message is transient and not persisted to the session event log on disk */ @@ -1316,6 +2323,10 @@ export interface LogRequest { * Optional URL the user can open in their browser for more details */ url?: string; + /** + * Optional actionable tip displayed alongside the message. Only honored on `level: "info"`. + */ + tip?: string; } /** * Identifier of the session event that was emitted for the log message. @@ -1329,6 +2340,53 @@ export interface LogResult { */ eventId: string; } +/** + * Parameters for (re)loading the merged LSP configuration set. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "LspInitializeRequest". + */ +/** @experimental */ +export interface LspInitializeRequest { + /** + * Working directory used to load project-level LSP configs. Defaults to the session working directory when omitted. + */ + workingDirectory?: string; + /** + * Git root used as the boundary when traversing for project-level LSP configs (supports monorepos). + */ + gitRoot?: string; + /** + * Force re-initialization even when LSP configs were already loaded for the working directory. + */ + force?: boolean; +} +/** + * The requestId previously passed to executeSampling that should be cancelled. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpCancelSamplingExecutionParams". + */ +/** @experimental */ +export interface McpCancelSamplingExecutionParams { + /** + * The requestId previously passed to executeSampling that should be cancelled + */ + requestId: string; +} +/** + * Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpCancelSamplingExecutionResult". + */ +/** @experimental */ +export interface McpCancelSamplingExecutionResult { + /** + * True if an in-flight execution with the given requestId was found and signalled to cancel. False when no such execution is in flight (already completed, never started, or cancelled by another caller). + */ + cancelled: boolean; +} /** * MCP server name and configuration to add to user configuration. * @@ -1548,6 +2606,48 @@ export interface McpEnableRequest { */ serverName: string; } +/** + * Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpExecuteSamplingParams". + */ +/** @experimental */ +export interface McpExecuteSamplingParams { + /** + * Caller-provided unique identifier for this sampling execution. Use this same ID with cancelSamplingExecution to cancel the in-flight call. Must be unique within the session for the lifetime of the call. + */ + requestId: string; + /** + * Name of the MCP server that initiated the sampling request + */ + serverName: string; + /** + * The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). + */ + mcpRequestId: string | number; + request: McpExecuteSamplingRequest; +} +/** + * Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpExecuteSamplingRequest". + */ +/** @experimental */ +export interface McpExecuteSamplingRequest { + [k: string]: unknown | undefined; +} +/** + * MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpExecuteSamplingResult". + */ +/** @experimental */ +export interface McpExecuteSamplingResult { + [k: string]: unknown | undefined; +} /** * Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, and the callback success-page copy. * @@ -1586,6 +2686,34 @@ export interface McpOauthLoginResult { */ authorizationUrl?: string; } +/** + * Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRemoveGitHubResult". + */ +/** @experimental */ +export interface McpRemoveGitHubResult { + /** + * True when the auto-managed `github` MCP server was removed; false when no removal happened (e.g. user has explicitly configured a `github` server, or the server was not registered). + */ + removed: boolean; +} +/** + * Outcome of an MCP sampling execution: success result, failure error, or cancellation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpSamplingExecutionResult". + */ +/** @experimental */ +export interface McpSamplingExecutionResult { + action: McpSamplingExecutionAction; + result?: McpExecuteSamplingResult; + /** + * Error description, present when action='failure'. + */ + error?: string; +} /** * Schema for the `McpServer` type. * @@ -1619,132 +2747,355 @@ export interface McpServerList { servers: McpServer[]; } /** - * Schema for the `Model` type. + * Mode controlling how MCP server env values are resolved (`direct` or `indirect`). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Model". + * via the `definition` "McpSetEnvValueModeParams". */ -export interface Model { - /** - * Model identifier (e.g., "claude-sonnet-4.5") - */ - id: string; +/** @experimental */ +export interface McpSetEnvValueModeParams { + mode: McpSetEnvValueModeDetails; +} +/** + * Env-value mode recorded on the session after the update. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpSetEnvValueModeResult". + */ +/** @experimental */ +export interface McpSetEnvValueModeResult { + mode: McpSetEnvValueModeDetails; +} +/** + * Model identifier and token limits used to compute the context-info breakdown. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataContextInfoRequest". + */ +/** @experimental */ +export interface MetadataContextInfoRequest { /** - * Display name + * Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default. */ - name: string; - capabilities: ModelCapabilities; - policy?: ModelPolicy; - billing?: ModelBilling; + promptTokenLimit: number; /** - * Supported reasoning effort levels (only present if model supports reasoning effort) + * Maximum output tokens allowed by the target model. Pass 0 if unknown. */ - supportedReasoningEfforts?: string[]; + outputTokenLimit: number; /** - * Default reasoning effort level (only present if model supports reasoning effort) + * Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. */ - defaultReasoningEffort?: string; - modelPickerCategory?: ModelPickerCategory; - modelPickerPriceCategory?: ModelPickerPriceCategory; + selectedModel?: string; } /** - * Model capabilities and limits + * Token breakdown for the session's current context window, or null if uninitialized. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilities". + * via the `definition` "MetadataContextInfoResult". */ -export interface ModelCapabilities { - supports?: ModelCapabilitiesSupports; - limits?: ModelCapabilitiesLimits; +/** @experimental */ +export interface MetadataContextInfoResult { + /** + * Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + */ + contextInfo?: SessionContextInfo | null; } /** - * Feature flags indicating what the model supports + * Indicates whether the local session is currently processing a turn or background continuation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesSupports". + * via the `definition` "MetadataIsProcessingResult". */ -export interface ModelCapabilitiesSupports { +/** @experimental */ +export interface MetadataIsProcessingResult { /** - * Whether this model supports vision/image input + * Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. */ - vision?: boolean; + processing: boolean; +} +/** + * Model identifier to use when re-tokenizing the session's existing messages. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataRecomputeContextTokensRequest". + */ +/** @experimental */ +export interface MetadataRecomputeContextTokensRequest { /** - * Whether this model supports reasoning effort configuration + * Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. */ - reasoningEffort?: boolean; + modelId: string; } /** - * Token limits for prompts, outputs, and context window + * Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesLimits". + * via the `definition` "MetadataRecomputeContextTokensResult". */ -export interface ModelCapabilitiesLimits { +/** @experimental */ +export interface MetadataRecomputeContextTokensResult { /** - * Maximum number of prompt/input tokens + * Sum of tokens across chat-context and system-context messages currently held by the session. */ - max_prompt_tokens?: number; + totalTokens: number; /** - * Maximum number of output/completion tokens + * Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). */ - max_output_tokens?: number; + messagesTokenCount: number; /** - * Maximum total context window size in tokens + * Tokens contributed by system/developer prompt snapshots. */ - max_context_window_tokens?: number; - vision?: ModelCapabilitiesLimitsVision; + systemTokenCount: number; } /** - * Vision-specific limits + * Updated working-directory/git context to record on the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesLimitsVision". + * via the `definition` "MetadataRecordContextChangeRequest". */ -export interface ModelCapabilitiesLimitsVision { +/** @experimental */ +export interface MetadataRecordContextChangeRequest { + context: SessionWorkingDirectoryContext; +} +/** + * Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionWorkingDirectoryContext". + */ +/** @experimental */ +export interface SessionWorkingDirectoryContext { /** - * MIME types the model accepts + * Current working directory path */ - supported_media_types: string[]; + cwd: string; /** - * Maximum number of images per prompt + * Root directory of the git repository, resolved via git rev-parse */ - max_prompt_images: number; + gitRoot?: string; /** - * Maximum image size in bytes + * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) */ - max_prompt_image_size: number; + repository?: string; + hostType?: SessionWorkingDirectoryContextHostType; + /** + * Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com") + */ + repositoryHost?: string; + /** + * Current git branch name + */ + branch?: string; + /** + * Head commit of the current git branch + */ + headCommit?: string; + /** + * Merge-base commit SHA (fork point from the remote default branch) + */ + baseCommit?: string; } /** - * Policy state (if applicable) + * Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelPolicy". + * via the `definition` "MetadataRecordContextChangeResult". */ -export interface ModelPolicy { - state: ModelPolicyState; +/** @experimental */ +export interface MetadataRecordContextChangeResult {} +/** + * Absolute path to set as the session's new working directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataSetWorkingDirectoryRequest". + */ +/** @experimental */ +export interface MetadataSetWorkingDirectoryRequest { /** - * Usage terms or conditions for this model + * Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. */ - terms?: string; + workingDirectory: string; } /** - * Billing information + * Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any related side-effects (file index, etc.); this method only updates the session's own recorded path. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBilling". + * via the `definition` "MetadataSetWorkingDirectoryResult". */ -export interface ModelBilling { +/** @experimental */ +export interface MetadataSetWorkingDirectoryResult { /** - * Billing cost multiplier relative to the base rate + * Working directory after the update */ - multiplier?: number; - tokenPrices?: ModelBillingTokenPrices; + workingDirectory: string; } /** - * Token-level pricing information for this model + * Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBillingTokenPrices". + * via the `definition` "MetadataSnapshotRemoteMetadata". + */ +/** @experimental */ +export interface MetadataSnapshotRemoteMetadata { + /** + * The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. + */ + resourceId?: string; + repository: MetadataSnapshotRemoteMetadataRepository; + /** + * The pull request number the remote session is associated with, if any. + */ + pullRequestNumber?: number; + taskType?: MetadataSnapshotRemoteMetadataTaskType; +} +/** + * The repository the remote session targets. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataSnapshotRemoteMetadataRepository". + */ +/** @experimental */ +export interface MetadataSnapshotRemoteMetadataRepository { + /** + * The GitHub owner (user or organization) of the target repository. + */ + owner: string; + /** + * The GitHub repository name (without owner). + */ + name: string; + /** + * The branch the remote session is operating on. + */ + branch: string; +} +/** + * Schema for the `Model` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "Model". + */ +export interface Model { + /** + * Model identifier (e.g., "claude-sonnet-4.5") + */ + id: string; + /** + * Display name + */ + name: string; + capabilities: ModelCapabilities; + policy?: ModelPolicy; + billing?: ModelBilling; + /** + * Supported reasoning effort levels (only present if model supports reasoning effort) + */ + supportedReasoningEfforts?: string[]; + /** + * Default reasoning effort level (only present if model supports reasoning effort) + */ + defaultReasoningEffort?: string; + modelPickerCategory?: ModelPickerCategory; + modelPickerPriceCategory?: ModelPickerPriceCategory; +} +/** + * Model capabilities and limits + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilities". + */ +export interface ModelCapabilities { + supports?: ModelCapabilitiesSupports; + limits?: ModelCapabilitiesLimits; +} +/** + * Feature flags indicating what the model supports + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesSupports". + */ +export interface ModelCapabilitiesSupports { + /** + * Whether this model supports vision/image input + */ + vision?: boolean; + /** + * Whether this model supports reasoning effort configuration + */ + reasoningEffort?: boolean; +} +/** + * Token limits for prompts, outputs, and context window + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesLimits". + */ +export interface ModelCapabilitiesLimits { + /** + * Maximum number of prompt/input tokens + */ + max_prompt_tokens?: number; + /** + * Maximum number of output/completion tokens + */ + max_output_tokens?: number; + /** + * Maximum total context window size in tokens + */ + max_context_window_tokens?: number; + vision?: ModelCapabilitiesLimitsVision; +} +/** + * Vision-specific limits + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesLimitsVision". + */ +export interface ModelCapabilitiesLimitsVision { + /** + * MIME types the model accepts + */ + supported_media_types: string[]; + /** + * Maximum number of images per prompt + */ + max_prompt_images: number; + /** + * Maximum image size in bytes + */ + max_prompt_image_size: number; +} +/** + * Policy state (if applicable) + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelPolicy". + */ +export interface ModelPolicy { + state: ModelPolicyState; + /** + * Usage terms or conditions for this model + */ + terms?: string; +} +/** + * Billing information + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelBilling". + */ +export interface ModelBilling { + /** + * Billing cost multiplier relative to the base rate + */ + multiplier?: number; + tokenPrices?: ModelBillingTokenPrices; +} +/** + * Token-level pricing information for this model + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelBillingTokenPrices". */ export interface ModelBillingTokenPrices { /** @@ -1843,6 +3194,30 @@ export interface ModelList { */ models: Model[]; } +/** + * Reasoning effort level to apply to the currently selected model. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelSetReasoningEffortRequest". + */ +export interface ModelSetReasoningEffortRequest { + /** + * Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. + */ + reasoningEffort: string; +} +/** + * Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelSetReasoningEffortResult". + */ +export interface ModelSetReasoningEffortResult { + /** + * Reasoning effort level recorded on the session after the update + */ + reasoningEffort: string; +} export interface ModelsListRequest { /** @@ -1901,6 +3276,30 @@ export interface NameGetResult { */ name: string | null; } +/** + * Auto-generated session summary to apply as the session's name when no user-set name exists. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "NameSetAutoRequest". + */ +export interface NameSetAutoRequest { + /** + * Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. + */ + summary: string; +} +/** + * Indicates whether the auto-generated summary was applied as the session's name. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "NameSetAutoResult". + */ +export interface NameSetAutoResult { + /** + * Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. + */ + applied: boolean; +} /** * New friendly name to apply to the session. * @@ -1913,6 +3312,31 @@ export interface NameSetRequest { */ name: string; } +/** + * Schema for the `PendingPermissionRequest` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PendingPermissionRequest". + */ +export interface PendingPermissionRequest { + /** + * Unique identifier for the pending permission request + */ + requestId: string; + request: PermissionPromptRequest; +} +/** + * List of pending permission requests reconstructed from event history. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PendingPermissionRequestList". + */ +export interface PendingPermissionRequestList { + /** + * Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. + */ + items: PendingPermissionRequest[]; +} /** * Schema for the `PermissionDecisionApproveOnce` type. * @@ -1921,7 +3345,7 @@ export interface NameSetRequest { */ export interface PermissionDecisionApproveOnce { /** - * The permission request was approved for this one instance + * Approve this single request only */ kind: "approve-once"; } @@ -1933,12 +3357,12 @@ export interface PermissionDecisionApproveOnce { */ export interface PermissionDecisionApproveForSession { /** - * Approved and remembered for the rest of the session + * Approve and remember for the rest of the session */ kind: "approve-for-session"; approval?: PermissionDecisionApproveForSessionApproval; /** - * The URL domain to approve for this session + * URL domain to approve for the rest of the session (URL prompts only) */ domain?: string; } @@ -2086,12 +3510,12 @@ export interface PermissionDecisionApproveForSessionApprovalExtensionPermissionA */ export interface PermissionDecisionApproveForLocation { /** - * Approved and persisted for this project location + * Approve and persist for this project location */ kind: "approve-for-location"; approval: PermissionDecisionApproveForLocationApproval; /** - * The location key (git root or cwd) to persist the approval to + * Location key (git root or cwd) to persist the approval to */ locationKey: string; } @@ -2239,11 +3663,11 @@ export interface PermissionDecisionApproveForLocationApprovalExtensionPermission */ export interface PermissionDecisionApprovePermanently { /** - * Approved and persisted across sessions + * Approve and persist across sessions (URL prompts only) */ kind: "approve-permanently"; /** - * The URL domain to approve permanently + * URL domain to approve permanently */ domain: string; } @@ -2255,11 +3679,11 @@ export interface PermissionDecisionApprovePermanently { */ export interface PermissionDecisionReject { /** - * Denied by the user during an interactive prompt + * Reject the request */ kind: "reject"; /** - * Optional feedback from the user explaining the denial + * Optional feedback explaining the rejection */ feedback?: string; } @@ -2271,738 +3695,2513 @@ export interface PermissionDecisionReject { */ export interface PermissionDecisionUserNotAvailable { /** - * Denied because user confirmation was unavailable + * No user is available to confirm the request */ kind: "user-not-available"; } /** - * Pending permission request ID and the decision to apply (approve/reject and scope). + * Schema for the `PermissionDecisionApproved` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionRequest". + * via the `definition` "PermissionDecisionApproved". */ -export interface PermissionDecisionRequest { +export interface PermissionDecisionApproved { /** - * Request ID of the pending permission request + * The permission request was approved */ - requestId: string; - result: PermissionDecision; + kind: "approved"; } /** - * Indicates whether the permission decision was applied; false when the request was already resolved. + * Schema for the `PermissionDecisionApprovedForSession` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionRequestResult". + * via the `definition` "PermissionDecisionApprovedForSession". */ -export interface PermissionRequestResult { +export interface PermissionDecisionApprovedForSession { /** - * Whether the permission request was handled successfully + * Approved and remembered for the rest of the session */ - success: boolean; + kind: "approved-for-session"; + approval: UserToolSessionApproval; } /** - * No parameters; clears all session-scoped tool permission approvals. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsResetSessionApprovalsRequest". - */ -export interface PermissionsResetSessionApprovalsRequest {} -/** - * Indicates whether the operation succeeded. + * Schema for the `PermissionDecisionApprovedForLocation` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsResetSessionApprovalsResult". + * via the `definition` "PermissionDecisionApprovedForLocation". */ -export interface PermissionsResetSessionApprovalsResult { +export interface PermissionDecisionApprovedForLocation { /** - * Whether the operation succeeded + * Approved and persisted for this project location */ - success: boolean; + kind: "approved-for-location"; + approval: UserToolSessionApproval; + /** + * The location key (git root or cwd) to persist the approval to + */ + locationKey: string; } /** - * Whether to auto-approve all tool permission requests for the rest of the session. + * Schema for the `PermissionDecisionCancelled` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllRequest". + * via the `definition` "PermissionDecisionCancelled". */ -export interface PermissionsSetApproveAllRequest { +export interface PermissionDecisionCancelled { /** - * Whether to auto-approve all tool permission requests + * The permission request was cancelled before a response was used */ - enabled: boolean; + kind: "cancelled"; + /** + * Optional explanation of why the request was cancelled + */ + reason?: string; } /** - * Indicates whether the operation succeeded. + * Schema for the `PermissionDecisionDeniedByRules` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllResult". + * via the `definition` "PermissionDecisionDeniedByRules". */ -export interface PermissionsSetApproveAllResult { +export interface PermissionDecisionDeniedByRules { /** - * Whether the operation succeeded + * Denied because approval rules explicitly blocked it */ - success: boolean; + kind: "denied-by-rules"; + /** + * Rules that denied the request + */ + rules: PermissionRule[]; } /** - * Optional message to echo back to the caller. + * Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PingRequest". + * via the `definition` "PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser". */ -export interface PingRequest { +export interface PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser { /** - * Optional message to echo back + * Denied because no approval rule matched and user confirmation was unavailable */ - message?: string; + kind: "denied-no-approval-rule-and-could-not-request-from-user"; } /** - * Server liveness response, including the echoed message, current timestamp, and protocol version. + * Schema for the `PermissionDecisionDeniedInteractivelyByUser` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PingResult". + * via the `definition` "PermissionDecisionDeniedInteractivelyByUser". */ -export interface PingResult { +export interface PermissionDecisionDeniedInteractivelyByUser { /** - * Echoed message (or default greeting) + * Denied by the user during an interactive prompt */ - message: string; + kind: "denied-interactively-by-user"; /** - * Server timestamp in milliseconds + * Optional feedback from the user explaining the denial */ - timestamp: number; + feedback?: string; /** - * Server protocol version number + * Whether to force-reject the current agent turn */ - protocolVersion: number; + forceReject?: boolean; } /** - * Existence, contents, and resolved path of the session plan file. + * Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanReadResult". + * via the `definition` "PermissionDecisionDeniedByContentExclusionPolicy". */ -export interface PlanReadResult { - /** - * Whether the plan file exists in the workspace - */ - exists: boolean; +export interface PermissionDecisionDeniedByContentExclusionPolicy { /** - * The content of the plan file, or null if it does not exist + * Denied by the organization's content exclusion policy */ - content: string | null; + kind: "denied-by-content-exclusion-policy"; /** - * Absolute file path of the plan file, or null if workspace is not enabled + * File path that triggered the exclusion */ - path: string | null; -} -/** - * Replacement contents to write to the session plan file. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanUpdateRequest". - */ -export interface PlanUpdateRequest { + path: string; /** - * The new content for the plan file + * Human-readable explanation of why the path was excluded */ - content: string; + message: string; } /** - * Schema for the `Plugin` type. + * Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Plugin". + * via the `definition` "PermissionDecisionDeniedByPermissionRequestHook". */ -/** @experimental */ -export interface Plugin { - /** - * Plugin name - */ - name: string; +export interface PermissionDecisionDeniedByPermissionRequestHook { /** - * Marketplace the plugin came from + * Denied by a permission request hook registered by an extension or plugin */ - marketplace: string; + kind: "denied-by-permission-request-hook"; /** - * Installed version + * Optional message from the hook explaining the denial */ - version?: string; + message?: string; /** - * Whether the plugin is currently enabled + * Whether to interrupt the current agent turn */ - enabled: boolean; + interrupt?: boolean; } /** - * Plugins installed for the session, with their enabled state and version metadata. + * Pending permission request ID and the decision to apply (approve/reject and scope). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginList". + * via the `definition` "PermissionDecisionRequest". */ -/** @experimental */ -export interface PluginList { +export interface PermissionDecisionRequest { /** - * Installed plugins + * Request ID of the pending permission request */ - plugins: Plugin[]; + requestId: string; + result: PermissionDecision; } /** - * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. + * Directory path to add to the session's allowed directories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteEnableRequest". + * via the `definition` "PermissionPathsAddParams". */ -/** @experimental */ -export interface RemoteEnableRequest { - mode?: RemoteSessionMode; +export interface PermissionPathsAddParams { + /** + * Directory to add to the allow-list. The runtime resolves and validates the path before adding. + */ + path: string; } /** - * GitHub URL for the session and a flag indicating whether remote steering is enabled. + * Path to evaluate against the session's allowed directories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteEnableResult". + * via the `definition` "PermissionPathsAllowedCheckParams". */ -/** @experimental */ -export interface RemoteEnableResult { - /** - * GitHub frontend URL for this session - */ - url?: string; +export interface PermissionPathsAllowedCheckParams { /** - * Whether remote steering is enabled + * Path to check against the session's allowed directories */ - remoteSteerable: boolean; + path: string; } /** - * Remote session connection result. + * Indicates whether the supplied path is within the session's allowed directories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteSessionConnectionResult". + * via the `definition` "PermissionPathsAllowedCheckResult". */ -/** @experimental */ -export interface RemoteSessionConnectionResult { +export interface PermissionPathsAllowedCheckResult { /** - * SDK session ID for the connected remote session. + * Whether the path is within the session's allowed directories */ - sessionId: string; - metadata: ConnectedRemoteSessionMetadata; + allowed: boolean; } /** - * Schema for the `ServerSkill` type. + * If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerSkill". + * via the `definition` "PermissionPathsConfig". */ -export interface ServerSkill { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Description of what the skill does - */ - description: string; - source: SkillSource; +export interface PermissionPathsConfig { /** - * Whether the skill can be invoked by the user as a slash command + * If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. */ - userInvocable: boolean; + unrestricted?: boolean; /** - * Whether the skill is currently enabled (based on global config) + * Additional directories to allow tool access to (in addition to the session's working directory). When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). */ - enabled: boolean; + additionalDirectories?: string[]; /** - * Absolute path to the skill file + * Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. */ - path?: string; + includeTempDirectory?: boolean; /** - * The project path this skill belongs to (only for project/inherited skills) + * Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. */ - projectPath?: string; + workspacePath?: string; } /** - * Skills discovered across global and project sources. + * Snapshot of the session's allow-listed directories and primary working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerSkillList". + * via the `definition` "PermissionPathsList". */ -export interface ServerSkillList { +export interface PermissionPathsList { /** - * All discovered skills across all sources + * All directories currently allowed for tool access on this session. */ - skills: ServerSkill[]; + directories: string[]; + /** + * The primary working directory for this session. + */ + primary: string; } /** - * Authentication status and account metadata for the session. + * Directory path to set as the session's new primary working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionAuthStatus". + * via the `definition` "PermissionPathsUpdatePrimaryParams". */ -export interface SessionAuthStatus { - /** - * Whether the session has resolved authentication - */ - isAuthenticated: boolean; - authType?: AuthInfoType; - /** - * Authentication host URL - */ - host?: string; - /** - * Authenticated login/username, if available - */ - login?: string; - /** - * Human-readable authentication status description - */ - statusMessage?: string; +export interface PermissionPathsUpdatePrimaryParams { /** - * Copilot plan tier (e.g., individual_pro, business) + * Directory to set as the new primary working directory for the session's permission policy. */ - copilotPlan?: string; + path: string; } /** - * File path, content to append, and optional mode for the client-provided session filesystem. + * Path to evaluate against the session's workspace (primary) directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsAppendFileRequest". + * via the `definition` "PermissionPathsWorkspaceCheckParams". */ -export interface SessionFsAppendFileRequest { +export interface PermissionPathsWorkspaceCheckParams { /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions + * Path to check against the session workspace directory */ path: string; - /** - * Content to append - */ - content: string; - /** - * Optional POSIX-style mode for newly created files - */ - mode?: number; } /** - * Describes a filesystem error. + * Indicates whether the supplied path is within the session's workspace directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsError". + * via the `definition` "PermissionPathsWorkspaceCheckResult". */ -export interface SessionFsError { - code: SessionFsErrorCode; +export interface PermissionPathsWorkspaceCheckResult { /** - * Free-form detail about the error, for logging/diagnostics + * Whether the path is within the session workspace directory */ - message?: string; + allowed: boolean; } /** - * Path to test for existence in the client-provided session filesystem. + * Notification payload describing the permission prompt that the client just rendered. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsExistsRequest". + * via the `definition` "PermissionPromptShownNotification". */ -export interface SessionFsExistsRequest { - /** - * Target session identifier - */ - sessionId: string; +export interface PermissionPromptShownNotification { /** - * Path using SessionFs conventions + * Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). */ - path: string; + message: string; } /** - * Indicates whether the requested path exists in the client-provided session filesystem. + * Indicates whether the permission decision was applied; false when the request was already resolved. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsExistsResult". + * via the `definition` "PermissionRequestResult". */ -export interface SessionFsExistsResult { +export interface PermissionRequestResult { /** - * Whether the path exists + * Whether the permission request was handled successfully */ - exists: boolean; + success: boolean; } /** - * Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. + * If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsMkdirRequest". + * via the `definition` "PermissionRulesSet". */ -export interface SessionFsMkdirRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; +export interface PermissionRulesSet { /** - * Create parent directories as needed + * Rules that auto-approve matching requests */ - recursive?: boolean; + approved: PermissionRule[]; /** - * Optional POSIX-style mode for newly created directories + * Rules that auto-deny matching requests */ - mode?: number; + denied: PermissionRule[]; } /** - * Directory path whose entries should be listed from the client-provided session filesystem. + * Schema for the `PermissionsConfigureAdditionalContentExclusionPolicy` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirRequest". + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicy". */ -export interface SessionFsReaddirRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; +export interface PermissionsConfigureAdditionalContentExclusionPolicy { + rules: PermissionsConfigureAdditionalContentExclusionPolicyRule[]; + last_updated_at: string | number; + scope: PermissionsConfigureAdditionalContentExclusionPolicyScope; + [k: string]: unknown | undefined; } /** - * Names of entries in the requested directory, or a filesystem error if the read failed. + * Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRule` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirResult". + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRule". */ -export interface SessionFsReaddirResult { - /** - * Entry names in the directory - */ - entries: string[]; - error?: SessionFsError; +export interface PermissionsConfigureAdditionalContentExclusionPolicyRule { + paths: string[]; + ifAnyMatch?: string[]; + ifNoneMatch?: string[]; + source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource; + [k: string]: unknown | undefined; } /** - * Schema for the `SessionFsReaddirWithTypesEntry` type. + * Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesEntry". + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRuleSource". */ -export interface SessionFsReaddirWithTypesEntry { - /** - * Entry name - */ +export interface PermissionsConfigureAdditionalContentExclusionPolicyRuleSource { name: string; - type: SessionFsReaddirWithTypesEntryType; + type: string; } /** - * Directory path whose entries (with type information) should be listed from the client-provided session filesystem. + * Patch of permission policy fields to apply (omit a field to leave it unchanged). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesRequest". + * via the `definition` "PermissionsConfigureParams". */ -export interface SessionFsReaddirWithTypesRequest { +export interface PermissionsConfigureParams { /** - * Target session identifier + * If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. */ - sessionId: string; + approveAllToolPermissionRequests?: boolean; /** - * Path using SessionFs conventions + * If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. */ - path: string; -} -/** - * Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesResult". - */ -export interface SessionFsReaddirWithTypesResult { + approveAllReadPermissionRequests?: boolean; + rules?: PermissionRulesSet; + paths?: PermissionPathsConfig; + urls?: PermissionUrlsConfig; /** - * Directory entries with type information + * If specified, replaces the host-supplied GitHub Content Exclusion policies on the session (combined with natively-discovered policies when evaluating tool/file access). Omit to leave the current policies unchanged. */ - entries: SessionFsReaddirWithTypesEntry[]; - error?: SessionFsError; + additionalContentExclusionPolicies?: PermissionsConfigureAdditionalContentExclusionPolicy[]; } /** - * Path of the file to read from the client-provided session filesystem. + * If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileRequest". + * via the `definition` "PermissionUrlsConfig". */ -export interface SessionFsReadFileRequest { +export interface PermissionUrlsConfig { /** - * Target session identifier + * If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. */ - sessionId: string; + unrestricted?: boolean; /** - * Path using SessionFs conventions + * Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. */ - path: string; + initialAllowed?: string[]; } /** - * File content as a UTF-8 string, or a filesystem error if the read failed. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileResult". + * via the `definition` "PermissionsConfigureResult". */ -export interface SessionFsReadFileResult { +export interface PermissionsConfigureResult { /** - * File content as UTF-8 string + * Whether the operation succeeded */ - content: string; - error?: SessionFsError; + success: boolean; } /** - * Source and destination paths for renaming or moving an entry in the client-provided session filesystem. + * Scope and add/remove instructions for modifying session- or location-scoped permission rules. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsRenameRequest". + * via the `definition` "PermissionsModifyRulesParams". */ -export interface SessionFsRenameRequest { +export interface PermissionsModifyRulesParams { + scope: PermissionsModifyRulesScope; /** - * Target session identifier + * Rules to add to the scope. Applied before `remove`/`removeAll`. */ - sessionId: string; + add?: PermissionRule[]; /** - * Source path using SessionFs conventions + * Specific rules to remove from the scope. Ignored when `removeAll` is true. */ - src: string; + remove?: PermissionRule[]; /** - * Destination path using SessionFs conventions + * When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. */ - dest: string; + removeAll?: boolean; } /** - * Path to remove from the client-provided session filesystem, with options for recursive removal and force. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsRmRequest". + * via the `definition` "PermissionsModifyRulesResult". + */ +export interface PermissionsModifyRulesResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsNotifyPromptShownResult". + */ +export interface PermissionsNotifyPromptShownResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsPathsAddResult". + */ +export interface PermissionsPathsAddResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * No parameters; returns the session's allow-listed directories. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsPathsListRequest". + */ +export interface PermissionsPathsListRequest {} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsPathsUpdatePrimaryResult". + */ +export interface PermissionsPathsUpdatePrimaryResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * No parameters; returns currently-pending permission requests for the session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsPendingRequestsRequest". + */ +export interface PermissionsPendingRequestsRequest {} +/** + * No parameters; clears all session-scoped tool permission approvals. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsResetSessionApprovalsRequest". + */ +export interface PermissionsResetSessionApprovalsRequest {} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsResetSessionApprovalsResult". + */ +export interface PermissionsResetSessionApprovalsResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Allow-all toggle for tool permission requests, with an optional telemetry source. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsSetApproveAllRequest". + */ +export interface PermissionsSetApproveAllRequest { + /** + * Whether to auto-approve all tool permission requests + */ + enabled: boolean; + source?: PermissionsSetApproveAllSource; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsSetApproveAllResult". + */ +export interface PermissionsSetApproveAllResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Toggles whether permission prompts should be bridged into session events for this client. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsSetRequiredRequest". + */ +export interface PermissionsSetRequiredRequest { + /** + * Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). + */ + required: boolean; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsSetRequiredResult". + */ +export interface PermissionsSetRequiredResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsUrlsSetUnrestrictedModeResult". + */ +export interface PermissionsUrlsSetUnrestrictedModeResult { + /** + * Whether the operation succeeded + */ + success: boolean; +} +/** + * Whether the URL-permission policy should run in unrestricted mode. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionUrlsSetUnrestrictedModeParams". + */ +export interface PermissionUrlsSetUnrestrictedModeParams { + /** + * Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. + */ + enabled: boolean; +} +/** + * Optional message to echo back to the caller. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PingRequest". + */ +export interface PingRequest { + /** + * Optional message to echo back + */ + message?: string; +} +/** + * Server liveness response, including the echoed message, current server timestamp, and protocol version. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PingResult". + */ +export interface PingResult { + /** + * Echoed message (or default greeting) + */ + message: string; + /** + * ISO 8601 timestamp when the server handled the ping + */ + timestamp: string; + /** + * Server protocol version number + */ + protocolVersion: number; +} +/** + * Existence, contents, and resolved path of the session plan file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PlanReadResult". + */ +export interface PlanReadResult { + /** + * Whether the plan file exists in the workspace + */ + exists: boolean; + /** + * The content of the plan file, or null if it does not exist + */ + content: string | null; + /** + * Absolute file path of the plan file, or null if workspace is not enabled + */ + path: string | null; +} +/** + * Replacement contents to write to the session plan file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PlanUpdateRequest". + */ +export interface PlanUpdateRequest { + /** + * The new content for the plan file + */ + content: string; +} +/** + * Schema for the `Plugin` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "Plugin". + */ +/** @experimental */ +export interface Plugin { + /** + * Plugin name + */ + name: string; + /** + * Marketplace the plugin came from + */ + marketplace: string; + /** + * Installed version + */ + version?: string; + /** + * Whether the plugin is currently enabled + */ + enabled: boolean; +} +/** + * Plugins installed for the session, with their enabled state and version metadata. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PluginList". + */ +/** @experimental */ +export interface PluginList { + /** + * Installed plugins + */ + plugins: Plugin[]; +} +/** + * Schema for the `QueuePendingItems` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueuePendingItems". + */ +/** @experimental */ +export interface QueuePendingItems { + kind: QueuePendingItemsKind; + /** + * Human-readable text to display for this queue entry in the UI + */ + displayText: string; +} +/** + * Snapshot of the session's pending queued items and immediate-steering messages. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueuePendingItemsResult". + */ +/** @experimental */ +export interface QueuePendingItemsResult { + /** + * Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. + */ + items: QueuePendingItems[]; + /** + * Display text for messages currently in the immediate steering queue (interjections sent during a running turn). + */ + steeringMessages: string[]; +} +/** + * Indicates whether a user-facing pending item was removed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueueRemoveMostRecentResult". + */ +/** @experimental */ +export interface QueueRemoveMostRecentResult { + /** + * True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. + */ + removed: boolean; +} +/** + * Event type to register consumer interest for, used by runtime gating logic. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RegisterEventInterestParams". + */ +/** @experimental */ +export interface RegisterEventInterestParams { + /** + * The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates the full interactive OAuth flow to the consumer; when no interest is registered the runtime installs a browserless fallback that silently reuses cached tokens). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. + */ + eventType: string; +} +/** + * Opaque handle representing an event-type interest registration. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RegisterEventInterestResult". + */ +/** @experimental */ +export interface RegisterEventInterestResult { + /** + * Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. + */ + handle: string; +} +/** + * Opaque handle previously returned by `registerInterest` to release. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ReleaseEventInterestParams". + */ +/** @experimental */ +export interface ReleaseEventInterestParams { + /** + * Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. + */ + handle: string; +} +/** + * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteEnableRequest". + */ +/** @experimental */ +export interface RemoteEnableRequest { + mode?: RemoteSessionMode; +} +/** + * GitHub URL for the session and a flag indicating whether remote steering is enabled. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteEnableResult". + */ +/** @experimental */ +export interface RemoteEnableResult { + /** + * GitHub frontend URL for this session + */ + url?: string; + /** + * Whether remote steering is enabled + */ + remoteSteerable: boolean; +} +/** + * New remote-steerability state to persist as a `session.remote_steerable_changed` event. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteNotifySteerableChangedRequest". + */ +/** @experimental */ +export interface RemoteNotifySteerableChangedRequest { + /** + * Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. + */ + remoteSteerable: boolean; +} +/** + * Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteNotifySteerableChangedResult". + */ +/** @experimental */ +export interface RemoteNotifySteerableChangedResult {} +/** + * Remote session connection result. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteSessionConnectionResult". + */ +/** @experimental */ +export interface RemoteSessionConnectionResult { + /** + * SDK session ID for the connected remote session. + */ + sessionId: string; + metadata: ConnectedRemoteSessionMetadata; +} +/** + * Schema for the `ScheduleEntry` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ScheduleEntry". + */ +/** @experimental */ +export interface ScheduleEntry { + /** + * Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). + */ + id: number; + /** + * Interval between scheduled ticks, in milliseconds. + */ + intervalMs: number; + /** + * Prompt text that gets enqueued on every tick. + */ + prompt: string; + /** + * Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). + */ + recurring: boolean; + /** + * Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. + */ + displayPrompt?: string; + /** + * ISO 8601 timestamp when the next tick is scheduled to fire. + */ + nextRunAt: string; +} +/** + * Snapshot of the currently active recurring prompts for this session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ScheduleList". + */ +/** @experimental */ +export interface ScheduleList { + /** + * Active scheduled prompts, ordered by id. + */ + entries: ScheduleEntry[]; +} +/** + * Identifier of the scheduled prompt to remove. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ScheduleStopRequest". + */ +/** @experimental */ +export interface ScheduleStopRequest { + /** + * Id of the scheduled prompt to remove. + */ + id: number; +} +/** + * Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ScheduleStopResult". + */ +/** @experimental */ +export interface ScheduleStopResult { + entry?: ScheduleEntry; +} +/** + * File attachment + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentFile". + */ +export interface SendAttachmentFile { + /** + * Attachment type discriminator + */ + type: "file"; + /** + * Absolute file path + */ + path: string; + /** + * User-facing display name for the attachment + */ + displayName: string; + lineRange?: SendAttachmentFileLineRange; +} +/** + * Optional line range to scope the attachment to a specific section of the file + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentFileLineRange". + */ +export interface SendAttachmentFileLineRange { + /** + * Start line number (1-based) + */ + start: number; + /** + * End line number (1-based, inclusive) + */ + end: number; +} +/** + * Directory attachment + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentDirectory". + */ +export interface SendAttachmentDirectory { + /** + * Attachment type discriminator + */ + type: "directory"; + /** + * Absolute directory path + */ + path: string; + /** + * User-facing display name for the attachment + */ + displayName: string; +} +/** + * Code selection attachment from an editor + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentSelection". + */ +export interface SendAttachmentSelection { + /** + * Attachment type discriminator + */ + type: "selection"; + /** + * Absolute path to the file containing the selection + */ + filePath: string; + /** + * User-facing display name for the selection + */ + displayName: string; + /** + * The selected text content + */ + text: string; + selection: SendAttachmentSelectionDetails; +} +/** + * Position range of the selection within the file + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentSelectionDetails". + */ +export interface SendAttachmentSelectionDetails { + start: SendAttachmentSelectionDetailsStart; + end: SendAttachmentSelectionDetailsEnd; +} +/** + * Start position of the selection + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentSelectionDetailsStart". + */ +export interface SendAttachmentSelectionDetailsStart { + /** + * Start line number (0-based) + */ + line: number; + /** + * Start character offset within the line (0-based) + */ + character: number; +} +/** + * End position of the selection + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentSelectionDetailsEnd". + */ +export interface SendAttachmentSelectionDetailsEnd { + /** + * End line number (0-based) + */ + line: number; + /** + * End character offset within the line (0-based) + */ + character: number; +} +/** + * GitHub issue, pull request, or discussion reference + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentGithubReference". + */ +export interface SendAttachmentGithubReference { + /** + * Attachment type discriminator + */ + type: "github_reference"; + /** + * Issue, pull request, or discussion number + */ + number: number; + /** + * Title of the referenced item + */ + title: string; + referenceType: SendAttachmentGithubReferenceType; + /** + * Current state of the referenced item (e.g., open, closed, merged) + */ + state: string; + /** + * URL to the referenced item on GitHub + */ + url: string; +} +/** + * Blob attachment with inline base64-encoded data + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendAttachmentBlob". + */ +export interface SendAttachmentBlob { + /** + * Attachment type discriminator + */ + type: "blob"; + /** + * Base64-encoded content + */ + data: string; + /** + * MIME type of the inline data + */ + mimeType: string; + /** + * User-facing display name for the attachment + */ + displayName?: string; +} +/** + * Parameters for sending a user message to the session + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendRequest". + */ +export interface SendRequest { + /** + * The user message text + */ + prompt: string; + /** + * If provided, this is shown in the timeline instead of `prompt` + */ + displayPrompt?: string; + /** + * Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message + */ + attachments?: SendAttachment[]; + mode?: SendMode; + /** + * If true, adds the message to the front of the queue instead of the end + */ + prepend?: boolean; + /** + * If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + */ + billable?: boolean; + /** + * If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange + */ + requiredTool?: string; + /** + * Optional provenance tag copied to the resulting user.message event. Supported values are `system`, `command-*`, and `schedule-*`. + */ + source?: { + [k: string]: unknown | undefined; + }; + agentMode?: SendAgentMode; + /** + * Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. + */ + requestHeaders?: { + [k: string]: string | undefined; + }; + /** + * W3C Trace Context traceparent header for distributed tracing of this agent turn + */ + traceparent?: string; + /** + * W3C Trace Context tracestate header for distributed tracing + */ + tracestate?: string; + /** + * If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. + */ + wait?: boolean; +} +/** + * Result of sending a user message + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendResult". + */ +export interface SendResult { + /** + * Unique identifier assigned to the message + */ + messageId: string; +} +/** + * Schema for the `ServerSkill` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ServerSkill". + */ +export interface ServerSkill { + /** + * Unique identifier for the skill + */ + name: string; + /** + * Description of what the skill does + */ + description: string; + source: SkillSource; + /** + * Whether the skill can be invoked by the user as a slash command + */ + userInvocable: boolean; + /** + * Whether the skill is currently enabled (based on global config) + */ + enabled: boolean; + /** + * Absolute path to the skill file + */ + path?: string; + /** + * The project path this skill belongs to (only for project/inherited skills) + */ + projectPath?: string; +} +/** + * Skills discovered across global and project sources. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ServerSkillList". + */ +export interface ServerSkillList { + /** + * All discovered skills across all sources + */ + skills: ServerSkill[]; +} +/** + * Authentication status and account metadata for the session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionAuthStatus". + */ +export interface SessionAuthStatus { + /** + * Whether the session has resolved authentication + */ + isAuthenticated: boolean; + authType?: AuthInfoType; + /** + * Authentication host URL + */ + host?: string; + /** + * Authenticated login/username, if available + */ + login?: string; + /** + * Human-readable authentication status description + */ + statusMessage?: string; + /** + * Copilot plan tier (e.g., individual_pro, business) + */ + copilotPlan?: string; +} +/** + * Map of sessionId -> bytes freed by removing the session's workspace directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionBulkDeleteResult". + */ +/** @experimental */ +export interface SessionBulkDeleteResult { + /** + * Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). + */ + freedBytes: { + [k: string]: number | undefined; + }; +} +/** + * Schema for the `SessionContext` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionContext". + */ +/** @experimental */ +export interface SessionContext { + /** + * Most recent working directory for this session + */ + cwd: string; + /** + * Git repository root, if the cwd was inside a git repo + */ + gitRoot?: string; + /** + * Repository slug in `owner/name` form, when known + */ + repository?: string; + hostType?: SessionContextHostType; + /** + * Active git branch + */ + branch?: string; +} +/** + * The same metadata records, with summary and context fields backfilled where available. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionEnrichMetadataResult". + */ +/** @experimental */ +export interface SessionEnrichMetadataResult { + /** + * Same records, with summary and context backfilled + */ + sessions: SessionMetadata[]; +} +/** + * Schema for the `SessionMetadata` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMetadata". + */ +/** @experimental */ +export interface SessionMetadata { + /** + * Stable session identifier + */ + sessionId: string; + /** + * Session creation time as an ISO 8601 timestamp + */ + startTime: string; + /** + * Last-modified time of the session's persisted state, as ISO 8601 + */ + modifiedTime: string; + /** + * Short summary of the session, when one has been derived + */ + summary?: string; + /** + * Optional human-friendly name set via /rename + */ + name?: string; + /** + * True for remote (GitHub) sessions; false for local + */ + isRemote: boolean; + context?: SessionContext; + /** + * GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. + */ + mcTaskId?: string; +} +/** + * File path, content to append, and optional mode for the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsAppendFileRequest". + */ +export interface SessionFsAppendFileRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; + /** + * Content to append + */ + content: string; + /** + * Optional POSIX-style mode for newly created files + */ + mode?: number; +} +/** + * Describes a filesystem error. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsError". + */ +export interface SessionFsError { + code: SessionFsErrorCode; + /** + * Free-form detail about the error, for logging/diagnostics + */ + message?: string; +} +/** + * Path to test for existence in the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsExistsRequest". + */ +export interface SessionFsExistsRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; +} +/** + * Indicates whether the requested path exists in the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsExistsResult". + */ +export interface SessionFsExistsResult { + /** + * Whether the path exists + */ + exists: boolean; +} +/** + * Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsMkdirRequest". + */ +export interface SessionFsMkdirRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; + /** + * Create parent directories as needed + */ + recursive?: boolean; + /** + * Optional POSIX-style mode for newly created directories + */ + mode?: number; +} +/** + * Directory path whose entries should be listed from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirRequest". + */ +export interface SessionFsReaddirRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; +} +/** + * Names of entries in the requested directory, or a filesystem error if the read failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirResult". + */ +export interface SessionFsReaddirResult { + /** + * Entry names in the directory + */ + entries: string[]; + error?: SessionFsError; +} +/** + * Schema for the `SessionFsReaddirWithTypesEntry` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirWithTypesEntry". + */ +export interface SessionFsReaddirWithTypesEntry { + /** + * Entry name + */ + name: string; + type: SessionFsReaddirWithTypesEntryType; +} +/** + * Directory path whose entries (with type information) should be listed from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirWithTypesRequest". + */ +export interface SessionFsReaddirWithTypesRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; +} +/** + * Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirWithTypesResult". + */ +export interface SessionFsReaddirWithTypesResult { + /** + * Directory entries with type information + */ + entries: SessionFsReaddirWithTypesEntry[]; + error?: SessionFsError; +} +/** + * Path of the file to read from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReadFileRequest". + */ +export interface SessionFsReadFileRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; +} +/** + * File content as a UTF-8 string, or a filesystem error if the read failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReadFileResult". + */ +export interface SessionFsReadFileResult { + /** + * File content as UTF-8 string + */ + content: string; + error?: SessionFsError; +} +/** + * Source and destination paths for renaming or moving an entry in the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsRenameRequest". + */ +export interface SessionFsRenameRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Source path using SessionFs conventions + */ + src: string; + /** + * Destination path using SessionFs conventions + */ + dest: string; +} +/** + * Path to remove from the client-provided session filesystem, with options for recursive removal and force. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsRmRequest". */ export interface SessionFsRmRequest { /** - * Target session identifier + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; + /** + * Remove directories and their contents recursively + */ + recursive?: boolean; + /** + * Ignore errors if the path does not exist + */ + force?: boolean; +} +/** + * Optional capabilities declared by the provider + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSetProviderCapabilities". + */ +export interface SessionFsSetProviderCapabilities { + /** + * Whether the provider supports SQLite query/exists operations + */ + sqlite?: boolean; +} +/** + * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSetProviderRequest". + */ +export interface SessionFsSetProviderRequest { + /** + * Initial working directory for sessions + */ + initialCwd: string; + /** + * Path within each session's SessionFs where the runtime stores files for that session + */ + sessionStatePath: string; + conventions: SessionFsSetProviderConventions; + capabilities?: SessionFsSetProviderCapabilities; +} +/** + * Indicates whether the calling client was registered as the session filesystem provider. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSetProviderResult". + */ +export interface SessionFsSetProviderResult { + /** + * Whether the provider was set successfully + */ + success: boolean; +} +/** + * Indicates whether the per-session SQLite database already exists. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteExistsResult". + */ +export interface SessionFsSqliteExistsResult { + /** + * Whether the session database already exists + */ + exists: boolean; +} +/** + * SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteQueryRequest". + */ +export interface SessionFsSqliteQueryRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * SQL query to execute + */ + query: string; + queryType: SessionFsSqliteQueryType; + /** + * Optional named bind parameters + */ + params?: { + [k: string]: (string | number | null) | undefined; + }; +} +/** + * Query results including rows, columns, and rows affected, or a filesystem error if execution failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteQueryResult". + */ +export interface SessionFsSqliteQueryResult { + /** + * For SELECT: array of row objects. For others: empty array. + */ + rows: { + [k: string]: unknown | undefined; + }[]; + /** + * Column names from the result set + */ + columns: string[]; + /** + * Number of rows affected (for INSERT/UPDATE/DELETE) + */ + rowsAffected: number; + /** + * SQLite last_insert_rowid() value for INSERT. + */ + lastInsertRowid?: number; + error?: SessionFsError; +} +/** + * Path whose metadata should be returned from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsStatRequest". + */ +export interface SessionFsStatRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; +} +/** + * Filesystem metadata for the requested path, or a filesystem error if the stat failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsStatResult". + */ +export interface SessionFsStatResult { + /** + * Whether the path is a file + */ + isFile: boolean; + /** + * Whether the path is a directory + */ + isDirectory: boolean; + /** + * File size in bytes + */ + size: number; + /** + * ISO 8601 timestamp of last modification + */ + mtime: string; + /** + * ISO 8601 timestamp of creation + */ + birthtime: string; + error?: SessionFsError; +} +/** + * File path, content to write, and optional mode for the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsWriteFileRequest". + */ +export interface SessionFsWriteFileRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; + /** + * Content to write + */ + content: string; + /** + * Optional POSIX-style mode for newly created files + */ + mode?: number; +} +/** + * Schema for the `SessionInstalledPlugin` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPlugin". + */ +/** @experimental */ +export interface SessionInstalledPlugin { + /** + * Plugin name + */ + name: string; + /** + * Marketplace the plugin came from (empty string for direct repo installs) + */ + marketplace: string; + /** + * Installed version, if known + */ + version?: string; + /** + * Installation timestamp (ISO-8601) + */ + installed_at: string; + /** + * Whether the plugin is currently enabled + */ + enabled: boolean; + /** + * Path where the plugin is cached locally + */ + cache_path?: string; + source?: SessionInstalledPluginSource; +} +/** + * Schema for the `SessionInstalledPluginSourceGithub` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPluginSourceGithub". + */ +/** @experimental */ +export interface SessionInstalledPluginSourceGithub { + /** + * Constant value. Always "github". + */ + source: "github"; + repo: string; + ref?: string; + path?: string; +} +/** + * Schema for the `SessionInstalledPluginSourceUrl` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPluginSourceUrl". + */ +/** @experimental */ +export interface SessionInstalledPluginSourceUrl { + /** + * Constant value. Always "url". + */ + source: "url"; + url: string; + ref?: string; + path?: string; +} +/** + * Schema for the `SessionInstalledPluginSourceLocal` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPluginSourceLocal". + */ +/** @experimental */ +export interface SessionInstalledPluginSourceLocal { + /** + * Constant value. Always "local". + */ + source: "local"; + path: string; +} +/** + * Persisted sessions matching the filter, ordered most-recently-modified first. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionList". + */ +/** @experimental */ +export interface SessionList { + /** + * Sessions ordered most-recently-modified first + */ + sessions: SessionMetadata[]; +} +/** + * Queued repo-level startup prompts and the total hook command count after loading. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionLoadDeferredRepoHooksResult". + */ +/** @experimental */ +export interface SessionLoadDeferredRepoHooksResult { + /** + * Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. + */ + startupPrompts: string[]; + /** + * Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. + */ + hookCount: number; +} +/** + * Point-in-time snapshot of slow-changing session identifier and state fields + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMetadataSnapshot". + */ +/** @experimental */ +export interface SessionMetadataSnapshot { + /** + * The unique identifier of the session + */ + sessionId: string; + /** + * ISO 8601 timestamp of when the session started + */ + startTime: string; + /** + * ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. + */ + modifiedTime: string; + /** + * Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process) + */ + isRemote: boolean; + /** + * True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. + */ + alreadyInUse: boolean; + /** + * Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace + */ + workspacePath: string | null; + /** + * User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. + */ + initialName?: string; + remoteMetadata?: MetadataSnapshotRemoteMetadata; + /** + * Short human-readable summary of the session, if known. Omitted when no summary has been generated. + */ + summary?: string; + /** + * Absolute path to the session's current working directory + */ + workingDirectory: string; + currentMode: MetadataSnapshotCurrentMode; + /** + * Currently selected model identifier, if any + */ + selectedModel?: string; + /** + * Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). + */ + workspace?: WorkspaceSummary | null; +} +/** + * Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionPruneResult". + */ +/** @experimental */ +export interface SessionPruneResult { + /** + * Session IDs that were deleted (always empty in dry-run mode) + */ + deleted: string[]; + /** + * Session IDs that would be deleted in dry-run mode (always empty otherwise) + */ + candidates: string[]; + /** + * Session IDs that were skipped (e.g., named sessions) + */ + skipped: string[]; + /** + * Total bytes freed (actual when not dry-run, projected when dry-run) + */ + freedBytes: number; + /** + * True when no deletions were actually performed + */ + dryRun: boolean; +} +/** + * Session IDs to close, deactivate, and delete from disk. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsBulkDeleteRequest". + */ +/** @experimental */ +export interface SessionsBulkDeleteRequest { + /** + * Session IDs to close, deactivate, and delete from disk + */ + sessionIds: string[]; +} +/** + * Session IDs to test for live in-use locks. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsCheckInUseRequest". + */ +/** @experimental */ +export interface SessionsCheckInUseRequest { + /** + * Session IDs to test for live in-use locks + */ + sessionIds: string[]; +} +/** + * Session IDs from the input set that are currently in use by another process. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsCheckInUseResult". + */ +/** @experimental */ +export interface SessionsCheckInUseResult { + /** + * Session IDs from the input set that are currently held by another running process via an alive lock file + */ + inUse: string[]; +} +/** + * Session ID to close. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsCloseRequest". + */ +/** @experimental */ +export interface SessionsCloseRequest { + /** + * Session ID to close */ sessionId: string; +} +/** + * Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsCloseResult". + */ +/** @experimental */ +export interface SessionsCloseResult {} +/** + * Session metadata records to enrich with summary and context information. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsEnrichMetadataRequest". + */ +/** @experimental */ +export interface SessionsEnrichMetadataRequest { /** - * Path using SessionFs conventions + * Session metadata records to enrich. Records that already have summary and context are returned unchanged. */ - path: string; + sessions: SessionMetadata[]; +} +/** + * New auth credentials to install on the session. Omit to leave credentials unchanged. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionSetCredentialsParams". + */ +export interface SessionSetCredentialsParams { + credentials?: AuthInfo; +} +/** + * Indicates whether the credential update succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionSetCredentialsResult". + */ +export interface SessionSetCredentialsResult { /** - * Remove directories and their contents recursively + * Whether the operation succeeded */ - recursive?: boolean; + success: boolean; +} +/** + * UUID prefix to resolve to a unique session ID. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsFindByPrefixRequest". + */ +/** @experimental */ +export interface SessionsFindByPrefixRequest { /** - * Ignore errors if the path does not exist + * UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. */ - force?: boolean; + prefix: string; } /** - * Optional capabilities declared by the provider + * Session ID matching the prefix, omitted when no unique match exists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderCapabilities". + * via the `definition` "SessionsFindByPrefixResult". */ -export interface SessionFsSetProviderCapabilities { +/** @experimental */ +export interface SessionsFindByPrefixResult { /** - * Whether the provider supports SQLite query/exists operations + * Omitted when no unique session matches the prefix (no match or ambiguous) */ - sqlite?: boolean; + sessionId?: string; } /** - * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. + * GitHub task ID to look up. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderRequest". + * via the `definition` "SessionsFindByTaskIDRequest". */ -export interface SessionFsSetProviderRequest { +/** @experimental */ +export interface SessionsFindByTaskIDRequest { /** - * Initial working directory for sessions + * GitHub task ID to look up */ - initialCwd: string; + taskId: string; +} +/** + * ID of the local session bound to the given GitHub task, or omitted when none. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsFindByTaskIDResult". + */ +/** @experimental */ +export interface SessionsFindByTaskIDResult { /** - * Path within each session's SessionFs where the runtime stores files for that session + * Omitted when no local session is bound to that GitHub task + */ + sessionId?: string; +} +/** + * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsForkRequest". + */ +/** @experimental */ +export interface SessionsForkRequest { + /** + * Source session ID to fork from + */ + sessionId: string; + /** + * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. + */ + toEventId?: string; + /** + * Optional friendly name to assign to the forked session. + */ + name?: string; +} +/** + * Identifier and optional friendly name assigned to the newly forked session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsForkResult". + */ +/** @experimental */ +export interface SessionsForkResult { + /** + * The new forked session's ID + */ + sessionId: string; + /** + * Friendly name assigned to the forked session, if any. + */ + name?: string; +} +/** + * Session ID whose event-log file path to compute. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsGetEventFilePathRequest". + */ +/** @experimental */ +export interface SessionsGetEventFilePathRequest { + /** + * Session ID whose event-log file path to compute + */ + sessionId: string; +} +/** + * Absolute path to the session's events.jsonl file on disk. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsGetEventFilePathResult". + */ +/** @experimental */ +export interface SessionsGetEventFilePathResult { + /** + * Absolute path to the session's events.jsonl file + */ + filePath: string; +} +/** + * Optional working-directory context used to score session relevance. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsGetLastForContextRequest". + */ +/** @experimental */ +export interface SessionsGetLastForContextRequest { + context?: SessionContext; +} +/** + * Most-relevant session ID for the supplied context, or omitted when no sessions exist. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsGetLastForContextResult". + */ +/** @experimental */ +export interface SessionsGetLastForContextResult { + /** + * Most-relevant session ID for the supplied context, or omitted when no sessions exist + */ + sessionId?: string; +} +/** + * Session ID to look up the persisted remote-steerable flag for. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsGetPersistedRemoteSteerableRequest". + */ +/** @experimental */ +export interface SessionsGetPersistedRemoteSteerableRequest { + /** + * Session ID to look up the persisted remote-steerable flag for + */ + sessionId: string; +} +/** + * The session's persisted remote-steerable flag, or omitted when no value has been persisted. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsGetPersistedRemoteSteerableResult". + */ +/** @experimental */ +export interface SessionsGetPersistedRemoteSteerableResult { + /** + * The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted + */ + remoteSteerable?: boolean; +} +/** + * Map of sessionId -> on-disk size in bytes for each session's workspace directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionSizes". + */ +/** @experimental */ +export interface SessionSizes { + /** + * Map of sessionId -> on-disk size in bytes for the session's workspace directory + */ + sizes: { + [k: string]: number | undefined; + }; +} +/** + * Optional metadata-load limit and context filter applied to the returned sessions. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsListRequest". + */ +/** @experimental */ +export interface SessionsListRequest { + /** + * When provided, only the first N sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every session. + */ + metadataLimit?: number; + /** + * Optional filter applied to the returned sessions + */ + filter?: { + /** + * Match sessions whose context.cwd equals this value + */ + cwd?: string; + /** + * Match sessions whose context.gitRoot equals this value + */ + gitRoot?: string; + /** + * Match sessions whose context.repository equals this value + */ + repository?: string; + /** + * Match sessions whose context.branch equals this value + */ + branch?: string; + }; +} +/** + * Active session ID whose deferred repo-level hooks should be loaded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsLoadDeferredRepoHooksRequest". + */ +/** @experimental */ +export interface SessionsLoadDeferredRepoHooksRequest { + /** + * Active session ID whose deferred repo-level hooks should be loaded + */ + sessionId: string; +} +/** + * Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsPruneOldRequest". + */ +/** @experimental */ +export interface SessionsPruneOldRequest { + /** + * Delete sessions whose modifiedTime is at least this many days old + */ + olderThanDays: number; + /** + * When true, only report what would be deleted without performing any deletion + */ + dryRun?: boolean; + /** + * When true, named sessions (set via /rename) are also eligible for pruning + */ + includeNamed?: boolean; + /** + * Session IDs that should never be considered for pruning + */ + excludeSessionIds?: string[]; +} +/** + * Session ID whose in-use lock should be released. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsReleaseLockRequest". + */ +/** @experimental */ +export interface SessionsReleaseLockRequest { + /** + * Session ID whose in-use lock should be released + */ + sessionId: string; +} +/** + * Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsReleaseLockResult". + */ +/** @experimental */ +export interface SessionsReleaseLockResult {} +/** + * Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsReloadPluginHooksRequest". + */ +/** @experimental */ +export interface SessionsReloadPluginHooksRequest { + /** + * Active session ID to reload hooks for + */ + sessionId: string; + /** + * When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. */ - sessionStatePath: string; - conventions: SessionFsSetProviderConventions; - capabilities?: SessionFsSetProviderCapabilities; + deferRepoHooks?: boolean; } /** - * Indicates whether the calling client was registered as the session filesystem provider. + * Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderResult". + * via the `definition` "SessionsReloadPluginHooksResult". */ -export interface SessionFsSetProviderResult { +/** @experimental */ +export interface SessionsReloadPluginHooksResult {} +/** + * Session ID whose pending events should be flushed to disk. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsSaveRequest". + */ +/** @experimental */ +export interface SessionsSaveRequest { /** - * Whether the provider was set successfully + * Session ID whose pending events should be flushed to disk */ - success: boolean; + sessionId: string; } /** - * Indicates whether the per-session SQLite database already exists. + * Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteExistsResult". + * via the `definition` "SessionsSaveResult". */ -export interface SessionFsSqliteExistsResult { +/** @experimental */ +export interface SessionsSaveResult {} +/** + * Manager-wide additional plugins to register; replaces any previously-configured set. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsSetAdditionalPluginsRequest". + */ +/** @experimental */ +export interface SessionsSetAdditionalPluginsRequest { /** - * Whether the session database already exists + * Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. */ - exists: boolean; + plugins: InstalledPlugin[]; } /** - * SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. + * Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteQueryRequest". + * via the `definition` "SessionsSetAdditionalPluginsResult". */ -export interface SessionFsSqliteQueryRequest { +/** @experimental */ +export interface SessionsSetAdditionalPluginsResult {} +/** + * Patch of mutable session options to apply to the running session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionUpdateOptionsParams". + */ +/** @experimental */ +export interface SessionUpdateOptionsParams { /** - * Target session identifier + * The model ID to use for assistant turns. */ - sessionId: string; + model?: string; /** - * SQL query to execute + * Reasoning effort for the selected model (model-defined enum). */ - query: string; - queryType: SessionFsSqliteQueryType; + reasoningEffort?: string; /** - * Optional named bind parameters + * Identifier of the client driving the session. */ - params?: { - [k: string]: (string | number | null) | undefined; + clientName?: string; + /** + * Identifier sent to LSP-style integrations. + */ + lspClientName?: string; + /** + * Stable integration identifier used for analytics and rate-limit attribution. + */ + integrationId?: string; + /** + * Map of feature-flag IDs to their boolean enabled state. + */ + featureFlags?: { + [k: string]: boolean | undefined; }; -} -/** - * Query results including rows, columns, and rows affected, or a filesystem error if execution failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteQueryResult". - */ -export interface SessionFsSqliteQueryResult { /** - * For SELECT: array of row objects. For others: empty array. + * Whether experimental capabilities are enabled. */ - rows: { + isExperimentalMode?: boolean; + /** + * Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the runtime. + */ + provider?: { [k: string]: unknown | undefined; - }[]; + }; /** - * Column names from the result set + * Absolute working-directory path for shell tools. */ - columns: string[]; + workingDirectory?: string; /** - * Number of rows affected (for INSERT/UPDATE/DELETE) + * Allowlist of tool names available to this session. */ - rowsAffected: number; + availableTools?: string[]; /** - * Last inserted row ID (for INSERT) + * Denylist of tool names for this session. */ - lastInsertRowid?: number; - error?: SessionFsError; -} -/** - * Path whose metadata should be returned from the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsStatRequest". - */ -export interface SessionFsStatRequest { + excludedTools?: string[]; /** - * Target session identifier + * Whether shell-script safety heuristics are enabled. */ - sessionId: string; + enableScriptSafety?: boolean; /** - * Path using SessionFs conventions + * Shell init profile (`None` or `NonInteractive`). */ - path: string; -} -/** - * Filesystem metadata for the requested path, or a filesystem error if the stat failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsStatResult". - */ -export interface SessionFsStatResult { + shellInitProfile?: string; /** - * Whether the path is a file + * Per-shell process flags (e.g., `pwsh` arguments). */ - isFile: boolean; + shellProcessFlags?: string[]; /** - * Whether the path is a directory + * Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime. */ - isDirectory: boolean; + sandboxConfig?: { + [k: string]: unknown | undefined; + }; /** - * File size in bytes + * Whether interactive shell sessions are logged. */ - size: number; + logInteractiveShells?: boolean; + envValueMode?: OptionsUpdateEnvValueMode; /** - * ISO 8601 timestamp of last modification + * Additional directories to search for skills. */ - mtime: string; + skillDirectories?: string[]; /** - * ISO 8601 timestamp of creation + * Skill IDs that should be excluded from this session. */ - birthtime: string; - error?: SessionFsError; -} -/** - * File path, content to write, and optional mode for the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsWriteFileRequest". - */ -export interface SessionFsWriteFileRequest { + disabledSkills?: string[]; /** - * Target session identifier + * Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions` and the runtime-side `ON_DEMAND_INSTRUCTIONS` feature flag. */ - sessionId: string; + enableOnDemandInstructionDiscovery?: boolean; /** - * Path using SessionFs conventions + * Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. */ - path: string; + installedPlugins?: SessionInstalledPlugin[]; /** - * Content to write + * Whether to default custom agents to local-only execution. */ - content: string; + customAgentsLocalOnly?: boolean; /** - * Optional POSIX-style mode for newly created files + * Whether to skip loading custom instruction sources. */ - mode?: number; -} -/** - * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsForkRequest". - */ -/** @experimental */ -export interface SessionsForkRequest { + skipCustomInstructions?: boolean; /** - * Source session ID to fork from + * Instruction source IDs to exclude from the system prompt. */ - sessionId: string; + disabledInstructionSources?: string[]; /** - * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. + * Whether to include the `Co-authored-by` trailer in commit messages. */ - toEventId?: string; + coauthorEnabled?: boolean; /** - * Optional friendly name to assign to the forked session. + * Optional path for trajectory output. */ - name?: string; + trajectoryFile?: string; + /** + * Whether to stream model responses. + */ + enableStreaming?: boolean; + /** + * Override URL for the Copilot API endpoint. + */ + copilotUrl?: string; + /** + * Whether to disable the `ask_user` tool (encourages autonomous behavior). + */ + askUserDisabled?: boolean; + /** + * Whether to allow auto-mode continuation across turns. + */ + continueOnAutoMode?: boolean; + /** + * Whether the session is running in an interactive UI. + */ + runningInInteractiveMode?: boolean; + /** + * Whether to surface reasoning-summary events from the model. + */ + enableReasoningSummaries?: boolean; + /** + * Runtime context discriminator (e.g., `cli`, `actions`). + */ + agentContext?: string; + /** + * Override directory for the session-events log. When unset, the runtime's default events log directory is used. + */ + eventsLogDirectory?: string; + /** + * Additional content-exclusion policies to merge into the session's policy set. Opaque shape; see `ContentExclusionApiResponse` in the runtime. + */ + additionalContentExclusionPolicies?: unknown[]; + /** + * Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). + */ + manageScheduleEnabled?: boolean; } /** - * Identifier and optional friendly name assigned to the newly forked session. + * Indicates whether the session options patch was applied successfully. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsForkResult". + * via the `definition` "SessionUpdateOptionsResult". */ /** @experimental */ -export interface SessionsForkResult { - /** - * The new forked session's ID - */ - sessionId: string; +export interface SessionUpdateOptionsResult { /** - * Friendly name assigned to the forked session, if any. + * Whether the operation succeeded */ - name?: string; + success: boolean; } /** * Shell command to run, with optional working directory and timeout in milliseconds. @@ -3061,6 +6260,19 @@ export interface ShellKillResult { */ killed: boolean; } +/** + * Parameters for shutting down the session + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShutdownRequest". + */ +export interface ShutdownRequest { + type?: ShutdownType; + /** + * Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. + */ + reason?: string; +} /** * Schema for the `Skill` type. * @@ -3090,6 +6302,10 @@ export interface Skill { * Absolute path to the skill file */ path?: string; + /** + * Name of the plugin that provides the skill, when source is 'plugin' + */ + pluginName?: string; } /** * Skills available to the session, with their enabled state. @@ -3158,6 +6374,48 @@ export interface SkillsEnableRequest { */ name: string; } +/** + * Skills invoked during this session, ordered by invocation time (most recent last). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillsGetInvokedResult". + */ +/** @experimental */ +export interface SkillsGetInvokedResult { + /** + * Skills invoked during this session, ordered by invocation time (most recent last) + */ + skills: SkillsInvokedSkill[]; +} +/** + * Schema for the `SkillsInvokedSkill` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillsInvokedSkill". + */ +/** @experimental */ +export interface SkillsInvokedSkill { + /** + * Unique identifier for the skill + */ + name: string; + /** + * Path to the SKILL.md file + */ + path: string; + /** + * Full content of the skill file + */ + content: string; + /** + * Tools that should be auto-approved when this skill is active, captured at invocation time + */ + allowedTools?: string[]; + /** + * Turn number when the skill was invoked + */ + invokedAtTurn: number; +} /** * Diagnostics from reloading skill definitions, with warnings and errors as separate lists. * @@ -3410,6 +6668,52 @@ export interface TasksCancelResult { */ cancelled: boolean; } +/** + * The first sync-waiting task that can currently be promoted to background mode. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TasksGetCurrentPromotableResult". + */ +/** @experimental */ +export interface TasksGetCurrentPromotableResult { + task?: TaskInfo; +} +/** + * Identifier of the background task to fetch progress for. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TasksGetProgressRequest". + */ +/** @experimental */ +export interface TasksGetProgressRequest { + /** + * Task identifier (agent ID or shell ID) + */ + id: string; +} +/** + * Progress information for the task, or null when no task with that ID is tracked. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TasksGetProgressResult". + */ +/** @experimental */ +export interface TasksGetProgressResult { + /** + * Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. + */ + progress?: TaskProgress | null; +} +/** + * The promoted task as it now exists in background mode, omitted if no promotable task was waiting. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TasksPromoteCurrentToBackgroundResult". + */ +/** @experimental */ +export interface TasksPromoteCurrentToBackgroundResult { + task?: TaskInfo; +} /** * Identifier of the task to promote to background mode. * @@ -3436,6 +6740,14 @@ export interface TasksPromoteToBackgroundResult { */ promoted: boolean; } +/** + * Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TasksRefreshResult". + */ +/** @experimental */ +export interface TasksRefreshResult {} /** * Identifier of the completed or cancelled task to remove from tracking. * @@ -3542,6 +6854,29 @@ export interface TasksStartAgentResult { */ agentId: string; } +/** + * Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TasksWaitForPendingResult". + */ +/** @experimental */ +export interface TasksWaitForPendingResult {} +/** + * Feature override key/value pairs to attach to subsequent telemetry events from this session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TelemetrySetFeatureOverridesRequest". + */ +/** @experimental */ +export interface TelemetrySetFeatureOverridesRequest { + /** + * Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. + */ + features: { + [k: string]: string | undefined; + }; +} /** * Schema for the `Tool` type. * @@ -3584,6 +6919,13 @@ export interface ToolList { */ tools: Tool[]; } +/** + * Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ToolsInitializeAndValidateResult". + */ +export interface ToolsInitializeAndValidateResult {} /** * Optional model identifier whose tool overrides should be applied to the listing. * @@ -3934,6 +7276,40 @@ export interface UIElicitationResult { */ success: boolean; } +/** + * Schema for the `UIExitPlanModeResponse` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIExitPlanModeResponse". + */ +export interface UIExitPlanModeResponse { + /** + * Whether the plan was approved. + */ + approved: boolean; + selectedAction?: UIExitPlanModeAction; + /** + * Whether subsequent edits should be auto-approved without confirmation. + */ + autoApproveEdits?: boolean; + /** + * Feedback from the user when they declined the plan or requested changes. + */ + feedback?: string; +} +/** + * Request ID of a pending `auto_mode_switch.requested` event and the user's response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingAutoModeSwitchRequest". + */ +export interface UIHandlePendingAutoModeSwitchRequest { + /** + * The unique request ID from the auto_mode_switch.requested event + */ + requestId: string; + response: UIAutoModeSwitchResponse; +} /** * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). * @@ -3947,6 +7323,118 @@ export interface UIHandlePendingElicitationRequest { requestId: string; result: UIElicitationResponse; } +/** + * Request ID of a pending `exit_plan_mode.requested` event and the user's response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingExitPlanModeRequest". + */ +export interface UIHandlePendingExitPlanModeRequest { + /** + * The unique request ID from the exit_plan_mode.requested event + */ + requestId: string; + response: UIExitPlanModeResponse; +} +/** + * Indicates whether the pending UI request was resolved by this call. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingResult". + */ +export interface UIHandlePendingResult { + /** + * True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. + */ + success: boolean; +} +/** + * Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingSamplingRequest". + */ +export interface UIHandlePendingSamplingRequest { + /** + * The unique request ID from the sampling.requested event + */ + requestId: string; + response?: UIHandlePendingSamplingResponse; +} +/** + * Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingSamplingResponse". + */ +export interface UIHandlePendingSamplingResponse { + [k: string]: unknown | undefined; +} +/** + * Request ID of a pending `user_input.requested` event and the user's response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingUserInputRequest". + */ +export interface UIHandlePendingUserInputRequest { + /** + * The unique request ID from the user_input.requested event + */ + requestId: string; + response: UIUserInputResponse; +} +/** + * Schema for the `UIUserInputResponse` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIUserInputResponse". + */ +export interface UIUserInputResponse { + /** + * The user's answer text + */ + answer: string; + /** + * True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. + */ + wasFreeform: boolean; +} +/** + * Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIRegisterDirectAutoModeSwitchHandlerResult". + */ +export interface UIRegisterDirectAutoModeSwitchHandlerResult { + /** + * Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. + */ + handle: string; +} +/** + * Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerRequest". + */ +export interface UIUnregisterDirectAutoModeSwitchHandlerRequest { + /** + * Handle previously returned by `registerDirectAutoModeSwitchHandler` + */ + handle: string; +} +/** + * Indicates whether the handle was active and the registration count was decremented. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerResult". + */ +export interface UIUnregisterDirectAutoModeSwitchHandlerResult { + /** + * True if the handle was active and decremented the counter; false if the handle was unknown. + */ + unregistered: boolean; +} /** * Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals. * @@ -3978,9 +7466,9 @@ export interface UsageGetMetricsResult { */ totalApiDurationMs: number; /** - * Session start timestamp (epoch milliseconds) + * ISO 8601 timestamp when the session started */ - sessionStartTime: number; + sessionStartTime: string; codeChanges: UsageMetricsCodeChanges; /** * Per-model token and request metrics, keyed by model identifier @@ -4034,6 +7522,10 @@ export interface UsageMetricsCodeChanges { * Number of distinct files modified */ filesModifiedCount: number; + /** + * Distinct file paths modified during the session + */ + filesModified: string[]; } /** * Schema for the `UsageMetricsModelMetric` type. @@ -4115,6 +7607,26 @@ export interface UsageMetricsModelMetricTokenDetail { */ tokenCount: number; } +/** + * Schema for the `WorkspacesCheckpoints` type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesCheckpoints". + */ +export interface WorkspacesCheckpoints { + /** + * Checkpoint number assigned by the workspace manager + */ + number: number; + /** + * Human-readable checkpoint title + */ + title: string; + /** + * Filename of the checkpoint within the workspace checkpoints directory + */ + filename: string; +} /** * Relative path and UTF-8 content for the workspace file to create or overwrite. * @@ -4132,7 +7644,7 @@ export interface WorkspacesCreateFileRequest { content: string; } /** - * Current workspace metadata for the session, or null when not available. + * Current workspace metadata for the session, including its absolute filesystem path when available. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema * via the `definition` "WorkspacesGetWorkspaceResult". @@ -4159,6 +7671,22 @@ export interface WorkspacesGetWorkspaceResult { mc_last_event_id?: string; chronicle_sync_dismissed?: boolean; } | null; + /** + * Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). + */ + path?: string; +} +/** + * Workspace checkpoints in chronological order; empty when the workspace is not enabled. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesListCheckpointsResult". + */ +export interface WorkspacesListCheckpointsResult { + /** + * Workspace checkpoints in chronological order. Empty when workspace is not enabled. + */ + checkpoints: WorkspacesCheckpoints[]; } /** * Relative paths of files stored in the session workspace files directory. @@ -4172,6 +7700,30 @@ export interface WorkspacesListFilesResult { */ files: string[]; } +/** + * Checkpoint number to read. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadCheckpointRequest". + */ +export interface WorkspacesReadCheckpointRequest { + /** + * Checkpoint number to read + */ + number: number; +} +/** + * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadCheckpointResult". + */ +export interface WorkspacesReadCheckpointResult { + /** + * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing + */ + content: string | null; +} /** * Relative path of the workspace file to read. * @@ -4196,6 +7748,43 @@ export interface WorkspacesReadFileResult { */ content: string; } +/** + * Pasted content to save as a UTF-8 file in the session workspace. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesSaveLargePasteRequest". + */ +export interface WorkspacesSaveLargePasteRequest { + /** + * Pasted content to save as a UTF-8 file + */ + content: string; +} +/** + * Descriptor for the saved paste file, or null when the workspace is unavailable. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesSaveLargePasteResult". + */ +export interface WorkspacesSaveLargePasteResult { + /** + * Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions) + */ + saved: { + /** + * Absolute filesystem path to the saved paste file + */ + filePath: string; + /** + * Filename within the workspace files directory + */ + filename: string; + /** + * Size of the saved file in bytes + */ + sizeBytes: number; + } | null; +} /** * Identifies the target session. * @@ -4217,7 +7806,7 @@ export function createServerRpc(connection: MessageConnection) { * * @param params Optional message to echo back to the caller. * - * @returns Server liveness response, including the echoed message, current timestamp, and protocol version. + * @returns Server liveness response, including the echoed message, current server timestamp, and protocol version. */ ping: async (params?: PingRequest): Promise => { return connection.sendRequest("ping", (params ?? {})); @@ -4394,8 +7983,197 @@ export function createServerRpc(connection: MessageConnection) { * * @returns Remote session connection result. */ - connect: async (params?: ConnectRemoteSessionParams): Promise => { - return connection.sendRequest("sessions.connect", (params ?? {})); + connect: async (params?: ConnectRemoteSessionParams): Promise => { + return connection.sendRequest("sessions.connect", (params ?? {})); + }, + /** + * Lists persisted sessions, optionally filtered by working-directory context. + * + * @param params Optional metadata-load limit and context filter applied to the returned sessions. + * + * @returns Persisted sessions matching the filter, ordered most-recently-modified first. + */ + list: async (params?: SessionsListRequest): Promise => { + return connection.sendRequest("sessions.list", (params ?? {})); + }, + /** + * Finds the local session bound to a GitHub task ID, if any. + * + * @param params GitHub task ID to look up. + * + * @returns ID of the local session bound to the given GitHub task, or omitted when none. + */ + findByTaskId: async (params: SessionsFindByTaskIDRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.findByTaskId", params); + }, + /** + * Resolves a UUID prefix to a unique session ID, if exactly one session matches. + * + * @param params UUID prefix to resolve to a unique session ID. + * + * @returns Session ID matching the prefix, omitted when no unique match exists. + */ + findByPrefix: async (params: SessionsFindByPrefixRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.findByPrefix", params); + }, + /** + * Returns the most-relevant prior session for a given working-directory context. + * + * @param params Optional working-directory context used to score session relevance. + * + * @returns Most-relevant session ID for the supplied context, or omitted when no sessions exist. + */ + getLastForContext: async (params?: SessionsGetLastForContextRequest): Promise => { + return connection.sendRequest("sessions.getLastForContext", (params ?? {})); + }, + /** + * Computes the absolute path to a session's persisted events.jsonl file. + * + * @param params Session ID whose event-log file path to compute. + * + * @returns Absolute path to the session's events.jsonl file on disk. + */ + getEventFilePath: async (params?: SessionsGetEventFilePathRequest): Promise => { + return connection.sendRequest("sessions.getEventFilePath", (params ?? {})); + }, + /** + * Returns the on-disk byte size of each session's workspace directory. + * + * @returns Map of sessionId -> on-disk size in bytes for each session's workspace directory. + */ + getSizes: async (): Promise => { + return connection.sendRequest("sessions.getSizes", {}); + }, + /** + * Returns the subset of the supplied session IDs that are currently held by another running process. + * + * @param params Session IDs to test for live in-use locks. + * + * @returns Session IDs from the input set that are currently in use by another process. + */ + checkInUse: async (params: SessionsCheckInUseRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.checkInUse", params); + }, + /** + * Returns a session's persisted remote-steerable flag, if any has been recorded. + * + * @param params Session ID to look up the persisted remote-steerable flag for. + * + * @returns The session's persisted remote-steerable flag, or omitted when no value has been persisted. + */ + getPersistedRemoteSteerable: async (params?: SessionsGetPersistedRemoteSteerableRequest): Promise => { + return connection.sendRequest("sessions.getPersistedRemoteSteerable", (params ?? {})); + }, + /** + * Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. + * + * @param params Session ID to close. + * + * @returns Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. + */ + close: async (params?: SessionsCloseRequest): Promise => { + return connection.sendRequest("sessions.close", (params ?? {})); + }, + /** + * Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. + * + * @param params Session IDs to close, deactivate, and delete from disk. + * + * @returns Map of sessionId -> bytes freed by removing the session's workspace directory. + */ + bulkDelete: async (params: SessionsBulkDeleteRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.bulkDelete", params); + }, + /** + * Deletes sessions older than the given threshold, with optional dry-run and exclusion list. + * + * @param params Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * + * @returns Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. + */ + pruneOld: async (params: SessionsPruneOldRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.pruneOld", params); + }, + /** + * Flushes a session's pending events to disk. + * + * @param params Session ID whose pending events should be flushed to disk. + * + * @returns Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). + */ + save: async (params?: SessionsSaveRequest): Promise => { + return connection.sendRequest("sessions.save", (params ?? {})); + }, + /** + * Releases the in-use lock held by this process for a session. + * + * @param params Session ID whose in-use lock should be released. + * + * @returns Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. + */ + releaseLock: async (params?: SessionsReleaseLockRequest): Promise => { + return connection.sendRequest("sessions.releaseLock", (params ?? {})); + }, + /** + * Backfills missing summary and context fields on the supplied session metadata records. + * + * @param params Session metadata records to enrich with summary and context information. + * + * @returns The same metadata records, with summary and context fields backfilled where available. + */ + enrichMetadata: async (params: SessionsEnrichMetadataRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.enrichMetadata", params); + }, + /** + * Reloads user, plugin, and (optionally) repo hooks on the active session. + * + * @param params Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * + * @returns Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. + */ + reloadPluginHooks: async (params?: SessionsReloadPluginHooksRequest): Promise => { + return connection.sendRequest("sessions.reloadPluginHooks", (params ?? {})); + }, + /** + * Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. + * + * @param params Active session ID whose deferred repo-level hooks should be loaded. + * + * @returns Queued repo-level startup prompts and the total hook command count after loading. + */ + loadDeferredRepoHooks: async (params?: SessionsLoadDeferredRepoHooksRequest): Promise => { + return connection.sendRequest("sessions.loadDeferredRepoHooks", (params ?? {})); + }, + /** + * Replaces the manager-wide additional plugins registered with the session manager. + * + * @param params Manager-wide additional plugins to register; replaces any previously-configured set. + * + * @returns Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. + */ + setAdditionalPlugins: async (params: SessionsSetAdditionalPluginsRequest): Promise => { + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("sessions.setAdditionalPlugins", params); }, }, }; @@ -4431,6 +8209,40 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.suspend", { sessionId }); }, + /** + * Sends a user message to the session and returns its message ID. + * + * @param params Parameters for sending a user message to the session + * + * @returns Result of sending a user message + */ + send: async (params: SendRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.send", { sessionId, ...params }); + }, + /** + * Aborts the current agent turn. + * + * @param params Parameters for aborting the current turn + * + * @returns Result of aborting the current turn + */ + abort: async (params?: AbortRequest): Promise => { + assertActive?.(); + return connection.sendRequest("session.abort", { sessionId, ...params }); + }, + /** + * Shuts down the session and persists its final state. Awaits any deferred sessionEnd hooks before resolving so user-supplied hook scripts complete before the runtime tears down. + * + * @param params Parameters for shutting down the session + */ + shutdown: async (params?: ShutdownRequest): Promise => { + assertActive?.(); + return connection.sendRequest("session.shutdown", { sessionId, ...params }); + }, auth: { /** * Gets authentication status and account metadata for the session. @@ -4441,12 +8253,23 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.auth.getStatus", { sessionId }); }, + /** + * Updates the session's auth credentials used for outbound model and API requests. + * + * @param params New auth credentials to install on the session. Omit to leave credentials unchanged. + * + * @returns Indicates whether the credential update succeeded. + */ + setCredentials: async (params?: SessionSetCredentialsParams): Promise => { + assertActive?.(); + return connection.sendRequest("session.auth.setCredentials", { sessionId, ...params }); + }, }, model: { /** * Gets the currently selected model for the session. * - * @returns The currently selected model for the session. + * @returns The currently selected model and reasoning effort for the session. */ getCurrent: async (): Promise => { assertActive?.(); @@ -4466,6 +8289,20 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.model.switchTo", { sessionId, ...params }); }, + /** + * Updates the session's reasoning effort without changing the selected model. + * + * @param params Reasoning effort level to apply to the currently selected model. + * + * @returns Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. + */ + setReasoningEffort: async (params: ModelSetReasoningEffortRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.model.setReasoningEffort", { sessionId, ...params }); + }, }, mode: { /** @@ -4512,6 +8349,20 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.name.set", { sessionId, ...params }); }, + /** + * Persists an auto-generated session summary as the session's name when no user-set name exists. + * + * @param params Auto-generated session summary to apply as the session's name when no user-set name exists. + * + * @returns Indicates whether the auto-generated summary was applied as the session's name. + */ + setAuto: async (params: NameSetAutoRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.name.setAuto", { sessionId, ...params }); + }, }, plan: { /** @@ -4547,7 +8398,7 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin /** * Gets current workspace metadata for the session. * - * @returns Current workspace metadata for the session, or null when not available. + * @returns Current workspace metadata for the session, including its absolute filesystem path when available. */ getWorkspace: async (): Promise => { assertActive?.(); @@ -4588,6 +8439,43 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.workspaces.createFile", { sessionId, ...params }); }, + /** + * Lists workspace checkpoints in chronological order. + * + * @returns Workspace checkpoints in chronological order; empty when the workspace is not enabled. + */ + listCheckpoints: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.workspaces.listCheckpoints", { sessionId }); + }, + /** + * Reads the content of a workspace checkpoint by number. + * + * @param params Checkpoint number to read. + * + * @returns Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. + */ + readCheckpoint: async (params: WorkspacesReadCheckpointRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.workspaces.readCheckpoint", { sessionId, ...params }); + }, + /** + * Saves pasted content as a UTF-8 file in the session workspace. + * + * @param params Pasted content to save as a UTF-8 file in the session workspace. + * + * @returns Descriptor for the saved paste file, or null when the workspace is unavailable. + */ + saveLargePaste: async (params: WorkspacesSaveLargePasteRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.workspaces.saveLargePaste", { sessionId, ...params }); + }, }, instructions: { /** @@ -4690,6 +8578,47 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.tasks.list", { sessionId }); }, + /** + * Refreshes metadata for any detached background shells the runtime knows about. + * + * @returns Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. + */ + refresh: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.tasks.refresh", { sessionId }); + }, + /** + * Waits for all in-flight background tasks and any follow-up turns to settle. + * + * @returns Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). + */ + waitForPending: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.tasks.waitForPending", { sessionId }); + }, + /** + * Returns progress information for a background task by ID. + * + * @param params Identifier of the background task to fetch progress for. + * + * @returns Progress information for the task, or null when no task with that ID is tracked. + */ + getProgress: async (params: TasksGetProgressRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.tasks.getProgress", { sessionId, ...params }); + }, + /** + * Returns the first sync-waiting task that can currently be promoted to background mode. + * + * @returns The first sync-waiting task that can currently be promoted to background mode. + */ + getCurrentPromotable: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.tasks.getCurrentPromotable", { sessionId }); + }, /** * Promotes an eligible synchronously-waited task so it continues running in the background. * @@ -4704,6 +8633,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.tasks.promoteToBackground", { sessionId, ...params }); }, + /** + * Atomically promotes the first promotable sync-waiting task to background mode and returns it. + * + * @returns The promoted task as it now exists in background mode, omitted if no promotable task was waiting. + */ + promoteCurrentToBackground: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.tasks.promoteCurrentToBackground", { sessionId }); + }, /** * Cancels a background task. * @@ -4758,6 +8696,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.skills.list", { sessionId }); }, + /** + * Returns the skills that have been invoked during this session. + * + * @returns Skills invoked during this session, ordered by invocation time (most recent last). + */ + getInvoked: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.skills.getInvoked", { sessionId }); + }, /** * Enables a skill for the session. * @@ -4791,6 +8738,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.skills.reload", { sessionId }); }, + /** + * Ensures the session's skill definitions have been loaded from disk. + */ + ensureLoaded: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.skills.ensureLoaded", { sessionId }); + }, }, /** @experimental */ mcp: { @@ -4834,6 +8788,57 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.mcp.reload", { sessionId }); }, + /** + * Runs an MCP sampling inference on behalf of an MCP server. + * + * @param params Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. + * + * @returns Outcome of an MCP sampling execution: success result, failure error, or cancellation. + */ + executeSampling: async (params: McpExecuteSamplingParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mcp.executeSampling", { sessionId, ...params }); + }, + /** + * Cancels an in-flight MCP sampling execution by request ID. + * + * @param params The requestId previously passed to executeSampling that should be cancelled. + * + * @returns Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. + */ + cancelSamplingExecution: async (params: McpCancelSamplingExecutionParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mcp.cancelSamplingExecution", { sessionId, ...params }); + }, + /** + * Sets how environment-variable values supplied to MCP servers are resolved (direct or indirect). + * + * @param params Mode controlling how MCP server env values are resolved (`direct` or `indirect`). + * + * @returns Env-value mode recorded on the session after the update. + */ + setEnvValueMode: async (params: McpSetEnvValueModeParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.mcp.setEnvValueMode", { sessionId, ...params }); + }, + /** + * Removes the auto-managed `github` MCP server when present. + * + * @returns Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). + */ + removeGitHub: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.mcp.removeGitHub", { sessionId }); + }, /** @experimental */ oauth: { /** @@ -4865,6 +8870,32 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin }, }, /** @experimental */ + options: { + /** + * Patches the genuinely-mutable subset of session options. + * + * @param params Patch of mutable session options to apply to the running session. + * + * @returns Indicates whether the session options patch was applied successfully. + */ + update: async (params?: SessionUpdateOptionsParams): Promise => { + assertActive?.(); + return connection.sendRequest("session.options.update", { sessionId, ...params }); + }, + }, + /** @experimental */ + lsp: { + /** + * Loads the merged LSP configuration set for the session's working directory. + * + * @param params Parameters for (re)loading the merged LSP configuration set. + */ + initialize: async (params?: LspInitializeRequest): Promise => { + assertActive?.(); + return connection.sendRequest("session.lsp.initialize", { sessionId, ...params }); + }, + }, + /** @experimental */ extensions: { /** * Lists extensions discovered for the session and their current status. @@ -4922,6 +8953,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.tools.handlePendingToolCall", { sessionId, ...params }); }, + /** + * Resolves, builds, and validates the runtime tool list for the session. + * + * @returns Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. + */ + initializeAndValidate: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.tools.initializeAndValidate", { sessionId }); + }, }, commands: { /** @@ -4942,73 +8982,206 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin * * @returns Result of invoking the slash command (text output, prompt to send to the agent, or completion). */ - invoke: async (params: CommandsInvokeRequest): Promise => { + invoke: async (params: CommandsInvokeRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.invoke", { sessionId, ...params }); + }, + /** + * Reports completion of a pending client-handled slash command. + * + * @param params Pending command request ID and an optional error if the client handler failed. + * + * @returns Indicates whether the pending client-handled command was completed successfully. + */ + handlePendingCommand: async (params: CommandsHandlePendingCommandRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.handlePendingCommand", { sessionId, ...params }); + }, + /** + * Executes a slash command synchronously and returns any error. + * + * @param params Slash command name and argument string to execute synchronously. + * + * @returns Error message produced while executing the command, if any. + */ + execute: async (params: ExecuteCommandParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.execute", { sessionId, ...params }); + }, + /** + * Enqueues a slash command for FIFO processing on the local session. + * + * @param params Slash-prefixed command string to enqueue for FIFO processing. + * + * @returns Indicates whether the command was accepted into the local execution queue. + */ + enqueue: async (params: EnqueueCommandParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.enqueue", { sessionId, ...params }); + }, + /** + * Reports whether the host actually executed a queued command and whether to continue processing. + * + * @param params Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). + * + * @returns Indicates whether the queued-command response was matched to a pending request. + */ + respondToQueuedCommand: async (params: CommandsRespondToQueuedCommandRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.commands.respondToQueuedCommand", { sessionId, ...params }); + }, + }, + /** @experimental */ + telemetry: { + /** + * Sets feature override key/value pairs to attach to subsequent telemetry events for the session. + * + * @param params Feature override key/value pairs to attach to subsequent telemetry events from this session. + */ + setFeatureOverrides: async (params: TelemetrySetFeatureOverridesRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.telemetry.setFeatureOverrides", { sessionId, ...params }); + }, + }, + ui: { + /** + * Requests structured input from a UI-capable client. + * + * @param params Prompt message and JSON schema describing the form fields to elicit from the user. + * + * @returns The elicitation response (accept with form values, decline, or cancel) + */ + elicitation: async (params: UIElicitationRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.ui.elicitation", { sessionId, ...params }); + }, + /** + * Provides the user response for a pending elicitation request. + * + * @param params Pending elicitation request ID and the user's response (accept/decline/cancel + form values). + * + * @returns Indicates whether the elicitation response was accepted; false if it was already resolved by another client. + */ + handlePendingElicitation: async (params: UIHandlePendingElicitationRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.ui.handlePendingElicitation", { sessionId, ...params }); + }, + /** + * Resolves a pending `user_input.requested` event with the user's response. + * + * @param params Request ID of a pending `user_input.requested` event and the user's response. + * + * @returns Indicates whether the pending UI request was resolved by this call. + */ + handlePendingUserInput: async (params: UIHandlePendingUserInputRequest): Promise => { assertActive?.(); if (params == null) { throw new TypeError("params is required"); } - return connection.sendRequest("session.commands.invoke", { sessionId, ...params }); + return connection.sendRequest("session.ui.handlePendingUserInput", { sessionId, ...params }); }, /** - * Reports completion of a pending client-handled slash command. + * Resolves a pending `sampling.requested` event with a sampling result, or rejects it. * - * @param params Pending command request ID and an optional error if the client handler failed. + * @param params Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). * - * @returns Indicates whether the pending client-handled command was completed successfully. + * @returns Indicates whether the pending UI request was resolved by this call. */ - handlePendingCommand: async (params: CommandsHandlePendingCommandRequest): Promise => { + handlePendingSampling: async (params: UIHandlePendingSamplingRequest): Promise => { assertActive?.(); if (params == null) { throw new TypeError("params is required"); } - return connection.sendRequest("session.commands.handlePendingCommand", { sessionId, ...params }); + return connection.sendRequest("session.ui.handlePendingSampling", { sessionId, ...params }); }, /** - * Responds to a queued command request from the session. + * Resolves a pending `auto_mode_switch.requested` event with the user's accept/decline decision. * - * @param params Queued command request ID and the result indicating whether the client handled it. + * @param params Request ID of a pending `auto_mode_switch.requested` event and the user's response. * - * @returns Indicates whether the queued-command response was accepted by the session. + * @returns Indicates whether the pending UI request was resolved by this call. */ - respondToQueuedCommand: async (params: CommandsRespondToQueuedCommandRequest): Promise => { + handlePendingAutoModeSwitch: async (params: UIHandlePendingAutoModeSwitchRequest): Promise => { assertActive?.(); if (params == null) { throw new TypeError("params is required"); } - return connection.sendRequest("session.commands.respondToQueuedCommand", { sessionId, ...params }); + return connection.sendRequest("session.ui.handlePendingAutoModeSwitch", { sessionId, ...params }); }, - }, - ui: { /** - * Requests structured input from a UI-capable client. + * Resolves a pending `exit_plan_mode.requested` event with the user's response. * - * @param params Prompt message and JSON schema describing the form fields to elicit from the user. + * @param params Request ID of a pending `exit_plan_mode.requested` event and the user's response. * - * @returns The elicitation response (accept with form values, decline, or cancel) + * @returns Indicates whether the pending UI request was resolved by this call. */ - elicitation: async (params: UIElicitationRequest): Promise => { + handlePendingExitPlanMode: async (params: UIHandlePendingExitPlanModeRequest): Promise => { assertActive?.(); if (params == null) { throw new TypeError("params is required"); } - return connection.sendRequest("session.ui.elicitation", { sessionId, ...params }); + return connection.sendRequest("session.ui.handlePendingExitPlanMode", { sessionId, ...params }); }, /** - * Provides the user response for a pending elicitation request. + * Registers an in-process handler for auto-mode-switch requests so the server bridge skips dispatch. * - * @param params Pending elicitation request ID and the user's response (accept/decline/cancel + form values). + * @returns Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). + */ + registerDirectAutoModeSwitchHandler: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.ui.registerDirectAutoModeSwitchHandler", { sessionId }); + }, + /** + * Unregisters a previously-registered in-process auto-mode-switch handler by its opaque handle. * - * @returns Indicates whether the elicitation response was accepted; false if it was already resolved by another client. + * @param params Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. + * + * @returns Indicates whether the handle was active and the registration count was decremented. */ - handlePendingElicitation: async (params: UIHandlePendingElicitationRequest): Promise => { + unregisterDirectAutoModeSwitchHandler: async (params: UIUnregisterDirectAutoModeSwitchHandlerRequest): Promise => { assertActive?.(); if (params == null) { throw new TypeError("params is required"); } - return connection.sendRequest("session.ui.handlePendingElicitation", { sessionId, ...params }); + return connection.sendRequest("session.ui.unregisterDirectAutoModeSwitchHandler", { sessionId, ...params }); }, }, permissions: { + /** + * Replaces selected permission policy fields (rules, paths, URLs, exclusions, allow-all flags) on the session. + * + * @param params Patch of permission policy fields to apply (omit a field to leave it unchanged). + * + * @returns Indicates whether the operation succeeded. + */ + configure: async (params?: PermissionsConfigureParams): Promise => { + assertActive?.(); + return connection.sendRequest("session.permissions.configure", { sessionId, ...params }); + }, /** * Provides a decision for a pending tool permission request. * @@ -5023,10 +9196,19 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.permissions.handlePendingPermissionRequest", { sessionId, ...params }); }, + /** + * Reconstructs the set of pending tool permission requests from the session's event history. + * + * @returns List of pending permission requests reconstructed from event history. + */ + pendingRequests: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.permissions.pendingRequests", { sessionId }); + }, /** * Enables or disables automatic approval of tool permission requests for the session. * - * @param params Whether to auto-approve all tool permission requests for the rest of the session. + * @param params Allow-all toggle for tool permission requests, with an optional telemetry source. * * @returns Indicates whether the operation succeeded. */ @@ -5037,6 +9219,34 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.permissions.setApproveAll", { sessionId, ...params }); }, + /** + * Adds or removes session-scoped or location-scoped permission rules. + * + * @param params Scope and add/remove instructions for modifying session- or location-scoped permission rules. + * + * @returns Indicates whether the operation succeeded. + */ + modifyRules: async (params: PermissionsModifyRulesParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.modifyRules", { sessionId, ...params }); + }, + /** + * Sets whether the client wants permission prompts bridged into session events. + * + * @param params Toggles whether permission prompts should be bridged into session events for this client. + * + * @returns Indicates whether the operation succeeded. + */ + setRequired: async (params: PermissionsSetRequiredRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.setRequired", { sessionId, ...params }); + }, /** * Clears session-scoped tool permission approvals. * @@ -5046,11 +9256,108 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.permissions.resetSessionApprovals", { sessionId }); }, + /** + * Notifies the runtime that a permission prompt UI has been shown to the user. + * + * @param params Notification payload describing the permission prompt that the client just rendered. + * + * @returns Indicates whether the operation succeeded. + */ + notifyPromptShown: async (params: PermissionPromptShownNotification): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.notifyPromptShown", { sessionId, ...params }); + }, + paths: { + /** + * Returns the session's allowed directories and primary working directory. + * + * @returns Snapshot of the session's allow-listed directories and primary working directory. + */ + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.permissions.paths.list", { sessionId }); + }, + /** + * Adds a directory to the session's allow-list. + * + * @param params Directory path to add to the session's allowed directories. + * + * @returns Indicates whether the operation succeeded. + */ + add: async (params: PermissionPathsAddParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.paths.add", { sessionId, ...params }); + }, + /** + * Updates the session's primary working directory used by the permission policy. + * + * @param params Directory path to set as the session's new primary working directory. + * + * @returns Indicates whether the operation succeeded. + */ + updatePrimary: async (params: PermissionPathsUpdatePrimaryParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.paths.updatePrimary", { sessionId, ...params }); + }, + /** + * Reports whether a path falls within any of the session's allowed directories. + * + * @param params Path to evaluate against the session's allowed directories. + * + * @returns Indicates whether the supplied path is within the session's allowed directories. + */ + isPathWithinAllowedDirectories: async (params: PermissionPathsAllowedCheckParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.paths.isPathWithinAllowedDirectories", { sessionId, ...params }); + }, + /** + * Reports whether a path falls within the session's workspace (primary) directory. + * + * @param params Path to evaluate against the session's workspace (primary) directory. + * + * @returns Indicates whether the supplied path is within the session's workspace directory. + */ + isPathWithinWorkspace: async (params: PermissionPathsWorkspaceCheckParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.paths.isPathWithinWorkspace", { sessionId, ...params }); + }, + }, + urls: { + /** + * Toggles the runtime's URL-permission policy between unrestricted and restricted modes. + * + * @param params Whether the URL-permission policy should run in unrestricted mode. + * + * @returns Indicates whether the operation succeeded. + */ + setUnrestrictedMode: async (params: PermissionUrlsSetUnrestrictedModeParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.permissions.urls.setUnrestrictedMode", { sessionId, ...params }); + }, + }, }, /** * Emits a user-visible session log event. * - * @param params Message text, optional severity level, persistence flag, and optional follow-up URL. + * @param params Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. * * @returns Identifier of the session event that was emitted for the log message. */ @@ -5061,6 +9368,83 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.log", { sessionId, ...params }); }, + /** @experimental */ + metadata: { + /** + * Returns a snapshot of the session's identifying metadata, mode, agent, and remote info. + * + * @returns Point-in-time snapshot of slow-changing session identifier and state fields + */ + snapshot: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.metadata.snapshot", { sessionId }); + }, + /** + * Reports whether the local session is currently processing user/agent messages. + * + * @returns Indicates whether the local session is currently processing a turn or background continuation. + */ + isProcessing: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.metadata.isProcessing", { sessionId }); + }, + /** + * Returns the token breakdown for the session's current context window for a given model. + * + * @param params Model identifier and token limits used to compute the context-info breakdown. + * + * @returns Token breakdown for the session's current context window, or null if uninitialized. + */ + contextInfo: async (params: MetadataContextInfoRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.metadata.contextInfo", { sessionId, ...params }); + }, + /** + * Records a working-directory/git context change and emits a `session.context_changed` event. + * + * @param params Updated working-directory/git context to record on the session. + * + * @returns Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). + */ + recordContextChange: async (params: MetadataRecordContextChangeRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.metadata.recordContextChange", { sessionId, ...params }); + }, + /** + * Updates the session's recorded working directory. + * + * @param params Absolute path to set as the session's new working directory. + * + * @returns Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any related side-effects (file index, etc.); this method only updates the session's own recorded path. + */ + setWorkingDirectory: async (params: MetadataSetWorkingDirectoryRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.metadata.setWorkingDirectory", { sessionId, ...params }); + }, + /** + * Re-tokenizes the session's existing messages against a model and returns aggregate token totals. + * + * @param params Model identifier to use when re-tokenizing the session's existing messages. + * + * @returns Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. + */ + recomputeContextTokens: async (params: MetadataRecomputeContextTokensRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.metadata.recomputeContextTokens", { sessionId, ...params }); + }, + }, shell: { /** * Starts a shell command and streams output through session notifications. @@ -5096,7 +9480,7 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin /** * Compacts the session history to reduce context usage. * - * @returns Compaction outcome with the number of tokens and messages removed and the resulting context window breakdown. + * @returns Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. */ compact: async (): Promise => { assertActive?.(); @@ -5116,6 +9500,112 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin } return connection.sendRequest("session.history.truncate", { sessionId, ...params }); }, + /** + * Cancels any in-progress background compaction on a local session. + * + * @returns Indicates whether an in-progress background compaction was cancelled. + */ + cancelBackgroundCompaction: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.history.cancelBackgroundCompaction", { sessionId }); + }, + /** + * Aborts any in-progress manual compaction on a local session. + * + * @returns Indicates whether an in-progress manual compaction was aborted. + */ + abortManualCompaction: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.history.abortManualCompaction", { sessionId }); + }, + /** + * Produces a markdown summary of the session's conversation context for hand-off scenarios. + * + * @returns Markdown summary of the conversation context (empty when not available). + */ + summarizeForHandoff: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.history.summarizeForHandoff", { sessionId }); + }, + }, + /** @experimental */ + queue: { + /** + * Returns the local session's pending user-facing queued items and steering messages. + * + * @returns Snapshot of the session's pending queued items and immediate-steering messages. + */ + pendingItems: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.queue.pendingItems", { sessionId }); + }, + /** + * Removes the most recently queued user-facing item (LIFO). + * + * @returns Indicates whether a user-facing pending item was removed. + */ + removeMostRecent: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.queue.removeMostRecent", { sessionId }); + }, + /** + * Clears all pending queued items on the local session. + */ + clear: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.queue.clear", { sessionId }); + }, + }, + /** @experimental */ + eventLog: { + /** + * Reads a batch of session events from a cursor, optionally waiting for new events. + * + * @param params Cursor, batch size, and optional long-poll/filter parameters for reading session events. + * + * @returns Batch of session events returned by a read, with cursor and continuation metadata. + */ + read: async (params?: EventLogReadRequest): Promise => { + assertActive?.(); + return connection.sendRequest("session.eventLog.read", { sessionId, ...params }); + }, + /** + * Returns a snapshot of the current tail cursor without consuming events. + * + * @returns Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session). + */ + tail: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.eventLog.tail", { sessionId }); + }, + /** + * Registers consumer interest in an event type for runtime gating purposes. + * + * @param params Event type to register consumer interest for, used by runtime gating logic. + * + * @returns Opaque handle representing an event-type interest registration. + */ + registerInterest: async (params: RegisterEventInterestParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.eventLog.registerInterest", { sessionId, ...params }); + }, + /** + * Releases a consumer's previously-registered interest in an event type. + * + * @param params Opaque handle previously returned by `registerInterest` to release. + * + * @returns Indicates whether the operation succeeded. + */ + releaseInterest: async (params: ReleaseEventInterestParams): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.eventLog.releaseInterest", { sessionId, ...params }); + }, }, /** @experimental */ usage: { @@ -5149,6 +9639,46 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin assertActive?.(); return connection.sendRequest("session.remote.disable", { sessionId }); }, + /** + * Persists a remote-steerability change emitted by the host as a session event. + * + * @param params New remote-steerability state to persist as a `session.remote_steerable_changed` event. + * + * @returns Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. + */ + notifySteerableChanged: async (params: RemoteNotifySteerableChangedRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.remote.notifySteerableChanged", { sessionId, ...params }); + }, + }, + /** @experimental */ + schedule: { + /** + * Lists the session's currently active scheduled prompts. + * + * @returns Snapshot of the currently active recurring prompts for this session. + */ + list: async (): Promise => { + assertActive?.(); + return connection.sendRequest("session.schedule.list", { sessionId }); + }, + /** + * Removes a scheduled prompt by id. + * + * @param params Identifier of the scheduled prompt to remove. + * + * @returns Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. + */ + stop: async (params: ScheduleStopRequest): Promise => { + assertActive?.(); + if (params == null) { + throw new TypeError("params is required"); + } + return connection.sendRequest("session.schedule.stop", { sessionId, ...params }); + }, }, }; } diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index c9cff98e8..2e501591f 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -1791,7 +1791,7 @@ export interface UserMessageData { */ isAutopilotContinuation?: boolean; /** - * Path-backed native document attachments that stayed on the tagged_files path flow because native upload would exceed the request size limit + * Path-backed native document attachments that stayed on the tagged_files path flow because native upload could not read them or would exceed the request size limit */ nativeDocumentPathFallbackPaths?: string[]; /** @@ -2623,7 +2623,7 @@ export interface AssistantUsageQuotaSnapshot { */ overageAllowedWithExhaustedQuota: boolean; /** - * Percentage of quota remaining (0.0 to 1.0) + * Percentage of quota remaining (0 to 100) */ remainingPercentage: number; /** @@ -4721,7 +4721,7 @@ export interface PermissionDeniedByRules { */ export interface PermissionRule { /** - * Optional rule argument matched against the request + * Argument value matched against the request, or null when the rule kind has no argument (e.g. 'read', 'write', 'memory'). */ argument: string | null; /** diff --git a/nodejs/test/e2e/commands.e2e.test.ts b/nodejs/test/e2e/commands.e2e.test.ts index ca8156fd4..bcee05439 100644 --- a/nodejs/test/e2e/commands.e2e.test.ts +++ b/nodejs/test/e2e/commands.e2e.test.ts @@ -6,6 +6,7 @@ import { afterAll, describe, expect, it } from "vitest"; import { CopilotClient, approveAll } from "../../src/index.js"; import type { SessionEvent } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; +import { markInactiveForResume } from "./harness/sdkTestHelper.js"; describe("Commands", async () => { // Use TCP mode so a second client can connect to the same CLI process @@ -83,7 +84,7 @@ describe("Commands", async () => { it("session with commands resumes successfully", async () => { const session1 = await client1.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; - await session1.disconnect(); + markInactiveForResume(session1); const session2 = await client1.resumeSession(sessionId, { onPermissionRequest: approveAll, diff --git a/nodejs/test/e2e/harness/sdkTestHelper.ts b/nodejs/test/e2e/harness/sdkTestHelper.ts index 183e216f2..b21a0d1c4 100644 --- a/nodejs/test/e2e/harness/sdkTestHelper.ts +++ b/nodejs/test/e2e/harness/sdkTestHelper.ts @@ -130,3 +130,7 @@ export function getNextEventOfType( }); }); } + +export function markInactiveForResume(session: CopilotSession): void { + session._markDisconnected(); +} diff --git a/nodejs/test/e2e/session.e2e.test.ts b/nodejs/test/e2e/session.e2e.test.ts index 750a9df01..3d8d3f7b9 100644 --- a/nodejs/test/e2e/session.e2e.test.ts +++ b/nodejs/test/e2e/session.e2e.test.ts @@ -3,7 +3,11 @@ import { describe, expect, it, onTestFinished, vi } from "vitest"; import { ParsedHttpExchange } from "../../../test/harness/replayingCapiProxy.js"; import { CopilotClient, approveAll, defineTool } from "../../src/index.js"; import { createSdkTestContext, isCI } from "./harness/sdkTestContext.js"; -import { getFinalAssistantMessage, getNextEventOfType } from "./harness/sdkTestHelper.js"; +import { + getFinalAssistantMessage, + getNextEventOfType, + markInactiveForResume, +} from "./harness/sdkTestHelper.js"; describe("Sessions", async () => { const { @@ -354,7 +358,7 @@ describe("Sessions", async () => { it("should resume session with a custom provider", async () => { const session = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session.sessionId; - await session.disconnect(); + markInactiveForResume(session); // Resume the session with a provider const session2 = await client.resumeSession(sessionId, { diff --git a/nodejs/test/e2e/session_config.e2e.test.ts b/nodejs/test/e2e/session_config.e2e.test.ts index 9adb8f26b..79f5da8ad 100644 --- a/nodejs/test/e2e/session_config.e2e.test.ts +++ b/nodejs/test/e2e/session_config.e2e.test.ts @@ -3,6 +3,7 @@ import { writeFile, mkdir } from "fs/promises"; import { join } from "path"; import { approveAll } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; +import { markInactiveForResume } from "./harness/sdkTestHelper.js"; describe("Session Configuration", async () => { const { copilotClient: client, workDir, openAiEndpoint } = await createSdkTestContext(); @@ -247,7 +248,7 @@ describe("Session Configuration", async () => { onPermissionRequest: approveAll, workingDirectory: projectDir, }); - await session1.disconnect(); + markInactiveForResume(session1); const session2 = await client.resumeSession(session1.sessionId, { onPermissionRequest: approveAll, workingDirectory: projectDir, @@ -305,7 +306,7 @@ describe("Session Configuration", async () => { it("should forward custom provider headers on resume", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; - await session1.disconnect(); + markInactiveForResume(session1); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll, @@ -386,7 +387,7 @@ describe("Session Configuration", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; - await session1.disconnect(); + markInactiveForResume(session1); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll, @@ -404,7 +405,7 @@ describe("Session Configuration", async () => { it("should apply systemMessage on session resume", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; - await session1.disconnect(); + markInactiveForResume(session1); const resumeInstruction = "End the response with RESUME_SYSTEM_MESSAGE_SENTINEL."; const session2 = await client.resumeSession(sessionId, { @@ -426,7 +427,7 @@ describe("Session Configuration", async () => { it("should apply availableTools on session resume", async () => { const session1 = await client.createSession({ onPermissionRequest: approveAll }); const sessionId = session1.sessionId; - await session1.disconnect(); + markInactiveForResume(session1); const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll, diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index d4aefa9ce..ab1e3996a 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING -from .session_events import EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, ReasoningSummary, SessionMode, SkillSource +from .session_events import AbortReason, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, McpServerSource, McpServerStatus, PermissionPromptRequest, PermissionRule, ReasoningSummary, SessionEvent, SessionMode, ShutdownType, SkillSource, UserToolSessionApproval if TYPE_CHECKING: from .._jsonrpc import JsonRpcClient @@ -39,14 +39,18 @@ def from_union(fs, x): pass assert False -def from_int(x: Any) -> int: - assert isinstance(x, int) and not isinstance(x, bool) - return x +def to_class(c: type[T], x: Any) -> dict: + assert isinstance(x, c) + return cast(Any, x).to_dict() def from_bool(x: Any) -> bool: assert isinstance(x, bool) return x +def from_int(x: Any) -> int: + assert isinstance(x, int) and not isinstance(x, bool) + return x + def from_float(x: Any) -> float: assert isinstance(x, (float, int)) and not isinstance(x, bool) return float(x) @@ -59,10 +63,6 @@ def from_dict(f: Callable[[Any], T], x: Any) -> dict[str, T]: assert isinstance(x, dict) return { k: f(v) for (k, v) in x.items() } -def to_class(c: type[T], x: Any) -> dict: - assert isinstance(x, c) - return cast(Any, x).to_dict() - def from_list(f: Callable[[Any], T], x: Any) -> list[T]: assert isinstance(x, list) return [f(y) for y in x] @@ -74,6 +74,49 @@ def to_enum(c: type[EnumT], x: Any) -> EnumT: def from_datetime(x: Any) -> datetime: return dateutil.parser.parse(x) +@dataclass +class AbortRequest: + """Parameters for aborting the current turn""" + + reason: AbortReason | None = None + """Finite reason code describing why the current turn was aborted""" + + @staticmethod + def from_dict(obj: Any) -> 'AbortRequest': + assert isinstance(obj, dict) + reason = from_union([AbortReason, from_none], obj.get("reason")) + return AbortRequest(reason) + + def to_dict(self) -> dict: + result: dict = {} + if self.reason is not None: + result["reason"] = from_union([lambda x: to_enum(AbortReason, x), from_none], self.reason) + return result + +@dataclass +class AbortResult: + """Result of aborting the current turn""" + + success: bool + """Whether the abort completed successfully""" + + error: str | None = None + """Error message if the abort failed""" + + @staticmethod + def from_dict(obj: Any) -> 'AbortResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + error = from_union([from_str, from_none], obj.get("error")) + return AbortResult(success, error) + + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + return result + @dataclass class AccountGetQuotaRequest: git_hub_token: str | None = None @@ -148,63 +191,68 @@ def to_dict(self) -> dict: return result # Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AgentInfo: - """Schema for the `AgentInfo` type. +class AgentInfoSource(Enum): + """Where the agent definition was loaded from""" - The newly selected custom agent - """ - description: str - """Description of the agent's purpose""" + BUILTIN = "builtin" + INHERITED = "inherited" + PLUGIN = "plugin" + PROJECT = "project" + REMOTE = "remote" + USER = "user" - display_name: str - """Human-readable display name""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AgentSelectRequest: + """Name of the custom agent to select for subsequent turns.""" name: str - """Unique identifier of the custom agent""" - - path: str | None = None - """Absolute local file path of the agent definition. Only set for file-based agents loaded - from disk; remote agents do not have a path. - """ + """Name of the custom agent to select""" @staticmethod - def from_dict(obj: Any) -> 'AgentInfo': + def from_dict(obj: Any) -> 'AgentSelectRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - display_name = from_str(obj.get("displayName")) name = from_str(obj.get("name")) - path = from_union([from_str, from_none], obj.get("path")) - return AgentInfo(description, display_name, name, path) + return AgentSelectRequest(name) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["displayName"] = from_str(self.display_name) result["name"] = from_str(self.name) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentSelectRequest: - """Name of the custom agent to select for subsequent turns.""" +class CopilotUserResponseEndpoints: + """Schema for the `CopilotUserResponseEndpoints` type.""" - name: str - """Name of the custom agent to select""" + api: str | None = None + origin_tracker: str | None = None + proxy: str | None = None + telemetry: str | None = None @staticmethod - def from_dict(obj: Any) -> 'AgentSelectRequest': + def from_dict(obj: Any) -> 'CopilotUserResponseEndpoints': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return AgentSelectRequest(name) + api = from_union([from_str, from_none], obj.get("api")) + origin_tracker = from_union([from_str, from_none], obj.get("origin-tracker")) + proxy = from_union([from_str, from_none], obj.get("proxy")) + telemetry = from_union([from_str, from_none], obj.get("telemetry")) + return CopilotUserResponseEndpoints(api, origin_tracker, proxy, telemetry) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + if self.api is not None: + result["api"] = from_union([from_str, from_none], self.api) + if self.origin_tracker is not None: + result["origin-tracker"] = from_union([from_str, from_none], self.origin_tracker) + if self.proxy is not None: + result["proxy"] = from_union([from_str, from_none], self.proxy) + if self.telemetry is not None: + result["telemetry"] = from_union([from_str, from_none], self.telemetry) return result +class APIKeyAuthInfoType(Enum): + API_KEY = "api-key" + class AuthInfoType(Enum): """Authentication type""" @@ -328,11 +376,11 @@ def to_dict(self) -> dict: @dataclass class CommandsRespondToQueuedCommandResult: - """Indicates whether the queued-command response was accepted by the session.""" + """Indicates whether the queued-command response was matched to a pending request.""" success: bool - """Whether the response was accepted (false if the requestId was not found or already - resolved) + """Whether a pending queued command with the given request ID was found and resolved. False + when the request was already resolved, cancelled, or unknown. """ @staticmethod @@ -459,23 +507,224 @@ class ContentFilterMode(Enum): MARKDOWN = "markdown" NONE = "none" +class Host(Enum): + HTTPS_GITHUB_COM = "https://github.com" + +class CopilotAPITokenAuthInfoType(Enum): + COPILOT_API_TOKEN = "copilot-api-token" + +@dataclass +class CopilotUserResponseQuotaSnapshotsChat: + """Schema for the `CopilotUserResponseQuotaSnapshotsChat` type.""" + + entitlement: float | None = None + has_quota: bool | None = None + overage_count: float | None = None + overage_permitted: bool | None = None + percent_remaining: float | None = None + quota_id: str | None = None + quota_remaining: float | None = None + quota_reset_at: float | None = None + remaining: float | None = None + timestamp_utc: str | None = None + token_based_billing: bool | None = None + unlimited: bool | None = None + + @staticmethod + def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshotsChat': + assert isinstance(obj, dict) + entitlement = from_union([from_float, from_none], obj.get("entitlement")) + has_quota = from_union([from_bool, from_none], obj.get("has_quota")) + overage_count = from_union([from_float, from_none], obj.get("overage_count")) + overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) + percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) + quota_id = from_union([from_str, from_none], obj.get("quota_id")) + quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) + quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) + remaining = from_union([from_float, from_none], obj.get("remaining")) + timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) + token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) + unlimited = from_union([from_bool, from_none], obj.get("unlimited")) + return CopilotUserResponseQuotaSnapshotsChat(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) + + def to_dict(self) -> dict: + result: dict = {} + if self.entitlement is not None: + result["entitlement"] = from_union([to_float, from_none], self.entitlement) + if self.has_quota is not None: + result["has_quota"] = from_union([from_bool, from_none], self.has_quota) + if self.overage_count is not None: + result["overage_count"] = from_union([to_float, from_none], self.overage_count) + if self.overage_permitted is not None: + result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) + if self.percent_remaining is not None: + result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) + if self.quota_id is not None: + result["quota_id"] = from_union([from_str, from_none], self.quota_id) + if self.quota_remaining is not None: + result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) + if self.quota_reset_at is not None: + result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) + if self.remaining is not None: + result["remaining"] = from_union([to_float, from_none], self.remaining) + if self.timestamp_utc is not None: + result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) + if self.token_based_billing is not None: + result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) + if self.unlimited is not None: + result["unlimited"] = from_union([from_bool, from_none], self.unlimited) + return result + +@dataclass +class CopilotUserResponseQuotaSnapshotsCompletions: + """Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type.""" + + entitlement: float | None = None + has_quota: bool | None = None + overage_count: float | None = None + overage_permitted: bool | None = None + percent_remaining: float | None = None + quota_id: str | None = None + quota_remaining: float | None = None + quota_reset_at: float | None = None + remaining: float | None = None + timestamp_utc: str | None = None + token_based_billing: bool | None = None + unlimited: bool | None = None + + @staticmethod + def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshotsCompletions': + assert isinstance(obj, dict) + entitlement = from_union([from_float, from_none], obj.get("entitlement")) + has_quota = from_union([from_bool, from_none], obj.get("has_quota")) + overage_count = from_union([from_float, from_none], obj.get("overage_count")) + overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) + percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) + quota_id = from_union([from_str, from_none], obj.get("quota_id")) + quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) + quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) + remaining = from_union([from_float, from_none], obj.get("remaining")) + timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) + token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) + unlimited = from_union([from_bool, from_none], obj.get("unlimited")) + return CopilotUserResponseQuotaSnapshotsCompletions(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) + + def to_dict(self) -> dict: + result: dict = {} + if self.entitlement is not None: + result["entitlement"] = from_union([to_float, from_none], self.entitlement) + if self.has_quota is not None: + result["has_quota"] = from_union([from_bool, from_none], self.has_quota) + if self.overage_count is not None: + result["overage_count"] = from_union([to_float, from_none], self.overage_count) + if self.overage_permitted is not None: + result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) + if self.percent_remaining is not None: + result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) + if self.quota_id is not None: + result["quota_id"] = from_union([from_str, from_none], self.quota_id) + if self.quota_remaining is not None: + result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) + if self.quota_reset_at is not None: + result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) + if self.remaining is not None: + result["remaining"] = from_union([to_float, from_none], self.remaining) + if self.timestamp_utc is not None: + result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) + if self.token_based_billing is not None: + result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) + if self.unlimited is not None: + result["unlimited"] = from_union([from_bool, from_none], self.unlimited) + return result + +@dataclass +class CopilotUserResponseQuotaSnapshotsPremiumInteractions: + """Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type.""" + + entitlement: float | None = None + has_quota: bool | None = None + overage_count: float | None = None + overage_permitted: bool | None = None + percent_remaining: float | None = None + quota_id: str | None = None + quota_remaining: float | None = None + quota_reset_at: float | None = None + remaining: float | None = None + timestamp_utc: str | None = None + token_based_billing: bool | None = None + unlimited: bool | None = None + + @staticmethod + def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshotsPremiumInteractions': + assert isinstance(obj, dict) + entitlement = from_union([from_float, from_none], obj.get("entitlement")) + has_quota = from_union([from_bool, from_none], obj.get("has_quota")) + overage_count = from_union([from_float, from_none], obj.get("overage_count")) + overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) + percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) + quota_id = from_union([from_str, from_none], obj.get("quota_id")) + quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) + quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) + remaining = from_union([from_float, from_none], obj.get("remaining")) + timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) + token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) + unlimited = from_union([from_bool, from_none], obj.get("unlimited")) + return CopilotUserResponseQuotaSnapshotsPremiumInteractions(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) + + def to_dict(self) -> dict: + result: dict = {} + if self.entitlement is not None: + result["entitlement"] = from_union([to_float, from_none], self.entitlement) + if self.has_quota is not None: + result["has_quota"] = from_union([from_bool, from_none], self.has_quota) + if self.overage_count is not None: + result["overage_count"] = from_union([to_float, from_none], self.overage_count) + if self.overage_permitted is not None: + result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) + if self.percent_remaining is not None: + result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) + if self.quota_id is not None: + result["quota_id"] = from_union([from_str, from_none], self.quota_id) + if self.quota_remaining is not None: + result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) + if self.quota_reset_at is not None: + result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) + if self.remaining is not None: + result["remaining"] = from_union([to_float, from_none], self.remaining) + if self.timestamp_utc is not None: + result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) + if self.token_based_billing is not None: + result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) + if self.unlimited is not None: + result["unlimited"] = from_union([from_bool, from_none], self.unlimited) + return result + @dataclass class CurrentModel: - """The currently selected model for the session.""" + """The currently selected model and reasoning effort for the session.""" model_id: str | None = None """Currently active model identifier""" + reasoning_effort: str | None = None + """Reasoning effort level currently applied to the active model, when one is set. Reads + `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the + two values are reported as a snapshot. + """ + @staticmethod def from_dict(obj: Any) -> 'CurrentModel': assert isinstance(obj, dict) model_id = from_union([from_str, from_none], obj.get("modelId")) - return CurrentModel(model_id) + reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) + return CurrentModel(model_id, reasoning_effort) def to_dict(self) -> dict: result: dict = {} if self.model_id is not None: result["modelId"] = from_union([from_str, from_none], self.model_id) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) return result class DiscoveredMCPServerType(Enum): @@ -486,6 +735,161 @@ class DiscoveredMCPServerType(Enum): SSE = "sse" STDIO = "stdio" +@dataclass +class EnqueueCommandParams: + """Slash-prefixed command string to enqueue for FIFO processing.""" + + command: str + """Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO + with any in-flight items; if the session is idle, processing kicks off immediately. + """ + + @staticmethod + def from_dict(obj: Any) -> 'EnqueueCommandParams': + assert isinstance(obj, dict) + command = from_str(obj.get("command")) + return EnqueueCommandParams(command) + + def to_dict(self) -> dict: + result: dict = {} + result["command"] = from_str(self.command) + return result + +@dataclass +class EnqueueCommandResult: + """Indicates whether the command was accepted into the local execution queue.""" + + queued: bool + """True when the command was accepted into the local execution queue. False when the call + targets a session that does not support local command queueing (e.g. remote sessions). + """ + + @staticmethod + def from_dict(obj: Any) -> 'EnqueueCommandResult': + assert isinstance(obj, dict) + queued = from_bool(obj.get("queued")) + return EnqueueCommandResult(queued) + + def to_dict(self) -> dict: + result: dict = {} + result["queued"] = from_bool(self.queued) + return result + +class EnvAuthInfoType(Enum): + ENV = "env" + +# Experimental: this type is part of an experimental API and may change or be removed. +class EventsAgentScope(Enum): + """Agent-scope filter: 'primary' returns only main-agent events plus events whose type + starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns + events from all agents (matching wildcard-subscription behavior). Default is 'all' to + preserve wildcard semantics for catch-up callers. + """ + ALL = "all" + PRIMARY = "primary" + +# Experimental: this type is part of an experimental API and may change or be removed. +class EventLogTypes(Enum): + EMPTY = "*" + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class EventLogReleaseInterestResult: + """Indicates whether the operation succeeded.""" + + success: bool + """Whether the operation succeeded""" + + @staticmethod + def from_dict(obj: Any) -> 'EventLogReleaseInterestResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + return EventLogReleaseInterestResult(success) + + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class EventLogTailResult: + """Snapshot of the current tail cursor without returning any events. Use this when a + consumer wants to subscribe to live events going forward without first paginating through + the entire persisted history (which would happen if `read` were called without a cursor + on a long-lived session). + """ + cursor: str + """Opaque cursor pointing at the current tail of the session's persisted-events history. + Pass back to `read` to receive only events that arrive AFTER this snapshot. When the + session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent + to omitting the cursor on a first read). + """ + + @staticmethod + def from_dict(obj: Any) -> 'EventLogTailResult': + assert isinstance(obj, dict) + cursor = from_str(obj.get("cursor")) + return EventLogTailResult(cursor) + + def to_dict(self) -> dict: + result: dict = {} + result["cursor"] = from_str(self.cursor) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +class EventsCursorStatus(Enum): + """Cursor status: 'ok' means the cursor was applied successfully; 'expired' means the cursor + referred to an event that no longer exists in history (e.g. truncated or compacted away) + and the read started from the beginning of the remaining history. + """ + EXPIRED = "expired" + OK = "ok" + +@dataclass +class ExecuteCommandParams: + """Slash command name and argument string to execute synchronously.""" + + args: str + """Argument string to pass to the command (empty string if none).""" + + command_name: str + """Name of the slash command to invoke (without the leading '/').""" + + @staticmethod + def from_dict(obj: Any) -> 'ExecuteCommandParams': + assert isinstance(obj, dict) + args = from_str(obj.get("args")) + command_name = from_str(obj.get("commandName")) + return ExecuteCommandParams(args, command_name) + + def to_dict(self) -> dict: + result: dict = {} + result["args"] = from_str(self.args) + result["commandName"] = from_str(self.command_name) + return result + +@dataclass +class ExecuteCommandResult: + """Error message produced while executing the command, if any.""" + + error: str | None = None + """Error message produced while executing the command, if any. Omitted when the handler + succeeded. + """ + + @staticmethod + def from_dict(obj: Any) -> 'ExecuteCommandResult': + assert isinstance(obj, dict) + error = from_union([from_str, from_none], obj.get("error")) + return ExecuteCommandResult(error) + + def to_dict(self) -> dict: + result: dict = {} + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + return result + # Experimental: this type is part of an experimental API and may change or be removed. class ExtensionSource(Enum): """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" @@ -618,6 +1022,9 @@ def to_dict(self) -> dict: result["started"] = from_bool(self.started) return result +class GhCLIAuthInfoType(Enum): + GH_CLI = "gh-cli" + @dataclass class HandlePendingToolCallResult: """Indicates whether the external tool call result was handled successfully.""" @@ -636,6 +1043,48 @@ def to_dict(self) -> dict: result["success"] = from_bool(self.success) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class HistoryAbortManualCompactionResult: + """Indicates whether an in-progress manual compaction was aborted.""" + + aborted: bool + """Whether an in-progress manual compaction was aborted. False when no manual compaction was + running, when its abort controller was already aborted, or when the session is remote. + """ + + @staticmethod + def from_dict(obj: Any) -> 'HistoryAbortManualCompactionResult': + assert isinstance(obj, dict) + aborted = from_bool(obj.get("aborted")) + return HistoryAbortManualCompactionResult(aborted) + + def to_dict(self) -> dict: + result: dict = {} + result["aborted"] = from_bool(self.aborted) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class HistoryCancelBackgroundCompactionResult: + """Indicates whether an in-progress background compaction was cancelled.""" + + cancelled: bool + """Whether an in-progress background compaction was cancelled. False when no compaction was + running, when the session is remote, or when the underlying processor was unavailable. + """ + + @staticmethod + def from_dict(obj: Any) -> 'HistoryCancelBackgroundCompactionResult': + assert isinstance(obj, dict) + cancelled = from_bool(obj.get("cancelled")) + return HistoryCancelBackgroundCompactionResult(cancelled) + + def to_dict(self) -> dict: + result: dict = {} + result["cancelled"] = from_bool(self.cancelled) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class HistoryCompactContextWindow: @@ -683,6 +1132,27 @@ def to_dict(self) -> dict: result["toolDefinitionsTokens"] = from_union([from_int, from_none], self.tool_definitions_tokens) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class HistorySummarizeForHandoffResult: + """Markdown summary of the conversation context (empty when not available).""" + + summary: str + """Markdown summary of the conversation context produced by an LLM. Empty string when there + are no messages or when the session does not support local summarization. + """ + + @staticmethod + def from_dict(obj: Any) -> 'HistorySummarizeForHandoffResult': + assert isinstance(obj, dict) + summary = from_str(obj.get("summary")) + return HistorySummarizeForHandoffResult(summary) + + def to_dict(self) -> dict: + result: dict = {} + result["summary"] = from_str(self.summary) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class HistoryTruncateRequest: @@ -721,10 +1191,28 @@ def to_dict(self) -> dict: result["eventsRemoved"] = from_int(self.events_removed) return result -class InstructionsSourcesLocation(Enum): - """Where this source lives — used for UI grouping""" +class HMACAuthInfoType(Enum): + HMAC = "hmac" - REPOSITORY = "repository" +class PurpleSource(Enum): + GITHUB = "github" + LOCAL = "local" + URL = "url" + +class FluffySource(Enum): + GITHUB = "github" + +class TentacledSource(Enum): + LOCAL = "local" + +class StickySource(Enum): + URL = "url" + +class InstructionsSourcesLocation(Enum): + """Where this source lives — used for UI grouping""" + + PLUGIN = "plugin" + REPOSITORY = "repository" USER = "user" WORKING_DIRECTORY = "working-directory" @@ -735,6 +1223,7 @@ class InstructionsSourcesType(Enum): HOME = "home" MODEL = "model" NESTED_AGENTS = "nested-agents" + PLUGIN = "plugin" REPO = "repo" VSCODE = "vscode" @@ -764,6 +1253,84 @@ def to_dict(self) -> dict: result["eventId"] = str(self.event_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class LspInitializeRequest: + """Parameters for (re)loading the merged LSP configuration set.""" + + force: bool | None = None + """Force re-initialization even when LSP configs were already loaded for the working + directory. + """ + git_root: str | None = None + """Git root used as the boundary when traversing for project-level LSP configs (supports + monorepos). + """ + working_directory: str | None = None + """Working directory used to load project-level LSP configs. Defaults to the session working + directory when omitted. + """ + + @staticmethod + def from_dict(obj: Any) -> 'LspInitializeRequest': + assert isinstance(obj, dict) + force = from_union([from_bool, from_none], obj.get("force")) + git_root = from_union([from_str, from_none], obj.get("gitRoot")) + working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) + return LspInitializeRequest(force, git_root, working_directory) + + def to_dict(self) -> dict: + result: dict = {} + if self.force is not None: + result["force"] = from_union([from_bool, from_none], self.force) + if self.git_root is not None: + result["gitRoot"] = from_union([from_str, from_none], self.git_root) + if self.working_directory is not None: + result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MCPCancelSamplingExecutionParams: + """The requestId previously passed to executeSampling that should be cancelled.""" + + request_id: str + """The requestId previously passed to executeSampling that should be cancelled""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPCancelSamplingExecutionParams': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + return MCPCancelSamplingExecutionParams(request_id) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MCPCancelSamplingExecutionResult: + """Indicates whether an in-flight sampling execution with the given requestId was found and + cancelled. + """ + cancelled: bool + """True if an in-flight execution with the given requestId was found and signalled to + cancel. False when no such execution is in flight (already completed, never started, or + cancelled by another caller). + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPCancelSamplingExecutionResult': + assert isinstance(obj, dict) + cancelled = from_bool(obj.get("cancelled")) + return MCPCancelSamplingExecutionResult(cancelled) + + def to_dict(self) -> dict: + result: dict = {} + result["cancelled"] = from_bool(self.cancelled) + return result + @dataclass class MCPServerConfigHTTPAuth: """Additional authentication configuration for this server.""" @@ -984,6 +1551,39 @@ def to_dict(self) -> dict: result["authorizationUrl"] = from_union([from_str, from_none], self.authorization_url) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MCPRemoveGitHubResult: + """Indicates whether the auto-managed `github` MCP server was removed (false when nothing to + remove). + """ + removed: bool + """True when the auto-managed `github` MCP server was removed; false when no removal + happened (e.g. user has explicitly configured a `github` server, or the server was not + registered). + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPRemoveGitHubResult': + assert isinstance(obj, dict) + removed = from_bool(obj.get("removed")) + return MCPRemoveGitHubResult(removed) + + def to_dict(self) -> dict: + result: dict = {} + result["removed"] = from_bool(self.removed) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +class MCPSamplingExecutionAction(Enum): + """Outcome of the sampling inference. 'success' produced a response; 'failure' encountered + an error (including agent-side rejection by content filter or criteria); 'cancelled' the + caller cancelled this execution via cancelSamplingExecution. + """ + CANCELLED = "cancelled" + FAILURE = "failure" + SUCCESS = "success" + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPServer: @@ -1020,6 +1620,257 @@ def to_dict(self) -> dict: result["source"] = from_union([lambda x: to_enum(McpServerSource, x), from_none], self.source) return result +# Experimental: this type is part of an experimental API and may change or be removed. +class MCPSetEnvValueModeDetails(Enum): + """How environment-variable values supplied to MCP servers are resolved. "direct" passes + literal string values; "indirect" treats values as references (e.g. names of environment + variables on the host) that the runtime resolves before launch. Defaults to the runtime's + startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI + prompt mode and ACP) set this to "direct". + + Mode recorded on the session after the update + + How env values are passed to MCP servers (`direct` inlines literal values; `indirect` + resolves at launch). + """ + DIRECT = "direct" + INDIRECT = "indirect" + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionContextInfo: + """Token-usage breakdown for the session's current context window""" + + buffer_tokens: int + """Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%)""" + + compaction_threshold: int + """Token count at which background compaction starts (configurable percentage of + promptTokenLimit) + """ + conversation_tokens: int + """Tokens consumed by user/assistant/tool messages""" + + limit: int + """Total context limit for /context display. promptTokenLimit + min(32k or 64k, + outputTokenLimit) depending on model. + """ + model_name: str + """The model used for token counting""" + + prompt_token_limit: int + """Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified)""" + + system_tokens: int + """Tokens consumed by the system prompt""" + + tool_definitions_tokens: int + """Tokens consumed by tool definitions sent to the model (excludes deferred tools)""" + + total_tokens: int + """Sum of system, conversation and tool-definition tokens""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionContextInfo': + assert isinstance(obj, dict) + buffer_tokens = from_int(obj.get("bufferTokens")) + compaction_threshold = from_int(obj.get("compactionThreshold")) + conversation_tokens = from_int(obj.get("conversationTokens")) + limit = from_int(obj.get("limit")) + model_name = from_str(obj.get("modelName")) + prompt_token_limit = from_int(obj.get("promptTokenLimit")) + system_tokens = from_int(obj.get("systemTokens")) + tool_definitions_tokens = from_int(obj.get("toolDefinitionsTokens")) + total_tokens = from_int(obj.get("totalTokens")) + return SessionContextInfo(buffer_tokens, compaction_threshold, conversation_tokens, limit, model_name, prompt_token_limit, system_tokens, tool_definitions_tokens, total_tokens) + + def to_dict(self) -> dict: + result: dict = {} + result["bufferTokens"] = from_int(self.buffer_tokens) + result["compactionThreshold"] = from_int(self.compaction_threshold) + result["conversationTokens"] = from_int(self.conversation_tokens) + result["limit"] = from_int(self.limit) + result["modelName"] = from_str(self.model_name) + result["promptTokenLimit"] = from_int(self.prompt_token_limit) + result["systemTokens"] = from_int(self.system_tokens) + result["toolDefinitionsTokens"] = from_int(self.tool_definitions_tokens) + result["totalTokens"] = from_int(self.total_tokens) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataIsProcessingResult: + """Indicates whether the local session is currently processing a turn or background + continuation. + """ + processing: bool + """Whether the session is currently processing user/agent messages. False for non-local + sessions (which don't run a local agentic loop). Reflects an in-flight turn or background + continuation. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MetadataIsProcessingResult': + assert isinstance(obj, dict) + processing = from_bool(obj.get("processing")) + return MetadataIsProcessingResult(processing) + + def to_dict(self) -> dict: + result: dict = {} + result["processing"] = from_bool(self.processing) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataRecomputeContextTokensResult: + """Re-tokenize the session's existing messages against `modelId` and return the token + totals. Useful for hosts that want an initial estimate of context usage on session + resume, before the next agent turn fires `session.context_info_changed` events. Returns + zeros for an empty session. + """ + messages_token_count: int + """Tokens contributed by user/assistant/tool messages (excludes system/developer prompts).""" + + system_token_count: int + """Tokens contributed by system/developer prompt snapshots.""" + + total_tokens: int + """Sum of tokens across chat-context and system-context messages currently held by the + session. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MetadataRecomputeContextTokensResult': + assert isinstance(obj, dict) + messages_token_count = from_int(obj.get("messagesTokenCount")) + system_token_count = from_int(obj.get("systemTokenCount")) + total_tokens = from_int(obj.get("totalTokens")) + return MetadataRecomputeContextTokensResult(messages_token_count, system_token_count, total_tokens) + + def to_dict(self) -> dict: + result: dict = {} + result["messagesTokenCount"] = from_int(self.messages_token_count) + result["systemTokenCount"] = from_int(self.system_token_count) + result["totalTokens"] = from_int(self.total_tokens) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +class SessionContextHostType(Enum): + """Hosting platform type of the repository + + Repository host type + + Repository host type, if known + """ + ADO = "ado" + GITHUB = "github" + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataRecordContextChangeResult: + """Notify the session that its working directory context has changed. Emits a + `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline + UI) can react. Use this when the host has detected a cwd/branch/repo change outside the + session's normal lifecycle (e.g., after a shell command in interactive mode). + """ + @staticmethod + def from_dict(obj: Any) -> 'MetadataRecordContextChangeResult': + assert isinstance(obj, dict) + return MetadataRecordContextChangeResult() + + def to_dict(self) -> dict: + result: dict = {} + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataSetWorkingDirectoryRequest: + """Absolute path to set as the session's new working directory.""" + + working_directory: str + """Absolute path to set as the session's working directory. The runtime updates the + session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) + anchor to it. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MetadataSetWorkingDirectoryRequest': + assert isinstance(obj, dict) + working_directory = from_str(obj.get("workingDirectory")) + return MetadataSetWorkingDirectoryRequest(working_directory) + + def to_dict(self) -> dict: + result: dict = {} + result["workingDirectory"] = from_str(self.working_directory) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataSetWorkingDirectoryResult: + """Update the session's working directory. Used by the host when the user explicitly changes + cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any + related side-effects (file index, etc.); this method only updates the session's own + recorded path. + """ + working_directory: str + """Working directory after the update""" + + @staticmethod + def from_dict(obj: Any) -> 'MetadataSetWorkingDirectoryResult': + assert isinstance(obj, dict) + working_directory = from_str(obj.get("workingDirectory")) + return MetadataSetWorkingDirectoryResult(working_directory) + + def to_dict(self) -> dict: + result: dict = {} + result["workingDirectory"] = from_str(self.working_directory) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +class MetadataSnapshotCurrentMode(Enum): + """The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot')""" + + AUTOPILOT = "autopilot" + INTERACTIVE = "interactive" + PLAN = "plan" + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataSnapshotRemoteMetadataRepository: + """The repository the remote session targets.""" + + branch: str + """The branch the remote session is operating on.""" + + name: str + """The GitHub repository name (without owner).""" + + owner: str + """The GitHub owner (user or organization) of the target repository.""" + + @staticmethod + def from_dict(obj: Any) -> 'MetadataSnapshotRemoteMetadataRepository': + assert isinstance(obj, dict) + branch = from_str(obj.get("branch")) + name = from_str(obj.get("name")) + owner = from_str(obj.get("owner")) + return MetadataSnapshotRemoteMetadataRepository(branch, name, owner) + + def to_dict(self) -> dict: + result: dict = {} + result["branch"] = from_str(self.branch) + result["name"] = from_str(self.name) + result["owner"] = from_str(self.owner) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +class MetadataSnapshotRemoteMetadataTaskType(Enum): + """Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` + invocation. + """ + CCA = "cca" + CLI = "cli" + @dataclass class ModeSetRequest: """Agent interaction mode to apply to the session.""" @@ -1203,6 +2054,46 @@ def to_dict(self) -> dict: result["vision"] = from_union([from_bool, from_none], self.vision) return result +@dataclass +class ModelSetReasoningEffortRequest: + """Reasoning effort level to apply to the currently selected model.""" + + reasoning_effort: str + """Reasoning effort level to apply to the currently selected model. The host is responsible + for validating the value against the model's supported levels before calling. + """ + + @staticmethod + def from_dict(obj: Any) -> 'ModelSetReasoningEffortRequest': + assert isinstance(obj, dict) + reasoning_effort = from_str(obj.get("reasoningEffort")) + return ModelSetReasoningEffortRequest(reasoning_effort) + + def to_dict(self) -> dict: + result: dict = {} + result["reasoningEffort"] = from_str(self.reasoning_effort) + return result + +@dataclass +class ModelSetReasoningEffortResult: + """Update the session's reasoning effort without changing the selected model. Use `switchTo` + instead when you also need to change the model. The runtime stores the effort on the + session and applies it to subsequent turns. + """ + reasoning_effort: str + """Reasoning effort level recorded on the session after the update""" + + @staticmethod + def from_dict(obj: Any) -> 'ModelSetReasoningEffortResult': + assert isinstance(obj, dict) + reasoning_effort = from_str(obj.get("reasoningEffort")) + return ModelSetReasoningEffortResult(reasoning_effort) + + def to_dict(self) -> dict: + result: dict = {} + result["reasoningEffort"] = from_str(self.reasoning_effort) + return result + @dataclass class ModelSwitchToResult: """The model identifier active on the session after the switch.""" @@ -1259,6 +2150,47 @@ def to_dict(self) -> dict: result["name"] = from_union([from_none, from_str], self.name) return result +@dataclass +class NameSetAutoRequest: + """Auto-generated session summary to apply as the session's name when no user-set name + exists. + """ + summary: str + """Auto-generated session summary. Empty/whitespace-only values are ignored; values are + trimmed before persisting. + """ + + @staticmethod + def from_dict(obj: Any) -> 'NameSetAutoRequest': + assert isinstance(obj, dict) + summary = from_str(obj.get("summary")) + return NameSetAutoRequest(summary) + + def to_dict(self) -> dict: + result: dict = {} + result["summary"] = from_str(self.summary) + return result + +@dataclass +class NameSetAutoResult: + """Indicates whether the auto-generated summary was applied as the session's name.""" + + applied: bool + """Whether the auto-generated summary was persisted. False if the session already has a + user-set name, the summary normalized to empty, or the session does not have a workspace. + """ + + @staticmethod + def from_dict(obj: Any) -> 'NameSetAutoResult': + assert isinstance(obj, dict) + applied = from_bool(obj.get("applied")) + return NameSetAutoResult(applied) + + def to_dict(self) -> dict: + result: dict = {} + result["applied"] = from_bool(self.applied) + return result + @dataclass class NameSetRequest: """New friendly name to apply to the session.""" @@ -1277,22 +2209,55 @@ def to_dict(self) -> dict: result["name"] = from_str(self.name) return result -class ApprovalKind(Enum): - COMMANDS = "commands" - CUSTOM_TOOL = "custom-tool" - EXTENSION_MANAGEMENT = "extension-management" - EXTENSION_PERMISSION_ACCESS = "extension-permission-access" - MCP = "mcp" - MCP_SAMPLING = "mcp-sampling" - MEMORY = "memory" - READ = "read" - WRITE = "write" +@dataclass +class PendingPermissionRequest: + """Schema for the `PendingPermissionRequest` type.""" -class PermissionDecisionKind(Enum): - APPROVE_FOR_LOCATION = "approve-for-location" + request: PermissionPromptRequest + """The user-facing permission prompt details (commands, write, read, mcp, url, memory, + custom-tool, path, hook) + """ + request_id: str + """Unique identifier for the pending permission request""" + + @staticmethod + def from_dict(obj: Any) -> 'PendingPermissionRequest': + assert isinstance(obj, dict) + request = PermissionPromptRequest.from_dict(obj.get("request")) + request_id = from_str(obj.get("requestId")) + return PendingPermissionRequest(request, request_id) + + def to_dict(self) -> dict: + result: dict = {} + result["request"] = to_class(PermissionPromptRequest, self.request) + result["requestId"] = from_str(self.request_id) + return result + +class ApprovalKind(Enum): + COMMANDS = "commands" + CUSTOM_TOOL = "custom-tool" + EXTENSION_MANAGEMENT = "extension-management" + EXTENSION_PERMISSION_ACCESS = "extension-permission-access" + MCP = "mcp" + MCP_SAMPLING = "mcp-sampling" + MEMORY = "memory" + READ = "read" + WRITE = "write" + +class PermissionDecisionKind(Enum): + APPROVED = "approved" + APPROVED_FOR_LOCATION = "approved-for-location" + APPROVED_FOR_SESSION = "approved-for-session" + APPROVE_FOR_LOCATION = "approve-for-location" APPROVE_FOR_SESSION = "approve-for-session" APPROVE_ONCE = "approve-once" APPROVE_PERMANENTLY = "approve-permanently" + CANCELLED = "cancelled" + DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" + DENIED_BY_RULES = "denied-by-rules" + DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" + DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" REJECT = "reject" USER_NOT_AVAILABLE = "user-not-available" @@ -1335,6 +2300,33 @@ class PermissionDecisionApproveOnceKind(Enum): class PermissionDecisionApprovePermanentlyKind(Enum): APPROVE_PERMANENTLY = "approve-permanently" +class PermissionDecisionApprovedKind(Enum): + APPROVED = "approved" + +class PermissionDecisionApprovedForLocationKind(Enum): + APPROVED_FOR_LOCATION = "approved-for-location" + +class PermissionDecisionApprovedForSessionKind(Enum): + APPROVED_FOR_SESSION = "approved-for-session" + +class PermissionDecisionCancelledKind(Enum): + CANCELLED = "cancelled" + +class PermissionDecisionDeniedByContentExclusionPolicyKind(Enum): + DENIED_BY_CONTENT_EXCLUSION_POLICY = "denied-by-content-exclusion-policy" + +class PermissionDecisionDeniedByPermissionRequestHookKind(Enum): + DENIED_BY_PERMISSION_REQUEST_HOOK = "denied-by-permission-request-hook" + +class PermissionDecisionDeniedByRulesKind(Enum): + DENIED_BY_RULES = "denied-by-rules" + +class PermissionDecisionDeniedInteractivelyByUserKind(Enum): + DENIED_INTERACTIVELY_BY_USER = "denied-interactively-by-user" + +class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind(Enum): + DENIED_NO_APPROVAL_RULE_AND_COULD_NOT_REQUEST_FROM_USER = "denied-no-approval-rule-and-could-not-request-from-user" + class PermissionDecisionRejectKind(Enum): REJECT = "reject" @@ -1342,6246 +2334,11849 @@ class PermissionDecisionUserNotAvailableKind(Enum): USER_NOT_AVAILABLE = "user-not-available" @dataclass -class PermissionRequestResult: - """Indicates whether the permission decision was applied; false when the request was already - resolved. +class PermissionPathsAddParams: + """Directory path to add to the session's allowed directories.""" + + path: str + """Directory to add to the allow-list. The runtime resolves and validates the path before + adding. """ - success: bool - """Whether the permission request was handled successfully""" @staticmethod - def from_dict(obj: Any) -> 'PermissionRequestResult': + def from_dict(obj: Any) -> 'PermissionPathsAddParams': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionRequestResult(success) + path = from_str(obj.get("path")) + return PermissionPathsAddParams(path) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["path"] = from_str(self.path) return result @dataclass -class PermissionsResetSessionApprovalsRequest: - """No parameters; clears all session-scoped tool permission approvals.""" +class PermissionPathsAllowedCheckParams: + """Path to evaluate against the session's allowed directories.""" + + path: str + """Path to check against the session's allowed directories""" + @staticmethod - def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsRequest': + def from_dict(obj: Any) -> 'PermissionPathsAllowedCheckParams': assert isinstance(obj, dict) - return PermissionsResetSessionApprovalsRequest() + path = from_str(obj.get("path")) + return PermissionPathsAllowedCheckParams(path) def to_dict(self) -> dict: result: dict = {} + result["path"] = from_str(self.path) return result @dataclass -class PermissionsResetSessionApprovalsResult: - """Indicates whether the operation succeeded.""" +class PermissionPathsAllowedCheckResult: + """Indicates whether the supplied path is within the session's allowed directories.""" - success: bool - """Whether the operation succeeded""" + allowed: bool + """Whether the path is within the session's allowed directories""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsResult': + def from_dict(obj: Any) -> 'PermissionPathsAllowedCheckResult': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsResetSessionApprovalsResult(success) + allowed = from_bool(obj.get("allowed")) + return PermissionPathsAllowedCheckResult(allowed) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["allowed"] = from_bool(self.allowed) return result @dataclass -class PermissionsSetApproveAllRequest: - """Whether to auto-approve all tool permission requests for the rest of the session.""" +class PermissionPathsList: + """Snapshot of the session's allow-listed directories and primary working directory.""" - enabled: bool - """Whether to auto-approve all tool permission requests""" + directories: list[str] + """All directories currently allowed for tool access on this session.""" + + primary: str + """The primary working directory for this session.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsSetApproveAllRequest': + def from_dict(obj: Any) -> 'PermissionPathsList': assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - return PermissionsSetApproveAllRequest(enabled) + directories = from_list(from_str, obj.get("directories")) + primary = from_str(obj.get("primary")) + return PermissionPathsList(directories, primary) def to_dict(self) -> dict: result: dict = {} - result["enabled"] = from_bool(self.enabled) + result["directories"] = from_list(from_str, self.directories) + result["primary"] = from_str(self.primary) return result @dataclass -class PermissionsSetApproveAllResult: - """Indicates whether the operation succeeded.""" +class PermissionPathsUpdatePrimaryParams: + """Directory path to set as the session's new primary working directory.""" - success: bool - """Whether the operation succeeded""" + path: str + """Directory to set as the new primary working directory for the session's permission policy.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionsSetApproveAllResult': + def from_dict(obj: Any) -> 'PermissionPathsUpdatePrimaryParams': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return PermissionsSetApproveAllResult(success) + path = from_str(obj.get("path")) + return PermissionPathsUpdatePrimaryParams(path) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["path"] = from_str(self.path) return result @dataclass -class PingRequest: - """Optional message to echo back to the caller.""" +class PermissionPathsWorkspaceCheckParams: + """Path to evaluate against the session's workspace (primary) directory.""" - message: str | None = None - """Optional message to echo back""" + path: str + """Path to check against the session workspace directory""" @staticmethod - def from_dict(obj: Any) -> 'PingRequest': + def from_dict(obj: Any) -> 'PermissionPathsWorkspaceCheckParams': assert isinstance(obj, dict) - message = from_union([from_str, from_none], obj.get("message")) - return PingRequest(message) + path = from_str(obj.get("path")) + return PermissionPathsWorkspaceCheckParams(path) def to_dict(self) -> dict: result: dict = {} - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) + result["path"] = from_str(self.path) return result @dataclass -class PingResult: - """Server liveness response, including the echoed message, current timestamp, and protocol - version. - """ - message: str - """Echoed message (or default greeting)""" +class PermissionPathsWorkspaceCheckResult: + """Indicates whether the supplied path is within the session's workspace directory.""" - protocol_version: int - """Server protocol version number""" - - timestamp: int - """Server timestamp in milliseconds""" + allowed: bool + """Whether the path is within the session workspace directory""" @staticmethod - def from_dict(obj: Any) -> 'PingResult': + def from_dict(obj: Any) -> 'PermissionPathsWorkspaceCheckResult': assert isinstance(obj, dict) - message = from_str(obj.get("message")) - protocol_version = from_int(obj.get("protocolVersion")) - timestamp = from_int(obj.get("timestamp")) - return PingResult(message, protocol_version, timestamp) + allowed = from_bool(obj.get("allowed")) + return PermissionPathsWorkspaceCheckResult(allowed) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - result["protocolVersion"] = from_int(self.protocol_version) - result["timestamp"] = from_int(self.timestamp) + result["allowed"] = from_bool(self.allowed) return result @dataclass -class PlanReadResult: - """Existence, contents, and resolved path of the session plan file.""" +class PermissionPromptShownNotification: + """Notification payload describing the permission prompt that the client just rendered.""" - exists: bool - """Whether the plan file exists in the workspace""" + message: str + """Human-readable description of the prompt the user is being asked to approve. Used by the + runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, + desktop notification). + """ - content: str | None = None - """The content of the plan file, or null if it does not exist""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionPromptShownNotification': + assert isinstance(obj, dict) + message = from_str(obj.get("message")) + return PermissionPromptShownNotification(message) - path: str | None = None - """Absolute file path of the plan file, or null if workspace is not enabled""" + def to_dict(self) -> dict: + result: dict = {} + result["message"] = from_str(self.message) + return result + +@dataclass +class PermissionRequestResult: + """Indicates whether the permission decision was applied; false when the request was already + resolved. + """ + success: bool + """Whether the permission request was handled successfully""" @staticmethod - def from_dict(obj: Any) -> 'PlanReadResult': + def from_dict(obj: Any) -> 'PermissionRequestResult': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - content = from_union([from_none, from_str], obj.get("content")) - path = from_union([from_none, from_str], obj.get("path")) - return PlanReadResult(exists, content, path) + success = from_bool(obj.get("success")) + return PermissionRequestResult(success) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) - result["content"] = from_union([from_none, from_str], self.content) - result["path"] = from_union([from_none, from_str], self.path) + result["success"] = from_bool(self.success) return result @dataclass -class PlanUpdateRequest: - """Replacement contents to write to the session plan file.""" +class PermissionRulesSet: + """If specified, replaces the session's approved/denied permission rules. Omit to leave the + current rules unchanged. + """ + approved: list[PermissionRule] + """Rules that auto-approve matching requests""" - content: str - """The new content for the plan file""" + denied: list[PermissionRule] + """Rules that auto-deny matching requests""" @staticmethod - def from_dict(obj: Any) -> 'PlanUpdateRequest': + def from_dict(obj: Any) -> 'PermissionRulesSet': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - return PlanUpdateRequest(content) + approved = from_list(PermissionRule.from_dict, obj.get("approved")) + denied = from_list(PermissionRule.from_dict, obj.get("denied")) + return PermissionRulesSet(approved, denied) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) + result["approved"] = from_list(lambda x: to_class(PermissionRule, x), self.approved) + result["denied"] = from_list(lambda x: to_class(PermissionRule, x), self.denied) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class Plugin: - """Schema for the `Plugin` type.""" +class PermissionUrlsConfig: + """If specified, replaces the session's URL-permission policy. The runtime constructs a + fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy + unchanged. + """ + initial_allowed: list[str] | None = None + """Initial list of allowed URL/domain patterns. Patterns may include path components. + Ignored when `unrestricted` is true. + """ + unrestricted: bool | None = None + """If true, the runtime allows access to all URLs without prompting. Initial allow-list is + ignored when this is true. + """ - enabled: bool - """Whether the plugin is currently enabled""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionUrlsConfig': + assert isinstance(obj, dict) + initial_allowed = from_union([lambda x: from_list(from_str, x), from_none], obj.get("initialAllowed")) + unrestricted = from_union([from_bool, from_none], obj.get("unrestricted")) + return PermissionUrlsConfig(initial_allowed, unrestricted) - marketplace: str - """Marketplace the plugin came from""" + def to_dict(self) -> dict: + result: dict = {} + if self.initial_allowed is not None: + result["initialAllowed"] = from_union([lambda x: from_list(from_str, x), from_none], self.initial_allowed) + if self.unrestricted is not None: + result["unrestricted"] = from_union([from_bool, from_none], self.unrestricted) + return result - name: str - """Plugin name""" +@dataclass +class PermissionUrlsSetUnrestrictedModeParams: + """Whether the URL-permission policy should run in unrestricted mode.""" - version: str | None = None - """Installed version""" + enabled: bool + """Whether to allow access to all URLs without prompting. Toggles the runtime's + URL-permission policy in place. + """ @staticmethod - def from_dict(obj: Any) -> 'Plugin': + def from_dict(obj: Any) -> 'PermissionUrlsSetUnrestrictedModeParams': assert isinstance(obj, dict) enabled = from_bool(obj.get("enabled")) - marketplace = from_str(obj.get("marketplace")) - name = from_str(obj.get("name")) - version = from_union([from_str, from_none], obj.get("version")) - return Plugin(enabled, marketplace, name, version) + return PermissionUrlsSetUnrestrictedModeParams(enabled) def to_dict(self) -> dict: result: dict = {} result["enabled"] = from_bool(self.enabled) - result["marketplace"] = from_str(self.marketplace) - result["name"] = from_str(self.name) - if self.version is not None: - result["version"] = from_union([from_str, from_none], self.version) return result @dataclass -class QueuedCommandHandled: - """Schema for the `QueuedCommandHandled` type.""" +class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource: + """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.""" - handled: bool - """The command was handled""" - - stop_processing_queue: bool | None = None - """If true, stop processing remaining queued items""" + name: str + type: str @staticmethod - def from_dict(obj: Any) -> 'QueuedCommandHandled': + def from_dict(obj: Any) -> 'PermissionsConfigureAdditionalContentExclusionPolicyRuleSource': assert isinstance(obj, dict) - handled = from_bool(obj.get("handled")) - stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) - return QueuedCommandHandled(handled, stop_processing_queue) + name = from_str(obj.get("name")) + type = from_str(obj.get("type")) + return PermissionsConfigureAdditionalContentExclusionPolicyRuleSource(name, type) def to_dict(self) -> dict: result: dict = {} - result["handled"] = from_bool(self.handled) - if self.stop_processing_queue is not None: - result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) + result["name"] = from_str(self.name) + result["type"] = from_str(self.type) return result +class PermissionsConfigureAdditionalContentExclusionPolicyScope(Enum): + """Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` + enumeration. + """ + ALL = "all" + REPO = "repo" + @dataclass -class QueuedCommandNotHandled: - """Schema for the `QueuedCommandNotHandled` type.""" +class PermissionsConfigureResult: + """Indicates whether the operation succeeded.""" - handled: bool - """The command was not handled""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'QueuedCommandNotHandled': + def from_dict(obj: Any) -> 'PermissionsConfigureResult': assert isinstance(obj, dict) - handled = from_bool(obj.get("handled")) - return QueuedCommandNotHandled(handled) + success = from_bool(obj.get("success")) + return PermissionsConfigureResult(success) def to_dict(self) -> dict: result: dict = {} - result["handled"] = from_bool(self.handled) + result["success"] = from_bool(self.success) return result -# Experimental: this type is part of an experimental API and may change or be removed. -class RemoteSessionMode(Enum): - """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub - without enabling remote steering, "on" enables both export and remote steering. +class PermissionsModifyRulesScope(Enum): + """Whether the change applies to ephemeral session-scoped rules (cleared at session end) or + to location-scoped rules persisted via the location-permissions config file. """ - EXPORT = "export" - OFF = "off" - ON = "on" + LOCATION = "location" + SESSION = "session" -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteEnableResult: - """GitHub URL for the session and a flag indicating whether remote steering is enabled.""" - - remote_steerable: bool - """Whether remote steering is enabled""" +class PermissionsModifyRulesResult: + """Indicates whether the operation succeeded.""" - url: str | None = None - """GitHub frontend URL for this session""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'RemoteEnableResult': + def from_dict(obj: Any) -> 'PermissionsModifyRulesResult': assert isinstance(obj, dict) - remote_steerable = from_bool(obj.get("remoteSteerable")) - url = from_union([from_str, from_none], obj.get("url")) - return RemoteEnableResult(remote_steerable, url) + success = from_bool(obj.get("success")) + return PermissionsModifyRulesResult(success) def to_dict(self) -> dict: result: dict = {} - result["remoteSteerable"] = from_bool(self.remote_steerable) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["success"] = from_bool(self.success) return result @dataclass -class ServerSkill: - """Schema for the `ServerSkill` type.""" +class PermissionsNotifyPromptShownResult: + """Indicates whether the operation succeeded.""" - description: str - """Description of what the skill does""" + success: bool + """Whether the operation succeeded""" - enabled: bool - """Whether the skill is currently enabled (based on global config)""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionsNotifyPromptShownResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + return PermissionsNotifyPromptShownResult(success) - name: str - """Unique identifier for the skill""" + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + return result - source: SkillSource - """Source location type (e.g., project, personal-copilot, plugin, builtin)""" +@dataclass +class PermissionsPathsAddResult: + """Indicates whether the operation succeeded.""" - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" + success: bool + """Whether the operation succeeded""" - path: str | None = None - """Absolute path to the skill file""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionsPathsAddResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + return PermissionsPathsAddResult(success) - project_path: str | None = None - """The project path this skill belongs to (only for project/inherited skills)""" + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + return result +@dataclass +class PermissionsPathsListRequest: + """No parameters; returns the session's allow-listed directories.""" @staticmethod - def from_dict(obj: Any) -> 'ServerSkill': + def from_dict(obj: Any) -> 'PermissionsPathsListRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = SkillSource(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - project_path = from_union([from_str, from_none], obj.get("projectPath")) - return ServerSkill(description, enabled, name, source, user_invocable, path, project_path) + return PermissionsPathsListRequest() def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(SkillSource, self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) - if self.project_path is not None: - result["projectPath"] = from_union([from_str, from_none], self.project_path) return result @dataclass -class SessionFSAppendFileRequest: - """File path, content to append, and optional mode for the client-provided session - filesystem. - """ - content: str - """Content to append""" +class PermissionsPathsUpdatePrimaryResult: + """Indicates whether the operation succeeded.""" - path: str - """Path using SessionFs conventions""" + success: bool + """Whether the operation succeeded""" - session_id: str - """Target session identifier""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionsPathsUpdatePrimaryResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + return PermissionsPathsUpdatePrimaryResult(success) - mode: int | None = None - """Optional POSIX-style mode for newly created files""" + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + return result +@dataclass +class PermissionsPendingRequestsRequest: + """No parameters; returns currently-pending permission requests for the session.""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSAppendFileRequest': + def from_dict(obj: Any) -> 'PermissionsPendingRequestsRequest': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - return SessionFSAppendFileRequest(content, path, session_id, mode) + return PermissionsPendingRequestsRequest() def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) return result -class SessionFSErrorCode(Enum): - """Error classification""" +@dataclass +class PermissionsResetSessionApprovalsRequest: + """No parameters; clears all session-scoped tool permission approvals.""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsRequest': + assert isinstance(obj, dict) + return PermissionsResetSessionApprovalsRequest() - ENOENT = "ENOENT" - UNKNOWN = "UNKNOWN" + def to_dict(self) -> dict: + result: dict = {} + return result @dataclass -class SessionFSExistsRequest: - """Path to test for existence in the client-provided session filesystem.""" - - path: str - """Path using SessionFs conventions""" +class PermissionsResetSessionApprovalsResult: + """Indicates whether the operation succeeded.""" - session_id: str - """Target session identifier""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSExistsRequest': + def from_dict(obj: Any) -> 'PermissionsResetSessionApprovalsResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSExistsRequest(path, session_id) + success = from_bool(obj.get("success")) + return PermissionsResetSessionApprovalsResult(success) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["success"] = from_bool(self.success) return result @dataclass -class SessionFSExistsResult: - """Indicates whether the requested path exists in the client-provided session filesystem.""" +class PermissionsSetApproveAllResult: + """Indicates whether the operation succeeded.""" - exists: bool - """Whether the path exists""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSExistsResult': + def from_dict(obj: Any) -> 'PermissionsSetApproveAllResult': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - return SessionFSExistsResult(exists) + success = from_bool(obj.get("success")) + return PermissionsSetApproveAllResult(success) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) + result["success"] = from_bool(self.success) return result @dataclass -class SessionFSMkdirRequest: - """Directory path to create in the client-provided session filesystem, with options for - recursive creation and POSIX mode. - """ - path: str - """Path using SessionFs conventions""" - - session_id: str - """Target session identifier""" - - mode: int | None = None - """Optional POSIX-style mode for newly created directories""" +class PermissionsSetRequiredRequest: + """Toggles whether permission prompts should be bridged into session events for this client.""" - recursive: bool | None = None - """Create parent directories as needed""" + required: bool + """Whether the client wants `permission.requested` events bridged from the session-owned + permission service. CLI clients that render prompt UI set this to `true` for as long as + their listener is mounted; headless callers leave it unset (the default is `false`). + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSMkdirRequest': + def from_dict(obj: Any) -> 'PermissionsSetRequiredRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - recursive = from_union([from_bool, from_none], obj.get("recursive")) - return SessionFSMkdirRequest(path, session_id, mode, recursive) + required = from_bool(obj.get("required")) + return PermissionsSetRequiredRequest(required) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) - if self.recursive is not None: - result["recursive"] = from_union([from_bool, from_none], self.recursive) + result["required"] = from_bool(self.required) return result @dataclass -class SessionFSReadFileRequest: - """Path of the file to read from the client-provided session filesystem.""" - - path: str - """Path using SessionFs conventions""" +class PermissionsSetRequiredResult: + """Indicates whether the operation succeeded.""" - session_id: str - """Target session identifier""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReadFileRequest': + def from_dict(obj: Any) -> 'PermissionsSetRequiredResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReadFileRequest(path, session_id) + success = from_bool(obj.get("success")) + return PermissionsSetRequiredResult(success) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["success"] = from_bool(self.success) return result @dataclass -class SessionFSReaddirRequest: - """Directory path whose entries should be listed from the client-provided session filesystem.""" - - path: str - """Path using SessionFs conventions""" +class PermissionsUrlsSetUnrestrictedModeResult: + """Indicates whether the operation succeeded.""" - session_id: str - """Target session identifier""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirRequest': + def from_dict(obj: Any) -> 'PermissionsUrlsSetUnrestrictedModeResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReaddirRequest(path, session_id) + success = from_bool(obj.get("success")) + return PermissionsUrlsSetUnrestrictedModeResult(success) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["success"] = from_bool(self.success) return result -class SessionFSReaddirWithTypesEntryType(Enum): - """Entry type""" - - DIRECTORY = "directory" - FILE = "file" - @dataclass -class SessionFSReaddirWithTypesRequest: - """Directory path whose entries (with type information) should be listed from the - client-provided session filesystem. - """ - path: str - """Path using SessionFs conventions""" +class PingRequest: + """Optional message to echo back to the caller.""" - session_id: str - """Target session identifier""" + message: str | None = None + """Optional message to echo back""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesRequest': + def from_dict(obj: Any) -> 'PingRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSReaddirWithTypesRequest(path, session_id) + message = from_union([from_str, from_none], obj.get("message")) + return PingRequest(message) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) return result @dataclass -class SessionFSRenameRequest: - """Source and destination paths for renaming or moving an entry in the client-provided - session filesystem. +class PingResult: + """Server liveness response, including the echoed message, current server timestamp, and + protocol version. """ - dest: str - """Destination path using SessionFs conventions""" + message: str + """Echoed message (or default greeting)""" - session_id: str - """Target session identifier""" + protocol_version: int + """Server protocol version number""" - src: str - """Source path using SessionFs conventions""" + timestamp: datetime + """ISO 8601 timestamp when the server handled the ping""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSRenameRequest': + def from_dict(obj: Any) -> 'PingResult': assert isinstance(obj, dict) - dest = from_str(obj.get("dest")) - session_id = from_str(obj.get("sessionId")) - src = from_str(obj.get("src")) - return SessionFSRenameRequest(dest, session_id, src) + message = from_str(obj.get("message")) + protocol_version = from_int(obj.get("protocolVersion")) + timestamp = from_datetime(obj.get("timestamp")) + return PingResult(message, protocol_version, timestamp) def to_dict(self) -> dict: result: dict = {} - result["dest"] = from_str(self.dest) - result["sessionId"] = from_str(self.session_id) - result["src"] = from_str(self.src) + result["message"] = from_str(self.message) + result["protocolVersion"] = from_int(self.protocol_version) + result["timestamp"] = self.timestamp.isoformat() return result @dataclass -class SessionFSRmRequest: - """Path to remove from the client-provided session filesystem, with options for recursive - removal and force. - """ - path: str - """Path using SessionFs conventions""" +class PlanReadResult: + """Existence, contents, and resolved path of the session plan file.""" - session_id: str - """Target session identifier""" + exists: bool + """Whether the plan file exists in the workspace""" - force: bool | None = None - """Ignore errors if the path does not exist""" + content: str | None = None + """The content of the plan file, or null if it does not exist""" - recursive: bool | None = None - """Remove directories and their contents recursively""" + path: str | None = None + """Absolute file path of the plan file, or null if workspace is not enabled""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSRmRequest': + def from_dict(obj: Any) -> 'PlanReadResult': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - force = from_union([from_bool, from_none], obj.get("force")) - recursive = from_union([from_bool, from_none], obj.get("recursive")) - return SessionFSRmRequest(path, session_id, force, recursive) + exists = from_bool(obj.get("exists")) + content = from_union([from_none, from_str], obj.get("content")) + path = from_union([from_none, from_str], obj.get("path")) + return PlanReadResult(exists, content, path) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.force is not None: - result["force"] = from_union([from_bool, from_none], self.force) - if self.recursive is not None: - result["recursive"] = from_union([from_bool, from_none], self.recursive) + result["exists"] = from_bool(self.exists) + result["content"] = from_union([from_none, from_str], self.content) + result["path"] = from_union([from_none, from_str], self.path) return result @dataclass -class SessionFSSetProviderCapabilities: - """Optional capabilities declared by the provider""" +class PlanUpdateRequest: + """Replacement contents to write to the session plan file.""" - sqlite: bool | None = None - """Whether the provider supports SQLite query/exists operations""" + content: str + """The new content for the plan file""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderCapabilities': + def from_dict(obj: Any) -> 'PlanUpdateRequest': assert isinstance(obj, dict) - sqlite = from_union([from_bool, from_none], obj.get("sqlite")) - return SessionFSSetProviderCapabilities(sqlite) + content = from_str(obj.get("content")) + return PlanUpdateRequest(content) def to_dict(self) -> dict: result: dict = {} - if self.sqlite is not None: - result["sqlite"] = from_union([from_bool, from_none], self.sqlite) + result["content"] = from_str(self.content) return result -class SessionFSSetProviderConventions(Enum): - """Path conventions used by this filesystem""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class Plugin: + """Schema for the `Plugin` type.""" - POSIX = "posix" - WINDOWS = "windows" + enabled: bool + """Whether the plugin is currently enabled""" -@dataclass -class SessionFSSetProviderResult: - """Indicates whether the calling client was registered as the session filesystem provider.""" + marketplace: str + """Marketplace the plugin came from""" - success: bool - """Whether the provider was set successfully""" + name: str + """Plugin name""" + + version: str | None = None + """Installed version""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderResult': + def from_dict(obj: Any) -> 'Plugin': assert isinstance(obj, dict) - success = from_bool(obj.get("success")) - return SessionFSSetProviderResult(success) + enabled = from_bool(obj.get("enabled")) + marketplace = from_str(obj.get("marketplace")) + name = from_str(obj.get("name")) + version = from_union([from_str, from_none], obj.get("version")) + return Plugin(enabled, marketplace, name, version) def to_dict(self) -> dict: result: dict = {} - result["success"] = from_bool(self.success) + result["enabled"] = from_bool(self.enabled) + result["marketplace"] = from_str(self.marketplace) + result["name"] = from_str(self.name) + if self.version is not None: + result["version"] = from_union([from_str, from_none], self.version) return result +# Experimental: this type is part of an experimental API and may change or be removed. +class QueuePendingItemsKind(Enum): + """Whether this item is a queued user message or a queued slash command / model change""" + + COMMAND = "command" + MESSAGE = "message" + +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSSqliteExistsRequest: - """Identifies the target session.""" +class QueueRemoveMostRecentResult: + """Indicates whether a user-facing pending item was removed.""" - session_id: str - """Target session identifier""" + removed: bool + """True if a user-facing pending item was removed (LIFO across both queues); false when no + removable items remained. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteExistsRequest': + def from_dict(obj: Any) -> 'QueueRemoveMostRecentResult': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - return SessionFSSqliteExistsRequest(session_id) + removed = from_bool(obj.get("removed")) + return QueueRemoveMostRecentResult(removed) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) + result["removed"] = from_bool(self.removed) return result @dataclass -class SessionFSSqliteExistsResult: - """Indicates whether the per-session SQLite database already exists.""" +class QueuedCommandHandled: + """Schema for the `QueuedCommandHandled` type.""" - exists: bool - """Whether the session database already exists""" + handled: bool + """The host actually executed the queued command.""" + + stop_processing_queue: bool | None = None + """When true, the runtime will not process subsequent queued commands until a new request + comes in. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteExistsResult': + def from_dict(obj: Any) -> 'QueuedCommandHandled': assert isinstance(obj, dict) - exists = from_bool(obj.get("exists")) - return SessionFSSqliteExistsResult(exists) + handled = from_bool(obj.get("handled")) + stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) + return QueuedCommandHandled(handled, stop_processing_queue) def to_dict(self) -> dict: result: dict = {} - result["exists"] = from_bool(self.exists) + result["handled"] = from_bool(self.handled) + if self.stop_processing_queue is not None: + result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) return result -class SessionFSSqliteQueryType(Enum): - """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT - (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) - """ - EXEC = "exec" - QUERY = "query" - RUN = "run" - @dataclass -class SessionFSStatRequest: - """Path whose metadata should be returned from the client-provided session filesystem.""" - - path: str - """Path using SessionFs conventions""" +class QueuedCommandNotHandled: + """Schema for the `QueuedCommandNotHandled` type.""" - session_id: str - """Target session identifier""" + handled: bool + """The host did not execute the queued command. Unblocks the queue without claiming the + command was processed (e.g. when the handler threw before completing). + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSStatRequest': + def from_dict(obj: Any) -> 'QueuedCommandNotHandled': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - return SessionFSStatRequest(path, session_id) + handled = from_bool(obj.get("handled")) + return QueuedCommandNotHandled(handled) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) + result["handled"] = from_bool(self.handled) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSWriteFileRequest: - """File path, content to write, and optional mode for the client-provided session filesystem.""" +class RegisterEventInterestParams: + """Event type to register consumer interest for, used by runtime gating logic.""" + + event_type: str + """The event type the consumer wants the runtime to treat as 'observed' for + behavior-switching gating. Some runtime code paths inspect whether any consumer is + interested in a specific event type and choose a different implementation accordingly + (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates the full + interactive OAuth flow to the consumer; when no interest is registered the runtime + installs a browserless fallback that silently reuses cached tokens). SDK clients that + long-poll events do NOT automatically appear as listeners to these gating checks — they + must explicitly call `registerInterest` for each event type they want the runtime to + count as having a consumer. Multiple registrations for the same event type from the same + or different consumers are tracked independently and must each be released. See: + `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, + `user_input.requested`, `elicitation.requested`, `command.queued`, + `exit_plan_mode.requested`. + """ - content: str - """Content to write""" + @staticmethod + def from_dict(obj: Any) -> 'RegisterEventInterestParams': + assert isinstance(obj, dict) + event_type = from_str(obj.get("eventType")) + return RegisterEventInterestParams(event_type) - path: str - """Path using SessionFs conventions""" + def to_dict(self) -> dict: + result: dict = {} + result["eventType"] = from_str(self.event_type) + return result - session_id: str - """Target session identifier""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class RegisterEventInterestResult: + """Opaque handle representing an event-type interest registration.""" - mode: int | None = None - """Optional POSIX-style mode for newly created files""" + handle: str + """Opaque handle for this registration. Pass to releaseInterest to release. Each call to + registerInterest produces a fresh handle, even when the same eventType is registered + multiple times. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSWriteFileRequest': + def from_dict(obj: Any) -> 'RegisterEventInterestResult': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - session_id = from_str(obj.get("sessionId")) - mode = from_union([from_int, from_none], obj.get("mode")) - return SessionFSWriteFileRequest(content, path, session_id, mode) + handle = from_str(obj.get("handle")) + return RegisterEventInterestResult(handle) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) - result["sessionId"] = from_str(self.session_id) - if self.mode is not None: - result["mode"] = from_union([from_int, from_none], self.mode) + result["handle"] = from_str(self.handle) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsForkRequest: - """Source session identifier to fork from, optional event-ID boundary, and optional friendly - name for the new session. - """ - session_id: str - """Source session ID to fork from""" - - name: str | None = None - """Optional friendly name to assign to the forked session.""" - - to_event_id: str | None = None - """Optional event ID boundary. When provided, the fork includes only events before this ID - (exclusive). When omitted, all events are included. +class ReleaseEventInterestParams: + """Opaque handle previously returned by `registerInterest` to release.""" + + handle: str + """Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown + or already-released handle is a no-op (returns success). When the last outstanding handle + for an event type is released, the runtime reverts to its 'no consumer' code path for + that event type. """ @staticmethod - def from_dict(obj: Any) -> 'SessionsForkRequest': + def from_dict(obj: Any) -> 'ReleaseEventInterestParams': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - name = from_union([from_str, from_none], obj.get("name")) - to_event_id = from_union([from_str, from_none], obj.get("toEventId")) - return SessionsForkRequest(session_id, name, to_event_id) + handle = from_str(obj.get("handle")) + return ReleaseEventInterestParams(handle) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.to_event_id is not None: - result["toEventId"] = from_union([from_str, from_none], self.to_event_id) + result["handle"] = from_str(self.handle) return result +# Experimental: this type is part of an experimental API and may change or be removed. +class RemoteSessionMode(Enum): + """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub + without enabling remote steering, "on" enables both export and remote steering. + """ + EXPORT = "export" + OFF = "off" + ON = "on" + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionsForkResult: - """Identifier and optional friendly name assigned to the newly forked session.""" +class RemoteEnableResult: + """GitHub URL for the session and a flag indicating whether remote steering is enabled.""" - session_id: str - """The new forked session's ID""" + remote_steerable: bool + """Whether remote steering is enabled""" - name: str | None = None - """Friendly name assigned to the forked session, if any.""" + url: str | None = None + """GitHub frontend URL for this session""" @staticmethod - def from_dict(obj: Any) -> 'SessionsForkResult': + def from_dict(obj: Any) -> 'RemoteEnableResult': assert isinstance(obj, dict) - session_id = from_str(obj.get("sessionId")) - name = from_union([from_str, from_none], obj.get("name")) - return SessionsForkResult(session_id, name) + remote_steerable = from_bool(obj.get("remoteSteerable")) + url = from_union([from_str, from_none], obj.get("url")) + return RemoteEnableResult(remote_steerable, url) def to_dict(self) -> dict: result: dict = {} - result["sessionId"] = from_str(self.session_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) + result["remoteSteerable"] = from_bool(self.remote_steerable) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ShellExecRequest: - """Shell command to run, with optional working directory and timeout in milliseconds.""" - - command: str - """Shell command to execute""" - - cwd: str | None = None - """Working directory (defaults to session working directory)""" +class RemoteNotifySteerableChangedRequest: + """New remote-steerability state to persist as a `session.remote_steerable_changed` event.""" - timeout: int | None = None - """Timeout in milliseconds (default: 30000)""" + remote_steerable: bool + """Whether the session now supports remote steering via GitHub. The runtime persists this as + a `session.remote_steerable_changed` event so resume/replay sees the up-to-date + capability. + """ @staticmethod - def from_dict(obj: Any) -> 'ShellExecRequest': + def from_dict(obj: Any) -> 'RemoteNotifySteerableChangedRequest': assert isinstance(obj, dict) - command = from_str(obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - return ShellExecRequest(command, cwd, timeout) - - def to_dict(self) -> dict: - result: dict = {} - result["command"] = from_str(self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - return result - -@dataclass -class ShellExecResult: - """Identifier of the spawned process, used to correlate streamed output and exit - notifications. - """ - process_id: str - """Unique identifier for tracking streamed output""" - - @staticmethod - def from_dict(obj: Any) -> 'ShellExecResult': - assert isinstance(obj, dict) - process_id = from_str(obj.get("processId")) - return ShellExecResult(process_id) + remote_steerable = from_bool(obj.get("remoteSteerable")) + return RemoteNotifySteerableChangedRequest(remote_steerable) def to_dict(self) -> dict: result: dict = {} - result["processId"] = from_str(self.process_id) + result["remoteSteerable"] = from_bool(self.remote_steerable) return result -class ShellKillSignal(Enum): - """Signal to send (default: SIGTERM)""" - - SIGINT = "SIGINT" - SIGKILL = "SIGKILL" - SIGTERM = "SIGTERM" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ShellKillResult: - """Indicates whether the signal was delivered; false if the process was unknown or already - exited. +class RemoteNotifySteerableChangedResult: + """Persist a steerability change as a `session.remote_steerable_changed` event. Used by the + host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a + remote exporter that the runtime does not directly own. """ - killed: bool - """Whether the signal was sent successfully""" - @staticmethod - def from_dict(obj: Any) -> 'ShellKillResult': + def from_dict(obj: Any) -> 'RemoteNotifySteerableChangedResult': assert isinstance(obj, dict) - killed = from_bool(obj.get("killed")) - return ShellKillResult(killed) + return RemoteNotifySteerableChangedResult() def to_dict(self) -> dict: result: dict = {} - result["killed"] = from_bool(self.killed) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class Skill: - """Schema for the `Skill` type.""" - - description: str - """Description of what the skill does""" +class ScheduleEntry: + """Schema for the `ScheduleEntry` type. - enabled: bool - """Whether the skill is currently enabled""" + The removed entry, or omitted if no entry matched. + """ + id: int + """Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt + from the event log). + """ + interval_ms: int + """Interval between scheduled ticks, in milliseconds.""" - name: str - """Unique identifier for the skill""" + next_run_at: datetime + """ISO 8601 timestamp when the next tick is scheduled to fire.""" - source: SkillSource - """Source location type (e.g., project, personal-copilot, plugin, builtin)""" + prompt: str + """Prompt text that gets enqueued on every tick.""" - user_invocable: bool - """Whether the skill can be invoked by the user as a slash command""" + recurring: bool + """Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`).""" - path: str | None = None - """Absolute path to the skill file""" + display_prompt: str | None = None + """Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a + skill-invocation schedule). The actual enqueued prompt is `prompt`. + """ @staticmethod - def from_dict(obj: Any) -> 'Skill': + def from_dict(obj: Any) -> 'ScheduleEntry': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = SkillSource(obj.get("source")) - user_invocable = from_bool(obj.get("userInvocable")) - path = from_union([from_str, from_none], obj.get("path")) - return Skill(description, enabled, name, source, user_invocable, path) + id = from_int(obj.get("id")) + interval_ms = from_int(obj.get("intervalMs")) + next_run_at = from_datetime(obj.get("nextRunAt")) + prompt = from_str(obj.get("prompt")) + recurring = from_bool(obj.get("recurring")) + display_prompt = from_union([from_str, from_none], obj.get("displayPrompt")) + return ScheduleEntry(id, interval_ms, next_run_at, prompt, recurring, display_prompt) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(SkillSource, self.source) - result["userInvocable"] = from_bool(self.user_invocable) - if self.path is not None: - result["path"] = from_union([from_str, from_none], self.path) + result["id"] = from_int(self.id) + result["intervalMs"] = from_int(self.interval_ms) + result["nextRunAt"] = self.next_run_at.isoformat() + result["prompt"] = from_str(self.prompt) + result["recurring"] = from_bool(self.recurring) + if self.display_prompt is not None: + result["displayPrompt"] = from_union([from_str, from_none], self.display_prompt) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillsDisableRequest: - """Name of the skill to disable for the session.""" +class ScheduleStopRequest: + """Identifier of the scheduled prompt to remove.""" - name: str - """Name of the skill to disable""" + id: int + """Id of the scheduled prompt to remove.""" @staticmethod - def from_dict(obj: Any) -> 'SkillsDisableRequest': + def from_dict(obj: Any) -> 'ScheduleStopRequest': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return SkillsDisableRequest(name) + id = from_int(obj.get("id")) + return ScheduleStopRequest(id) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["id"] = from_int(self.id) return result +class SendAgentMode(Enum): + """The UI mode the agent was in when this message was sent. Defaults to the session's + current mode. + """ + AUTOPILOT = "autopilot" + INTERACTIVE = "interactive" + PLAN = "plan" + SHELL = "shell" + @dataclass -class SkillsDiscoverRequest: - """Optional project paths and additional skill directories to include in discovery.""" +class SendAttachmentFileLineRange: + """Optional line range to scope the attachment to a specific section of the file""" - project_paths: list[str] | None = None - """Optional list of project directory paths to scan for project-scoped skills""" + end: int + """End line number (1-based, inclusive)""" - skill_directories: list[str] | None = None - """Optional list of additional skill directory paths to include""" + start: int + """Start line number (1-based)""" @staticmethod - def from_dict(obj: Any) -> 'SkillsDiscoverRequest': + def from_dict(obj: Any) -> 'SendAttachmentFileLineRange': assert isinstance(obj, dict) - project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) - return SkillsDiscoverRequest(project_paths, skill_directories) + end = from_int(obj.get("end")) + start = from_int(obj.get("start")) + return SendAttachmentFileLineRange(end, start) def to_dict(self) -> dict: result: dict = {} - if self.project_paths is not None: - result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) - if self.skill_directories is not None: - result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) + result["end"] = from_int(self.end) + result["start"] = from_int(self.start) return result -# Experimental: this type is part of an experimental API and may change or be removed. +class SendAttachmentGithubReferenceTypeEnum(Enum): + """Type of GitHub reference""" + + DISCUSSION = "discussion" + ISSUE = "issue" + PR = "pr" + @dataclass -class SkillsEnableRequest: - """Name of the skill to enable for the session.""" +class SendAttachmentSelectionDetailsEnd: + """End position of the selection""" - name: str - """Name of the skill to enable""" + character: int + """End character offset within the line (0-based)""" + + line: int + """End line number (0-based)""" @staticmethod - def from_dict(obj: Any) -> 'SkillsEnableRequest': + def from_dict(obj: Any) -> 'SendAttachmentSelectionDetailsEnd': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - return SkillsEnableRequest(name) + character = from_int(obj.get("character")) + line = from_int(obj.get("line")) + return SendAttachmentSelectionDetailsEnd(character, line) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) + result["character"] = from_int(self.character) + result["line"] = from_int(self.line) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillsLoadDiagnostics: - """Diagnostics from reloading skill definitions, with warnings and errors as separate lists.""" +class SendAttachmentSelectionDetailsStart: + """Start position of the selection""" - errors: list[str] - """Errors emitted while loading skills (e.g. skills that failed to load entirely)""" + character: int + """Start character offset within the line (0-based)""" - warnings: list[str] - """Warnings emitted while loading skills (e.g. skills that loaded but had issues)""" + line: int + """Start line number (0-based)""" @staticmethod - def from_dict(obj: Any) -> 'SkillsLoadDiagnostics': + def from_dict(obj: Any) -> 'SendAttachmentSelectionDetailsStart': assert isinstance(obj, dict) - errors = from_list(from_str, obj.get("errors")) - warnings = from_list(from_str, obj.get("warnings")) - return SkillsLoadDiagnostics(errors, warnings) + character = from_int(obj.get("character")) + line = from_int(obj.get("line")) + return SendAttachmentSelectionDetailsStart(character, line) def to_dict(self) -> dict: result: dict = {} - result["errors"] = from_list(from_str, self.errors) - result["warnings"] = from_list(from_str, self.warnings) + result["character"] = from_int(self.character) + result["line"] = from_int(self.line) return result -class SlashCommandAgentPromptResultKind(Enum): - AGENT_PROMPT = "agent-prompt" - -class SlashCommandCompletedResultKind(Enum): - COMPLETED = "completed" - -class SlashCommandInvocationResultKind(Enum): - AGENT_PROMPT = "agent-prompt" - COMPLETED = "completed" - TEXT = "text" - -# Experimental: this type is part of an experimental API and may change or be removed. -class TaskExecutionMode(Enum): - """Whether task execution is synchronously awaited or managed in the background""" +class SendAttachmentType(Enum): + BLOB = "blob" + DIRECTORY = "directory" + FILE = "file" + GITHUB_REFERENCE = "github_reference" + SELECTION = "selection" - BACKGROUND = "background" - SYNC = "sync" +class SendAttachmentBlobType(Enum): + BLOB = "blob" -# Experimental: this type is part of an experimental API and may change or be removed. -class TaskStatus(Enum): - """Current lifecycle status of the task""" +class SendAttachmentFileType(Enum): + FILE = "file" - CANCELLED = "cancelled" - COMPLETED = "completed" - FAILED = "failed" - IDLE = "idle" - RUNNING = "running" +class SendAttachmentGithubReferenceType(Enum): + GITHUB_REFERENCE = "github_reference" -class TaskAgentInfoType(Enum): - AGENT = "agent" +class SendAttachmentSelectionType(Enum): + SELECTION = "selection" -# Experimental: this type is part of an experimental API and may change or be removed. -class TaskShellInfoAttachmentMode(Enum): - """Whether the shell runs inside a managed PTY session or as an independent background - process +class SendMode(Enum): + """How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` + interjects during an in-progress turn. """ - ATTACHED = "attached" - DETACHED = "detached" - -class TaskInfoType(Enum): - AGENT = "agent" - SHELL = "shell" - -class TaskShellInfoType(Enum): - SHELL = "shell" + ENQUEUE = "enqueue" + IMMEDIATE = "immediate" -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksCancelRequest: - """Identifier of the background task to cancel.""" +class SendResult: + """Result of sending a user message""" - id: str - """Task identifier""" + message_id: str + """Unique identifier assigned to the message""" @staticmethod - def from_dict(obj: Any) -> 'TasksCancelRequest': + def from_dict(obj: Any) -> 'SendResult': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksCancelRequest(id) + message_id = from_str(obj.get("messageId")) + return SendResult(message_id) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) + result["messageId"] = from_str(self.message_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksCancelResult: - """Indicates whether the background task was successfully cancelled.""" +class ServerSkill: + """Schema for the `ServerSkill` type.""" - cancelled: bool - """Whether the task was successfully cancelled""" + description: str + """Description of what the skill does""" - @staticmethod - def from_dict(obj: Any) -> 'TasksCancelResult': - assert isinstance(obj, dict) - cancelled = from_bool(obj.get("cancelled")) - return TasksCancelResult(cancelled) + enabled: bool + """Whether the skill is currently enabled (based on global config)""" - def to_dict(self) -> dict: - result: dict = {} - result["cancelled"] = from_bool(self.cancelled) - return result + name: str + """Unique identifier for the skill""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksPromoteToBackgroundRequest: - """Identifier of the task to promote to background mode.""" + source: SkillSource + """Source location type (e.g., project, personal-copilot, plugin, builtin)""" - id: str - """Task identifier""" + user_invocable: bool + """Whether the skill can be invoked by the user as a slash command""" + + path: str | None = None + """Absolute path to the skill file""" + + project_path: str | None = None + """The project path this skill belongs to (only for project/inherited skills)""" @staticmethod - def from_dict(obj: Any) -> 'TasksPromoteToBackgroundRequest': + def from_dict(obj: Any) -> 'ServerSkill': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksPromoteToBackgroundRequest(id) + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = SkillSource(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_str, from_none], obj.get("path")) + project_path = from_union([from_str, from_none], obj.get("projectPath")) + return ServerSkill(description, enabled, name, source, user_invocable, path, project_path) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(SkillSource, self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.project_path is not None: + result["projectPath"] = from_union([from_str, from_none], self.project_path) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksPromoteToBackgroundResult: - """Indicates whether the task was successfully promoted to background mode.""" +class SessionBulkDeleteResult: + """Map of sessionId -> bytes freed by removing the session's workspace directory.""" - promoted: bool - """Whether the task was successfully promoted to background mode""" + freed_bytes: dict[str, int] + """Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions + whose deletion failed are omitted from this map (failures are logged on the server but + not surfaced per-id; check the map for absent IDs to detect them). + """ @staticmethod - def from_dict(obj: Any) -> 'TasksPromoteToBackgroundResult': + def from_dict(obj: Any) -> 'SessionBulkDeleteResult': assert isinstance(obj, dict) - promoted = from_bool(obj.get("promoted")) - return TasksPromoteToBackgroundResult(promoted) + freed_bytes = from_dict(from_int, obj.get("freedBytes")) + return SessionBulkDeleteResult(freed_bytes) def to_dict(self) -> dict: result: dict = {} - result["promoted"] = from_bool(self.promoted) + result["freedBytes"] = from_dict(from_int, self.freed_bytes) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksRemoveRequest: - """Identifier of the completed or cancelled task to remove from tracking.""" - - id: str - """Task identifier""" +class SessionFSAppendFileRequest: + """File path, content to append, and optional mode for the client-provided session + filesystem. + """ + content: str + """Content to append""" - @staticmethod - def from_dict(obj: Any) -> 'TasksRemoveRequest': - assert isinstance(obj, dict) - id = from_str(obj.get("id")) - return TasksRemoveRequest(id) + path: str + """Path using SessionFs conventions""" - def to_dict(self) -> dict: - result: dict = {} - result["id"] = from_str(self.id) - return result + session_id: str + """Target session identifier""" -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksRemoveResult: - """Indicates whether the task was removed. False when the task does not exist or is still - running/idle. - """ - removed: bool - """Whether the task was removed. Returns false if the task does not exist or is still - running/idle (cancel it first). - """ + mode: int | None = None + """Optional POSIX-style mode for newly created files""" @staticmethod - def from_dict(obj: Any) -> 'TasksRemoveResult': + def from_dict(obj: Any) -> 'SessionFSAppendFileRequest': assert isinstance(obj, dict) - removed = from_bool(obj.get("removed")) - return TasksRemoveResult(removed) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + return SessionFSAppendFileRequest(content, path, session_id, mode) def to_dict(self) -> dict: result: dict = {} - result["removed"] = from_bool(self.removed) + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class TasksSendMessageRequest: - """Identifier of the target agent task, message content, and optional sender agent ID.""" +class SessionFSErrorCode(Enum): + """Error classification""" - id: str - """Agent task identifier""" + ENOENT = "ENOENT" + UNKNOWN = "UNKNOWN" - message: str - """Message content to send to the agent""" +@dataclass +class SessionFSExistsRequest: + """Path to test for existence in the client-provided session filesystem.""" - from_agent_id: str | None = None - """Agent ID of the sender, if sent on behalf of another agent""" + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'TasksSendMessageRequest': + def from_dict(obj: Any) -> 'SessionFSExistsRequest': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - message = from_str(obj.get("message")) - from_agent_id = from_union([from_str, from_none], obj.get("fromAgentId")) - return TasksSendMessageRequest(id, message, from_agent_id) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSExistsRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) - result["message"] = from_str(self.message) - if self.from_agent_id is not None: - result["fromAgentId"] = from_union([from_str, from_none], self.from_agent_id) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksSendMessageResult: - """Indicates whether the message was delivered, with an error message when delivery failed.""" - - sent: bool - """Whether the message was successfully delivered or steered""" +class SessionFSExistsResult: + """Indicates whether the requested path exists in the client-provided session filesystem.""" - error: str | None = None - """Error message if delivery failed""" + exists: bool + """Whether the path exists""" @staticmethod - def from_dict(obj: Any) -> 'TasksSendMessageResult': + def from_dict(obj: Any) -> 'SessionFSExistsResult': assert isinstance(obj, dict) - sent = from_bool(obj.get("sent")) - error = from_union([from_str, from_none], obj.get("error")) - return TasksSendMessageResult(sent, error) + exists = from_bool(obj.get("exists")) + return SessionFSExistsResult(exists) def to_dict(self) -> dict: result: dict = {} - result["sent"] = from_bool(self.sent) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) + result["exists"] = from_bool(self.exists) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksStartAgentRequest: - """Agent type, prompt, name, and optional description and model override for the new task.""" - - agent_type: str - """Type of agent to start (e.g., 'explore', 'task', 'general-purpose')""" - - name: str - """Short name for the agent, used to generate a human-readable ID""" +class SessionFSMkdirRequest: + """Directory path to create in the client-provided session filesystem, with options for + recursive creation and POSIX mode. + """ + path: str + """Path using SessionFs conventions""" - prompt: str - """Task prompt for the agent""" + session_id: str + """Target session identifier""" - description: str | None = None - """Short description of the task""" + mode: int | None = None + """Optional POSIX-style mode for newly created directories""" - model: str | None = None - """Optional model override""" + recursive: bool | None = None + """Create parent directories as needed""" @staticmethod - def from_dict(obj: Any) -> 'TasksStartAgentRequest': + def from_dict(obj: Any) -> 'SessionFSMkdirRequest': assert isinstance(obj, dict) - agent_type = from_str(obj.get("agentType")) - name = from_str(obj.get("name")) - prompt = from_str(obj.get("prompt")) - description = from_union([from_str, from_none], obj.get("description")) - model = from_union([from_str, from_none], obj.get("model")) - return TasksStartAgentRequest(agent_type, name, prompt, description, model) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + recursive = from_union([from_bool, from_none], obj.get("recursive")) + return SessionFSMkdirRequest(path, session_id, mode, recursive) def to_dict(self) -> dict: result: dict = {} - result["agentType"] = from_str(self.agent_type) - result["name"] = from_str(self.name) - result["prompt"] = from_str(self.prompt) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) + if self.recursive is not None: + result["recursive"] = from_union([from_bool, from_none], self.recursive) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TasksStartAgentResult: - """Identifier assigned to the newly started background agent task.""" +class SessionFSReadFileRequest: + """Path of the file to read from the client-provided session filesystem.""" - agent_id: str - """Generated agent ID for the background task""" + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'TasksStartAgentResult': + def from_dict(obj: Any) -> 'SessionFSReadFileRequest': assert isinstance(obj, dict) - agent_id = from_str(obj.get("agentId")) - return TasksStartAgentResult(agent_id) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReadFileRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["agentId"] = from_str(self.agent_id) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class Tool: - """Schema for the `Tool` type.""" - - description: str - """Description of what the tool does""" - - name: str - """Tool identifier (e.g., "bash", "grep", "str_replace_editor")""" +class SessionFSReaddirRequest: + """Directory path whose entries should be listed from the client-provided session filesystem.""" - instructions: str | None = None - """Optional instructions for how to use this tool effectively""" + path: str + """Path using SessionFs conventions""" - namespaced_name: str | None = None - """Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP - tools) - """ - parameters: dict[str, Any] | None = None - """JSON Schema for the tool's input parameters""" + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'Tool': + def from_dict(obj: Any) -> 'SessionFSReaddirRequest': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - name = from_str(obj.get("name")) - instructions = from_union([from_str, from_none], obj.get("instructions")) - namespaced_name = from_union([from_str, from_none], obj.get("namespacedName")) - parameters = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("parameters")) - return Tool(description, name, instructions, namespaced_name, parameters) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReaddirRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["name"] = from_str(self.name) - if self.instructions is not None: - result["instructions"] = from_union([from_str, from_none], self.instructions) - if self.namespaced_name is not None: - result["namespacedName"] = from_union([from_str, from_none], self.namespaced_name) - if self.parameters is not None: - result["parameters"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.parameters) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result -@dataclass -class ToolsListRequest: - """Optional model identifier whose tool overrides should be applied to the listing.""" +class SessionFSReaddirWithTypesEntryType(Enum): + """Entry type""" - model: str | None = None - """Optional model ID — when provided, the returned tool list reflects model-specific - overrides + DIRECTORY = "directory" + FILE = "file" + +@dataclass +class SessionFSReaddirWithTypesRequest: + """Directory path whose entries (with type information) should be listed from the + client-provided session filesystem. """ + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'ToolsListRequest': + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesRequest': assert isinstance(obj, dict) - model = from_union([from_str, from_none], obj.get("model")) - return ToolsListRequest(model) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSReaddirWithTypesRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result @dataclass -class UIElicitationArrayAnyOfFieldItemsAnyOf: - """Schema for the `UIElicitationArrayAnyOfFieldItemsAnyOf` type.""" +class SessionFSRenameRequest: + """Source and destination paths for renaming or moving an entry in the client-provided + session filesystem. + """ + dest: str + """Destination path using SessionFs conventions""" - const: str - """Value submitted when this option is selected.""" + session_id: str + """Target session identifier""" - title: str - """Display label for this option.""" + src: str + """Source path using SessionFs conventions""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItemsAnyOf': + def from_dict(obj: Any) -> 'SessionFSRenameRequest': assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return UIElicitationArrayAnyOfFieldItemsAnyOf(const, title) + dest = from_str(obj.get("dest")) + session_id = from_str(obj.get("sessionId")) + src = from_str(obj.get("src")) + return SessionFSRenameRequest(dest, session_id, src) def to_dict(self) -> dict: result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) + result["dest"] = from_str(self.dest) + result["sessionId"] = from_str(self.session_id) + result["src"] = from_str(self.src) return result -class UIElicitationArrayAnyOfFieldType(Enum): - ARRAY = "array" - -class UIElicitationArrayEnumFieldItemsType(Enum): - STRING = "string" - -class UIElicitationSchemaPropertyStringFormat(Enum): - """Optional format hint that constrains the accepted input.""" - - DATE = "date" - DATE_TIME = "date-time" - EMAIL = "email" - URI = "uri" - @dataclass -class UIElicitationStringOneOfFieldOneOf: - """Schema for the `UIElicitationStringOneOfFieldOneOf` type.""" +class SessionFSRmRequest: + """Path to remove from the client-provided session filesystem, with options for recursive + removal and force. + """ + path: str + """Path using SessionFs conventions""" - const: str - """Value submitted when this option is selected.""" + session_id: str + """Target session identifier""" - title: str - """Display label for this option.""" + force: bool | None = None + """Ignore errors if the path does not exist""" + + recursive: bool | None = None + """Remove directories and their contents recursively""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringOneOfFieldOneOf': + def from_dict(obj: Any) -> 'SessionFSRmRequest': assert isinstance(obj, dict) - const = from_str(obj.get("const")) - title = from_str(obj.get("title")) - return UIElicitationStringOneOfFieldOneOf(const, title) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + force = from_union([from_bool, from_none], obj.get("force")) + recursive = from_union([from_bool, from_none], obj.get("recursive")) + return SessionFSRmRequest(path, session_id, force, recursive) def to_dict(self) -> dict: result: dict = {} - result["const"] = from_str(self.const) - result["title"] = from_str(self.title) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.force is not None: + result["force"] = from_union([from_bool, from_none], self.force) + if self.recursive is not None: + result["recursive"] = from_union([from_bool, from_none], self.recursive) return result -class UIElicitationSchemaPropertyType(Enum): - """Numeric type accepted by the field.""" +@dataclass +class SessionFSSetProviderCapabilities: + """Optional capabilities declared by the provider""" - ARRAY = "array" - BOOLEAN = "boolean" - INTEGER = "integer" - NUMBER = "number" - STRING = "string" + sqlite: bool | None = None + """Whether the provider supports SQLite query/exists operations""" -class UIElicitationSchemaType(Enum): - OBJECT = "object" + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSetProviderCapabilities': + assert isinstance(obj, dict) + sqlite = from_union([from_bool, from_none], obj.get("sqlite")) + return SessionFSSetProviderCapabilities(sqlite) -class UIElicitationResponseAction(Enum): - """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" + def to_dict(self) -> dict: + result: dict = {} + if self.sqlite is not None: + result["sqlite"] = from_union([from_bool, from_none], self.sqlite) + return result - ACCEPT = "accept" - CANCEL = "cancel" - DECLINE = "decline" +class SessionFSSetProviderConventions(Enum): + """Path conventions used by this filesystem""" + + POSIX = "posix" + WINDOWS = "windows" @dataclass -class UIElicitationResult: - """Indicates whether the elicitation response was accepted; false if it was already resolved - by another client. - """ +class SessionFSSetProviderResult: + """Indicates whether the calling client was registered as the session filesystem provider.""" + success: bool - """Whether the response was accepted. False if the request was already resolved by another - client. - """ + """Whether the provider was set successfully""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationResult': + def from_dict(obj: Any) -> 'SessionFSSetProviderResult': assert isinstance(obj, dict) success = from_bool(obj.get("success")) - return UIElicitationResult(success) + return SessionFSSetProviderResult(success) def to_dict(self) -> dict: result: dict = {} result["success"] = from_bool(self.success) return result -class UIElicitationSchemaPropertyBooleanType(Enum): - BOOLEAN = "boolean" +@dataclass +class SessionFSSqliteExistsRequest: + """Identifies the target session.""" -class UIElicitationSchemaPropertyNumberType(Enum): - """Numeric type accepted by the field.""" + session_id: str + """Target session identifier""" - INTEGER = "integer" - NUMBER = "number" + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSqliteExistsRequest': + assert isinstance(obj, dict) + session_id = from_str(obj.get("sessionId")) + return SessionFSSqliteExistsRequest(session_id) + + def to_dict(self) -> dict: + result: dict = {} + result["sessionId"] = from_str(self.session_id) + return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsCodeChanges: - """Aggregated code change metrics""" +class SessionFSSqliteExistsResult: + """Indicates whether the per-session SQLite database already exists.""" - files_modified_count: int - """Number of distinct files modified""" + exists: bool + """Whether the session database already exists""" - lines_added: int - """Total lines of code added""" + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSqliteExistsResult': + assert isinstance(obj, dict) + exists = from_bool(obj.get("exists")) + return SessionFSSqliteExistsResult(exists) - lines_removed: int - """Total lines of code removed""" + def to_dict(self) -> dict: + result: dict = {} + result["exists"] = from_bool(self.exists) + return result + +class SessionFSSqliteQueryType(Enum): + """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT + (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) + """ + EXEC = "exec" + QUERY = "query" + RUN = "run" + +@dataclass +class SessionFSStatRequest: + """Path whose metadata should be returned from the client-provided session filesystem.""" + + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsCodeChanges': + def from_dict(obj: Any) -> 'SessionFSStatRequest': assert isinstance(obj, dict) - files_modified_count = from_int(obj.get("filesModifiedCount")) - lines_added = from_int(obj.get("linesAdded")) - lines_removed = from_int(obj.get("linesRemoved")) - return UsageMetricsCodeChanges(files_modified_count, lines_added, lines_removed) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + return SessionFSStatRequest(path, session_id) def to_dict(self) -> dict: result: dict = {} - result["filesModifiedCount"] = from_int(self.files_modified_count) - result["linesAdded"] = from_int(self.lines_added) - result["linesRemoved"] = from_int(self.lines_removed) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsModelMetricRequests: - """Request count and cost metrics for this model""" +class SessionFSWriteFileRequest: + """File path, content to write, and optional mode for the client-provided session filesystem.""" - cost: float - """User-initiated premium request cost (with multiplier applied)""" + content: str + """Content to write""" - count: int - """Number of API requests made with this model""" + path: str + """Path using SessionFs conventions""" + + session_id: str + """Target session identifier""" + + mode: int | None = None + """Optional POSIX-style mode for newly created files""" @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetricRequests': + def from_dict(obj: Any) -> 'SessionFSWriteFileRequest': assert isinstance(obj, dict) - cost = from_float(obj.get("cost")) - count = from_int(obj.get("count")) - return UsageMetricsModelMetricRequests(cost, count) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + session_id = from_str(obj.get("sessionId")) + mode = from_union([from_int, from_none], obj.get("mode")) + return SessionFSWriteFileRequest(content, path, session_id, mode) def to_dict(self) -> dict: result: dict = {} - result["cost"] = to_float(self.cost) - result["count"] = from_int(self.count) + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + result["sessionId"] = from_str(self.session_id) + if self.mode is not None: + result["mode"] = from_union([from_int, from_none], self.mode) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsModelMetricTokenDetail: - """Schema for the `UsageMetricsModelMetricTokenDetail` type.""" +class SessionLoadDeferredRepoHooksResult: + """Queued repo-level startup prompts and the total hook command count after loading.""" - token_count: int - """Accumulated token count for this token type""" + hook_count: int + """Total hook command count (user + plugin + repo) loaded for the session by this call. + Captured atomically with startupPrompts so callers don't need to read a separate counter. + """ + startup_prompts: list[str] + """Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo + configs were pending, or when disableAllHooks is set. + """ @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetricTokenDetail': + def from_dict(obj: Any) -> 'SessionLoadDeferredRepoHooksResult': assert isinstance(obj, dict) - token_count = from_int(obj.get("tokenCount")) - return UsageMetricsModelMetricTokenDetail(token_count) + hook_count = from_int(obj.get("hookCount")) + startup_prompts = from_list(from_str, obj.get("startupPrompts")) + return SessionLoadDeferredRepoHooksResult(hook_count, startup_prompts) def to_dict(self) -> dict: result: dict = {} - result["tokenCount"] = from_int(self.token_count) + result["hookCount"] = from_int(self.hook_count) + result["startupPrompts"] = from_list(from_str, self.startup_prompts) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsModelMetricUsage: - """Token usage metrics for this model""" - - cache_read_tokens: int - """Total tokens read from prompt cache""" +class SessionPruneResult: + """Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes + freed, and the dry-run flag. + """ + candidates: list[str] + """Session IDs that would be deleted in dry-run mode (always empty otherwise)""" - cache_write_tokens: int - """Total tokens written to prompt cache""" + deleted: list[str] + """Session IDs that were deleted (always empty in dry-run mode)""" - input_tokens: int - """Total input tokens consumed""" + dry_run: bool + """True when no deletions were actually performed""" - output_tokens: int - """Total output tokens produced""" + freed_bytes: int + """Total bytes freed (actual when not dry-run, projected when dry-run)""" - reasoning_tokens: int | None = None - """Total output tokens used for reasoning""" + skipped: list[str] + """Session IDs that were skipped (e.g., named sessions)""" @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetricUsage': + def from_dict(obj: Any) -> 'SessionPruneResult': assert isinstance(obj, dict) - cache_read_tokens = from_int(obj.get("cacheReadTokens")) - cache_write_tokens = from_int(obj.get("cacheWriteTokens")) - input_tokens = from_int(obj.get("inputTokens")) - output_tokens = from_int(obj.get("outputTokens")) - reasoning_tokens = from_union([from_int, from_none], obj.get("reasoningTokens")) - return UsageMetricsModelMetricUsage(cache_read_tokens, cache_write_tokens, input_tokens, output_tokens, reasoning_tokens) + candidates = from_list(from_str, obj.get("candidates")) + deleted = from_list(from_str, obj.get("deleted")) + dry_run = from_bool(obj.get("dryRun")) + freed_bytes = from_int(obj.get("freedBytes")) + skipped = from_list(from_str, obj.get("skipped")) + return SessionPruneResult(candidates, deleted, dry_run, freed_bytes, skipped) def to_dict(self) -> dict: result: dict = {} - result["cacheReadTokens"] = from_int(self.cache_read_tokens) - result["cacheWriteTokens"] = from_int(self.cache_write_tokens) - result["inputTokens"] = from_int(self.input_tokens) - result["outputTokens"] = from_int(self.output_tokens) - if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_int, from_none], self.reasoning_tokens) + result["candidates"] = from_list(from_str, self.candidates) + result["deleted"] = from_list(from_str, self.deleted) + result["dryRun"] = from_bool(self.dry_run) + result["freedBytes"] = from_int(self.freed_bytes) + result["skipped"] = from_list(from_str, self.skipped) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsTokenDetail: - """Schema for the `UsageMetricsTokenDetail` type.""" +class SessionSetCredentialsResult: + """Indicates whether the credential update succeeded.""" - token_count: int - """Accumulated token count for this token type""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsTokenDetail': + def from_dict(obj: Any) -> 'SessionSetCredentialsResult': assert isinstance(obj, dict) - token_count = from_int(obj.get("tokenCount")) - return UsageMetricsTokenDetail(token_count) + success = from_bool(obj.get("success")) + return SessionSetCredentialsResult(success) def to_dict(self) -> dict: result: dict = {} - result["tokenCount"] = from_int(self.token_count) + result["success"] = from_bool(self.success) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class WorkspacesCreateFileRequest: - """Relative path and UTF-8 content for the workspace file to create or overwrite.""" - - content: str - """File content to write as a UTF-8 string""" +class SessionSizes: + """Map of sessionId -> on-disk size in bytes for each session's workspace directory.""" - path: str - """Relative path within the workspace files directory""" + sizes: dict[str, int] + """Map of sessionId -> on-disk size in bytes for the session's workspace directory""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': + def from_dict(obj: Any) -> 'SessionSizes': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - path = from_str(obj.get("path")) - return WorkspacesCreateFileRequest(content, path) + sizes = from_dict(from_int, obj.get("sizes")) + return SessionSizes(sizes) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["path"] = from_str(self.path) + result["sizes"] = from_dict(from_int, self.sizes) return result -class HostType(Enum): - ADO = "ado" - GITHUB = "github" - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class WorkspacesListFilesResult: - """Relative paths of files stored in the session workspace files directory.""" +class SessionUpdateOptionsResult: + """Indicates whether the session options patch was applied successfully.""" - files: list[str] - """Relative file paths in the workspace files directory""" + success: bool + """Whether the operation succeeded""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesListFilesResult': + def from_dict(obj: Any) -> 'SessionUpdateOptionsResult': assert isinstance(obj, dict) - files = from_list(from_str, obj.get("files")) - return WorkspacesListFilesResult(files) + success = from_bool(obj.get("success")) + return SessionUpdateOptionsResult(success) def to_dict(self) -> dict: result: dict = {} - result["files"] = from_list(from_str, self.files) + result["success"] = from_bool(self.success) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class WorkspacesReadFileRequest: - """Relative path of the workspace file to read.""" +class SessionsBulkDeleteRequest: + """Session IDs to close, deactivate, and delete from disk.""" - path: str - """Relative path within the workspace files directory""" + session_ids: list[str] + """Session IDs to close, deactivate, and delete from disk""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': + def from_dict(obj: Any) -> 'SessionsBulkDeleteRequest': assert isinstance(obj, dict) - path = from_str(obj.get("path")) - return WorkspacesReadFileRequest(path) + session_ids = from_list(from_str, obj.get("sessionIds")) + return SessionsBulkDeleteRequest(session_ids) def to_dict(self) -> dict: result: dict = {} - result["path"] = from_str(self.path) + result["sessionIds"] = from_list(from_str, self.session_ids) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class WorkspacesReadFileResult: - """Contents of the requested workspace file as a UTF-8 string.""" +class SessionsCheckInUseRequest: + """Session IDs to test for live in-use locks.""" - content: str - """File content as a UTF-8 string""" + session_ids: list[str] + """Session IDs to test for live in-use locks""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesReadFileResult': + def from_dict(obj: Any) -> 'SessionsCheckInUseRequest': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - return WorkspacesReadFileResult(content) + session_ids = from_list(from_str, obj.get("sessionIds")) + return SessionsCheckInUseRequest(session_ids) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) + result["sessionIds"] = from_list(from_str, self.session_ids) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AccountGetQuotaResult: - """Quota usage snapshots for the resolved user, keyed by quota type.""" +class SessionsCheckInUseResult: + """Session IDs from the input set that are currently in use by another process.""" - quota_snapshots: dict[str, AccountQuotaSnapshot] - """Quota snapshots keyed by type (e.g., chat, completions, premium_interactions)""" + in_use: list[str] + """Session IDs from the input set that are currently held by another running process via an + alive lock file + """ @staticmethod - def from_dict(obj: Any) -> 'AccountGetQuotaResult': + def from_dict(obj: Any) -> 'SessionsCheckInUseResult': assert isinstance(obj, dict) - quota_snapshots = from_dict(AccountQuotaSnapshot.from_dict, obj.get("quotaSnapshots")) - return AccountGetQuotaResult(quota_snapshots) + in_use = from_list(from_str, obj.get("inUse")) + return SessionsCheckInUseResult(in_use) def to_dict(self) -> dict: result: dict = {} - result["quotaSnapshots"] = from_dict(lambda x: to_class(AccountQuotaSnapshot, x), self.quota_snapshots) + result["inUse"] = from_list(from_str, self.in_use) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentGetCurrentResult: - """The currently selected custom agent, or null when using the default agent.""" +class SessionsCloseRequest: + """Session ID to close.""" - agent: AgentInfo | None = None - """Currently selected custom agent, or null if using the default agent""" + session_id: str + """Session ID to close""" @staticmethod - def from_dict(obj: Any) -> 'AgentGetCurrentResult': + def from_dict(obj: Any) -> 'SessionsCloseRequest': assert isinstance(obj, dict) - agent = from_union([AgentInfo.from_dict, from_none], obj.get("agent")) - return AgentGetCurrentResult(agent) + session_id = from_str(obj.get("sessionId")) + return SessionsCloseRequest(session_id) def to_dict(self) -> dict: result: dict = {} - if self.agent is not None: - result["agent"] = from_union([lambda x: to_class(AgentInfo, x), from_none], self.agent) + result["sessionId"] = from_str(self.session_id) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentList: - """Custom agents available to the session.""" - - agents: list[AgentInfo] - """Available custom agents""" - +class SessionsCloseResult: + """Closes a session: emits shutdown, flushes pending events to disk, releases the in-use + lock, disposes the active session. Idempotent: succeeds even if the session is not + currently active. + """ @staticmethod - def from_dict(obj: Any) -> 'AgentList': + def from_dict(obj: Any) -> 'SessionsCloseResult': assert isinstance(obj, dict) - agents = from_list(AgentInfo.from_dict, obj.get("agents")) - return AgentList(agents) + return SessionsCloseResult() def to_dict(self) -> dict: result: dict = {} - result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentReloadResult: - """Custom agents available to the session after reloading definitions from disk.""" +class SessionsFindByPrefixRequest: + """UUID prefix to resolve to a unique session ID.""" - agents: list[AgentInfo] - """Reloaded custom agents""" + prefix: str + """UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when + there is no match or the prefix matches multiple sessions. + """ @staticmethod - def from_dict(obj: Any) -> 'AgentReloadResult': + def from_dict(obj: Any) -> 'SessionsFindByPrefixRequest': assert isinstance(obj, dict) - agents = from_list(AgentInfo.from_dict, obj.get("agents")) - return AgentReloadResult(agents) + prefix = from_str(obj.get("prefix")) + return SessionsFindByPrefixRequest(prefix) def to_dict(self) -> dict: result: dict = {} - result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) + result["prefix"] = from_str(self.prefix) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class AgentSelectResult: - """The newly selected custom agent.""" +class SessionsFindByPrefixResult: + """Session ID matching the prefix, omitted when no unique match exists.""" - agent: AgentInfo - """The newly selected custom agent""" + session_id: str | None = None + """Omitted when no unique session matches the prefix (no match or ambiguous)""" @staticmethod - def from_dict(obj: Any) -> 'AgentSelectResult': + def from_dict(obj: Any) -> 'SessionsFindByPrefixResult': assert isinstance(obj, dict) - agent = AgentInfo.from_dict(obj.get("agent")) - return AgentSelectResult(agent) + session_id = from_union([from_str, from_none], obj.get("sessionId")) + return SessionsFindByPrefixResult(session_id) def to_dict(self) -> dict: result: dict = {} - result["agent"] = to_class(AgentInfo, self.agent) + if self.session_id is not None: + result["sessionId"] = from_union([from_str, from_none], self.session_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionAuthStatus: - """Authentication status and account metadata for the session.""" - - is_authenticated: bool - """Whether the session has resolved authentication""" +class SessionsFindByTaskIDRequest: + """GitHub task ID to look up.""" - auth_type: AuthInfoType | None = None - """Authentication type""" + task_id: str + """GitHub task ID to look up""" - copilot_plan: str | None = None - """Copilot plan tier (e.g., individual_pro, business)""" + @staticmethod + def from_dict(obj: Any) -> 'SessionsFindByTaskIDRequest': + assert isinstance(obj, dict) + task_id = from_str(obj.get("taskId")) + return SessionsFindByTaskIDRequest(task_id) - host: str | None = None - """Authentication host URL""" + def to_dict(self) -> dict: + result: dict = {} + result["taskId"] = from_str(self.task_id) + return result - login: str | None = None - """Authenticated login/username, if available""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsFindByTaskIDResult: + """ID of the local session bound to the given GitHub task, or omitted when none.""" - status_message: str | None = None - """Human-readable authentication status description""" + session_id: str | None = None + """Omitted when no local session is bound to that GitHub task""" @staticmethod - def from_dict(obj: Any) -> 'SessionAuthStatus': + def from_dict(obj: Any) -> 'SessionsFindByTaskIDResult': assert isinstance(obj, dict) - is_authenticated = from_bool(obj.get("isAuthenticated")) - auth_type = from_union([AuthInfoType, from_none], obj.get("authType")) - copilot_plan = from_union([from_str, from_none], obj.get("copilotPlan")) - host = from_union([from_str, from_none], obj.get("host")) - login = from_union([from_str, from_none], obj.get("login")) - status_message = from_union([from_str, from_none], obj.get("statusMessage")) - return SessionAuthStatus(is_authenticated, auth_type, copilot_plan, host, login, status_message) + session_id = from_union([from_str, from_none], obj.get("sessionId")) + return SessionsFindByTaskIDResult(session_id) def to_dict(self) -> dict: result: dict = {} - result["isAuthenticated"] = from_bool(self.is_authenticated) - if self.auth_type is not None: - result["authType"] = from_union([lambda x: to_enum(AuthInfoType, x), from_none], self.auth_type) - if self.copilot_plan is not None: - result["copilotPlan"] = from_union([from_str, from_none], self.copilot_plan) - if self.host is not None: - result["host"] = from_union([from_str, from_none], self.host) - if self.login is not None: - result["login"] = from_union([from_str, from_none], self.login) - if self.status_message is not None: - result["statusMessage"] = from_union([from_str, from_none], self.status_message) + if self.session_id is not None: + result["sessionId"] = from_union([from_str, from_none], self.session_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SlashCommandInput: - """Optional unstructured input hint""" - - hint: str - """Hint to display when command input has not been provided""" +class SessionsForkRequest: + """Source session identifier to fork from, optional event-ID boundary, and optional friendly + name for the new session. + """ + session_id: str + """Source session ID to fork from""" - completion: SlashCommandInputCompletion | None = None - """Optional completion hint for the input (e.g. 'directory' for filesystem path completion)""" + name: str | None = None + """Optional friendly name to assign to the forked session.""" - preserve_multiline_input: bool | None = None - """When true, clients should pass the full text after the command name as a single argument - rather than splitting on whitespace - """ - required: bool | None = None - """When true, the command requires non-empty input; clients should render the input hint as - required + to_event_id: str | None = None + """Optional event ID boundary. When provided, the fork includes only events before this ID + (exclusive). When omitted, all events are included. """ @staticmethod - def from_dict(obj: Any) -> 'SlashCommandInput': + def from_dict(obj: Any) -> 'SessionsForkRequest': assert isinstance(obj, dict) - hint = from_str(obj.get("hint")) - completion = from_union([SlashCommandInputCompletion, from_none], obj.get("completion")) - preserve_multiline_input = from_union([from_bool, from_none], obj.get("preserveMultilineInput")) - required = from_union([from_bool, from_none], obj.get("required")) - return SlashCommandInput(hint, completion, preserve_multiline_input, required) + session_id = from_str(obj.get("sessionId")) + name = from_union([from_str, from_none], obj.get("name")) + to_event_id = from_union([from_str, from_none], obj.get("toEventId")) + return SessionsForkRequest(session_id, name, to_event_id) def to_dict(self) -> dict: result: dict = {} - result["hint"] = from_str(self.hint) - if self.completion is not None: - result["completion"] = from_union([lambda x: to_enum(SlashCommandInputCompletion, x), from_none], self.completion) - if self.preserve_multiline_input is not None: - result["preserveMultilineInput"] = from_union([from_bool, from_none], self.preserve_multiline_input) - if self.required is not None: - result["required"] = from_union([from_bool, from_none], self.required) + result["sessionId"] = from_str(self.session_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.to_event_id is not None: + result["toEventId"] = from_union([from_str, from_none], self.to_event_id) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ConnectedRemoteSessionMetadata: - """Metadata for a connected remote session.""" - - kind: ConnectedRemoteSessionMetadataKind - """Neutral SDK discriminator for the connected remote session kind.""" - - modified_time: datetime - """Last session update time as an ISO 8601 string.""" - - repository: ConnectedRemoteSessionMetadataRepository - """Repository associated with the connected remote session.""" +class SessionsForkResult: + """Identifier and optional friendly name assigned to the newly forked session.""" session_id: str - """SDK session ID for the connected remote session.""" - - start_time: datetime - """Session start time as an ISO 8601 string.""" + """The new forked session's ID""" name: str | None = None - """Optional friendly session name.""" + """Friendly name assigned to the forked session, if any.""" - pull_request_number: int | None = None - """Pull request number associated with the session.""" + @staticmethod + def from_dict(obj: Any) -> 'SessionsForkResult': + assert isinstance(obj, dict) + session_id = from_str(obj.get("sessionId")) + name = from_union([from_str, from_none], obj.get("name")) + return SessionsForkResult(session_id, name) - resource_id: str | None = None - """Original remote resource identifier.""" - - stale_at: datetime | None = None - """Remote session staleness deadline as an ISO 8601 string.""" + def to_dict(self) -> dict: + result: dict = {} + result["sessionId"] = from_str(self.session_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + return result - state: str | None = None - """Remote session state returned by the backing service.""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsGetEventFilePathRequest: + """Session ID whose event-log file path to compute.""" - summary: str | None = None - """Optional session summary.""" + session_id: str + """Session ID whose event-log file path to compute""" @staticmethod - def from_dict(obj: Any) -> 'ConnectedRemoteSessionMetadata': + def from_dict(obj: Any) -> 'SessionsGetEventFilePathRequest': assert isinstance(obj, dict) - kind = ConnectedRemoteSessionMetadataKind(obj.get("kind")) - modified_time = from_datetime(obj.get("modifiedTime")) - repository = ConnectedRemoteSessionMetadataRepository.from_dict(obj.get("repository")) session_id = from_str(obj.get("sessionId")) - start_time = from_datetime(obj.get("startTime")) - name = from_union([from_str, from_none], obj.get("name")) - pull_request_number = from_union([from_int, from_none], obj.get("pullRequestNumber")) - resource_id = from_union([from_str, from_none], obj.get("resourceId")) - stale_at = from_union([from_datetime, from_none], obj.get("staleAt")) - state = from_union([from_str, from_none], obj.get("state")) - summary = from_union([from_str, from_none], obj.get("summary")) - return ConnectedRemoteSessionMetadata(kind, modified_time, repository, session_id, start_time, name, pull_request_number, resource_id, stale_at, state, summary) + return SessionsGetEventFilePathRequest(session_id) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(ConnectedRemoteSessionMetadataKind, self.kind) - result["modifiedTime"] = self.modified_time.isoformat() - result["repository"] = to_class(ConnectedRemoteSessionMetadataRepository, self.repository) result["sessionId"] = from_str(self.session_id) - result["startTime"] = self.start_time.isoformat() - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.pull_request_number is not None: - result["pullRequestNumber"] = from_union([from_int, from_none], self.pull_request_number) - if self.resource_id is not None: - result["resourceId"] = from_union([from_str, from_none], self.resource_id) - if self.stale_at is not None: - result["staleAt"] = from_union([lambda x: x.isoformat(), from_none], self.stale_at) - if self.state is not None: - result["state"] = from_union([from_str, from_none], self.state) - if self.summary is not None: - result["summary"] = from_union([from_str, from_none], self.summary) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPServerConfigStdio: - """Stdio MCP server configuration launched as a child process.""" - - command: str - """Executable command used to start the Stdio MCP server process.""" - - args: list[str] | None = None - """Command-line arguments passed to the Stdio MCP server process.""" - - cwd: str | None = None - """Working directory for the Stdio MCP server process.""" - - env: dict[str, str] | None = None - """Environment variables to pass to the Stdio MCP server process.""" - - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None - """Content filtering mode to apply to all tools, or a map of tool name to content filtering - mode. - """ - is_default_server: bool | None = None - """Whether this server is a built-in fallback used when the user has not configured their - own server. - """ - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" +class SessionsGetEventFilePathResult: + """Absolute path to the session's events.jsonl file on disk.""" - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" + file_path: str + """Absolute path to the session's events.jsonl file""" @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfigStdio': + def from_dict(obj: Any) -> 'SessionsGetEventFilePathResult': assert isinstance(obj, dict) - command = from_str(obj.get("command")) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - return MCPServerConfigStdio(command, args, cwd, env, filter_mapping, is_default_server, timeout, tools) + file_path = from_str(obj.get("filePath")) + return SessionsGetEventFilePathResult(file_path) def to_dict(self) -> dict: result: dict = {} - result["command"] = from_str(self.command) - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + result["filePath"] = from_str(self.file_path) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class DiscoveredMCPServer: - """Schema for the `DiscoveredMcpServer` type.""" - - enabled: bool - """Whether the server is enabled (not in the disabled list)""" +class SessionsGetLastForContextResult: + """Most-relevant session ID for the supplied context, or omitted when no sessions exist.""" - name: str - """Server name (config key)""" - - source: McpServerSource - """Configuration source: user, workspace, plugin, or builtin""" - - type: DiscoveredMCPServerType | None = None - """Server transport type: stdio, http, sse, or memory""" + session_id: str | None = None + """Most-relevant session ID for the supplied context, or omitted when no sessions exist""" @staticmethod - def from_dict(obj: Any) -> 'DiscoveredMCPServer': + def from_dict(obj: Any) -> 'SessionsGetLastForContextResult': assert isinstance(obj, dict) - enabled = from_bool(obj.get("enabled")) - name = from_str(obj.get("name")) - source = McpServerSource(obj.get("source")) - type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) - return DiscoveredMCPServer(enabled, name, source, type) + session_id = from_union([from_str, from_none], obj.get("sessionId")) + return SessionsGetLastForContextResult(session_id) def to_dict(self) -> dict: result: dict = {} - result["enabled"] = from_bool(self.enabled) - result["name"] = from_str(self.name) - result["source"] = to_enum(McpServerSource, self.source) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) + if self.session_id is not None: + result["sessionId"] = from_union([from_str, from_none], self.session_id) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class Extension: - """Schema for the `Extension` type.""" - - id: str - """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')""" +class SessionsGetPersistedRemoteSteerableRequest: + """Session ID to look up the persisted remote-steerable flag for.""" - name: str - """Extension name (directory name)""" - - source: ExtensionSource - """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" - - status: ExtensionStatus - """Current status: running, disabled, failed, or starting""" - - pid: int | None = None - """Process ID if the extension is running""" + session_id: str + """Session ID to look up the persisted remote-steerable flag for""" @staticmethod - def from_dict(obj: Any) -> 'Extension': + def from_dict(obj: Any) -> 'SessionsGetPersistedRemoteSteerableRequest': assert isinstance(obj, dict) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - source = ExtensionSource(obj.get("source")) - status = ExtensionStatus(obj.get("status")) - pid = from_union([from_int, from_none], obj.get("pid")) - return Extension(id, name, source, status, pid) + session_id = from_str(obj.get("sessionId")) + return SessionsGetPersistedRemoteSteerableRequest(session_id) def to_dict(self) -> dict: result: dict = {} - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - result["source"] = to_enum(ExtensionSource, self.source) - result["status"] = to_enum(ExtensionStatus, self.status) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) + result["sessionId"] = from_str(self.session_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmBinaryResultsForLlm: - """Binary result returned by a tool for the model""" - - data: str - """Base64-encoded binary data""" - - mime_type: str - """MIME type of the binary data""" - - type: ExternalToolTextResultForLlmBinaryResultsForLlmType - """Binary result type discriminator. Use "image" for images and "resource" for other binary - data. +class SessionsGetPersistedRemoteSteerableResult: + """The session's persisted remote-steerable flag, or omitted when no value has been + persisted. + """ + remote_steerable: bool | None = None + """The session's persisted remote-steerable flag if recorded; omitted when no value has been + persisted """ - description: str | None = None - """Human-readable description of the binary data""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmBinaryResultsForLlm': + def from_dict(obj: Any) -> 'SessionsGetPersistedRemoteSteerableResult': assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = ExternalToolTextResultForLlmBinaryResultsForLlmType(obj.get("type")) - description = from_union([from_str, from_none], obj.get("description")) - return ExternalToolTextResultForLlmBinaryResultsForLlm(data, mime_type, type, description) + remote_steerable = from_union([from_bool, from_none], obj.get("remoteSteerable")) + return SessionsGetPersistedRemoteSteerableResult(remote_steerable) def to_dict(self) -> dict: result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(ExternalToolTextResultForLlmBinaryResultsForLlmType, self.type) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) + if self.remote_steerable is not None: + result["remoteSteerable"] = from_union([from_bool, from_none], self.remote_steerable) return result @dataclass -class ExternalToolTextResultForLlmContentResourceLinkIcon: - """Icon image for a resource""" +class Filter: + """Optional filter applied to the returned sessions""" - src: str - """URL or path to the icon image""" + branch: str | None = None + """Match sessions whose context.branch equals this value""" - mime_type: str | None = None - """MIME type of the icon image""" + cwd: str | None = None + """Match sessions whose context.cwd equals this value""" - sizes: list[str] | None = None - """Available icon sizes (e.g., ['16x16', '32x32'])""" + git_root: str | None = None + """Match sessions whose context.gitRoot equals this value""" - theme: ExternalToolTextResultForLlmContentResourceLinkIconTheme | None = None - """Theme variant this icon is intended for""" + repository: str | None = None + """Match sessions whose context.repository equals this value""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLinkIcon': + def from_dict(obj: Any) -> 'Filter': assert isinstance(obj, dict) - src = from_str(obj.get("src")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) - sizes = from_union([lambda x: from_list(from_str, x), from_none], obj.get("sizes")) - theme = from_union([ExternalToolTextResultForLlmContentResourceLinkIconTheme, from_none], obj.get("theme")) - return ExternalToolTextResultForLlmContentResourceLinkIcon(src, mime_type, sizes, theme) + branch = from_union([from_str, from_none], obj.get("branch")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + git_root = from_union([from_str, from_none], obj.get("gitRoot")) + repository = from_union([from_str, from_none], obj.get("repository")) + return Filter(branch, cwd, git_root, repository) def to_dict(self) -> dict: result: dict = {} - result["src"] = from_str(self.src) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) - if self.sizes is not None: - result["sizes"] = from_union([lambda x: from_list(from_str, x), from_none], self.sizes) - if self.theme is not None: - result["theme"] = from_union([lambda x: to_enum(ExternalToolTextResultForLlmContentResourceLinkIconTheme, x), from_none], self.theme) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.git_root is not None: + result["gitRoot"] = from_union([from_str, from_none], self.git_root) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) return result -ExternalToolTextResultForLlmContentResourceDetails = EmbeddedTextResourceContents | EmbeddedBlobResourceContents - +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmContentAudio: - """Audio content block with base64-encoded data""" - - data: str - """Base64-encoded audio data""" - - mime_type: str - """MIME type of the audio (e.g., audio/wav, audio/mpeg)""" +class SessionsLoadDeferredRepoHooksRequest: + """Active session ID whose deferred repo-level hooks should be loaded.""" - type: ExternalToolTextResultForLlmContentAudioType - """Content block type discriminator""" + session_id: str + """Active session ID whose deferred repo-level hooks should be loaded""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentAudio': + def from_dict(obj: Any) -> 'SessionsLoadDeferredRepoHooksRequest': assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = ExternalToolTextResultForLlmContentAudioType(obj.get("type")) - return ExternalToolTextResultForLlmContentAudio(data, mime_type, type) + session_id = from_str(obj.get("sessionId")) + return SessionsLoadDeferredRepoHooksRequest(session_id) def to_dict(self) -> dict: result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(ExternalToolTextResultForLlmContentAudioType, self.type) + result["sessionId"] = from_str(self.session_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmContentImage: - """Image content block with base64-encoded data""" +class SessionsPruneOldRequest: + """Age threshold and optional flags controlling which old sessions are pruned (or simulated + when dryRun is true). + """ + older_than_days: int + """Delete sessions whose modifiedTime is at least this many days old""" - data: str - """Base64-encoded image data""" + dry_run: bool | None = None + """When true, only report what would be deleted without performing any deletion""" - mime_type: str - """MIME type of the image (e.g., image/png, image/jpeg)""" + exclude_session_ids: list[str] | None = None + """Session IDs that should never be considered for pruning""" - type: ExternalToolTextResultForLlmContentImageType - """Content block type discriminator""" + include_named: bool | None = None + """When true, named sessions (set via /rename) are also eligible for pruning""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentImage': + def from_dict(obj: Any) -> 'SessionsPruneOldRequest': assert isinstance(obj, dict) - data = from_str(obj.get("data")) - mime_type = from_str(obj.get("mimeType")) - type = ExternalToolTextResultForLlmContentImageType(obj.get("type")) - return ExternalToolTextResultForLlmContentImage(data, mime_type, type) + older_than_days = from_int(obj.get("olderThanDays")) + dry_run = from_union([from_bool, from_none], obj.get("dryRun")) + exclude_session_ids = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludeSessionIds")) + include_named = from_union([from_bool, from_none], obj.get("includeNamed")) + return SessionsPruneOldRequest(older_than_days, dry_run, exclude_session_ids, include_named) def to_dict(self) -> dict: result: dict = {} - result["data"] = from_str(self.data) - result["mimeType"] = from_str(self.mime_type) - result["type"] = to_enum(ExternalToolTextResultForLlmContentImageType, self.type) + result["olderThanDays"] = from_int(self.older_than_days) + if self.dry_run is not None: + result["dryRun"] = from_union([from_bool, from_none], self.dry_run) + if self.exclude_session_ids is not None: + result["excludeSessionIds"] = from_union([lambda x: from_list(from_str, x), from_none], self.exclude_session_ids) + if self.include_named is not None: + result["includeNamed"] = from_union([from_bool, from_none], self.include_named) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmContentResource: - """Embedded resource content block with inline text or binary data""" - - resource: ExternalToolTextResultForLlmContentResourceDetails - """The embedded resource contents, either text or base64-encoded binary""" +class SessionsReleaseLockRequest: + """Session ID whose in-use lock should be released.""" - type: ExternalToolTextResultForLlmContentResourceType - """Content block type discriminator""" + session_id: str + """Session ID whose in-use lock should be released""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResource': + def from_dict(obj: Any) -> 'SessionsReleaseLockRequest': assert isinstance(obj, dict) - resource = (lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x))(obj.get("resource")) - type = ExternalToolTextResultForLlmContentResourceType(obj.get("type")) - return ExternalToolTextResultForLlmContentResource(resource, type) + session_id = from_str(obj.get("sessionId")) + return SessionsReleaseLockRequest(session_id) def to_dict(self) -> dict: result: dict = {} - result["resource"] = from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], self.resource) - result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceType, self.type) + result["sessionId"] = from_str(self.session_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmContentTerminal: - """Terminal/shell output content block with optional exit code and working directory""" +class SessionsReleaseLockResult: + """Release the in-use lock held by this process for the given session. No-op when this + process does not currently hold a lock for the session. + """ + @staticmethod + def from_dict(obj: Any) -> 'SessionsReleaseLockResult': + assert isinstance(obj, dict) + return SessionsReleaseLockResult() - text: str - """Terminal/shell output text""" + def to_dict(self) -> dict: + result: dict = {} + return result - type: ExternalToolTextResultForLlmContentTerminalType - """Content block type discriminator""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsReloadPluginHooksRequest: + """Active session ID and an optional flag for deferring repo-level hooks until folder trust.""" - cwd: str | None = None - """Working directory where the command was executed""" + session_id: str + """Active session ID to reload hooks for""" - exit_code: float | None = None - """Process exit code, if the command has completed""" + defer_repo_hooks: bool | None = None + """When true, skip repo-level hooks. Use before folder trust is confirmed; + loadDeferredRepoHooks loads them post-trust. + """ @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentTerminal': + def from_dict(obj: Any) -> 'SessionsReloadPluginHooksRequest': assert isinstance(obj, dict) - text = from_str(obj.get("text")) - type = ExternalToolTextResultForLlmContentTerminalType(obj.get("type")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - exit_code = from_union([from_float, from_none], obj.get("exitCode")) - return ExternalToolTextResultForLlmContentTerminal(text, type, cwd, exit_code) + session_id = from_str(obj.get("sessionId")) + defer_repo_hooks = from_union([from_bool, from_none], obj.get("deferRepoHooks")) + return SessionsReloadPluginHooksRequest(session_id, defer_repo_hooks) def to_dict(self) -> dict: result: dict = {} - result["text"] = from_str(self.text) - result["type"] = to_enum(ExternalToolTextResultForLlmContentTerminalType, self.type) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.exit_code is not None: - result["exitCode"] = from_union([to_float, from_none], self.exit_code) + result["sessionId"] = from_str(self.session_id) + if self.defer_repo_hooks is not None: + result["deferRepoHooks"] = from_union([from_bool, from_none], self.defer_repo_hooks) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmContentText: - """Plain text content block""" - - text: str - """The text content""" - - type: KindEnum - """Content block type discriminator""" - +class SessionsReloadPluginHooksResult: + """Reload all hooks (user, plugin, optionally repo) and apply them to the active session. + Call after installing or removing plugins so their hooks take effect immediately. No-op + when no active session matches the given sessionId. + """ @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentText': + def from_dict(obj: Any) -> 'SessionsReloadPluginHooksResult': assert isinstance(obj, dict) - text = from_str(obj.get("text")) - type = KindEnum(obj.get("type")) - return ExternalToolTextResultForLlmContentText(text, type) + return SessionsReloadPluginHooksResult() def to_dict(self) -> dict: result: dict = {} - result["text"] = from_str(self.text) - result["type"] = to_enum(KindEnum, self.type) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SlashCommandTextResult: - """Schema for the `SlashCommandTextResult` type.""" +class SessionsSaveRequest: + """Session ID whose pending events should be flushed to disk.""" - kind: KindEnum - """Text result discriminator""" - - text: str - """Text output for the client to render""" + session_id: str + """Session ID whose pending events should be flushed to disk""" - markdown: bool | None = None - """Whether text contains Markdown""" + @staticmethod + def from_dict(obj: Any) -> 'SessionsSaveRequest': + assert isinstance(obj, dict) + session_id = from_str(obj.get("sessionId")) + return SessionsSaveRequest(session_id) - preserve_ansi: bool | None = None - """Whether ANSI sequences should be preserved""" + def to_dict(self) -> dict: + result: dict = {} + result["sessionId"] = from_str(self.session_id) + return result - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsSaveResult: + """Flush a session's pending events to disk. No-op when no writer exists for the session + (e.g., already closed). """ - @staticmethod - def from_dict(obj: Any) -> 'SlashCommandTextResult': + def from_dict(obj: Any) -> 'SessionsSaveResult': assert isinstance(obj, dict) - kind = KindEnum(obj.get("kind")) - text = from_str(obj.get("text")) - markdown = from_union([from_bool, from_none], obj.get("markdown")) - preserve_ansi = from_union([from_bool, from_none], obj.get("preserveAnsi")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - return SlashCommandTextResult(kind, text, markdown, preserve_ansi, runtime_settings_changed) + return SessionsSaveResult() def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(KindEnum, self.kind) - result["text"] = from_str(self.text) - if self.markdown is not None: - result["markdown"] = from_union([from_bool, from_none], self.markdown) - if self.preserve_ansi is not None: - result["preserveAnsi"] = from_union([from_bool, from_none], self.preserve_ansi) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class HistoryCompactResult: - """Compaction outcome with the number of tokens and messages removed and the resulting - context window breakdown. +class SessionsSetAdditionalPluginsResult: + """Replace the manager-wide additional plugins. New session creations and subsequent hook + reloads see the new set; already-running sessions keep their existing hook installation + until the next reload. """ - messages_removed: int - """Number of messages removed during compaction""" - - success: bool - """Whether compaction completed successfully""" - - tokens_removed: int - """Number of tokens freed by compaction""" - - context_window: HistoryCompactContextWindow | None = None - """Post-compaction context window usage breakdown""" - @staticmethod - def from_dict(obj: Any) -> 'HistoryCompactResult': + def from_dict(obj: Any) -> 'SessionsSetAdditionalPluginsResult': assert isinstance(obj, dict) - messages_removed = from_int(obj.get("messagesRemoved")) - success = from_bool(obj.get("success")) - tokens_removed = from_int(obj.get("tokensRemoved")) - context_window = from_union([HistoryCompactContextWindow.from_dict, from_none], obj.get("contextWindow")) - return HistoryCompactResult(messages_removed, success, tokens_removed, context_window) + return SessionsSetAdditionalPluginsResult() def to_dict(self) -> dict: result: dict = {} - result["messagesRemoved"] = from_int(self.messages_removed) - result["success"] = from_bool(self.success) - result["tokensRemoved"] = from_int(self.tokens_removed) - if self.context_window is not None: - result["contextWindow"] = from_union([lambda x: to_class(HistoryCompactContextWindow, x), from_none], self.context_window) return result @dataclass -class InstructionsSources: - """Schema for the `InstructionsSources` type.""" - - content: str - """Raw content of the instruction file""" - - id: str - """Unique identifier for this source (used for toggling)""" +class ShellExecRequest: + """Shell command to run, with optional working directory and timeout in milliseconds.""" - label: str - """Human-readable label""" + command: str + """Shell command to execute""" - location: InstructionsSourcesLocation - """Where this source lives — used for UI grouping""" + cwd: str | None = None + """Working directory (defaults to session working directory)""" - source_path: str - """File path relative to repo or absolute for home""" + timeout: int | None = None + """Timeout in milliseconds (default: 30000)""" - type: InstructionsSourcesType - """Category of instruction source — used for merge logic""" + @staticmethod + def from_dict(obj: Any) -> 'ShellExecRequest': + assert isinstance(obj, dict) + command = from_str(obj.get("command")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + return ShellExecRequest(command, cwd, timeout) - apply_to: str | None = None - """Glob pattern from frontmatter — when set, this instruction applies only to matching files""" + def to_dict(self) -> dict: + result: dict = {} + result["command"] = from_str(self.command) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + return result - description: str | None = None - """Short description (body after frontmatter) for use in instruction tables""" +@dataclass +class ShellExecResult: + """Identifier of the spawned process, used to correlate streamed output and exit + notifications. + """ + process_id: str + """Unique identifier for tracking streamed output""" @staticmethod - def from_dict(obj: Any) -> 'InstructionsSources': + def from_dict(obj: Any) -> 'ShellExecResult': assert isinstance(obj, dict) - content = from_str(obj.get("content")) - id = from_str(obj.get("id")) - label = from_str(obj.get("label")) - location = InstructionsSourcesLocation(obj.get("location")) - source_path = from_str(obj.get("sourcePath")) - type = InstructionsSourcesType(obj.get("type")) - apply_to = from_union([from_str, from_none], obj.get("applyTo")) - description = from_union([from_str, from_none], obj.get("description")) - return InstructionsSources(content, id, label, location, source_path, type, apply_to, description) + process_id = from_str(obj.get("processId")) + return ShellExecResult(process_id) def to_dict(self) -> dict: result: dict = {} - result["content"] = from_str(self.content) - result["id"] = from_str(self.id) - result["label"] = from_str(self.label) - result["location"] = to_enum(InstructionsSourcesLocation, self.location) - result["sourcePath"] = from_str(self.source_path) - result["type"] = to_enum(InstructionsSourcesType, self.type) - if self.apply_to is not None: - result["applyTo"] = from_union([from_str, from_none], self.apply_to) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) + result["processId"] = from_str(self.process_id) return result -@dataclass -class LogRequest: - """Message text, optional severity level, persistence flag, and optional follow-up URL.""" - - message: str - """Human-readable message""" +class ShellKillSignal(Enum): + """Signal to send (default: SIGTERM)""" - ephemeral: bool | None = None - """When true, the message is transient and not persisted to the session event log on disk""" + SIGINT = "SIGINT" + SIGKILL = "SIGKILL" + SIGTERM = "SIGTERM" - level: SessionLogLevel | None = None - """Log severity level. Determines how the message is displayed in the timeline. Defaults to - "info". +@dataclass +class ShellKillResult: + """Indicates whether the signal was delivered; false if the process was unknown or already + exited. """ - url: str | None = None - """Optional URL the user can open in their browser for more details""" + killed: bool + """Whether the signal was sent successfully""" @staticmethod - def from_dict(obj: Any) -> 'LogRequest': + def from_dict(obj: Any) -> 'ShellKillResult': assert isinstance(obj, dict) - message = from_str(obj.get("message")) - ephemeral = from_union([from_bool, from_none], obj.get("ephemeral")) - level = from_union([SessionLogLevel, from_none], obj.get("level")) - url = from_union([from_str, from_none], obj.get("url")) - return LogRequest(message, ephemeral, level, url) + killed = from_bool(obj.get("killed")) + return ShellKillResult(killed) def to_dict(self) -> dict: result: dict = {} - result["message"] = from_str(self.message) - if self.ephemeral is not None: - result["ephemeral"] = from_union([from_bool, from_none], self.ephemeral) - if self.level is not None: - result["level"] = from_union([lambda x: to_enum(SessionLogLevel, x), from_none], self.level) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["killed"] = from_bool(self.killed) return result @dataclass -class MCPServerConfig: - """MCP server configuration (stdio process or remote HTTP/SSE) - - Stdio MCP server configuration launched as a child process. +class ShutdownRequest: + """Parameters for shutting down the session""" - Remote MCP server configuration accessed over HTTP or SSE. + reason: str | None = None + """Optional human-readable reason. Typically the message of the error that triggered + shutdown when type is 'error'. """ - args: list[str] | None = None - """Command-line arguments passed to the Stdio MCP server process.""" + type: ShutdownType | None = None + """Why the session is being shut down. Defaults to "routine" when omitted.""" - command: str | None = None - """Executable command used to start the Stdio MCP server process.""" + @staticmethod + def from_dict(obj: Any) -> 'ShutdownRequest': + assert isinstance(obj, dict) + reason = from_union([from_str, from_none], obj.get("reason")) + type = from_union([ShutdownType, from_none], obj.get("type")) + return ShutdownRequest(reason, type) - cwd: str | None = None - """Working directory for the Stdio MCP server process.""" - - env: dict[str, str] | None = None - """Environment variables to pass to the Stdio MCP server process.""" - - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None - """Content filtering mode to apply to all tools, or a map of tool name to content filtering - mode. - """ - is_default_server: bool | None = None - """Whether this server is a built-in fallback used when the user has not configured their - own server. - """ - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" + def to_dict(self) -> dict: + result: dict = {} + if self.reason is not None: + result["reason"] = from_union([from_str, from_none], self.reason) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(ShutdownType, x), from_none], self.type) + return result - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class Skill: + """Schema for the `Skill` type.""" - auth: MCPServerConfigHTTPAuth | None = None - """Additional authentication configuration for this server.""" + description: str + """Description of what the skill does""" - headers: dict[str, str] | None = None - """HTTP headers to include in requests to the remote MCP server.""" + enabled: bool + """Whether the skill is currently enabled""" - oauth_client_id: str | None = None - """OAuth client ID for a pre-registered remote MCP OAuth client.""" + name: str + """Unique identifier for the skill""" - oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None - """OAuth grant type to use when authenticating to the remote MCP server.""" + source: SkillSource + """Source location type (e.g., project, personal-copilot, plugin, builtin)""" - oauth_public_client: bool | None = None - """Whether the configured OAuth client is public and does not require a client secret.""" + user_invocable: bool + """Whether the skill can be invoked by the user as a slash command""" - type: MCPServerConfigHTTPType | None = None - """Remote transport type. Defaults to "http" when omitted.""" + path: str | None = None + """Absolute path to the skill file""" - url: str | None = None - """URL of the remote MCP server endpoint.""" + plugin_name: str | None = None + """Name of the plugin that provides the skill, when source is 'plugin'""" @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfig': + def from_dict(obj: Any) -> 'Skill': assert isinstance(obj, dict) - args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) - command = from_union([from_str, from_none], obj.get("command")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) - filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) - type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) - url = from_union([from_str, from_none], obj.get("url")) - return MCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, auth, headers, oauth_client_id, oauth_grant_type, oauth_public_client, type, url) + description = from_str(obj.get("description")) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = SkillSource(obj.get("source")) + user_invocable = from_bool(obj.get("userInvocable")) + path = from_union([from_str, from_none], obj.get("path")) + plugin_name = from_union([from_str, from_none], obj.get("pluginName")) + return Skill(description, enabled, name, source, user_invocable, path, plugin_name) def to_dict(self) -> dict: result: dict = {} - if self.args is not None: - result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) - if self.command is not None: - result["command"] = from_union([from_str, from_none], self.command) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.env is not None: - result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.auth is not None: - result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_grant_type is not None: - result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) - if self.url is not None: - result["url"] = from_union([from_str, from_none], self.url) + result["description"] = from_str(self.description) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(SkillSource, self.source) + result["userInvocable"] = from_bool(self.user_invocable) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.plugin_name is not None: + result["pluginName"] = from_union([from_str, from_none], self.plugin_name) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPServerConfigHTTP: - """Remote MCP server configuration accessed over HTTP or SSE.""" - - url: str - """URL of the remote MCP server endpoint.""" - - auth: MCPServerConfigHTTPAuth | None = None - """Additional authentication configuration for this server.""" - - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None - """Content filtering mode to apply to all tools, or a map of tool name to content filtering - mode. - """ - headers: dict[str, str] | None = None - """HTTP headers to include in requests to the remote MCP server.""" +class SkillsDisableRequest: + """Name of the skill to disable for the session.""" - is_default_server: bool | None = None - """Whether this server is a built-in fallback used when the user has not configured their - own server. - """ - oauth_client_id: str | None = None - """OAuth client ID for a pre-registered remote MCP OAuth client.""" + name: str + """Name of the skill to disable""" - oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None - """OAuth grant type to use when authenticating to the remote MCP server.""" + @staticmethod + def from_dict(obj: Any) -> 'SkillsDisableRequest': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + return SkillsDisableRequest(name) - oauth_public_client: bool | None = None - """Whether the configured OAuth client is public and does not require a client secret.""" + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + return result - timeout: int | None = None - """Timeout in milliseconds for tool calls to this server.""" +@dataclass +class SkillsDiscoverRequest: + """Optional project paths and additional skill directories to include in discovery.""" - tools: list[str] | None = None - """Tools to include. Defaults to all tools if not specified.""" + project_paths: list[str] | None = None + """Optional list of project directory paths to scan for project-scoped skills""" - type: MCPServerConfigHTTPType | None = None - """Remote transport type. Defaults to "http" when omitted.""" + skill_directories: list[str] | None = None + """Optional list of additional skill directory paths to include""" @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfigHTTP': + def from_dict(obj: Any) -> 'SkillsDiscoverRequest': assert isinstance(obj, dict) - url = from_str(obj.get("url")) - auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) - filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) - headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) - is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) - oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) - oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) - oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) - timeout = from_union([from_int, from_none], obj.get("timeout")) - tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) - return MCPServerConfigHTTP(url, auth, filter_mapping, headers, is_default_server, oauth_client_id, oauth_grant_type, oauth_public_client, timeout, tools, type) + project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) + skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) + return SkillsDiscoverRequest(project_paths, skill_directories) def to_dict(self) -> dict: result: dict = {} - result["url"] = from_str(self.url) - if self.auth is not None: - result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) - if self.filter_mapping is not None: - result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) - if self.headers is not None: - result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) - if self.is_default_server is not None: - result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) - if self.oauth_client_id is not None: - result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) - if self.oauth_grant_type is not None: - result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) - if self.oauth_public_client is not None: - result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) - if self.timeout is not None: - result["timeout"] = from_union([from_int, from_none], self.timeout) - if self.tools is not None: - result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) + if self.project_paths is not None: + result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) + if self.skill_directories is not None: + result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPServerList: - """MCP servers configured for the session, with their connection status.""" +class SkillsEnableRequest: + """Name of the skill to enable for the session.""" - servers: list[MCPServer] - """Configured MCP servers""" + name: str + """Name of the skill to enable""" @staticmethod - def from_dict(obj: Any) -> 'MCPServerList': + def from_dict(obj: Any) -> 'SkillsEnableRequest': assert isinstance(obj, dict) - servers = from_list(MCPServer.from_dict, obj.get("servers")) - return MCPServerList(servers) + name = from_str(obj.get("name")) + return SkillsEnableRequest(name) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_list(lambda x: to_class(MCPServer, x), self.servers) + result["name"] = from_str(self.name) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelBilling: - """Billing information""" +class SkillsInvokedSkill: + """Schema for the `SkillsInvokedSkill` type.""" - multiplier: float | None = None - """Billing cost multiplier relative to the base rate""" + content: str + """Full content of the skill file""" - token_prices: ModelBillingTokenPrices | None = None - """Token-level pricing information for this model""" + invoked_at_turn: int + """Turn number when the skill was invoked""" + + name: str + """Unique identifier for the skill""" + + path: str + """Path to the SKILL.md file""" + + allowed_tools: list[str] | None = None + """Tools that should be auto-approved when this skill is active, captured at invocation time""" @staticmethod - def from_dict(obj: Any) -> 'ModelBilling': + def from_dict(obj: Any) -> 'SkillsInvokedSkill': assert isinstance(obj, dict) - multiplier = from_union([from_float, from_none], obj.get("multiplier")) - token_prices = from_union([ModelBillingTokenPrices.from_dict, from_none], obj.get("tokenPrices")) - return ModelBilling(multiplier, token_prices) + content = from_str(obj.get("content")) + invoked_at_turn = from_int(obj.get("invokedAtTurn")) + name = from_str(obj.get("name")) + path = from_str(obj.get("path")) + allowed_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("allowedTools")) + return SkillsInvokedSkill(content, invoked_at_turn, name, path, allowed_tools) def to_dict(self) -> dict: result: dict = {} - if self.multiplier is not None: - result["multiplier"] = from_union([to_float, from_none], self.multiplier) - if self.token_prices is not None: - result["tokenPrices"] = from_union([lambda x: to_class(ModelBillingTokenPrices, x), from_none], self.token_prices) + result["content"] = from_str(self.content) + result["invokedAtTurn"] = from_int(self.invoked_at_turn) + result["name"] = from_str(self.name) + result["path"] = from_str(self.path) + if self.allowed_tools is not None: + result["allowedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.allowed_tools) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelCapabilitiesLimits: - """Token limits for prompts, outputs, and context window""" +class SkillsLoadDiagnostics: + """Diagnostics from reloading skill definitions, with warnings and errors as separate lists.""" - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" - - max_output_tokens: int | None = None - """Maximum number of output/completion tokens""" - - max_prompt_tokens: int | None = None - """Maximum number of prompt/input tokens""" + errors: list[str] + """Errors emitted while loading skills (e.g. skills that failed to load entirely)""" - vision: ModelCapabilitiesLimitsVision | None = None - """Vision-specific limits""" + warnings: list[str] + """Warnings emitted while loading skills (e.g. skills that loaded but had issues)""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesLimits': + def from_dict(obj: Any) -> 'SkillsLoadDiagnostics': assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([ModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) + errors = from_list(from_str, obj.get("errors")) + warnings = from_list(from_str, obj.get("warnings")) + return SkillsLoadDiagnostics(errors, warnings) def to_dict(self) -> dict: result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesLimitsVision, x), from_none], self.vision) + result["errors"] = from_list(from_str, self.errors) + result["warnings"] = from_list(from_str, self.warnings) return result -@dataclass -class ModelPolicy: - """Policy state (if applicable)""" +class SlashCommandAgentPromptResultKind(Enum): + AGENT_PROMPT = "agent-prompt" - state: ModelPolicyState - """Current policy state for this model""" +class SlashCommandCompletedResultKind(Enum): + COMPLETED = "completed" - terms: str | None = None - """Usage terms or conditions for this model""" +class SlashCommandInvocationResultKind(Enum): + AGENT_PROMPT = "agent-prompt" + COMPLETED = "completed" + TEXT = "text" + +# Experimental: this type is part of an experimental API and may change or be removed. +class TaskExecutionMode(Enum): + """Whether task execution is synchronously awaited or managed in the background""" + + BACKGROUND = "background" + SYNC = "sync" + +# Experimental: this type is part of an experimental API and may change or be removed. +class TaskStatus(Enum): + """Current lifecycle status of the task""" + + CANCELLED = "cancelled" + COMPLETED = "completed" + FAILED = "failed" + IDLE = "idle" + RUNNING = "running" + +class TaskAgentInfoType(Enum): + AGENT = "agent" + +@dataclass +class RecentActivity: + message: str + """Display message, e.g., "▸ bash", "✓ edit src/foo.ts\"""" + + timestamp: datetime + """ISO 8601 timestamp when this event occurred""" @staticmethod - def from_dict(obj: Any) -> 'ModelPolicy': + def from_dict(obj: Any) -> 'RecentActivity': assert isinstance(obj, dict) - state = ModelPolicyState(obj.get("state")) - terms = from_union([from_str, from_none], obj.get("terms")) - return ModelPolicy(state, terms) + message = from_str(obj.get("message")) + timestamp = from_datetime(obj.get("timestamp")) + return RecentActivity(message, timestamp) def to_dict(self) -> dict: result: dict = {} - result["state"] = to_enum(ModelPolicyState, self.state) - if self.terms is not None: - result["terms"] = from_union([from_str, from_none], self.terms) + result["message"] = from_str(self.message) + result["timestamp"] = self.timestamp.isoformat() return result -@dataclass -class ModelCapabilitiesOverrideLimits: - """Token limits for prompts, outputs, and context window""" +class TaskAgentProgressType(Enum): + AGENT = "agent" + SHELL = "shell" - max_context_window_tokens: int | None = None - """Maximum total context window size in tokens""" +# Experimental: this type is part of an experimental API and may change or be removed. +class TaskShellInfoAttachmentMode(Enum): + """Whether the shell runs inside a managed PTY session or as an independent background + process + """ + ATTACHED = "attached" + DETACHED = "detached" - max_output_tokens: int | None = None - """Maximum number of output/completion tokens""" +class TaskShellInfoType(Enum): + SHELL = "shell" - max_prompt_tokens: int | None = None - """Maximum number of prompt/input tokens""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TasksCancelRequest: + """Identifier of the background task to cancel.""" - vision: ModelCapabilitiesOverrideLimitsVision | None = None - """Vision-specific limits""" + id: str + """Task identifier""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimits': + def from_dict(obj: Any) -> 'TasksCancelRequest': assert isinstance(obj, dict) - max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) - max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) - max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) - vision = from_union([ModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) - return ModelCapabilitiesOverrideLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) + id = from_str(obj.get("id")) + return TasksCancelRequest(id) def to_dict(self) -> dict: result: dict = {} - if self.max_context_window_tokens is not None: - result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) - if self.max_output_tokens is not None: - result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) - if self.max_prompt_tokens is not None: - result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) - if self.vision is not None: - result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForLocationApprovalCommands: - """Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type.""" - - command_identifiers: list[str] - """Command identifiers covered by this approval.""" +class TasksCancelResult: + """Indicates whether the background task was successfully cancelled.""" - kind: PermissionDecisionApproveForLocationApprovalCommandsKind - """Approval scoped to specific command identifiers.""" + cancelled: bool + """Whether the task was successfully cancelled""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCommands': + def from_dict(obj: Any) -> 'TasksCancelResult': assert isinstance(obj, dict) - command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) - kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalCommands(command_identifiers, kind) + cancelled = from_bool(obj.get("cancelled")) + return TasksCancelResult(cancelled) def to_dict(self) -> dict: result: dict = {} - result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) + result["cancelled"] = from_bool(self.cancelled) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalCommands: - """Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type.""" - - command_identifiers: list[str] - """Command identifiers covered by this approval.""" +class TasksGetProgressRequest: + """Identifier of the background task to fetch progress for.""" - kind: PermissionDecisionApproveForLocationApprovalCommandsKind - """Approval scoped to specific command identifiers.""" + id: str + """Task identifier (agent ID or shell ID)""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCommands': + def from_dict(obj: Any) -> 'TasksGetProgressRequest': assert isinstance(obj, dict) - command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) - kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalCommands(command_identifiers, kind) + id = from_str(obj.get("id")) + return TasksGetProgressRequest(id) def to_dict(self) -> dict: result: dict = {} - result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForLocationApprovalCustomTool: - """Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type.""" - - kind: PermissionDecisionApproveForLocationApprovalCustomToolKind - """Approval covering a custom tool.""" +class TasksPromoteToBackgroundRequest: + """Identifier of the task to promote to background mode.""" - tool_name: str - """Custom tool name.""" + id: str + """Task identifier""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCustomTool': + def from_dict(obj: Any) -> 'TasksPromoteToBackgroundRequest': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) - tool_name = from_str(obj.get("toolName")) - return PermissionDecisionApproveForLocationApprovalCustomTool(kind, tool_name) + id = from_str(obj.get("id")) + return TasksPromoteToBackgroundRequest(id) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) - result["toolName"] = from_str(self.tool_name) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalCustomTool: - """Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type.""" - - kind: PermissionDecisionApproveForLocationApprovalCustomToolKind - """Approval covering a custom tool.""" +class TasksPromoteToBackgroundResult: + """Indicates whether the task was successfully promoted to background mode.""" - tool_name: str - """Custom tool name.""" + promoted: bool + """Whether the task was successfully promoted to background mode""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCustomTool': + def from_dict(obj: Any) -> 'TasksPromoteToBackgroundResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) - tool_name = from_str(obj.get("toolName")) - return PermissionDecisionApproveForSessionApprovalCustomTool(kind, tool_name) + promoted = from_bool(obj.get("promoted")) + return TasksPromoteToBackgroundResult(promoted) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) - result["toolName"] = from_str(self.tool_name) + result["promoted"] = from_bool(self.promoted) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForLocationApprovalExtensionManagement: - """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type.""" - - kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind - """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. +class TasksRefreshResult: + """Refresh metadata for any detached background shells the runtime knows about. Use after a + long pause to pick up exit/output state for shells running outside the agent loop. """ - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionManagement': + def from_dict(obj: Any) -> 'TasksRefreshResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) - operation = from_union([from_str, from_none], obj.get("operation")) - return PermissionDecisionApproveForLocationApprovalExtensionManagement(kind, operation) + return TasksRefreshResult() def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalExtensionManagement: - """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type.""" - - kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind - """Approval covering extension lifecycle operations such as enable, disable, or reload.""" +class TasksRemoveRequest: + """Identifier of the completed or cancelled task to remove from tracking.""" - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. - """ + id: str + """Task identifier""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionManagement': + def from_dict(obj: Any) -> 'TasksRemoveRequest': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) - operation = from_union([from_str, from_none], obj.get("operation")) - return PermissionDecisionApproveForSessionApprovalExtensionManagement(kind, operation) + id = from_str(obj.get("id")) + return TasksRemoveRequest(id) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) + result["id"] = from_str(self.id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForLocationApprovalMCP: - """Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPKind - """Approval covering an MCP tool.""" - - server_name: str - """MCP server name.""" - - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server.""" +class TasksRemoveResult: + """Indicates whether the task was removed. False when the task does not exist or is still + running/idle. + """ + removed: bool + """Whether the task was removed. Returns false if the task does not exist or is still + running/idle (cancel it first). + """ @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCP': + def from_dict(obj: Any) -> 'TasksRemoveResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - return PermissionDecisionApproveForLocationApprovalMCP(kind, server_name, tool_name) + removed = from_bool(obj.get("removed")) + return TasksRemoveResult(removed) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) - result["serverName"] = from_str(self.server_name) - result["toolName"] = from_union([from_none, from_str], self.tool_name) + result["removed"] = from_bool(self.removed) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalMCP: - """Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.""" +class TasksSendMessageRequest: + """Identifier of the target agent task, message content, and optional sender agent ID.""" - kind: PermissionDecisionApproveForLocationApprovalMCPKind - """Approval covering an MCP tool.""" + id: str + """Agent task identifier""" - server_name: str - """MCP server name.""" + message: str + """Message content to send to the agent""" - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server.""" + from_agent_id: str | None = None + """Agent ID of the sender, if sent on behalf of another agent""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCP': + def from_dict(obj: Any) -> 'TasksSendMessageRequest': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - return PermissionDecisionApproveForSessionApprovalMCP(kind, server_name, tool_name) + id = from_str(obj.get("id")) + message = from_str(obj.get("message")) + from_agent_id = from_union([from_str, from_none], obj.get("fromAgentId")) + return TasksSendMessageRequest(id, message, from_agent_id) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) - result["serverName"] = from_str(self.server_name) - result["toolName"] = from_union([from_none, from_str], self.tool_name) + result["id"] = from_str(self.id) + result["message"] = from_str(self.message) + if self.from_agent_id is not None: + result["fromAgentId"] = from_union([from_str, from_none], self.from_agent_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForLocationApprovalMCPSampling: - """Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.""" +class TasksSendMessageResult: + """Indicates whether the message was delivered, with an error message when delivery failed.""" - kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind - """Approval covering MCP sampling requests for a server.""" + sent: bool + """Whether the message was successfully delivered or steered""" - server_name: str - """MCP server name.""" + error: str | None = None + """Error message if delivery failed""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCPSampling': + def from_dict(obj: Any) -> 'TasksSendMessageResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - return PermissionDecisionApproveForLocationApprovalMCPSampling(kind, server_name) + sent = from_bool(obj.get("sent")) + error = from_union([from_str, from_none], obj.get("error")) + return TasksSendMessageResult(sent, error) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) - result["serverName"] = from_str(self.server_name) + result["sent"] = from_bool(self.sent) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalMCPSampling: - """Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.""" - - kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind - """Approval covering MCP sampling requests for a server.""" +class TasksStartAgentRequest: + """Agent type, prompt, name, and optional description and model override for the new task.""" - server_name: str - """MCP server name.""" + agent_type: str + """Type of agent to start (e.g., 'explore', 'task', 'general-purpose')""" - @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCPSampling': - assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) - server_name = from_str(obj.get("serverName")) - return PermissionDecisionApproveForSessionApprovalMCPSampling(kind, server_name) + name: str + """Short name for the agent, used to generate a human-readable ID""" - def to_dict(self) -> dict: - result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) - result["serverName"] = from_str(self.server_name) - return result + prompt: str + """Task prompt for the agent""" -@dataclass -class PermissionDecisionApproveForLocationApprovalMemory: - """Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.""" + description: str | None = None + """Short description of the task""" - kind: PermissionDecisionApproveForLocationApprovalMemoryKind - """Approval covering writes to long-term memory.""" + model: str | None = None + """Optional model override""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMemory': + def from_dict(obj: Any) -> 'TasksStartAgentRequest': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalMemory(kind) + agent_type = from_str(obj.get("agentType")) + name = from_str(obj.get("name")) + prompt = from_str(obj.get("prompt")) + description = from_union([from_str, from_none], obj.get("description")) + model = from_union([from_str, from_none], obj.get("model")) + return TasksStartAgentRequest(agent_type, name, prompt, description, model) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) + result["agentType"] = from_str(self.agent_type) + result["name"] = from_str(self.name) + result["prompt"] = from_str(self.prompt) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalMemory: - """Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.""" +class TasksStartAgentResult: + """Identifier assigned to the newly started background agent task.""" - kind: PermissionDecisionApproveForLocationApprovalMemoryKind - """Approval covering writes to long-term memory.""" + agent_id: str + """Generated agent ID for the background task""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMemory': + def from_dict(obj: Any) -> 'TasksStartAgentResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalMemory(kind) + agent_id = from_str(obj.get("agentId")) + return TasksStartAgentResult(agent_id) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) + result["agentId"] = from_str(self.agent_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForLocationApprovalRead: - """Schema for the `PermissionDecisionApproveForLocationApprovalRead` type.""" - - kind: PermissionDecisionApproveForLocationApprovalReadKind - """Approval covering read-only filesystem operations.""" - +class TasksWaitForPendingResult: + """Wait until all in-flight background tasks (agents + shells) and any follow-up turns + scheduled by their completions have settled. Returns when the runtime is fully drained or + after an internal timeout (default 10 minutes; configurable via + COPILOT_TASK_WAIT_TIMEOUT_SECONDS). + """ @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalRead': + def from_dict(obj: Any) -> 'TasksWaitForPendingResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalRead(kind) + return TasksWaitForPendingResult() def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class PermissionDecisionApproveForSessionApprovalRead: - """Schema for the `PermissionDecisionApproveForSessionApprovalRead` type.""" - - kind: PermissionDecisionApproveForLocationApprovalReadKind - """Approval covering read-only filesystem operations.""" +class TelemetrySetFeatureOverridesRequest: + """Feature override key/value pairs to attach to subsequent telemetry events from this + session. + """ + features: dict[str, str] + """Override key/value pairs to attach to subsequent telemetry events from this session. + Replaces any previously-set overrides. + """ @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalRead': + def from_dict(obj: Any) -> 'TelemetrySetFeatureOverridesRequest': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalRead(kind) + features = from_dict(from_str, obj.get("features")) + return TelemetrySetFeatureOverridesRequest(features) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) + result["features"] = from_dict(from_str, self.features) return result +class TokenAuthInfoType(Enum): + TOKEN = "token" + @dataclass -class PermissionDecisionApproveForLocationApprovalWrite: - """Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type.""" +class Tool: + """Schema for the `Tool` type.""" - kind: PermissionDecisionApproveForLocationApprovalWriteKind - """Approval covering filesystem write operations.""" + description: str + """Description of what the tool does""" + + name: str + """Tool identifier (e.g., "bash", "grep", "str_replace_editor")""" + + instructions: str | None = None + """Optional instructions for how to use this tool effectively""" + + namespaced_name: str | None = None + """Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP + tools) + """ + parameters: dict[str, Any] | None = None + """JSON Schema for the tool's input parameters""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalWrite': + def from_dict(obj: Any) -> 'Tool': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalWrite(kind) + description = from_str(obj.get("description")) + name = from_str(obj.get("name")) + instructions = from_union([from_str, from_none], obj.get("instructions")) + namespaced_name = from_union([from_str, from_none], obj.get("namespacedName")) + parameters = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("parameters")) + return Tool(description, name, instructions, namespaced_name, parameters) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) + result["description"] = from_str(self.description) + result["name"] = from_str(self.name) + if self.instructions is not None: + result["instructions"] = from_union([from_str, from_none], self.instructions) + if self.namespaced_name is not None: + result["namespacedName"] = from_union([from_str, from_none], self.namespaced_name) + if self.parameters is not None: + result["parameters"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.parameters) return result @dataclass -class PermissionDecisionApproveForSessionApprovalWrite: - """Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type.""" - - kind: PermissionDecisionApproveForLocationApprovalWriteKind - """Approval covering filesystem write operations.""" - +class ToolsInitializeAndValidateResult: + """Resolve, build, and validate the runtime tool list for this session. Subagent sessions + and consumer flows that need an initialized tool set before `send` invoke this. Default + base-class implementation is a no-op for sessions that don't support tool validation. + """ @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalWrite': + def from_dict(obj: Any) -> 'ToolsInitializeAndValidateResult': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalWrite(kind) + return ToolsInitializeAndValidateResult() def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) return result @dataclass -class PermissionDecisionApproveOnce: - """Schema for the `PermissionDecisionApproveOnce` type.""" +class ToolsListRequest: + """Optional model identifier whose tool overrides should be applied to the listing.""" - kind: PermissionDecisionApproveOnceKind - """The permission request was approved for this one instance""" + model: str | None = None + """Optional model ID — when provided, the returned tool list reflects model-specific + overrides + """ @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveOnce': + def from_dict(obj: Any) -> 'ToolsListRequest': assert isinstance(obj, dict) - kind = PermissionDecisionApproveOnceKind(obj.get("kind")) - return PermissionDecisionApproveOnce(kind) + model = from_union([from_str, from_none], obj.get("model")) + return ToolsListRequest(model) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveOnceKind, self.kind) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) return result +class UIAutoModeSwitchResponse(Enum): + """User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist + as setting), or no (decline). + """ + NO = "no" + YES = "yes" + YES_ALWAYS = "yes_always" + @dataclass -class PermissionDecisionApprovePermanently: - """Schema for the `PermissionDecisionApprovePermanently` type.""" +class UIElicitationArrayAnyOfFieldItemsAnyOf: + """Schema for the `UIElicitationArrayAnyOfFieldItemsAnyOf` type.""" - domain: str - """The URL domain to approve permanently""" + const: str + """Value submitted when this option is selected.""" - kind: PermissionDecisionApprovePermanentlyKind - """Approved and persisted across sessions""" + title: str + """Display label for this option.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApprovePermanently': + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItemsAnyOf': assert isinstance(obj, dict) - domain = from_str(obj.get("domain")) - kind = PermissionDecisionApprovePermanentlyKind(obj.get("kind")) - return PermissionDecisionApprovePermanently(domain, kind) + const = from_str(obj.get("const")) + title = from_str(obj.get("title")) + return UIElicitationArrayAnyOfFieldItemsAnyOf(const, title) def to_dict(self) -> dict: result: dict = {} - result["domain"] = from_str(self.domain) - result["kind"] = to_enum(PermissionDecisionApprovePermanentlyKind, self.kind) + result["const"] = from_str(self.const) + result["title"] = from_str(self.title) return result +class UIElicitationArrayAnyOfFieldType(Enum): + ARRAY = "array" + +class UIElicitationArrayEnumFieldItemsType(Enum): + STRING = "string" + +class UIElicitationSchemaPropertyStringFormat(Enum): + """Optional format hint that constrains the accepted input.""" + + DATE = "date" + DATE_TIME = "date-time" + EMAIL = "email" + URI = "uri" + @dataclass -class PermissionDecisionReject: - """Schema for the `PermissionDecisionReject` type.""" +class UIElicitationStringOneOfFieldOneOf: + """Schema for the `UIElicitationStringOneOfFieldOneOf` type.""" - kind: PermissionDecisionRejectKind - """Denied by the user during an interactive prompt""" + const: str + """Value submitted when this option is selected.""" - feedback: str | None = None - """Optional feedback from the user explaining the denial""" + title: str + """Display label for this option.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionReject': + def from_dict(obj: Any) -> 'UIElicitationStringOneOfFieldOneOf': assert isinstance(obj, dict) - kind = PermissionDecisionRejectKind(obj.get("kind")) - feedback = from_union([from_str, from_none], obj.get("feedback")) - return PermissionDecisionReject(kind, feedback) + const = from_str(obj.get("const")) + title = from_str(obj.get("title")) + return UIElicitationStringOneOfFieldOneOf(const, title) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionRejectKind, self.kind) - if self.feedback is not None: - result["feedback"] = from_union([from_str, from_none], self.feedback) + result["const"] = from_str(self.const) + result["title"] = from_str(self.title) return result -@dataclass -class PermissionDecisionUserNotAvailable: - """Schema for the `PermissionDecisionUserNotAvailable` type.""" +class UIElicitationSchemaPropertyType(Enum): + """Numeric type accepted by the field.""" - kind: PermissionDecisionUserNotAvailableKind - """Denied because user confirmation was unavailable""" + ARRAY = "array" + BOOLEAN = "boolean" + INTEGER = "integer" + NUMBER = "number" + STRING = "string" + +class UIElicitationSchemaType(Enum): + OBJECT = "object" + +class UIElicitationResponseAction(Enum): + """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" + + ACCEPT = "accept" + CANCEL = "cancel" + DECLINE = "decline" + +@dataclass +class UIElicitationResult: + """Indicates whether the elicitation response was accepted; false if it was already resolved + by another client. + """ + success: bool + """Whether the response was accepted. False if the request was already resolved by another + client. + """ @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionUserNotAvailable': + def from_dict(obj: Any) -> 'UIElicitationResult': assert isinstance(obj, dict) - kind = PermissionDecisionUserNotAvailableKind(obj.get("kind")) - return PermissionDecisionUserNotAvailable(kind) + success = from_bool(obj.get("success")) + return UIElicitationResult(success) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionUserNotAvailableKind, self.kind) + result["success"] = from_bool(self.success) return result -# Experimental: this type is part of an experimental API and may change or be removed. +class UIElicitationSchemaPropertyBooleanType(Enum): + BOOLEAN = "boolean" + +class UIElicitationSchemaPropertyNumberType(Enum): + """Numeric type accepted by the field.""" + + INTEGER = "integer" + NUMBER = "number" + +class UIExitPlanModeAction(Enum): + """The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, + otherwise 'interactive'. + """ + AUTOPILOT = "autopilot" + AUTOPILOT_FLEET = "autopilot_fleet" + EXIT_ONLY = "exit_only" + INTERACTIVE = "interactive" + @dataclass -class PluginList: - """Plugins installed for the session, with their enabled state and version metadata.""" +class UIHandlePendingResult: + """Indicates whether the pending UI request was resolved by this call.""" - plugins: list[Plugin] - """Installed plugins""" + success: bool + """True if the request was still pending and was resolved by this call. False if the request + ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise + no longer pending. + """ @staticmethod - def from_dict(obj: Any) -> 'PluginList': + def from_dict(obj: Any) -> 'UIHandlePendingResult': assert isinstance(obj, dict) - plugins = from_list(Plugin.from_dict, obj.get("plugins")) - return PluginList(plugins) + success = from_bool(obj.get("success")) + return UIHandlePendingResult(success) def to_dict(self) -> dict: result: dict = {} - result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins) + result["success"] = from_bool(self.success) return result @dataclass -class QueuedCommandResult: - """Result of the queued command execution - - Schema for the `QueuedCommandHandled` type. +class UIHandlePendingSamplingRequest: + """Request ID of a pending `sampling.requested` event and an optional sampling result + payload (omit to reject). + """ + request_id: str + """The unique request ID from the sampling.requested event""" - Schema for the `QueuedCommandNotHandled` type. + response: dict[str, Any] | None = None + """Optional sampling result payload. Omit to reject/cancel the sampling request without + providing a result. """ - handled: bool - """The command was handled - The command was not handled + @staticmethod + def from_dict(obj: Any) -> 'UIHandlePendingSamplingRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + response = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("response")) + return UIHandlePendingSamplingRequest(request_id, response) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + if self.response is not None: + result["response"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.response) + return result + +@dataclass +class UIUserInputResponse: + """Schema for the `UIUserInputResponse` type.""" + + answer: str + """The user's answer text""" + + was_freeform: bool + """True if the user typed a freeform response, false if they selected a presented choice. + Used by telemetry to differentiate between free text input and choice selection. """ - stop_processing_queue: bool | None = None - """If true, stop processing remaining queued items""" @staticmethod - def from_dict(obj: Any) -> 'QueuedCommandResult': + def from_dict(obj: Any) -> 'UIUserInputResponse': assert isinstance(obj, dict) - handled = from_bool(obj.get("handled")) - stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) - return QueuedCommandResult(handled, stop_processing_queue) + answer = from_str(obj.get("answer")) + was_freeform = from_bool(obj.get("wasFreeform")) + return UIUserInputResponse(answer, was_freeform) def to_dict(self) -> dict: result: dict = {} - result["handled"] = from_bool(self.handled) - if self.stop_processing_queue is not None: - result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) + result["answer"] = from_str(self.answer) + result["wasFreeform"] = from_bool(self.was_freeform) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteEnableRequest: - """Optional remote session mode ("off", "export", or "on"); defaults to enabling both export - and remote steering. +class UIRegisterDirectAutoModeSwitchHandlerResult: + """Register an in-process handler for `auto_mode_switch.requested` events. The caller still + attaches the actual listener via the standard event-subscription mechanism; this + registration solely tells the server bridge to skip its own dispatch (so a remote client + doesn't race the in-process handler for the same requestId). """ - mode: RemoteSessionMode | None = None - """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub - without enabling remote steering, "on" enables both export and remote steering. + handle: str + """Opaque handle representing the registration. Pass this same handle to + `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. + Multiple registrations are reference-counted; the server bridge will only dispatch + auto-mode-switch requests when no handles are active. """ @staticmethod - def from_dict(obj: Any) -> 'RemoteEnableRequest': + def from_dict(obj: Any) -> 'UIRegisterDirectAutoModeSwitchHandlerResult': assert isinstance(obj, dict) - mode = from_union([RemoteSessionMode, from_none], obj.get("mode")) - return RemoteEnableRequest(mode) + handle = from_str(obj.get("handle")) + return UIRegisterDirectAutoModeSwitchHandlerResult(handle) def to_dict(self) -> dict: result: dict = {} - if self.mode is not None: - result["mode"] = from_union([lambda x: to_enum(RemoteSessionMode, x), from_none], self.mode) + result["handle"] = from_str(self.handle) return result @dataclass -class ServerSkillList: - """Skills discovered across global and project sources.""" +class UIUnregisterDirectAutoModeSwitchHandlerRequest: + """Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release.""" - skills: list[ServerSkill] - """All discovered skills across all sources""" + handle: str + """Handle previously returned by `registerDirectAutoModeSwitchHandler`""" @staticmethod - def from_dict(obj: Any) -> 'ServerSkillList': + def from_dict(obj: Any) -> 'UIUnregisterDirectAutoModeSwitchHandlerRequest': assert isinstance(obj, dict) - skills = from_list(ServerSkill.from_dict, obj.get("skills")) - return ServerSkillList(skills) + handle = from_str(obj.get("handle")) + return UIUnregisterDirectAutoModeSwitchHandlerRequest(handle) def to_dict(self) -> dict: result: dict = {} - result["skills"] = from_list(lambda x: to_class(ServerSkill, x), self.skills) + result["handle"] = from_str(self.handle) return result @dataclass -class SessionFSError: - """Describes a filesystem error.""" - - code: SessionFSErrorCode - """Error classification""" +class UIUnregisterDirectAutoModeSwitchHandlerResult: + """Indicates whether the handle was active and the registration count was decremented.""" - message: str | None = None - """Free-form detail about the error, for logging/diagnostics""" + unregistered: bool + """True if the handle was active and decremented the counter; false if the handle was + unknown. + """ @staticmethod - def from_dict(obj: Any) -> 'SessionFSError': + def from_dict(obj: Any) -> 'UIUnregisterDirectAutoModeSwitchHandlerResult': assert isinstance(obj, dict) - code = SessionFSErrorCode(obj.get("code")) - message = from_union([from_str, from_none], obj.get("message")) - return SessionFSError(code, message) + unregistered = from_bool(obj.get("unregistered")) + return UIUnregisterDirectAutoModeSwitchHandlerResult(unregistered) def to_dict(self) -> dict: result: dict = {} - result["code"] = to_enum(SessionFSErrorCode, self.code) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) + result["unregistered"] = from_bool(self.unregistered) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSReaddirWithTypesEntry: - """Schema for the `SessionFsReaddirWithTypesEntry` type.""" +class UsageMetricsCodeChanges: + """Aggregated code change metrics""" - name: str - """Entry name""" + files_modified: list[str] + """Distinct file paths modified during the session""" - type: SessionFSReaddirWithTypesEntryType - """Entry type""" + files_modified_count: int + """Number of distinct files modified""" + + lines_added: int + """Total lines of code added""" + + lines_removed: int + """Total lines of code removed""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesEntry': + def from_dict(obj: Any) -> 'UsageMetricsCodeChanges': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - type = SessionFSReaddirWithTypesEntryType(obj.get("type")) - return SessionFSReaddirWithTypesEntry(name, type) + files_modified = from_list(from_str, obj.get("filesModified")) + files_modified_count = from_int(obj.get("filesModifiedCount")) + lines_added = from_int(obj.get("linesAdded")) + lines_removed = from_int(obj.get("linesRemoved")) + return UsageMetricsCodeChanges(files_modified, files_modified_count, lines_added, lines_removed) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["type"] = to_enum(SessionFSReaddirWithTypesEntryType, self.type) + result["filesModified"] = from_list(from_str, self.files_modified) + result["filesModifiedCount"] = from_int(self.files_modified_count) + result["linesAdded"] = from_int(self.lines_added) + result["linesRemoved"] = from_int(self.lines_removed) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSSetProviderRequest: - """Initial working directory, session-state path layout, and path conventions used to - register the calling SDK client as the session filesystem provider. - """ - conventions: SessionFSSetProviderConventions - """Path conventions used by this filesystem""" - - initial_cwd: str - """Initial working directory for sessions""" +class UsageMetricsModelMetricRequests: + """Request count and cost metrics for this model""" - session_state_path: str - """Path within each session's SessionFs where the runtime stores files for that session""" + cost: float + """User-initiated premium request cost (with multiplier applied)""" - capabilities: SessionFSSetProviderCapabilities | None = None - """Optional capabilities declared by the provider""" + count: int + """Number of API requests made with this model""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSetProviderRequest': + def from_dict(obj: Any) -> 'UsageMetricsModelMetricRequests': assert isinstance(obj, dict) - conventions = SessionFSSetProviderConventions(obj.get("conventions")) - initial_cwd = from_str(obj.get("initialCwd")) - session_state_path = from_str(obj.get("sessionStatePath")) - capabilities = from_union([SessionFSSetProviderCapabilities.from_dict, from_none], obj.get("capabilities")) - return SessionFSSetProviderRequest(conventions, initial_cwd, session_state_path, capabilities) + cost = from_float(obj.get("cost")) + count = from_int(obj.get("count")) + return UsageMetricsModelMetricRequests(cost, count) def to_dict(self) -> dict: result: dict = {} - result["conventions"] = to_enum(SessionFSSetProviderConventions, self.conventions) - result["initialCwd"] = from_str(self.initial_cwd) - result["sessionStatePath"] = from_str(self.session_state_path) - if self.capabilities is not None: - result["capabilities"] = from_union([lambda x: to_class(SessionFSSetProviderCapabilities, x), from_none], self.capabilities) + result["cost"] = to_float(self.cost) + result["count"] = from_int(self.count) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SessionFSSqliteQueryRequest: - """SQL query, query type, and optional bind parameters for executing a SQLite query against - the per-session database. - """ - query: str - """SQL query to execute""" - - query_type: SessionFSSqliteQueryType - """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT - (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) - """ - session_id: str - """Target session identifier""" +class UsageMetricsModelMetricTokenDetail: + """Schema for the `UsageMetricsModelMetricTokenDetail` type.""" - params: dict[str, float | str | None] | None = None - """Optional named bind parameters""" + token_count: int + """Accumulated token count for this token type""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteQueryRequest': + def from_dict(obj: Any) -> 'UsageMetricsModelMetricTokenDetail': assert isinstance(obj, dict) - query = from_str(obj.get("query")) - query_type = SessionFSSqliteQueryType(obj.get("queryType")) - session_id = from_str(obj.get("sessionId")) - params = from_union([lambda x: from_dict(lambda x: from_union([from_none, from_float, from_str], x), x), from_none], obj.get("params")) - return SessionFSSqliteQueryRequest(query, query_type, session_id, params) + token_count = from_int(obj.get("tokenCount")) + return UsageMetricsModelMetricTokenDetail(token_count) def to_dict(self) -> dict: result: dict = {} - result["query"] = from_str(self.query) - result["queryType"] = to_enum(SessionFSSqliteQueryType, self.query_type) - result["sessionId"] = from_str(self.session_id) - if self.params is not None: - result["params"] = from_union([lambda x: from_dict(lambda x: from_union([from_none, to_float, from_str], x), x), from_none], self.params) + result["tokenCount"] = from_int(self.token_count) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ShellKillRequest: - """Identifier of a process previously returned by "shell.exec" and the signal to send.""" +class UsageMetricsModelMetricUsage: + """Token usage metrics for this model""" - process_id: str - """Process identifier returned by shell.exec""" + cache_read_tokens: int + """Total tokens read from prompt cache""" - signal: ShellKillSignal | None = None - """Signal to send (default: SIGTERM)""" + cache_write_tokens: int + """Total tokens written to prompt cache""" + + input_tokens: int + """Total input tokens consumed""" + + output_tokens: int + """Total output tokens produced""" + + reasoning_tokens: int | None = None + """Total output tokens used for reasoning""" @staticmethod - def from_dict(obj: Any) -> 'ShellKillRequest': + def from_dict(obj: Any) -> 'UsageMetricsModelMetricUsage': assert isinstance(obj, dict) - process_id = from_str(obj.get("processId")) - signal = from_union([ShellKillSignal, from_none], obj.get("signal")) - return ShellKillRequest(process_id, signal) + cache_read_tokens = from_int(obj.get("cacheReadTokens")) + cache_write_tokens = from_int(obj.get("cacheWriteTokens")) + input_tokens = from_int(obj.get("inputTokens")) + output_tokens = from_int(obj.get("outputTokens")) + reasoning_tokens = from_union([from_int, from_none], obj.get("reasoningTokens")) + return UsageMetricsModelMetricUsage(cache_read_tokens, cache_write_tokens, input_tokens, output_tokens, reasoning_tokens) def to_dict(self) -> dict: result: dict = {} - result["processId"] = from_str(self.process_id) - if self.signal is not None: - result["signal"] = from_union([lambda x: to_enum(ShellKillSignal, x), from_none], self.signal) + result["cacheReadTokens"] = from_int(self.cache_read_tokens) + result["cacheWriteTokens"] = from_int(self.cache_write_tokens) + result["inputTokens"] = from_int(self.input_tokens) + result["outputTokens"] = from_int(self.output_tokens) + if self.reasoning_tokens is not None: + result["reasoningTokens"] = from_union([from_int, from_none], self.reasoning_tokens) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SkillList: - """Skills available to the session, with their enabled state.""" +class UsageMetricsTokenDetail: + """Schema for the `UsageMetricsTokenDetail` type.""" - skills: list[Skill] - """Available skills""" + token_count: int + """Accumulated token count for this token type""" @staticmethod - def from_dict(obj: Any) -> 'SkillList': + def from_dict(obj: Any) -> 'UsageMetricsTokenDetail': assert isinstance(obj, dict) - skills = from_list(Skill.from_dict, obj.get("skills")) - return SkillList(skills) + token_count = from_int(obj.get("tokenCount")) + return UsageMetricsTokenDetail(token_count) def to_dict(self) -> dict: result: dict = {} - result["skills"] = from_list(lambda x: to_class(Skill, x), self.skills) + result["tokenCount"] = from_int(self.token_count) return result +class UserAuthInfoType(Enum): + USER = "user" + @dataclass -class SkillsConfigSetDisabledSkillsRequest: - """Skill names to mark as disabled in global configuration, replacing any previous list.""" +class WorkspacesCheckpoints: + """Schema for the `WorkspacesCheckpoints` type.""" - disabled_skills: list[str] - """List of skill names to disable""" + filename: str + """Filename of the checkpoint within the workspace checkpoints directory""" + + number: int + """Checkpoint number assigned by the workspace manager""" + + title: str + """Human-readable checkpoint title""" @staticmethod - def from_dict(obj: Any) -> 'SkillsConfigSetDisabledSkillsRequest': + def from_dict(obj: Any) -> 'WorkspacesCheckpoints': assert isinstance(obj, dict) - disabled_skills = from_list(from_str, obj.get("disabledSkills")) - return SkillsConfigSetDisabledSkillsRequest(disabled_skills) + filename = from_str(obj.get("filename")) + number = from_int(obj.get("number")) + title = from_str(obj.get("title")) + return WorkspacesCheckpoints(filename, number, title) def to_dict(self) -> dict: result: dict = {} - result["disabledSkills"] = from_list(from_str, self.disabled_skills) + result["filename"] = from_str(self.filename) + result["number"] = from_int(self.number) + result["title"] = from_str(self.title) return result @dataclass -class SlashCommandAgentPromptResult: - """Schema for the `SlashCommandAgentPromptResult` type.""" +class WorkspacesCreateFileRequest: + """Relative path and UTF-8 content for the workspace file to create or overwrite.""" - display_prompt: str - """Prompt text to display to the user""" + content: str + """File content to write as a UTF-8 string""" - kind: SlashCommandAgentPromptResultKind - """Agent prompt result discriminator""" + path: str + """Relative path within the workspace files directory""" - prompt: str - """Prompt to submit to the agent""" + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': + assert isinstance(obj, dict) + content = from_str(obj.get("content")) + path = from_str(obj.get("path")) + return WorkspacesCreateFileRequest(content, path) - mode: SessionMode | None = None - """Optional target session mode for the agent prompt""" + def to_dict(self) -> dict: + result: dict = {} + result["content"] = from_str(self.content) + result["path"] = from_str(self.path) + return result - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh - """ +@dataclass +class WorkspacesListFilesResult: + """Relative paths of files stored in the session workspace files directory.""" + + files: list[str] + """Relative file paths in the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandAgentPromptResult': + def from_dict(obj: Any) -> 'WorkspacesListFilesResult': assert isinstance(obj, dict) - display_prompt = from_str(obj.get("displayPrompt")) - kind = SlashCommandAgentPromptResultKind(obj.get("kind")) - prompt = from_str(obj.get("prompt")) - mode = from_union([SessionMode, from_none], obj.get("mode")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - return SlashCommandAgentPromptResult(display_prompt, kind, prompt, mode, runtime_settings_changed) + files = from_list(from_str, obj.get("files")) + return WorkspacesListFilesResult(files) def to_dict(self) -> dict: result: dict = {} - result["displayPrompt"] = from_str(self.display_prompt) - result["kind"] = to_enum(SlashCommandAgentPromptResultKind, self.kind) - result["prompt"] = from_str(self.prompt) - if self.mode is not None: - result["mode"] = from_union([lambda x: to_enum(SessionMode, x), from_none], self.mode) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + result["files"] = from_list(from_str, self.files) return result @dataclass -class SlashCommandCompletedResult: - """Schema for the `SlashCommandCompletedResult` type.""" - - kind: SlashCommandCompletedResultKind - """Completed result discriminator""" - - message: str | None = None - """Optional user-facing message describing the completed command""" +class WorkspacesReadCheckpointRequest: + """Checkpoint number to read.""" - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh - """ + number: int + """Checkpoint number to read""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandCompletedResult': + def from_dict(obj: Any) -> 'WorkspacesReadCheckpointRequest': assert isinstance(obj, dict) - kind = SlashCommandCompletedResultKind(obj.get("kind")) - message = from_union([from_str, from_none], obj.get("message")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - return SlashCommandCompletedResult(kind, message, runtime_settings_changed) + number = from_int(obj.get("number")) + return WorkspacesReadCheckpointRequest(number) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(SlashCommandCompletedResultKind, self.kind) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + result["number"] = from_int(self.number) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskShellInfo: - """Schema for the `TaskShellInfo` type.""" +class WorkspacesReadCheckpointResult: + """Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing.""" - attachment_mode: TaskShellInfoAttachmentMode - """Whether the shell runs inside a managed PTY session or as an independent background - process - """ - command: str - """Command being executed""" + content: str | None = None + """Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing""" - description: str - """Short description of the task""" + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesReadCheckpointResult': + assert isinstance(obj, dict) + content = from_union([from_none, from_str], obj.get("content")) + return WorkspacesReadCheckpointResult(content) - id: str - """Unique task identifier""" + def to_dict(self) -> dict: + result: dict = {} + result["content"] = from_union([from_none, from_str], self.content) + return result - started_at: datetime - """ISO 8601 timestamp when the task was started""" +@dataclass +class WorkspacesReadFileRequest: + """Relative path of the workspace file to read.""" - status: TaskStatus - """Current lifecycle status of the task""" + path: str + """Relative path within the workspace files directory""" - type: TaskShellInfoType - """Task kind""" + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': + assert isinstance(obj, dict) + path = from_str(obj.get("path")) + return WorkspacesReadFileRequest(path) - can_promote_to_background: bool | None = None - """Whether this shell task can be promoted to background mode""" + def to_dict(self) -> dict: + result: dict = {} + result["path"] = from_str(self.path) + return result - completed_at: datetime | None = None - """ISO 8601 timestamp when the task finished""" +@dataclass +class WorkspacesReadFileResult: + """Contents of the requested workspace file as a UTF-8 string.""" - execution_mode: TaskExecutionMode | None = None - """Whether task execution is synchronously awaited or managed in the background""" + content: str + """File content as a UTF-8 string""" - log_path: str | None = None - """Path to the detached shell log, when available""" + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesReadFileResult': + assert isinstance(obj, dict) + content = from_str(obj.get("content")) + return WorkspacesReadFileResult(content) - pid: int | None = None - """Process ID when available""" + def to_dict(self) -> dict: + result: dict = {} + result["content"] = from_str(self.content) + return result + +@dataclass +class WorkspacesSaveLargePasteRequest: + """Pasted content to save as a UTF-8 file in the session workspace.""" + + content: str + """Pasted content to save as a UTF-8 file""" @staticmethod - def from_dict(obj: Any) -> 'TaskShellInfo': + def from_dict(obj: Any) -> 'WorkspacesSaveLargePasteRequest': assert isinstance(obj, dict) - attachment_mode = TaskShellInfoAttachmentMode(obj.get("attachmentMode")) - command = from_str(obj.get("command")) - description = from_str(obj.get("description")) - id = from_str(obj.get("id")) - started_at = from_datetime(obj.get("startedAt")) - status = TaskStatus(obj.get("status")) - type = TaskShellInfoType(obj.get("type")) - can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) - completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) - execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) - log_path = from_union([from_str, from_none], obj.get("logPath")) - pid = from_union([from_int, from_none], obj.get("pid")) - return TaskShellInfo(attachment_mode, command, description, id, started_at, status, type, can_promote_to_background, completed_at, execution_mode, log_path, pid) + content = from_str(obj.get("content")) + return WorkspacesSaveLargePasteRequest(content) def to_dict(self) -> dict: result: dict = {} - result["attachmentMode"] = to_enum(TaskShellInfoAttachmentMode, self.attachment_mode) - result["command"] = from_str(self.command) - result["description"] = from_str(self.description) - result["id"] = from_str(self.id) - result["startedAt"] = self.started_at.isoformat() - result["status"] = to_enum(TaskStatus, self.status) - result["type"] = to_enum(TaskShellInfoType, self.type) - if self.can_promote_to_background is not None: - result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) - if self.completed_at is not None: - result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) - if self.execution_mode is not None: - result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) - if self.log_path is not None: - result["logPath"] = from_union([from_str, from_none], self.log_path) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) + result["content"] = from_str(self.content) return result @dataclass -class ToolList: - """Built-in tools available for the requested model, with their parameters and instructions.""" +class Saved: + filename: str + """Filename within the workspace files directory""" - tools: list[Tool] - """List of available built-in tools with metadata""" + file_path: str + """Absolute filesystem path to the saved paste file""" + + size_bytes: int + """Size of the saved file in bytes""" @staticmethod - def from_dict(obj: Any) -> 'ToolList': + def from_dict(obj: Any) -> 'Saved': assert isinstance(obj, dict) - tools = from_list(Tool.from_dict, obj.get("tools")) - return ToolList(tools) + filename = from_str(obj.get("filename")) + file_path = from_str(obj.get("filePath")) + size_bytes = from_int(obj.get("sizeBytes")) + return Saved(filename, file_path, size_bytes) def to_dict(self) -> dict: result: dict = {} - result["tools"] = from_list(lambda x: to_class(Tool, x), self.tools) + result["filename"] = from_str(self.filename) + result["filePath"] = from_str(self.file_path) + result["sizeBytes"] = from_int(self.size_bytes) return result @dataclass -class UIElicitationArrayAnyOfFieldItems: - """Schema applied to each item in the array.""" +class AccountGetQuotaResult: + """Quota usage snapshots for the resolved user, keyed by quota type.""" - any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] - """Selectable options, each with a value and a display label.""" + quota_snapshots: dict[str, AccountQuotaSnapshot] + """Quota snapshots keyed by type (e.g., chat, completions, premium_interactions)""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItems': + def from_dict(obj: Any) -> 'AccountGetQuotaResult': assert isinstance(obj, dict) - any_of = from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, obj.get("anyOf")) - return UIElicitationArrayAnyOfFieldItems(any_of) + quota_snapshots = from_dict(AccountQuotaSnapshot.from_dict, obj.get("quotaSnapshots")) + return AccountGetQuotaResult(quota_snapshots) def to_dict(self) -> dict: result: dict = {} - result["anyOf"] = from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), self.any_of) + result["quotaSnapshots"] = from_dict(lambda x: to_class(AccountQuotaSnapshot, x), self.quota_snapshots) return result @dataclass -class UIElicitationArrayEnumFieldItems: - """Schema applied to each item in the array.""" +class SessionAuthStatus: + """Authentication status and account metadata for the session.""" - enum: list[str] - """Allowed string values for each selected item.""" + is_authenticated: bool + """Whether the session has resolved authentication""" - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" + auth_type: AuthInfoType | None = None + """Authentication type""" + + copilot_plan: str | None = None + """Copilot plan tier (e.g., individual_pro, business)""" + + host: str | None = None + """Authentication host URL""" + + login: str | None = None + """Authenticated login/username, if available""" + + status_message: str | None = None + """Human-readable authentication status description""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayEnumFieldItems': + def from_dict(obj: Any) -> 'SessionAuthStatus': assert isinstance(obj, dict) - enum = from_list(from_str, obj.get("enum")) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - return UIElicitationArrayEnumFieldItems(enum, type) + is_authenticated = from_bool(obj.get("isAuthenticated")) + auth_type = from_union([AuthInfoType, from_none], obj.get("authType")) + copilot_plan = from_union([from_str, from_none], obj.get("copilotPlan")) + host = from_union([from_str, from_none], obj.get("host")) + login = from_union([from_str, from_none], obj.get("login")) + status_message = from_union([from_str, from_none], obj.get("statusMessage")) + return SessionAuthStatus(is_authenticated, auth_type, copilot_plan, host, login, status_message) def to_dict(self) -> dict: result: dict = {} - result["enum"] = from_list(from_str, self.enum) - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + result["isAuthenticated"] = from_bool(self.is_authenticated) + if self.auth_type is not None: + result["authType"] = from_union([lambda x: to_enum(AuthInfoType, x), from_none], self.auth_type) + if self.copilot_plan is not None: + result["copilotPlan"] = from_union([from_str, from_none], self.copilot_plan) + if self.host is not None: + result["host"] = from_union([from_str, from_none], self.host) + if self.login is not None: + result["login"] = from_union([from_str, from_none], self.login) + if self.status_message is not None: + result["statusMessage"] = from_union([from_str, from_none], self.status_message) return result @dataclass -class UIElicitationArrayFieldItems: - """Schema applied to each item in the array.""" +class SlashCommandInput: + """Optional unstructured input hint""" - enum: list[str] | None = None - """Allowed string values for each selected item.""" + hint: str + """Hint to display when command input has not been provided""" - type: UIElicitationArrayEnumFieldItemsType | None = None - """Type discriminator. Always "string".""" + completion: SlashCommandInputCompletion | None = None + """Optional completion hint for the input (e.g. 'directory' for filesystem path completion)""" - any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] | None = None - """Selectable options, each with a value and a display label.""" + preserve_multiline_input: bool | None = None + """When true, clients should pass the full text after the command name as a single argument + rather than splitting on whitespace + """ + required: bool | None = None + """When true, the command requires non-empty input; clients should render the input hint as + required + """ @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayFieldItems': + def from_dict(obj: Any) -> 'SlashCommandInput': assert isinstance(obj, dict) - enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) - type = from_union([UIElicitationArrayEnumFieldItemsType, from_none], obj.get("type")) - any_of = from_union([lambda x: from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, x), from_none], obj.get("anyOf")) - return UIElicitationArrayFieldItems(enum, type, any_of) + hint = from_str(obj.get("hint")) + completion = from_union([SlashCommandInputCompletion, from_none], obj.get("completion")) + preserve_multiline_input = from_union([from_bool, from_none], obj.get("preserveMultilineInput")) + required = from_union([from_bool, from_none], obj.get("required")) + return SlashCommandInput(hint, completion, preserve_multiline_input, required) def to_dict(self) -> dict: result: dict = {} - if self.enum is not None: - result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) - if self.type is not None: - result["type"] = from_union([lambda x: to_enum(UIElicitationArrayEnumFieldItemsType, x), from_none], self.type) - if self.any_of is not None: - result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), x), from_none], self.any_of) + result["hint"] = from_str(self.hint) + if self.completion is not None: + result["completion"] = from_union([lambda x: to_enum(SlashCommandInputCompletion, x), from_none], self.completion) + if self.preserve_multiline_input is not None: + result["preserveMultilineInput"] = from_union([from_bool, from_none], self.preserve_multiline_input) + if self.required is not None: + result["required"] = from_union([from_bool, from_none], self.required) return result @dataclass -class UIElicitationStringEnumField: - """Single-select string field whose allowed values are defined inline.""" - - enum: list[str] - """Allowed string values.""" - - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" - - default: str | None = None - """Default value selected when the form is first shown.""" +class SendAttachmentDirectory: + """Directory attachment""" - description: str | None = None - """Help text describing the field.""" + display_name: str + """User-facing display name for the attachment""" - enum_names: list[str] | None = None - """Optional display labels for each enum value, in the same order as `enum`.""" + path: str + """Absolute directory path""" - title: str | None = None - """Human-readable label for the field.""" + type: SlashCommandInputCompletion + """Attachment type discriminator""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringEnumField': + def from_dict(obj: Any) -> 'SendAttachmentDirectory': assert isinstance(obj, dict) - enum = from_list(from_str, obj.get("enum")) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationStringEnumField(enum, type, default, description, enum_names, title) + display_name = from_str(obj.get("displayName")) + path = from_str(obj.get("path")) + type = SlashCommandInputCompletion(obj.get("type")) + return SendAttachmentDirectory(display_name, path, type) def to_dict(self) -> dict: result: dict = {} - result["enum"] = from_list(from_str, self.enum) - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.enum_names is not None: - result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["displayName"] = from_str(self.display_name) + result["path"] = from_str(self.path) + result["type"] = to_enum(SlashCommandInputCompletion, self.type) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationSchemaPropertyString: - """Free-text string field with optional length and format constraints.""" +class ConnectedRemoteSessionMetadata: + """Metadata for a connected remote session.""" - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" + kind: ConnectedRemoteSessionMetadataKind + """Neutral SDK discriminator for the connected remote session kind.""" - default: str | None = None - """Default value populated in the input when the form is first shown.""" + modified_time: datetime + """Last session update time as an ISO 8601 string.""" - description: str | None = None - """Help text describing the field.""" + repository: ConnectedRemoteSessionMetadataRepository + """Repository associated with the connected remote session.""" - format: UIElicitationSchemaPropertyStringFormat | None = None - """Optional format hint that constrains the accepted input.""" + session_id: str + """SDK session ID for the connected remote session.""" - max_length: float | None = None - """Maximum number of characters allowed.""" + start_time: datetime + """Session start time as an ISO 8601 string.""" - min_length: float | None = None - """Minimum number of characters required.""" + name: str | None = None + """Optional friendly session name.""" - title: str | None = None - """Human-readable label for the field.""" + pull_request_number: int | None = None + """Pull request number associated with the session.""" + + resource_id: str | None = None + """Original remote resource identifier.""" + + stale_at: datetime | None = None + """Remote session staleness deadline as an ISO 8601 string.""" + + state: str | None = None + """Remote session state returned by the backing service.""" + + summary: str | None = None + """Optional session summary.""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyString': + def from_dict(obj: Any) -> 'ConnectedRemoteSessionMetadata': assert isinstance(obj, dict) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) - max_length = from_union([from_float, from_none], obj.get("maxLength")) - min_length = from_union([from_float, from_none], obj.get("minLength")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationSchemaPropertyString(type, default, description, format, max_length, min_length, title) + kind = ConnectedRemoteSessionMetadataKind(obj.get("kind")) + modified_time = from_datetime(obj.get("modifiedTime")) + repository = ConnectedRemoteSessionMetadataRepository.from_dict(obj.get("repository")) + session_id = from_str(obj.get("sessionId")) + start_time = from_datetime(obj.get("startTime")) + name = from_union([from_str, from_none], obj.get("name")) + pull_request_number = from_union([from_int, from_none], obj.get("pullRequestNumber")) + resource_id = from_union([from_str, from_none], obj.get("resourceId")) + stale_at = from_union([from_datetime, from_none], obj.get("staleAt")) + state = from_union([from_str, from_none], obj.get("state")) + summary = from_union([from_str, from_none], obj.get("summary")) + return ConnectedRemoteSessionMetadata(kind, modified_time, repository, session_id, start_time, name, pull_request_number, resource_id, stale_at, state, summary) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.format is not None: - result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) - if self.max_length is not None: - result["maxLength"] = from_union([to_float, from_none], self.max_length) - if self.min_length is not None: - result["minLength"] = from_union([to_float, from_none], self.min_length) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["kind"] = to_enum(ConnectedRemoteSessionMetadataKind, self.kind) + result["modifiedTime"] = self.modified_time.isoformat() + result["repository"] = to_class(ConnectedRemoteSessionMetadataRepository, self.repository) + result["sessionId"] = from_str(self.session_id) + result["startTime"] = self.start_time.isoformat() + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.pull_request_number is not None: + result["pullRequestNumber"] = from_union([from_int, from_none], self.pull_request_number) + if self.resource_id is not None: + result["resourceId"] = from_union([from_str, from_none], self.resource_id) + if self.stale_at is not None: + result["staleAt"] = from_union([lambda x: x.isoformat(), from_none], self.stale_at) + if self.state is not None: + result["state"] = from_union([from_str, from_none], self.state) + if self.summary is not None: + result["summary"] = from_union([from_str, from_none], self.summary) return result @dataclass -class UIElicitationStringOneOfField: - """Single-select string field where each option pairs a value with a display label.""" +class MCPServerConfigStdio: + """Stdio MCP server configuration launched as a child process.""" - one_of: list[UIElicitationStringOneOfFieldOneOf] - """Selectable options, each with a value and a display label.""" + command: str + """Executable command used to start the Stdio MCP server process.""" - type: UIElicitationArrayEnumFieldItemsType - """Type discriminator. Always "string".""" + args: list[str] | None = None + """Command-line arguments passed to the Stdio MCP server process.""" - default: str | None = None - """Default value selected when the form is first shown.""" + cwd: str | None = None + """Working directory for the Stdio MCP server process.""" - description: str | None = None - """Help text describing the field.""" + env: dict[str, str] | None = None + """Environment variables to pass to the Stdio MCP server process.""" - title: str | None = None - """Human-readable label for the field.""" + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None + """Content filtering mode to apply to all tools, or a map of tool name to content filtering + mode. + """ + is_default_server: bool | None = None + """Whether this server is a built-in fallback used when the user has not configured their + own server. + """ + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" + + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationStringOneOfField': + def from_dict(obj: Any) -> 'MCPServerConfigStdio': assert isinstance(obj, dict) - one_of = from_list(UIElicitationStringOneOfFieldOneOf.from_dict, obj.get("oneOf")) - type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) - default = from_union([from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationStringOneOfField(one_of, type, default, description, title) + command = from_str(obj.get("command")) + args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) + filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + return MCPServerConfigStdio(command, args, cwd, env, filter_mapping, is_default_server, timeout, tools) def to_dict(self) -> dict: result: dict = {} - result["oneOf"] = from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), self.one_of) - result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) - if self.default is not None: - result["default"] = from_union([from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["command"] = from_str(self.command) + if self.args is not None: + result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.env is not None: + result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) return result @dataclass -class UIElicitationResponse: - """The elicitation response (accept with form values, decline, or cancel)""" +class CopilotUserResponseQuotaSnapshots: + """Schema for the `CopilotUserResponseQuotaSnapshotsChat` type. - action: UIElicitationResponseAction - """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" + Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type. - content: dict[str, float | bool | list[str] | str] | None = None - """The form values submitted by the user (present when action is 'accept')""" + Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type. + """ + entitlement: float | None = None + has_quota: bool | None = None + overage_count: float | None = None + overage_permitted: bool | None = None + percent_remaining: float | None = None + quota_id: str | None = None + quota_remaining: float | None = None + quota_reset_at: float | None = None + remaining: float | None = None + timestamp_utc: str | None = None + token_based_billing: bool | None = None + unlimited: bool | None = None @staticmethod - def from_dict(obj: Any) -> 'UIElicitationResponse': + def from_dict(obj: Any) -> 'CopilotUserResponseQuotaSnapshots': assert isinstance(obj, dict) - action = UIElicitationResponseAction(obj.get("action")) - content = from_union([lambda x: from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], obj.get("content")) - return UIElicitationResponse(action, content) + entitlement = from_union([from_float, from_none], obj.get("entitlement")) + has_quota = from_union([from_bool, from_none], obj.get("has_quota")) + overage_count = from_union([from_float, from_none], obj.get("overage_count")) + overage_permitted = from_union([from_bool, from_none], obj.get("overage_permitted")) + percent_remaining = from_union([from_float, from_none], obj.get("percent_remaining")) + quota_id = from_union([from_str, from_none], obj.get("quota_id")) + quota_remaining = from_union([from_float, from_none], obj.get("quota_remaining")) + quota_reset_at = from_union([from_float, from_none], obj.get("quota_reset_at")) + remaining = from_union([from_float, from_none], obj.get("remaining")) + timestamp_utc = from_union([from_str, from_none], obj.get("timestamp_utc")) + token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) + unlimited = from_union([from_bool, from_none], obj.get("unlimited")) + return CopilotUserResponseQuotaSnapshots(entitlement, has_quota, overage_count, overage_permitted, percent_remaining, quota_id, quota_remaining, quota_reset_at, remaining, timestamp_utc, token_based_billing, unlimited) def to_dict(self) -> dict: result: dict = {} - result["action"] = to_enum(UIElicitationResponseAction, self.action) - if self.content is not None: - result["content"] = from_union([lambda x: from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], self.content) + if self.entitlement is not None: + result["entitlement"] = from_union([to_float, from_none], self.entitlement) + if self.has_quota is not None: + result["has_quota"] = from_union([from_bool, from_none], self.has_quota) + if self.overage_count is not None: + result["overage_count"] = from_union([to_float, from_none], self.overage_count) + if self.overage_permitted is not None: + result["overage_permitted"] = from_union([from_bool, from_none], self.overage_permitted) + if self.percent_remaining is not None: + result["percent_remaining"] = from_union([to_float, from_none], self.percent_remaining) + if self.quota_id is not None: + result["quota_id"] = from_union([from_str, from_none], self.quota_id) + if self.quota_remaining is not None: + result["quota_remaining"] = from_union([to_float, from_none], self.quota_remaining) + if self.quota_reset_at is not None: + result["quota_reset_at"] = from_union([to_float, from_none], self.quota_reset_at) + if self.remaining is not None: + result["remaining"] = from_union([to_float, from_none], self.remaining) + if self.timestamp_utc is not None: + result["timestamp_utc"] = from_union([from_str, from_none], self.timestamp_utc) + if self.token_based_billing is not None: + result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) + if self.unlimited is not None: + result["unlimited"] = from_union([from_bool, from_none], self.unlimited) return result @dataclass -class UIElicitationSchemaPropertyBoolean: - """Boolean field rendered as a yes/no toggle.""" +class DiscoveredMCPServer: + """Schema for the `DiscoveredMcpServer` type.""" - type: UIElicitationSchemaPropertyBooleanType - """Type discriminator. Always "boolean".""" + enabled: bool + """Whether the server is enabled (not in the disabled list)""" - default: bool | None = None - """Default value selected when the form is first shown.""" + name: str + """Server name (config key)""" - description: str | None = None - """Help text describing the field.""" + source: McpServerSource + """Configuration source: user, workspace, plugin, or builtin""" - title: str | None = None - """Human-readable label for the field.""" + type: DiscoveredMCPServerType | None = None + """Server transport type: stdio, http, sse, or memory""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyBoolean': + def from_dict(obj: Any) -> 'DiscoveredMCPServer': assert isinstance(obj, dict) - type = UIElicitationSchemaPropertyBooleanType(obj.get("type")) - default = from_union([from_bool, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationSchemaPropertyBoolean(type, default, description, title) + enabled = from_bool(obj.get("enabled")) + name = from_str(obj.get("name")) + source = McpServerSource(obj.get("source")) + type = from_union([DiscoveredMCPServerType, from_none], obj.get("type")) + return DiscoveredMCPServer(enabled, name, source, type) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationSchemaPropertyBooleanType, self.type) - if self.default is not None: - result["default"] = from_union([from_bool, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["enabled"] = from_bool(self.enabled) + result["name"] = from_str(self.name) + result["source"] = to_enum(McpServerSource, self.source) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(DiscoveredMCPServerType, x), from_none], self.type) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationSchemaPropertyNumber: - """Numeric field accepting either a number or an integer.""" - - type: UIElicitationSchemaPropertyNumberType - """Numeric type accepted by the field.""" - - default: float | None = None - """Default value populated in the input when the form is first shown.""" +class EventLogReadRequest: + """Cursor, batch size, and optional long-poll/filter parameters for reading session events.""" + + agent_scope: EventsAgentScope | None = None + """Agent-scope filter: 'primary' returns only main-agent events plus events whose type + starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns + events from all agents (matching wildcard-subscription behavior). Default is 'all' to + preserve wildcard semantics for catch-up callers. + """ + cursor: str | None = None + """Opaque cursor returned by a previous read. Omit on the first call to start from the + beginning of the session's persisted history. + """ + max: int | None = None + """Maximum number of events to return in this batch (1–1000, default 200).""" + + types: list[str] | EventLogTypes | None = None + """Either '*' to receive all event types, or a non-empty list of event types to receive""" + + wait_ms: int | None = None + """Milliseconds to wait for new events when the cursor is at the tail of history. 0 + (default) returns immediately even if no events are available. Capped at 30000ms. + Ephemeral events that arrive during the wait are delivered in this batch but are NOT + replayable on a subsequent read (use a non-zero waitMs in your next call to capture + future ephemerals as they happen). + """ - description: str | None = None - """Help text describing the field.""" + @staticmethod + def from_dict(obj: Any) -> 'EventLogReadRequest': + assert isinstance(obj, dict) + agent_scope = from_union([EventsAgentScope, from_none], obj.get("agentScope")) + cursor = from_union([from_str, from_none], obj.get("cursor")) + max = from_union([from_int, from_none], obj.get("max")) + types = from_union([lambda x: from_list(from_str, x), EventLogTypes, from_none], obj.get("types")) + wait_ms = from_union([from_int, from_none], obj.get("waitMs")) + return EventLogReadRequest(agent_scope, cursor, max, types, wait_ms) - maximum: float | None = None - """Maximum allowed value (inclusive).""" + def to_dict(self) -> dict: + result: dict = {} + if self.agent_scope is not None: + result["agentScope"] = from_union([lambda x: to_enum(EventsAgentScope, x), from_none], self.agent_scope) + if self.cursor is not None: + result["cursor"] = from_union([from_str, from_none], self.cursor) + if self.max is not None: + result["max"] = from_union([from_int, from_none], self.max) + if self.types is not None: + result["types"] = from_union([lambda x: from_list(from_str, x), lambda x: to_enum(EventLogTypes, x), from_none], self.types) + if self.wait_ms is not None: + result["waitMs"] = from_union([from_int, from_none], self.wait_ms) + return result - minimum: float | None = None - """Minimum allowed value (inclusive).""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class EventsReadResult: + """Batch of session events returned by a read, with cursor and continuation metadata.""" - title: str | None = None - """Human-readable label for the field.""" + cursor: str + """Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue + from where this read left off. Always present, even when no events were returned. + """ + cursor_status: EventsCursorStatus + """Cursor status: 'ok' means the cursor was applied successfully; 'expired' means the cursor + referred to an event that no longer exists in history (e.g. truncated or compacted away) + and the read started from the beginning of the remaining history. + """ + events: list[SessionEvent] + """Events are delivered in two batches per read: persisted events first (in append order), + then ephemeral events (in seq order). When `waitMs > 0` and the catch-up batches were + empty, post-wait events follow the same two-batch ordering. Persisted and ephemeral + events do not interleave within a single read. + """ + has_more: bool + """True when the read returned `max` events and more events are available immediately. When + false, the next read with a non-zero `waitMs` will block until a new event arrives or the + wait expires. + """ @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyNumber': + def from_dict(obj: Any) -> 'EventsReadResult': assert isinstance(obj, dict) - type = UIElicitationSchemaPropertyNumberType(obj.get("type")) - default = from_union([from_float, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - maximum = from_union([from_float, from_none], obj.get("maximum")) - minimum = from_union([from_float, from_none], obj.get("minimum")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationSchemaPropertyNumber(type, default, description, maximum, minimum, title) + cursor = from_str(obj.get("cursor")) + cursor_status = EventsCursorStatus(obj.get("cursorStatus")) + events = from_list(SessionEvent.from_dict, obj.get("events")) + has_more = from_bool(obj.get("hasMore")) + return EventsReadResult(cursor, cursor_status, events, has_more) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationSchemaPropertyNumberType, self.type) - if self.default is not None: - result["default"] = from_union([to_float, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.maximum is not None: - result["maximum"] = from_union([to_float, from_none], self.maximum) - if self.minimum is not None: - result["minimum"] = from_union([to_float, from_none], self.minimum) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["cursor"] = from_str(self.cursor) + result["cursorStatus"] = to_enum(EventsCursorStatus, self.cursor_status) + result["events"] = from_list(lambda x: to_class(SessionEvent, x), self.events) + result["hasMore"] = from_bool(self.has_more) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageMetricsModelMetric: - """Schema for the `UsageMetricsModelMetric` type.""" +class Extension: + """Schema for the `Extension` type.""" - requests: UsageMetricsModelMetricRequests - """Request count and cost metrics for this model""" + id: str + """Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper')""" - usage: UsageMetricsModelMetricUsage - """Token usage metrics for this model""" + name: str + """Extension name (directory name)""" - token_details: dict[str, UsageMetricsModelMetricTokenDetail] | None = None - """Token count details per type""" + source: ExtensionSource + """Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/)""" - total_nano_aiu: int | None = None - """Accumulated nano-AI units cost for this model""" + status: ExtensionStatus + """Current status: running, disabled, failed, or starting""" + + pid: int | None = None + """Process ID if the extension is running""" @staticmethod - def from_dict(obj: Any) -> 'UsageMetricsModelMetric': + def from_dict(obj: Any) -> 'Extension': assert isinstance(obj, dict) - requests = UsageMetricsModelMetricRequests.from_dict(obj.get("requests")) - usage = UsageMetricsModelMetricUsage.from_dict(obj.get("usage")) - token_details = from_union([lambda x: from_dict(UsageMetricsModelMetricTokenDetail.from_dict, x), from_none], obj.get("tokenDetails")) - total_nano_aiu = from_union([from_int, from_none], obj.get("totalNanoAiu")) - return UsageMetricsModelMetric(requests, usage, token_details, total_nano_aiu) + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + source = ExtensionSource(obj.get("source")) + status = ExtensionStatus(obj.get("status")) + pid = from_union([from_int, from_none], obj.get("pid")) + return Extension(id, name, source, status, pid) def to_dict(self) -> dict: result: dict = {} - result["requests"] = to_class(UsageMetricsModelMetricRequests, self.requests) - result["usage"] = to_class(UsageMetricsModelMetricUsage, self.usage) - if self.token_details is not None: - result["tokenDetails"] = from_union([lambda x: from_dict(lambda x: to_class(UsageMetricsModelMetricTokenDetail, x), x), from_none], self.token_details) - if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_int, from_none], self.total_nano_aiu) - return result - -@dataclass -class Workspace: - id: UUID - branch: str | None = None - chronicle_sync_dismissed: bool | None = None - created_at: datetime | None = None - cwd: str | None = None - git_root: str | None = None - host_type: HostType | None = None - mc_last_event_id: str | None = None - mc_session_id: str | None = None - mc_task_id: str | None = None - name: str | None = None - remote_steerable: bool | None = None - repository: str | None = None - summary_count: int | None = None - updated_at: datetime | None = None - user_named: bool | None = None - - @staticmethod - def from_dict(obj: Any) -> 'Workspace': - assert isinstance(obj, dict) - id = UUID(obj.get("id")) - branch = from_union([from_str, from_none], obj.get("branch")) - chronicle_sync_dismissed = from_union([from_bool, from_none], obj.get("chronicle_sync_dismissed")) - created_at = from_union([from_datetime, from_none], obj.get("created_at")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - git_root = from_union([from_str, from_none], obj.get("git_root")) - host_type = from_union([HostType, from_none], obj.get("host_type")) - mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) - mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) - mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) - name = from_union([from_str, from_none], obj.get("name")) - remote_steerable = from_union([from_bool, from_none], obj.get("remote_steerable")) - repository = from_union([from_str, from_none], obj.get("repository")) - summary_count = from_union([from_int, from_none], obj.get("summary_count")) - updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) - user_named = from_union([from_bool, from_none], obj.get("user_named")) - return Workspace(id, branch, chronicle_sync_dismissed, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, remote_steerable, repository, summary_count, updated_at, user_named) - - def to_dict(self) -> dict: - result: dict = {} - result["id"] = str(self.id) - if self.branch is not None: - result["branch"] = from_union([from_str, from_none], self.branch) - if self.chronicle_sync_dismissed is not None: - result["chronicle_sync_dismissed"] = from_union([from_bool, from_none], self.chronicle_sync_dismissed) - if self.created_at is not None: - result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.git_root is not None: - result["git_root"] = from_union([from_str, from_none], self.git_root) - if self.host_type is not None: - result["host_type"] = from_union([lambda x: to_enum(HostType, x), from_none], self.host_type) - if self.mc_last_event_id is not None: - result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) - if self.mc_session_id is not None: - result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) - if self.mc_task_id is not None: - result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.remote_steerable is not None: - result["remote_steerable"] = from_union([from_bool, from_none], self.remote_steerable) - if self.repository is not None: - result["repository"] = from_union([from_str, from_none], self.repository) - if self.summary_count is not None: - result["summary_count"] = from_union([from_int, from_none], self.summary_count) - if self.updated_at is not None: - result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) - if self.user_named is not None: - result["user_named"] = from_union([from_bool, from_none], self.user_named) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + result["source"] = to_enum(ExtensionSource, self.source) + result["status"] = to_enum(ExtensionStatus, self.status) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) return result @dataclass -class SlashCommandInfo: - """Schema for the `SlashCommandInfo` type.""" +class ExternalToolTextResultForLlmBinaryResultsForLlm: + """Binary result returned by a tool for the model""" - allow_during_agent_execution: bool - """Whether the command may run while an agent turn is active""" + data: str + """Base64-encoded binary data""" - description: str - """Human-readable command description""" + mime_type: str + """MIME type of the binary data""" - kind: SlashCommandKind - """Coarse command category for grouping and behavior: runtime built-in, skill-backed - command, or SDK/client-owned command + type: ExternalToolTextResultForLlmBinaryResultsForLlmType + """Binary result type discriminator. Use "image" for images and "resource" for other binary + data. """ - name: str - """Canonical command name without a leading slash""" - - aliases: list[str] | None = None - """Canonical aliases without leading slashes""" - - experimental: bool | None = None - """Whether the command is experimental""" - - input: SlashCommandInput | None = None - """Optional unstructured input hint""" + description: str | None = None + """Human-readable description of the binary data""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandInfo': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmBinaryResultsForLlm': assert isinstance(obj, dict) - allow_during_agent_execution = from_bool(obj.get("allowDuringAgentExecution")) - description = from_str(obj.get("description")) - kind = SlashCommandKind(obj.get("kind")) - name = from_str(obj.get("name")) - aliases = from_union([lambda x: from_list(from_str, x), from_none], obj.get("aliases")) - experimental = from_union([from_bool, from_none], obj.get("experimental")) - input = from_union([SlashCommandInput.from_dict, from_none], obj.get("input")) - return SlashCommandInfo(allow_during_agent_execution, description, kind, name, aliases, experimental, input) + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = ExternalToolTextResultForLlmBinaryResultsForLlmType(obj.get("type")) + description = from_union([from_str, from_none], obj.get("description")) + return ExternalToolTextResultForLlmBinaryResultsForLlm(data, mime_type, type, description) def to_dict(self) -> dict: result: dict = {} - result["allowDuringAgentExecution"] = from_bool(self.allow_during_agent_execution) - result["description"] = from_str(self.description) - result["kind"] = to_enum(SlashCommandKind, self.kind) - result["name"] = from_str(self.name) - if self.aliases is not None: - result["aliases"] = from_union([lambda x: from_list(from_str, x), from_none], self.aliases) - if self.experimental is not None: - result["experimental"] = from_union([from_bool, from_none], self.experimental) - if self.input is not None: - result["input"] = from_union([lambda x: to_class(SlashCommandInput, x), from_none], self.input) + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(ExternalToolTextResultForLlmBinaryResultsForLlmType, self.type) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class RemoteSessionConnectionResult: - """Remote session connection result.""" +class ExternalToolTextResultForLlmContentResourceLinkIcon: + """Icon image for a resource""" - metadata: ConnectedRemoteSessionMetadata - """Metadata for a connected remote session.""" + src: str + """URL or path to the icon image""" - session_id: str - """SDK session ID for the connected remote session.""" + mime_type: str | None = None + """MIME type of the icon image""" + + sizes: list[str] | None = None + """Available icon sizes (e.g., ['16x16', '32x32'])""" + + theme: ExternalToolTextResultForLlmContentResourceLinkIconTheme | None = None + """Theme variant this icon is intended for""" @staticmethod - def from_dict(obj: Any) -> 'RemoteSessionConnectionResult': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLinkIcon': assert isinstance(obj, dict) - metadata = ConnectedRemoteSessionMetadata.from_dict(obj.get("metadata")) - session_id = from_str(obj.get("sessionId")) - return RemoteSessionConnectionResult(metadata, session_id) + src = from_str(obj.get("src")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + sizes = from_union([lambda x: from_list(from_str, x), from_none], obj.get("sizes")) + theme = from_union([ExternalToolTextResultForLlmContentResourceLinkIconTheme, from_none], obj.get("theme")) + return ExternalToolTextResultForLlmContentResourceLinkIcon(src, mime_type, sizes, theme) def to_dict(self) -> dict: result: dict = {} - result["metadata"] = to_class(ConnectedRemoteSessionMetadata, self.metadata) - result["sessionId"] = from_str(self.session_id) + result["src"] = from_str(self.src) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + if self.sizes is not None: + result["sizes"] = from_union([lambda x: from_list(from_str, x), from_none], self.sizes) + if self.theme is not None: + result["theme"] = from_union([lambda x: to_enum(ExternalToolTextResultForLlmContentResourceLinkIconTheme, x), from_none], self.theme) return result +ExternalToolTextResultForLlmContentResourceDetails = EmbeddedTextResourceContents | EmbeddedBlobResourceContents + @dataclass -class MCPDiscoverResult: - """MCP servers discovered from user, workspace, plugin, and built-in sources.""" +class ExternalToolTextResultForLlmContentAudio: + """Audio content block with base64-encoded data""" - servers: list[DiscoveredMCPServer] - """MCP servers discovered from all sources""" + data: str + """Base64-encoded audio data""" + + mime_type: str + """MIME type of the audio (e.g., audio/wav, audio/mpeg)""" + + type: ExternalToolTextResultForLlmContentAudioType + """Content block type discriminator""" @staticmethod - def from_dict(obj: Any) -> 'MCPDiscoverResult': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentAudio': assert isinstance(obj, dict) - servers = from_list(DiscoveredMCPServer.from_dict, obj.get("servers")) - return MCPDiscoverResult(servers) + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = ExternalToolTextResultForLlmContentAudioType(obj.get("type")) + return ExternalToolTextResultForLlmContentAudio(data, mime_type, type) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_list(lambda x: to_class(DiscoveredMCPServer, x), self.servers) + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(ExternalToolTextResultForLlmContentAudioType, self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExtensionList: - """Extensions discovered for the session, with their current status.""" +class ExternalToolTextResultForLlmContentImage: + """Image content block with base64-encoded data""" - extensions: list[Extension] - """Discovered extensions and their current status""" + data: str + """Base64-encoded image data""" + + mime_type: str + """MIME type of the image (e.g., image/png, image/jpeg)""" + + type: ExternalToolTextResultForLlmContentImageType + """Content block type discriminator""" @staticmethod - def from_dict(obj: Any) -> 'ExtensionList': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentImage': assert isinstance(obj, dict) - extensions = from_list(Extension.from_dict, obj.get("extensions")) - return ExtensionList(extensions) + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = ExternalToolTextResultForLlmContentImageType(obj.get("type")) + return ExternalToolTextResultForLlmContentImage(data, mime_type, type) def to_dict(self) -> dict: result: dict = {} - result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions) + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(ExternalToolTextResultForLlmContentImageType, self.type) return result @dataclass -class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess: - """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` - type. - """ - extension_name: str - """Extension name.""" +class ExternalToolTextResultForLlmContentResource: + """Embedded resource content block with inline text or binary data""" - kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind - """Approval covering an extension's request to access a permission-gated capability.""" + resource: ExternalToolTextResultForLlmContentResourceDetails + """The embedded resource contents, either text or base64-encoded binary""" + + type: ExternalToolTextResultForLlmContentResourceType + """Content block type discriminator""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResource': assert isinstance(obj, dict) - extension_name = from_str(obj.get("extensionName")) - kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) - return PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess(extension_name, kind) + resource = (lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x))(obj.get("resource")) + type = ExternalToolTextResultForLlmContentResourceType(obj.get("type")) + return ExternalToolTextResultForLlmContentResource(resource, type) def to_dict(self) -> dict: result: dict = {} - result["extensionName"] = from_str(self.extension_name) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + result["resource"] = from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], self.resource) + result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceType, self.type) return result @dataclass -class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess: - """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` - type. - """ - extension_name: str - """Extension name.""" +class ExternalToolTextResultForLlmContentTerminal: + """Terminal/shell output content block with optional exit code and working directory""" - kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind - """Approval covering an extension's request to access a permission-gated capability.""" + text: str + """Terminal/shell output text""" + + type: ExternalToolTextResultForLlmContentTerminalType + """Content block type discriminator""" + + cwd: str | None = None + """Working directory where the command was executed""" + + exit_code: int | None = None + """Process exit code, if the command has completed""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess': + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentTerminal': assert isinstance(obj, dict) - extension_name = from_str(obj.get("extensionName")) - kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) - return PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess(extension_name, kind) + text = from_str(obj.get("text")) + type = ExternalToolTextResultForLlmContentTerminalType(obj.get("type")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + exit_code = from_union([from_int, from_none], obj.get("exitCode")) + return ExternalToolTextResultForLlmContentTerminal(text, type, cwd, exit_code) def to_dict(self) -> dict: result: dict = {} - result["extensionName"] = from_str(self.extension_name) - result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + result["text"] = from_str(self.text) + result["type"] = to_enum(ExternalToolTextResultForLlmContentTerminalType, self.type) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.exit_code is not None: + result["exitCode"] = from_union([from_int, from_none], self.exit_code) return result @dataclass -class ExternalToolTextResultForLlmContent: - """A content block within a tool result, which may be text, terminal output, image, audio, - or a resource - - Plain text content block +class ExternalToolTextResultForLlmContentText: + """Plain text content block""" - Terminal/shell output content block with optional exit code and working directory + text: str + """The text content""" - Image content block with base64-encoded data + type: KindEnum + """Content block type discriminator""" - Audio content block with base64-encoded data + @staticmethod + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentText': + assert isinstance(obj, dict) + text = from_str(obj.get("text")) + type = KindEnum(obj.get("type")) + return ExternalToolTextResultForLlmContentText(text, type) - Resource link content block referencing an external resource + def to_dict(self) -> dict: + result: dict = {} + result["text"] = from_str(self.text) + result["type"] = to_enum(KindEnum, self.type) + return result - Embedded resource content block with inline text or binary data - """ - type: ExternalToolTextResultForLlmContentType - """Content block type discriminator""" +@dataclass +class SlashCommandTextResult: + """Schema for the `SlashCommandTextResult` type.""" - text: str | None = None - """The text content + kind: KindEnum + """Text result discriminator""" - Terminal/shell output text - """ - cwd: str | None = None - """Working directory where the command was executed""" + text: str + """Text output for the client to render""" - exit_code: float | None = None - """Process exit code, if the command has completed""" + markdown: bool | None = None + """Whether text contains Markdown""" - data: str | None = None - """Base64-encoded image data + preserve_ansi: bool | None = None + """Whether ANSI sequences should be preserved""" - Base64-encoded audio data + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh """ - mime_type: str | None = None - """MIME type of the image (e.g., image/png, image/jpeg) - - MIME type of the audio (e.g., audio/wav, audio/mpeg) - MIME type of the resource content - """ - description: str | None = None - """Human-readable description of the resource""" + @staticmethod + def from_dict(obj: Any) -> 'SlashCommandTextResult': + assert isinstance(obj, dict) + kind = KindEnum(obj.get("kind")) + text = from_str(obj.get("text")) + markdown = from_union([from_bool, from_none], obj.get("markdown")) + preserve_ansi = from_union([from_bool, from_none], obj.get("preserveAnsi")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + return SlashCommandTextResult(kind, text, markdown, preserve_ansi, runtime_settings_changed) - icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None - """Icons associated with this resource""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(KindEnum, self.kind) + result["text"] = from_str(self.text) + if self.markdown is not None: + result["markdown"] = from_union([from_bool, from_none], self.markdown) + if self.preserve_ansi is not None: + result["preserveAnsi"] = from_union([from_bool, from_none], self.preserve_ansi) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + return result - name: str | None = None - """Resource name identifier""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class HistoryCompactResult: + """Compaction outcome with the number of tokens and messages removed, summary text, and the + resulting context window breakdown. + """ + messages_removed: int + """Number of messages removed during compaction""" - size: float | None = None - """Size of the resource in bytes""" + success: bool + """Whether compaction completed successfully""" - title: str | None = None - """Human-readable display title for the resource""" + tokens_removed: int + """Number of tokens freed by compaction""" - uri: str | None = None - """URI identifying the resource""" + context_window: HistoryCompactContextWindow | None = None + """Post-compaction context window usage breakdown""" - resource: ExternalToolTextResultForLlmContentResourceDetails | None = None - """The embedded resource contents, either text or base64-encoded binary""" + summary_content: str | None = None + """Summary text produced by compaction. Omitted when compaction did not produce a summary + (e.g. failure path). + """ @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContent': + def from_dict(obj: Any) -> 'HistoryCompactResult': assert isinstance(obj, dict) - type = ExternalToolTextResultForLlmContentType(obj.get("type")) - text = from_union([from_str, from_none], obj.get("text")) - cwd = from_union([from_str, from_none], obj.get("cwd")) - exit_code = from_union([from_float, from_none], obj.get("exitCode")) - data = from_union([from_str, from_none], obj.get("data")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) - description = from_union([from_str, from_none], obj.get("description")) - icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) - name = from_union([from_str, from_none], obj.get("name")) - size = from_union([from_float, from_none], obj.get("size")) - title = from_union([from_str, from_none], obj.get("title")) - uri = from_union([from_str, from_none], obj.get("uri")) - resource = from_union([(lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x)), from_none], obj.get("resource")) - return ExternalToolTextResultForLlmContent(type, text, cwd, exit_code, data, mime_type, description, icons, name, size, title, uri, resource) + messages_removed = from_int(obj.get("messagesRemoved")) + success = from_bool(obj.get("success")) + tokens_removed = from_int(obj.get("tokensRemoved")) + context_window = from_union([HistoryCompactContextWindow.from_dict, from_none], obj.get("contextWindow")) + summary_content = from_union([from_str, from_none], obj.get("summaryContent")) + return HistoryCompactResult(messages_removed, success, tokens_removed, context_window, summary_content) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(ExternalToolTextResultForLlmContentType, self.type) - if self.text is not None: - result["text"] = from_union([from_str, from_none], self.text) - if self.cwd is not None: - result["cwd"] = from_union([from_str, from_none], self.cwd) - if self.exit_code is not None: - result["exitCode"] = from_union([to_float, from_none], self.exit_code) - if self.data is not None: - result["data"] = from_union([from_str, from_none], self.data) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.icons is not None: - result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) - if self.name is not None: - result["name"] = from_union([from_str, from_none], self.name) - if self.size is not None: - result["size"] = from_union([to_float, from_none], self.size) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) - if self.uri is not None: - result["uri"] = from_union([from_str, from_none], self.uri) - if self.resource is not None: - result["resource"] = from_union([lambda x: from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], x), from_none], self.resource) + result["messagesRemoved"] = from_int(self.messages_removed) + result["success"] = from_bool(self.success) + result["tokensRemoved"] = from_int(self.tokens_removed) + if self.context_window is not None: + result["contextWindow"] = from_union([lambda x: to_class(HistoryCompactContextWindow, x), from_none], self.context_window) + if self.summary_content is not None: + result["summaryContent"] = from_union([from_str, from_none], self.summary_content) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ExternalToolTextResultForLlmContentResourceLink: - """Resource link content block referencing an external resource""" - - name: str - """Resource name identifier""" +class InstalledPluginSourceGithub: + """Schema for the `InstalledPluginSourceGithub` type.""" - type: ExternalToolTextResultForLlmContentResourceLinkType - """Content block type discriminator""" + repo: str + source: FluffySource + """Constant value. Always "github".""" - uri: str - """URI identifying the resource""" + path: str | None = None + ref: str | None = None - description: str | None = None - """Human-readable description of the resource""" + @staticmethod + def from_dict(obj: Any) -> 'InstalledPluginSourceGithub': + assert isinstance(obj, dict) + repo = from_str(obj.get("repo")) + source = FluffySource(obj.get("source")) + path = from_union([from_str, from_none], obj.get("path")) + ref = from_union([from_str, from_none], obj.get("ref")) + return InstalledPluginSourceGithub(repo, source, path, ref) - icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None - """Icons associated with this resource""" + def to_dict(self) -> dict: + result: dict = {} + result["repo"] = from_str(self.repo) + result["source"] = to_enum(FluffySource, self.source) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.ref is not None: + result["ref"] = from_union([from_str, from_none], self.ref) + return result - mime_type: str | None = None - """MIME type of the resource content""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionInstalledPluginSourceGithub: + """Schema for the `SessionInstalledPluginSourceGithub` type.""" - size: float | None = None - """Size of the resource in bytes""" + repo: str + source: FluffySource + """Constant value. Always "github".""" - title: str | None = None - """Human-readable display title for the resource""" + path: str | None = None + ref: str | None = None @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLink': + def from_dict(obj: Any) -> 'SessionInstalledPluginSourceGithub': assert isinstance(obj, dict) - name = from_str(obj.get("name")) - type = ExternalToolTextResultForLlmContentResourceLinkType(obj.get("type")) - uri = from_str(obj.get("uri")) - description = from_union([from_str, from_none], obj.get("description")) - icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) - mime_type = from_union([from_str, from_none], obj.get("mimeType")) - size = from_union([from_float, from_none], obj.get("size")) - title = from_union([from_str, from_none], obj.get("title")) - return ExternalToolTextResultForLlmContentResourceLink(name, type, uri, description, icons, mime_type, size, title) + repo = from_str(obj.get("repo")) + source = FluffySource(obj.get("source")) + path = from_union([from_str, from_none], obj.get("path")) + ref = from_union([from_str, from_none], obj.get("ref")) + return SessionInstalledPluginSourceGithub(repo, source, path, ref) def to_dict(self) -> dict: result: dict = {} - result["name"] = from_str(self.name) - result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceLinkType, self.type) - result["uri"] = from_str(self.uri) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.icons is not None: - result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) - if self.mime_type is not None: - result["mimeType"] = from_union([from_str, from_none], self.mime_type) - if self.size is not None: - result["size"] = from_union([to_float, from_none], self.size) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["repo"] = from_str(self.repo) + result["source"] = to_enum(FluffySource, self.source) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.ref is not None: + result["ref"] = from_union([from_str, from_none], self.ref) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class InstructionsGetSourcesResult: - """Instruction sources loaded for the session, in merge order.""" +class InstalledPluginSourceLocal: + """Schema for the `InstalledPluginSourceLocal` type.""" - sources: list[InstructionsSources] - """Instruction sources for the session""" + path: str + source: TentacledSource + """Constant value. Always "local".""" @staticmethod - def from_dict(obj: Any) -> 'InstructionsGetSourcesResult': + def from_dict(obj: Any) -> 'InstalledPluginSourceLocal': assert isinstance(obj, dict) - sources = from_list(InstructionsSources.from_dict, obj.get("sources")) - return InstructionsGetSourcesResult(sources) + path = from_str(obj.get("path")) + source = TentacledSource(obj.get("source")) + return InstalledPluginSourceLocal(path, source) def to_dict(self) -> dict: result: dict = {} - result["sources"] = from_list(lambda x: to_class(InstructionsSources, x), self.sources) + result["path"] = from_str(self.path) + result["source"] = to_enum(TentacledSource, self.source) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPConfigAddRequest: - """MCP server name and configuration to add to user configuration.""" +class SessionInstalledPluginSourceLocal: + """Schema for the `SessionInstalledPluginSourceLocal` type.""" - config: MCPServerConfig - """MCP server configuration (stdio process or remote HTTP/SSE)""" - - name: str - """Unique name for the MCP server""" - - @staticmethod - def from_dict(obj: Any) -> 'MCPConfigAddRequest': - assert isinstance(obj, dict) - config = MCPServerConfig.from_dict(obj.get("config")) - name = from_str(obj.get("name")) - return MCPConfigAddRequest(config, name) - - def to_dict(self) -> dict: - result: dict = {} - result["config"] = to_class(MCPServerConfig, self.config) - result["name"] = from_str(self.name) - return result - -@dataclass -class MCPConfigList: - """User-configured MCP servers, keyed by server name.""" - - servers: dict[str, MCPServerConfig] - """All MCP servers from user config, keyed by name""" + path: str + source: TentacledSource + """Constant value. Always "local".""" @staticmethod - def from_dict(obj: Any) -> 'MCPConfigList': + def from_dict(obj: Any) -> 'SessionInstalledPluginSourceLocal': assert isinstance(obj, dict) - servers = from_dict(MCPServerConfig.from_dict, obj.get("servers")) - return MCPConfigList(servers) + path = from_str(obj.get("path")) + source = TentacledSource(obj.get("source")) + return SessionInstalledPluginSourceLocal(path, source) def to_dict(self) -> dict: result: dict = {} - result["servers"] = from_dict(lambda x: to_class(MCPServerConfig, x), self.servers) + result["path"] = from_str(self.path) + result["source"] = to_enum(TentacledSource, self.source) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class MCPConfigUpdateRequest: - """MCP server name and replacement configuration to write to user configuration.""" +class InstalledPluginSourceURL: + """Schema for the `InstalledPluginSourceUrl` type.""" - config: MCPServerConfig - """MCP server configuration (stdio process or remote HTTP/SSE)""" + source: StickySource + """Constant value. Always "url".""" - name: str - """Name of the MCP server to update""" + url: str + path: str | None = None + ref: str | None = None @staticmethod - def from_dict(obj: Any) -> 'MCPConfigUpdateRequest': + def from_dict(obj: Any) -> 'InstalledPluginSourceURL': assert isinstance(obj, dict) - config = MCPServerConfig.from_dict(obj.get("config")) - name = from_str(obj.get("name")) - return MCPConfigUpdateRequest(config, name) + source = StickySource(obj.get("source")) + url = from_str(obj.get("url")) + path = from_union([from_str, from_none], obj.get("path")) + ref = from_union([from_str, from_none], obj.get("ref")) + return InstalledPluginSourceURL(source, url, path, ref) def to_dict(self) -> dict: result: dict = {} - result["config"] = to_class(MCPServerConfig, self.config) - result["name"] = from_str(self.name) + result["source"] = to_enum(StickySource, self.source) + result["url"] = from_str(self.url) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.ref is not None: + result["ref"] = from_union([from_str, from_none], self.ref) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelCapabilitiesOverride: - """Override individual model capabilities resolved by the runtime""" +class SessionInstalledPluginSourceURL: + """Schema for the `SessionInstalledPluginSourceUrl` type.""" - limits: ModelCapabilitiesOverrideLimits | None = None - """Token limits for prompts, outputs, and context window""" + source: StickySource + """Constant value. Always "url".""" - supports: ModelCapabilitiesOverrideSupports | None = None - """Feature flags indicating what the model supports""" + url: str + path: str | None = None + ref: str | None = None @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilitiesOverride': + def from_dict(obj: Any) -> 'SessionInstalledPluginSourceURL': assert isinstance(obj, dict) - limits = from_union([ModelCapabilitiesOverrideLimits.from_dict, from_none], obj.get("limits")) - supports = from_union([ModelCapabilitiesOverrideSupports.from_dict, from_none], obj.get("supports")) - return ModelCapabilitiesOverride(limits, supports) + source = StickySource(obj.get("source")) + url = from_str(obj.get("url")) + path = from_union([from_str, from_none], obj.get("path")) + ref = from_union([from_str, from_none], obj.get("ref")) + return SessionInstalledPluginSourceURL(source, url, path, ref) def to_dict(self) -> dict: result: dict = {} - if self.limits is not None: - result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimits, x), from_none], self.limits) - if self.supports is not None: - result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideSupports, x), from_none], self.supports) + result["source"] = to_enum(StickySource, self.source) + result["url"] = from_str(self.url) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.ref is not None: + result["ref"] = from_union([from_str, from_none], self.ref) return result @dataclass -class CommandsRespondToQueuedCommandRequest: - """Queued command request ID and the result indicating whether the client handled it.""" +class InstructionsSources: + """Schema for the `InstructionsSources` type.""" - request_id: str - """Request ID from the queued command event""" + content: str + """Raw content of the instruction file""" - result: QueuedCommandResult - """Result of the queued command execution""" + id: str + """Unique identifier for this source (used for toggling)""" - @staticmethod - def from_dict(obj: Any) -> 'CommandsRespondToQueuedCommandRequest': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = QueuedCommandResult.from_dict(obj.get("result")) - return CommandsRespondToQueuedCommandRequest(request_id, result) + label: str + """Human-readable label""" - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(QueuedCommandResult, self.result) - return result + location: InstructionsSourcesLocation + """Where this source lives — used for UI grouping""" -@dataclass -class SessionFSReadFileResult: - """File content as a UTF-8 string, or a filesystem error if the read failed.""" + source_path: str + """File path relative to repo or absolute for home""" - content: str - """File content as UTF-8 string""" + type: InstructionsSourcesType + """Category of instruction source — used for merge logic""" - error: SessionFSError | None = None - """Describes a filesystem error.""" + apply_to: list[str] | None = None + """Glob pattern(s) from frontmatter — when set, this instruction applies only to matching + files + """ + default_disabled: bool | None = None + """When true, this source starts disabled and must be toggled on by the user""" + + description: str | None = None + """Short description (body after frontmatter) for use in instruction tables""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReadFileResult': + def from_dict(obj: Any) -> 'InstructionsSources': assert isinstance(obj, dict) content = from_str(obj.get("content")) - error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) - return SessionFSReadFileResult(content, error) + id = from_str(obj.get("id")) + label = from_str(obj.get("label")) + location = InstructionsSourcesLocation(obj.get("location")) + source_path = from_str(obj.get("sourcePath")) + type = InstructionsSourcesType(obj.get("type")) + apply_to = from_union([lambda x: from_list(from_str, x), from_none], obj.get("applyTo")) + default_disabled = from_union([from_bool, from_none], obj.get("defaultDisabled")) + description = from_union([from_str, from_none], obj.get("description")) + return InstructionsSources(content, id, label, location, source_path, type, apply_to, default_disabled, description) def to_dict(self) -> dict: result: dict = {} result["content"] = from_str(self.content) - if self.error is not None: - result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + result["id"] = from_str(self.id) + result["label"] = from_str(self.label) + result["location"] = to_enum(InstructionsSourcesLocation, self.location) + result["sourcePath"] = from_str(self.source_path) + result["type"] = to_enum(InstructionsSourcesType, self.type) + if self.apply_to is not None: + result["applyTo"] = from_union([lambda x: from_list(from_str, x), from_none], self.apply_to) + if self.default_disabled is not None: + result["defaultDisabled"] = from_union([from_bool, from_none], self.default_disabled) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) return result @dataclass -class SessionFSReaddirResult: - """Names of entries in the requested directory, or a filesystem error if the read failed.""" +class LogRequest: + """Message text, optional severity level, persistence flag, optional follow-up URL, and + optional tip. + """ + message: str + """Human-readable message""" - entries: list[str] - """Entry names in the directory""" + ephemeral: bool | None = None + """When true, the message is transient and not persisted to the session event log on disk""" - error: SessionFSError | None = None - """Describes a filesystem error.""" + level: SessionLogLevel | None = None + """Log severity level. Determines how the message is displayed in the timeline. Defaults to + "info". + """ + tip: str | None = None + """Optional actionable tip displayed alongside the message. Only honored on `level: "info"`.""" + + type: str | None = None + """Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps + to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". + """ + url: str | None = None + """Optional URL the user can open in their browser for more details""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirResult': + def from_dict(obj: Any) -> 'LogRequest': assert isinstance(obj, dict) - entries = from_list(from_str, obj.get("entries")) - error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) - return SessionFSReaddirResult(entries, error) + message = from_str(obj.get("message")) + ephemeral = from_union([from_bool, from_none], obj.get("ephemeral")) + level = from_union([SessionLogLevel, from_none], obj.get("level")) + tip = from_union([from_str, from_none], obj.get("tip")) + type = from_union([from_str, from_none], obj.get("type")) + url = from_union([from_str, from_none], obj.get("url")) + return LogRequest(message, ephemeral, level, tip, type, url) def to_dict(self) -> dict: result: dict = {} - result["entries"] = from_list(from_str, self.entries) - if self.error is not None: - result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + result["message"] = from_str(self.message) + if self.ephemeral is not None: + result["ephemeral"] = from_union([from_bool, from_none], self.ephemeral) + if self.level is not None: + result["level"] = from_union([lambda x: to_enum(SessionLogLevel, x), from_none], self.level) + if self.tip is not None: + result["tip"] = from_union([from_str, from_none], self.tip) + if self.type is not None: + result["type"] = from_union([from_str, from_none], self.type) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) return result @dataclass -class SessionFSSqliteQueryResult: - """Query results including rows, columns, and rows affected, or a filesystem error if - execution failed. - """ - columns: list[str] - """Column names from the result set""" +class MCPServerConfig: + """MCP server configuration (stdio process or remote HTTP/SSE) - rows: list[dict[str, Any]] - """For SELECT: array of row objects. For others: empty array.""" + Stdio MCP server configuration launched as a child process. - rows_affected: int - """Number of rows affected (for INSERT/UPDATE/DELETE)""" + Remote MCP server configuration accessed over HTTP or SSE. + """ + args: list[str] | None = None + """Command-line arguments passed to the Stdio MCP server process.""" - error: SessionFSError | None = None - """Describes a filesystem error.""" + command: str | None = None + """Executable command used to start the Stdio MCP server process.""" - last_insert_rowid: float | None = None - """Last inserted row ID (for INSERT)""" + cwd: str | None = None + """Working directory for the Stdio MCP server process.""" - @staticmethod - def from_dict(obj: Any) -> 'SessionFSSqliteQueryResult': - assert isinstance(obj, dict) - columns = from_list(from_str, obj.get("columns")) - rows = from_list(lambda x: from_dict(lambda x: x, x), obj.get("rows")) - rows_affected = from_int(obj.get("rowsAffected")) - error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) - last_insert_rowid = from_union([from_float, from_none], obj.get("lastInsertRowid")) - return SessionFSSqliteQueryResult(columns, rows, rows_affected, error, last_insert_rowid) + env: dict[str, str] | None = None + """Environment variables to pass to the Stdio MCP server process.""" - def to_dict(self) -> dict: - result: dict = {} - result["columns"] = from_list(from_str, self.columns) - result["rows"] = from_list(lambda x: from_dict(lambda x: x, x), self.rows) - result["rowsAffected"] = from_int(self.rows_affected) - if self.error is not None: - result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) - if self.last_insert_rowid is not None: - result["lastInsertRowid"] = from_union([to_float, from_none], self.last_insert_rowid) - return result + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None + """Content filtering mode to apply to all tools, or a map of tool name to content filtering + mode. + """ + is_default_server: bool | None = None + """Whether this server is a built-in fallback used when the user has not configured their + own server. + """ + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" -@dataclass -class SessionFSStatResult: - """Filesystem metadata for the requested path, or a filesystem error if the stat failed.""" + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" - birthtime: datetime - """ISO 8601 timestamp of creation""" + auth: MCPServerConfigHTTPAuth | None = None + """Additional authentication configuration for this server.""" - is_directory: bool - """Whether the path is a directory""" + headers: dict[str, str] | None = None + """HTTP headers to include in requests to the remote MCP server.""" - is_file: bool - """Whether the path is a file""" + oauth_client_id: str | None = None + """OAuth client ID for a pre-registered remote MCP OAuth client.""" - mtime: datetime - """ISO 8601 timestamp of last modification""" + oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None + """OAuth grant type to use when authenticating to the remote MCP server.""" - size: int - """File size in bytes""" + oauth_public_client: bool | None = None + """Whether the configured OAuth client is public and does not require a client secret.""" - error: SessionFSError | None = None - """Describes a filesystem error.""" + type: MCPServerConfigHTTPType | None = None + """Remote transport type. Defaults to "http" when omitted.""" - @staticmethod - def from_dict(obj: Any) -> 'SessionFSStatResult': + url: str | None = None + """URL of the remote MCP server endpoint.""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPServerConfig': assert isinstance(obj, dict) - birthtime = from_datetime(obj.get("birthtime")) - is_directory = from_bool(obj.get("isDirectory")) - is_file = from_bool(obj.get("isFile")) - mtime = from_datetime(obj.get("mtime")) - size = from_int(obj.get("size")) - error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) - return SessionFSStatResult(birthtime, is_directory, is_file, mtime, size, error) + args = from_union([lambda x: from_list(from_str, x), from_none], obj.get("args")) + command = from_union([from_str, from_none], obj.get("command")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + env = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("env")) + filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) + headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) + oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) + oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) + oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) + type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) + url = from_union([from_str, from_none], obj.get("url")) + return MCPServerConfig(args, command, cwd, env, filter_mapping, is_default_server, timeout, tools, auth, headers, oauth_client_id, oauth_grant_type, oauth_public_client, type, url) def to_dict(self) -> dict: result: dict = {} - result["birthtime"] = self.birthtime.isoformat() - result["isDirectory"] = from_bool(self.is_directory) - result["isFile"] = from_bool(self.is_file) - result["mtime"] = self.mtime.isoformat() - result["size"] = from_int(self.size) - if self.error is not None: - result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + if self.args is not None: + result["args"] = from_union([lambda x: from_list(from_str, x), from_none], self.args) + if self.command is not None: + result["command"] = from_union([from_str, from_none], self.command) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.env is not None: + result["env"] = from_union([lambda x: from_dict(from_str, x), from_none], self.env) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.auth is not None: + result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) + if self.headers is not None: + result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) + if self.oauth_client_id is not None: + result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) + if self.oauth_grant_type is not None: + result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) + if self.oauth_public_client is not None: + result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) return result @dataclass -class SessionFSReaddirWithTypesResult: - """Entries in the requested directory paired with file/directory type information, or a - filesystem error if the read failed. +class MCPServerConfigHTTP: + """Remote MCP server configuration accessed over HTTP or SSE.""" + + url: str + """URL of the remote MCP server endpoint.""" + + auth: MCPServerConfigHTTPAuth | None = None + """Additional authentication configuration for this server.""" + + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode | None = None + """Content filtering mode to apply to all tools, or a map of tool name to content filtering + mode. """ - entries: list[SessionFSReaddirWithTypesEntry] - """Directory entries with type information""" + headers: dict[str, str] | None = None + """HTTP headers to include in requests to the remote MCP server.""" - error: SessionFSError | None = None - """Describes a filesystem error.""" + is_default_server: bool | None = None + """Whether this server is a built-in fallback used when the user has not configured their + own server. + """ + oauth_client_id: str | None = None + """OAuth client ID for a pre-registered remote MCP OAuth client.""" + + oauth_grant_type: MCPServerConfigHTTPOauthGrantType | None = None + """OAuth grant type to use when authenticating to the remote MCP server.""" + + oauth_public_client: bool | None = None + """Whether the configured OAuth client is public and does not require a client secret.""" + + timeout: int | None = None + """Timeout in milliseconds for tool calls to this server.""" + + tools: list[str] | None = None + """Tools to include. Defaults to all tools if not specified.""" + + type: MCPServerConfigHTTPType | None = None + """Remote transport type. Defaults to "http" when omitted.""" @staticmethod - def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesResult': + def from_dict(obj: Any) -> 'MCPServerConfigHTTP': assert isinstance(obj, dict) - entries = from_list(SessionFSReaddirWithTypesEntry.from_dict, obj.get("entries")) - error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) - return SessionFSReaddirWithTypesResult(entries, error) + url = from_str(obj.get("url")) + auth = from_union([MCPServerConfigHTTPAuth.from_dict, from_none], obj.get("auth")) + filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode, from_none], obj.get("filterMapping")) + headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("headers")) + is_default_server = from_union([from_bool, from_none], obj.get("isDefaultServer")) + oauth_client_id = from_union([from_str, from_none], obj.get("oauthClientId")) + oauth_grant_type = from_union([MCPServerConfigHTTPOauthGrantType, from_none], obj.get("oauthGrantType")) + oauth_public_client = from_union([from_bool, from_none], obj.get("oauthPublicClient")) + timeout = from_union([from_int, from_none], obj.get("timeout")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + type = from_union([MCPServerConfigHTTPType, from_none], obj.get("type")) + return MCPServerConfigHTTP(url, auth, filter_mapping, headers, is_default_server, oauth_client_id, oauth_grant_type, oauth_public_client, timeout, tools, type) def to_dict(self) -> dict: result: dict = {} - result["entries"] = from_list(lambda x: to_class(SessionFSReaddirWithTypesEntry, x), self.entries) - if self.error is not None: - result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + result["url"] = from_str(self.url) + if self.auth is not None: + result["auth"] = from_union([lambda x: to_class(MCPServerConfigHTTPAuth, x), from_none], self.auth) + if self.filter_mapping is not None: + result["filterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x), from_none], self.filter_mapping) + if self.headers is not None: + result["headers"] = from_union([lambda x: from_dict(from_str, x), from_none], self.headers) + if self.is_default_server is not None: + result["isDefaultServer"] = from_union([from_bool, from_none], self.is_default_server) + if self.oauth_client_id is not None: + result["oauthClientId"] = from_union([from_str, from_none], self.oauth_client_id) + if self.oauth_grant_type is not None: + result["oauthGrantType"] = from_union([lambda x: to_enum(MCPServerConfigHTTPOauthGrantType, x), from_none], self.oauth_grant_type) + if self.oauth_public_client is not None: + result["oauthPublicClient"] = from_union([from_bool, from_none], self.oauth_public_client) + if self.timeout is not None: + result["timeout"] = from_union([from_int, from_none], self.timeout) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(MCPServerConfigHTTPType, x), from_none], self.type) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class SlashCommandInvocationResult: - """Result of invoking the slash command (text output, prompt to send to the agent, or - completion). - - Schema for the `SlashCommandTextResult` type. - - Schema for the `SlashCommandAgentPromptResult` type. - - Schema for the `SlashCommandCompletedResult` type. - """ - kind: SlashCommandInvocationResultKind - """Text result discriminator - - Agent prompt result discriminator +class MCPSamplingExecutionResult: + """Outcome of an MCP sampling execution: success result, failure error, or cancellation.""" - Completed result discriminator + action: MCPSamplingExecutionAction + """Outcome of the sampling inference. 'success' produced a response; 'failure' encountered + an error (including agent-side rejection by content filter or criteria); 'cancelled' the + caller cancelled this execution via cancelSamplingExecution. """ - markdown: bool | None = None - """Whether text contains Markdown""" - - preserve_ansi: bool | None = None - """Whether ANSI sequences should be preserved""" + error: str | None = None + """Error description, present when action='failure'.""" - runtime_settings_changed: bool | None = None - """True when the invocation mutated user runtime settings; consumers caching settings should - refresh + result: dict[str, Any] | None = None + """MCP CreateMessageResult payload (with optional 'tools' extension), present when + action='success'. Treated as opaque at the schema layer; consumers should + construct/consume it per the MCP CreateMessageResult shape. """ - text: str | None = None - """Text output for the client to render""" - display_prompt: str | None = None - """Prompt text to display to the user""" + @staticmethod + def from_dict(obj: Any) -> 'MCPSamplingExecutionResult': + assert isinstance(obj, dict) + action = MCPSamplingExecutionAction(obj.get("action")) + error = from_union([from_str, from_none], obj.get("error")) + result = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("result")) + return MCPSamplingExecutionResult(action, error, result) - mode: SessionMode | None = None - """Optional target session mode for the agent prompt""" + def to_dict(self) -> dict: + result: dict = {} + result["action"] = to_enum(MCPSamplingExecutionAction, self.action) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result is not None: + result["result"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.result) + return result - prompt: str | None = None - """Prompt to submit to the agent""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MCPServerList: + """MCP servers configured for the session, with their connection status.""" - message: str | None = None - """Optional user-facing message describing the completed command""" + servers: list[MCPServer] + """Configured MCP servers""" @staticmethod - def from_dict(obj: Any) -> 'SlashCommandInvocationResult': + def from_dict(obj: Any) -> 'MCPServerList': assert isinstance(obj, dict) - kind = SlashCommandInvocationResultKind(obj.get("kind")) - markdown = from_union([from_bool, from_none], obj.get("markdown")) - preserve_ansi = from_union([from_bool, from_none], obj.get("preserveAnsi")) - runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) - text = from_union([from_str, from_none], obj.get("text")) - display_prompt = from_union([from_str, from_none], obj.get("displayPrompt")) - mode = from_union([SessionMode, from_none], obj.get("mode")) - prompt = from_union([from_str, from_none], obj.get("prompt")) - message = from_union([from_str, from_none], obj.get("message")) - return SlashCommandInvocationResult(kind, markdown, preserve_ansi, runtime_settings_changed, text, display_prompt, mode, prompt, message) + servers = from_list(MCPServer.from_dict, obj.get("servers")) + return MCPServerList(servers) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(SlashCommandInvocationResultKind, self.kind) - if self.markdown is not None: - result["markdown"] = from_union([from_bool, from_none], self.markdown) - if self.preserve_ansi is not None: - result["preserveAnsi"] = from_union([from_bool, from_none], self.preserve_ansi) - if self.runtime_settings_changed is not None: - result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) - if self.text is not None: - result["text"] = from_union([from_str, from_none], self.text) - if self.display_prompt is not None: - result["displayPrompt"] = from_union([from_str, from_none], self.display_prompt) - if self.mode is not None: - result["mode"] = from_union([lambda x: to_enum(SessionMode, x), from_none], self.mode) - if self.prompt is not None: - result["prompt"] = from_union([from_str, from_none], self.prompt) - if self.message is not None: - result["message"] = from_union([from_str, from_none], self.message) + result["servers"] = from_list(lambda x: to_class(MCPServer, x), self.servers) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationArrayAnyOfField: - """Multi-select string field where each option pairs a value with a display label.""" +class MCPSetEnvValueModeParams: + """Mode controlling how MCP server env values are resolved (`direct` or `indirect`).""" + + mode: MCPSetEnvValueModeDetails + """How environment-variable values supplied to MCP servers are resolved. "direct" passes + literal string values; "indirect" treats values as references (e.g. names of environment + variables on the host) that the runtime resolves before launch. Defaults to the runtime's + startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI + prompt mode and ACP) set this to "direct". + """ - items: UIElicitationArrayAnyOfFieldItems - """Schema applied to each item in the array.""" + @staticmethod + def from_dict(obj: Any) -> 'MCPSetEnvValueModeParams': + assert isinstance(obj, dict) + mode = MCPSetEnvValueModeDetails(obj.get("mode")) + return MCPSetEnvValueModeParams(mode) - type: UIElicitationArrayAnyOfFieldType - """Type discriminator. Always "array".""" + def to_dict(self) -> dict: + result: dict = {} + result["mode"] = to_enum(MCPSetEnvValueModeDetails, self.mode) + return result - default: list[str] | None = None - """Default values selected when the form is first shown.""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MCPSetEnvValueModeResult: + """Env-value mode recorded on the session after the update.""" - description: str | None = None - """Help text describing the field.""" + mode: MCPSetEnvValueModeDetails + """Mode recorded on the session after the update""" - max_items: float | None = None - """Maximum number of items the user may select.""" + @staticmethod + def from_dict(obj: Any) -> 'MCPSetEnvValueModeResult': + assert isinstance(obj, dict) + mode = MCPSetEnvValueModeDetails(obj.get("mode")) + return MCPSetEnvValueModeResult(mode) - min_items: float | None = None - """Minimum number of items the user must select.""" + def to_dict(self) -> dict: + result: dict = {} + result["mode"] = to_enum(MCPSetEnvValueModeDetails, self.mode) + return result - title: str | None = None - """Human-readable label for the field.""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataContextInfoResult: + """Token breakdown for the session's current context window, or null if uninitialized.""" + + context_info: SessionContextInfo | None = None + """Token breakdown for the current context window, or null if the session has not yet been + initialized (no system prompt or tool metadata cached). + """ @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfField': + def from_dict(obj: Any) -> 'MetadataContextInfoResult': assert isinstance(obj, dict) - items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("items")) - type = UIElicitationArrayAnyOfFieldType(obj.get("type")) - default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - max_items = from_union([from_float, from_none], obj.get("maxItems")) - min_items = from_union([from_float, from_none], obj.get("minItems")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationArrayAnyOfField(items, type, default, description, max_items, min_items, title) + context_info = from_union([SessionContextInfo.from_dict, from_none], obj.get("contextInfo")) + return MetadataContextInfoResult(context_info) def to_dict(self) -> dict: result: dict = {} - result["items"] = to_class(UIElicitationArrayAnyOfFieldItems, self.items) - result["type"] = to_enum(UIElicitationArrayAnyOfFieldType, self.type) - if self.default is not None: - result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.max_items is not None: - result["maxItems"] = from_union([to_float, from_none], self.max_items) - if self.min_items is not None: - result["minItems"] = from_union([to_float, from_none], self.min_items) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + if self.context_info is not None: + result["contextInfo"] = from_union([lambda x: to_class(SessionContextInfo, x), from_none], self.context_info) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationArrayEnumField: - """Multi-select string field whose allowed values are defined inline.""" - - items: UIElicitationArrayEnumFieldItems - """Schema applied to each item in the array.""" +class SessionWorkingDirectoryContext: + """Updated working directory and git context. Emitted as the new payload of + `session.context_changed`. + """ + cwd: str + """Current working directory path""" - type: UIElicitationArrayAnyOfFieldType - """Type discriminator. Always "array".""" + base_commit: str | None = None + """Merge-base commit SHA (fork point from the remote default branch)""" - default: list[str] | None = None - """Default values selected when the form is first shown.""" + branch: str | None = None + """Current git branch name""" - description: str | None = None - """Help text describing the field.""" + git_root: str | None = None + """Root directory of the git repository, resolved via git rev-parse""" - max_items: float | None = None - """Maximum number of items the user may select.""" + head_commit: str | None = None + """Head commit of the current git branch""" - min_items: float | None = None - """Minimum number of items the user must select.""" + host_type: SessionContextHostType | None = None + """Hosting platform type of the repository""" - title: str | None = None - """Human-readable label for the field.""" + repository: str | None = None + """Repository identifier derived from the git remote URL ("owner/name" for GitHub, + "org/project/repo" for Azure DevOps) + """ + repository_host: str | None = None + """Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com")""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationArrayEnumField': + def from_dict(obj: Any) -> 'SessionWorkingDirectoryContext': assert isinstance(obj, dict) - items = UIElicitationArrayEnumFieldItems.from_dict(obj.get("items")) - type = UIElicitationArrayAnyOfFieldType(obj.get("type")) - default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - max_items = from_union([from_float, from_none], obj.get("maxItems")) - min_items = from_union([from_float, from_none], obj.get("minItems")) - title = from_union([from_str, from_none], obj.get("title")) - return UIElicitationArrayEnumField(items, type, default, description, max_items, min_items, title) + cwd = from_str(obj.get("cwd")) + base_commit = from_union([from_str, from_none], obj.get("baseCommit")) + branch = from_union([from_str, from_none], obj.get("branch")) + git_root = from_union([from_str, from_none], obj.get("gitRoot")) + head_commit = from_union([from_str, from_none], obj.get("headCommit")) + host_type = from_union([SessionContextHostType, from_none], obj.get("hostType")) + repository = from_union([from_str, from_none], obj.get("repository")) + repository_host = from_union([from_str, from_none], obj.get("repositoryHost")) + return SessionWorkingDirectoryContext(cwd, base_commit, branch, git_root, head_commit, host_type, repository, repository_host) def to_dict(self) -> dict: result: dict = {} - result["items"] = to_class(UIElicitationArrayEnumFieldItems, self.items) - result["type"] = to_enum(UIElicitationArrayAnyOfFieldType, self.type) - if self.default is not None: - result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.max_items is not None: - result["maxItems"] = from_union([to_float, from_none], self.max_items) - if self.min_items is not None: - result["minItems"] = from_union([to_float, from_none], self.min_items) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) + result["cwd"] = from_str(self.cwd) + if self.base_commit is not None: + result["baseCommit"] = from_union([from_str, from_none], self.base_commit) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.git_root is not None: + result["gitRoot"] = from_union([from_str, from_none], self.git_root) + if self.head_commit is not None: + result["headCommit"] = from_union([from_str, from_none], self.head_commit) + if self.host_type is not None: + result["hostType"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + if self.repository_host is not None: + result["repositoryHost"] = from_union([from_str, from_none], self.repository_host) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UIElicitationSchemaProperty: - """Definition for a single elicitation form field. +class SessionContext: + """Schema for the `SessionContext` type. - Single-select string field whose allowed values are defined inline. + Optional working-directory context used to score session relevance. When omitted the + most-recently-modified session wins. + """ + cwd: str + """Most recent working directory for this session""" - Single-select string field where each option pairs a value with a display label. + branch: str | None = None + """Active git branch""" - Multi-select string field whose allowed values are defined inline. + git_root: str | None = None + """Git repository root, if the cwd was inside a git repo""" - Multi-select string field where each option pairs a value with a display label. + host_type: SessionContextHostType | None = None + """Repository host type""" - Boolean field rendered as a yes/no toggle. + repository: str | None = None + """Repository slug in `owner/name` form, when known""" - Free-text string field with optional length and format constraints. + @staticmethod + def from_dict(obj: Any) -> 'SessionContext': + assert isinstance(obj, dict) + cwd = from_str(obj.get("cwd")) + branch = from_union([from_str, from_none], obj.get("branch")) + git_root = from_union([from_str, from_none], obj.get("gitRoot")) + host_type = from_union([SessionContextHostType, from_none], obj.get("hostType")) + repository = from_union([from_str, from_none], obj.get("repository")) + return SessionContext(cwd, branch, git_root, host_type, repository) - Numeric field accepting either a number or an integer. - """ - type: UIElicitationSchemaPropertyType - """Type discriminator. Always "string". + def to_dict(self) -> dict: + result: dict = {} + result["cwd"] = from_str(self.cwd) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.git_root is not None: + result["gitRoot"] = from_union([from_str, from_none], self.git_root) + if self.host_type is not None: + result["hostType"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + return result - Type discriminator. Always "array". +@dataclass +class Workspace: + id: UUID + branch: str | None = None + chronicle_sync_dismissed: bool | None = None + created_at: datetime | None = None + cwd: str | None = None + git_root: str | None = None + host_type: SessionContextHostType | None = None + mc_last_event_id: str | None = None + mc_session_id: str | None = None + mc_task_id: str | None = None + name: str | None = None + remote_steerable: bool | None = None + repository: str | None = None + summary_count: int | None = None + updated_at: datetime | None = None + user_named: bool | None = None - Type discriminator. Always "boolean". + @staticmethod + def from_dict(obj: Any) -> 'Workspace': + assert isinstance(obj, dict) + id = UUID(obj.get("id")) + branch = from_union([from_str, from_none], obj.get("branch")) + chronicle_sync_dismissed = from_union([from_bool, from_none], obj.get("chronicle_sync_dismissed")) + created_at = from_union([from_datetime, from_none], obj.get("created_at")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + git_root = from_union([from_str, from_none], obj.get("git_root")) + host_type = from_union([SessionContextHostType, from_none], obj.get("host_type")) + mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) + mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) + mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) + name = from_union([from_str, from_none], obj.get("name")) + remote_steerable = from_union([from_bool, from_none], obj.get("remote_steerable")) + repository = from_union([from_str, from_none], obj.get("repository")) + summary_count = from_union([from_int, from_none], obj.get("summary_count")) + updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) + user_named = from_union([from_bool, from_none], obj.get("user_named")) + return Workspace(id, branch, chronicle_sync_dismissed, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, remote_steerable, repository, summary_count, updated_at, user_named) - Numeric type accepted by the field. + def to_dict(self) -> dict: + result: dict = {} + result["id"] = str(self.id) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.chronicle_sync_dismissed is not None: + result["chronicle_sync_dismissed"] = from_union([from_bool, from_none], self.chronicle_sync_dismissed) + if self.created_at is not None: + result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.git_root is not None: + result["git_root"] = from_union([from_str, from_none], self.git_root) + if self.host_type is not None: + result["host_type"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) + if self.mc_last_event_id is not None: + result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) + if self.mc_session_id is not None: + result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) + if self.mc_task_id is not None: + result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.remote_steerable is not None: + result["remote_steerable"] = from_union([from_bool, from_none], self.remote_steerable) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + if self.summary_count is not None: + result["summary_count"] = from_union([from_int, from_none], self.summary_count) + if self.updated_at is not None: + result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + if self.user_named is not None: + result["user_named"] = from_union([from_bool, from_none], self.user_named) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataSnapshotRemoteMetadata: + """Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are + immutable for the lifetime of the session. """ - default: float | bool | list[str] | str | None = None - """Default value selected when the form is first shown. + repository: MetadataSnapshotRemoteMetadataRepository + """The repository the remote session targets.""" - Default values selected when the form is first shown. + pull_request_number: int | None = None + """The pull request number the remote session is associated with, if any.""" - Default value populated in the input when the form is first shown. + resource_id: str | None = None + """The original resource identifier (task ID or PR node ID), preserved across event-replay + reconstructions. Falls back to `sessionId` when absent. + """ + task_type: MetadataSnapshotRemoteMetadataTaskType | None = None + """Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` + invocation. """ - description: str | None = None - """Help text describing the field.""" - enum: list[str] | None = None - """Allowed string values.""" + @staticmethod + def from_dict(obj: Any) -> 'MetadataSnapshotRemoteMetadata': + assert isinstance(obj, dict) + repository = MetadataSnapshotRemoteMetadataRepository.from_dict(obj.get("repository")) + pull_request_number = from_union([from_int, from_none], obj.get("pullRequestNumber")) + resource_id = from_union([from_str, from_none], obj.get("resourceId")) + task_type = from_union([MetadataSnapshotRemoteMetadataTaskType, from_none], obj.get("taskType")) + return MetadataSnapshotRemoteMetadata(repository, pull_request_number, resource_id, task_type) - enum_names: list[str] | None = None - """Optional display labels for each enum value, in the same order as `enum`.""" + def to_dict(self) -> dict: + result: dict = {} + result["repository"] = to_class(MetadataSnapshotRemoteMetadataRepository, self.repository) + if self.pull_request_number is not None: + result["pullRequestNumber"] = from_union([from_int, from_none], self.pull_request_number) + if self.resource_id is not None: + result["resourceId"] = from_union([from_str, from_none], self.resource_id) + if self.task_type is not None: + result["taskType"] = from_union([lambda x: to_enum(MetadataSnapshotRemoteMetadataTaskType, x), from_none], self.task_type) + return result - title: str | None = None - """Human-readable label for the field.""" +@dataclass +class ModelBilling: + """Billing information""" - one_of: list[UIElicitationStringOneOfFieldOneOf] | None = None - """Selectable options, each with a value and a display label.""" + multiplier: float | None = None + """Billing cost multiplier relative to the base rate""" - items: UIElicitationArrayFieldItems | None = None - """Schema applied to each item in the array.""" + token_prices: ModelBillingTokenPrices | None = None + """Token-level pricing information for this model""" - max_items: float | None = None - """Maximum number of items the user may select.""" + @staticmethod + def from_dict(obj: Any) -> 'ModelBilling': + assert isinstance(obj, dict) + multiplier = from_union([from_float, from_none], obj.get("multiplier")) + token_prices = from_union([ModelBillingTokenPrices.from_dict, from_none], obj.get("tokenPrices")) + return ModelBilling(multiplier, token_prices) - min_items: float | None = None - """Minimum number of items the user must select.""" + def to_dict(self) -> dict: + result: dict = {} + if self.multiplier is not None: + result["multiplier"] = from_union([to_float, from_none], self.multiplier) + if self.token_prices is not None: + result["tokenPrices"] = from_union([lambda x: to_class(ModelBillingTokenPrices, x), from_none], self.token_prices) + return result - format: UIElicitationSchemaPropertyStringFormat | None = None - """Optional format hint that constrains the accepted input.""" +@dataclass +class ModelCapabilitiesLimits: + """Token limits for prompts, outputs, and context window""" - max_length: float | None = None - """Maximum number of characters allowed.""" + max_context_window_tokens: int | None = None + """Maximum total context window size in tokens""" - min_length: float | None = None - """Minimum number of characters required.""" + max_output_tokens: int | None = None + """Maximum number of output/completion tokens""" - maximum: float | None = None - """Maximum allowed value (inclusive).""" + max_prompt_tokens: int | None = None + """Maximum number of prompt/input tokens""" - minimum: float | None = None - """Minimum allowed value (inclusive).""" + vision: ModelCapabilitiesLimitsVision | None = None + """Vision-specific limits""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchemaProperty': + def from_dict(obj: Any) -> 'ModelCapabilitiesLimits': assert isinstance(obj, dict) - type = UIElicitationSchemaPropertyType(obj.get("type")) - default = from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str, from_none], obj.get("default")) - description = from_union([from_str, from_none], obj.get("description")) - enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) - enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) - title = from_union([from_str, from_none], obj.get("title")) - one_of = from_union([lambda x: from_list(UIElicitationStringOneOfFieldOneOf.from_dict, x), from_none], obj.get("oneOf")) - items = from_union([UIElicitationArrayFieldItems.from_dict, from_none], obj.get("items")) - max_items = from_union([from_float, from_none], obj.get("maxItems")) - min_items = from_union([from_float, from_none], obj.get("minItems")) - format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) - max_length = from_union([from_float, from_none], obj.get("maxLength")) - min_length = from_union([from_float, from_none], obj.get("minLength")) - maximum = from_union([from_float, from_none], obj.get("maximum")) - minimum = from_union([from_float, from_none], obj.get("minimum")) - return UIElicitationSchemaProperty(type, default, description, enum, enum_names, title, one_of, items, max_items, min_items, format, max_length, min_length, maximum, minimum) + max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) + max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) + max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) + vision = from_union([ModelCapabilitiesLimitsVision.from_dict, from_none], obj.get("vision")) + return ModelCapabilitiesLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) def to_dict(self) -> dict: result: dict = {} - result["type"] = to_enum(UIElicitationSchemaPropertyType, self.type) - if self.default is not None: - result["default"] = from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str, from_none], self.default) - if self.description is not None: - result["description"] = from_union([from_str, from_none], self.description) - if self.enum is not None: - result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) - if self.enum_names is not None: - result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) - if self.title is not None: - result["title"] = from_union([from_str, from_none], self.title) - if self.one_of is not None: - result["oneOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), x), from_none], self.one_of) - if self.items is not None: - result["items"] = from_union([lambda x: to_class(UIElicitationArrayFieldItems, x), from_none], self.items) - if self.max_items is not None: - result["maxItems"] = from_union([to_float, from_none], self.max_items) - if self.min_items is not None: - result["minItems"] = from_union([to_float, from_none], self.min_items) - if self.format is not None: - result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) - if self.max_length is not None: - result["maxLength"] = from_union([to_float, from_none], self.max_length) - if self.min_length is not None: - result["minLength"] = from_union([to_float, from_none], self.min_length) - if self.maximum is not None: - result["maximum"] = from_union([to_float, from_none], self.maximum) - if self.minimum is not None: - result["minimum"] = from_union([to_float, from_none], self.minimum) + if self.max_context_window_tokens is not None: + result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) + if self.max_output_tokens is not None: + result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) + if self.max_prompt_tokens is not None: + result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) + if self.vision is not None: + result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesLimitsVision, x), from_none], self.vision) return result @dataclass -class UIHandlePendingElicitationRequest: - """Pending elicitation request ID and the user's response (accept/decline/cancel + form - values). - """ - request_id: str - """The unique request ID from the elicitation.requested event""" +class ModelPolicy: + """Policy state (if applicable)""" - result: UIElicitationResponse - """The elicitation response (accept with form values, decline, or cancel)""" + state: ModelPolicyState + """Current policy state for this model""" + + terms: str | None = None + """Usage terms or conditions for this model""" @staticmethod - def from_dict(obj: Any) -> 'UIHandlePendingElicitationRequest': + def from_dict(obj: Any) -> 'ModelPolicy': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = UIElicitationResponse.from_dict(obj.get("result")) - return UIHandlePendingElicitationRequest(request_id, result) + state = ModelPolicyState(obj.get("state")) + terms = from_union([from_str, from_none], obj.get("terms")) + return ModelPolicy(state, terms) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(UIElicitationResponse, self.result) + result["state"] = to_enum(ModelPolicyState, self.state) + if self.terms is not None: + result["terms"] = from_union([from_str, from_none], self.terms) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class UsageGetMetricsResult: - """Accumulated session usage metrics, including premium request cost, token counts, model - breakdown, and code-change totals. - """ - code_changes: UsageMetricsCodeChanges - """Aggregated code change metrics""" +class ModelCapabilitiesOverrideLimits: + """Token limits for prompts, outputs, and context window""" - last_call_input_tokens: int - """Input tokens from the most recent main-agent API call""" + max_context_window_tokens: int | None = None + """Maximum total context window size in tokens""" - last_call_output_tokens: int - """Output tokens from the most recent main-agent API call""" + max_output_tokens: int | None = None + """Maximum number of output/completion tokens""" - model_metrics: dict[str, UsageMetricsModelMetric] - """Per-model token and request metrics, keyed by model identifier""" + max_prompt_tokens: int | None = None + """Maximum number of prompt/input tokens""" - session_start_time: int - """Session start timestamp (epoch milliseconds)""" + vision: ModelCapabilitiesOverrideLimitsVision | None = None + """Vision-specific limits""" - total_api_duration_ms: float - """Total time spent in model API calls (milliseconds)""" + @staticmethod + def from_dict(obj: Any) -> 'ModelCapabilitiesOverrideLimits': + assert isinstance(obj, dict) + max_context_window_tokens = from_union([from_int, from_none], obj.get("max_context_window_tokens")) + max_output_tokens = from_union([from_int, from_none], obj.get("max_output_tokens")) + max_prompt_tokens = from_union([from_int, from_none], obj.get("max_prompt_tokens")) + vision = from_union([ModelCapabilitiesOverrideLimitsVision.from_dict, from_none], obj.get("vision")) + return ModelCapabilitiesOverrideLimits(max_context_window_tokens, max_output_tokens, max_prompt_tokens, vision) - total_premium_request_cost: float - """Total user-initiated premium request cost across all models (may be fractional due to - multipliers) + def to_dict(self) -> dict: + result: dict = {} + if self.max_context_window_tokens is not None: + result["max_context_window_tokens"] = from_union([from_int, from_none], self.max_context_window_tokens) + if self.max_output_tokens is not None: + result["max_output_tokens"] = from_union([from_int, from_none], self.max_output_tokens) + if self.max_prompt_tokens is not None: + result["max_prompt_tokens"] = from_union([from_int, from_none], self.max_prompt_tokens) + if self.vision is not None: + result["vision"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimitsVision, x), from_none], self.vision) + return result + +@dataclass +class PendingPermissionRequestList: + """List of pending permission requests reconstructed from event history.""" + + items: list[PendingPermissionRequest] + """Pending permission prompts reconstructed from the session's event history. Equivalent to + the set of `permission.requested` events that have not yet been followed by a matching + `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts + that were emitted before the client attached to the session. """ - total_user_requests: int - """Raw count of user-initiated API requests""" - current_model: str | None = None - """Currently active model identifier""" + @staticmethod + def from_dict(obj: Any) -> 'PendingPermissionRequestList': + assert isinstance(obj, dict) + items = from_list(PendingPermissionRequest.from_dict, obj.get("items")) + return PendingPermissionRequestList(items) - token_details: dict[str, UsageMetricsTokenDetail] | None = None - """Session-wide per-token-type accumulated token counts""" + def to_dict(self) -> dict: + result: dict = {} + result["items"] = from_list(lambda x: to_class(PendingPermissionRequest, x), self.items) + return result - total_nano_aiu: int | None = None - """Session-wide accumulated nano-AI units cost""" +@dataclass +class PermissionDecisionApproveForLocationApprovalCommands: + """Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type.""" + + command_identifiers: list[str] + """Command identifiers covered by this approval.""" + + kind: PermissionDecisionApproveForLocationApprovalCommandsKind + """Approval scoped to specific command identifiers.""" @staticmethod - def from_dict(obj: Any) -> 'UsageGetMetricsResult': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCommands': assert isinstance(obj, dict) - code_changes = UsageMetricsCodeChanges.from_dict(obj.get("codeChanges")) - last_call_input_tokens = from_int(obj.get("lastCallInputTokens")) - last_call_output_tokens = from_int(obj.get("lastCallOutputTokens")) - model_metrics = from_dict(UsageMetricsModelMetric.from_dict, obj.get("modelMetrics")) - session_start_time = from_int(obj.get("sessionStartTime")) - total_api_duration_ms = from_float(obj.get("totalApiDurationMs")) - total_premium_request_cost = from_float(obj.get("totalPremiumRequestCost")) - total_user_requests = from_int(obj.get("totalUserRequests")) - current_model = from_union([from_str, from_none], obj.get("currentModel")) - token_details = from_union([lambda x: from_dict(UsageMetricsTokenDetail.from_dict, x), from_none], obj.get("tokenDetails")) - total_nano_aiu = from_union([from_int, from_none], obj.get("totalNanoAiu")) - return UsageGetMetricsResult(code_changes, last_call_input_tokens, last_call_output_tokens, model_metrics, session_start_time, total_api_duration_ms, total_premium_request_cost, total_user_requests, current_model, token_details, total_nano_aiu) + command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) + kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalCommands(command_identifiers, kind) def to_dict(self) -> dict: result: dict = {} - result["codeChanges"] = to_class(UsageMetricsCodeChanges, self.code_changes) - result["lastCallInputTokens"] = from_int(self.last_call_input_tokens) - result["lastCallOutputTokens"] = from_int(self.last_call_output_tokens) - result["modelMetrics"] = from_dict(lambda x: to_class(UsageMetricsModelMetric, x), self.model_metrics) - result["sessionStartTime"] = from_int(self.session_start_time) - result["totalApiDurationMs"] = to_float(self.total_api_duration_ms) - result["totalPremiumRequestCost"] = to_float(self.total_premium_request_cost) - result["totalUserRequests"] = from_int(self.total_user_requests) - if self.current_model is not None: - result["currentModel"] = from_union([from_str, from_none], self.current_model) - if self.token_details is not None: - result["tokenDetails"] = from_union([lambda x: from_dict(lambda x: to_class(UsageMetricsTokenDetail, x), x), from_none], self.token_details) - if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_int, from_none], self.total_nano_aiu) + result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) return result @dataclass -class WorkspacesGetWorkspaceResult: - """Current workspace metadata for the session, or null when not available.""" +class PermissionDecisionApproveForSessionApprovalCommands: + """Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type.""" - workspace: Workspace | None = None - """Current workspace metadata, or null if not available""" + command_identifiers: list[str] + """Command identifiers covered by this approval.""" + + kind: PermissionDecisionApproveForLocationApprovalCommandsKind + """Approval scoped to specific command identifiers.""" @staticmethod - def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCommands': assert isinstance(obj, dict) - workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) - return WorkspacesGetWorkspaceResult(workspace) + command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) + kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalCommands(command_identifiers, kind) def to_dict(self) -> dict: result: dict = {} - result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) + result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) return result @dataclass -class CommandList: - """Slash commands available in the session, after applying any include/exclude filters.""" +class UserToolSessionApprovalCommands: + """Schema for the `UserToolSessionApprovalCommands` type.""" - commands: list[SlashCommandInfo] - """Commands available in this session""" + command_identifiers: list[str] + """Command identifiers approved by the user""" + + kind: PermissionDecisionApproveForLocationApprovalCommandsKind + """Command approval kind""" @staticmethod - def from_dict(obj: Any) -> 'CommandList': + def from_dict(obj: Any) -> 'UserToolSessionApprovalCommands': assert isinstance(obj, dict) - commands = from_list(SlashCommandInfo.from_dict, obj.get("commands")) - return CommandList(commands) + command_identifiers = from_list(from_str, obj.get("commandIdentifiers")) + kind = PermissionDecisionApproveForLocationApprovalCommandsKind(obj.get("kind")) + return UserToolSessionApprovalCommands(command_identifiers, kind) def to_dict(self) -> dict: result: dict = {} - result["commands"] = from_list(lambda x: to_class(SlashCommandInfo, x), self.commands) + result["commandIdentifiers"] = from_list(from_str, self.command_identifiers) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCommandsKind, self.kind) return result @dataclass -class PermissionDecisionApproveForLocationApproval: - """The approval to persist for this location +class PermissionDecisionApproveForLocationApprovalCustomTool: + """Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type.""" - Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type. + kind: PermissionDecisionApproveForLocationApprovalCustomToolKind + """Approval covering a custom tool.""" - Schema for the `PermissionDecisionApproveForLocationApprovalRead` type. + tool_name: str + """Custom tool name.""" - Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalCustomTool': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) + tool_name = from_str(obj.get("toolName")) + return PermissionDecisionApproveForLocationApprovalCustomTool(kind, tool_name) - Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) + result["toolName"] = from_str(self.tool_name) + return result - Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type. +@dataclass +class PermissionDecisionApproveForSessionApprovalCustomTool: + """Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type.""" - Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type. + kind: PermissionDecisionApproveForLocationApprovalCustomToolKind + """Approval covering a custom tool.""" - Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type. + tool_name: str + """Custom tool name.""" - Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalCustomTool': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) + tool_name = from_str(obj.get("toolName")) + return PermissionDecisionApproveForSessionApprovalCustomTool(kind, tool_name) - Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` - type. - """ - kind: ApprovalKind - """Approval scoped to specific command identifiers. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) + result["toolName"] = from_str(self.tool_name) + return result - Approval covering read-only filesystem operations. +@dataclass +class UserToolSessionApprovalCustomTool: + """Schema for the `UserToolSessionApprovalCustomTool` type.""" - Approval covering filesystem write operations. + kind: PermissionDecisionApproveForLocationApprovalCustomToolKind + """Custom tool approval kind""" - Approval covering an MCP tool. - - Approval covering MCP sampling requests for a server. - - Approval covering writes to long-term memory. - - Approval covering a custom tool. + tool_name: str + """Custom tool name""" - Approval covering extension lifecycle operations such as enable, disable, or reload. + @staticmethod + def from_dict(obj: Any) -> 'UserToolSessionApprovalCustomTool': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalCustomToolKind(obj.get("kind")) + tool_name = from_str(obj.get("toolName")) + return UserToolSessionApprovalCustomTool(kind, tool_name) - Approval covering an extension's request to access a permission-gated capability. - """ - command_identifiers: list[str] | None = None - """Command identifiers covered by this approval.""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalCustomToolKind, self.kind) + result["toolName"] = from_str(self.tool_name) + return result - server_name: str | None = None - """MCP server name.""" +@dataclass +class PermissionDecisionApproveForLocationApprovalExtensionManagement: + """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type.""" - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server. + kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind + """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - Custom tool name. - """ operation: str | None = None """Optional operation identifier; when omitted, the approval covers all extension management operations. """ - extension_name: str | None = None - """Extension name.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApproval': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionManagement': assert isinstance(obj, dict) - kind = ApprovalKind(obj.get("kind")) - command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) - server_name = from_union([from_str, from_none], obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) + kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) operation = from_union([from_str, from_none], obj.get("operation")) - extension_name = from_union([from_str, from_none], obj.get("extensionName")) - return PermissionDecisionApproveForLocationApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) + return PermissionDecisionApproveForLocationApprovalExtensionManagement(kind, operation) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(ApprovalKind, self.kind) - if self.command_identifiers is not None: - result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) - if self.server_name is not None: - result["serverName"] = from_union([from_str, from_none], self.server_name) - if self.tool_name is not None: - result["toolName"] = from_union([from_none, from_str], self.tool_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) if self.operation is not None: result["operation"] = from_union([from_str, from_none], self.operation) - if self.extension_name is not None: - result["extensionName"] = from_union([from_str, from_none], self.extension_name) return result @dataclass -class PermissionDecisionApproveForIonApproval: - """The approval to add as a session-scoped rule +class PermissionDecisionApproveForSessionApprovalExtensionManagement: + """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type.""" - Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type. + kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind + """Approval covering extension lifecycle operations such as enable, disable, or reload.""" - Schema for the `PermissionDecisionApproveForSessionApprovalRead` type. + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. + """ - Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionManagement': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) + operation = from_union([from_str, from_none], obj.get("operation")) + return PermissionDecisionApproveForSessionApprovalExtensionManagement(kind, operation) - Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) + return result - Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type. +@dataclass +class PermissionDecisionApproveForLocationApprovalMCP: + """Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.""" - Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type. + kind: PermissionDecisionApproveForLocationApprovalMCPKind + """Approval covering an MCP tool.""" - Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type. + server_name: str + """MCP server name.""" - Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type. + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server.""" - Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` - type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCP': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + return PermissionDecisionApproveForLocationApprovalMCP(kind, server_name, tool_name) - The approval to persist for this location + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) + result["serverName"] = from_str(self.server_name) + result["toolName"] = from_union([from_none, from_str], self.tool_name) + return result - Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type. +@dataclass +class PermissionDecisionApproveForSessionApprovalMCP: + """Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.""" - Schema for the `PermissionDecisionApproveForLocationApprovalRead` type. + kind: PermissionDecisionApproveForLocationApprovalMCPKind + """Approval covering an MCP tool.""" - Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type. + server_name: str + """MCP server name.""" - Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type. + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server.""" - Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCP': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + return PermissionDecisionApproveForSessionApprovalMCP(kind, server_name, tool_name) - Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) + result["serverName"] = from_str(self.server_name) + result["toolName"] = from_union([from_none, from_str], self.tool_name) + return result - Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type. +@dataclass +class UserToolSessionApprovalMCP: + """Schema for the `UserToolSessionApprovalMcp` type.""" - Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type. + kind: PermissionDecisionApproveForLocationApprovalMCPKind + """MCP tool approval kind""" - Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` - type. - """ - kind: ApprovalKind - """Approval scoped to specific command identifiers. + server_name: str + """MCP server name""" - Approval covering read-only filesystem operations. + tool_name: str | None = None + """Optional MCP tool name, or null for all tools on the server""" - Approval covering filesystem write operations. + @staticmethod + def from_dict(obj: Any) -> 'UserToolSessionApprovalMCP': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMCPKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + return UserToolSessionApprovalMCP(kind, server_name, tool_name) - Approval covering an MCP tool. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPKind, self.kind) + result["serverName"] = from_str(self.server_name) + result["toolName"] = from_union([from_none, from_str], self.tool_name) + return result - Approval covering MCP sampling requests for a server. +@dataclass +class PermissionDecisionApproveForLocationApprovalMCPSampling: + """Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.""" - Approval covering writes to long-term memory. + kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind + """Approval covering MCP sampling requests for a server.""" - Approval covering a custom tool. + server_name: str + """MCP server name.""" - Approval covering extension lifecycle operations such as enable, disable, or reload. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMCPSampling': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + return PermissionDecisionApproveForLocationApprovalMCPSampling(kind, server_name) - Approval covering an extension's request to access a permission-gated capability. - """ - command_identifiers: list[str] | None = None - """Command identifiers covered by this approval.""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) + result["serverName"] = from_str(self.server_name) + return result - server_name: str | None = None - """MCP server name.""" +@dataclass +class PermissionDecisionApproveForSessionApprovalMCPSampling: + """Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.""" - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server. + kind: PermissionDecisionApproveForLocationApprovalMCPSamplingKind + """Approval covering MCP sampling requests for a server.""" - Custom tool name. - """ - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. - """ - extension_name: str | None = None - """Extension name.""" + server_name: str + """MCP server name.""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForIonApproval': + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMCPSampling': assert isinstance(obj, dict) - kind = ApprovalKind(obj.get("kind")) - command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) - server_name = from_union([from_str, from_none], obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - operation = from_union([from_str, from_none], obj.get("operation")) - extension_name = from_union([from_str, from_none], obj.get("extensionName")) - return PermissionDecisionApproveForIonApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) + kind = PermissionDecisionApproveForLocationApprovalMCPSamplingKind(obj.get("kind")) + server_name = from_str(obj.get("serverName")) + return PermissionDecisionApproveForSessionApprovalMCPSampling(kind, server_name) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(ApprovalKind, self.kind) - if self.command_identifiers is not None: - result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) - if self.server_name is not None: - result["serverName"] = from_union([from_str, from_none], self.server_name) - if self.tool_name is not None: - result["toolName"] = from_union([from_none, from_str], self.tool_name) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) - if self.extension_name is not None: - result["extensionName"] = from_union([from_str, from_none], self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMCPSamplingKind, self.kind) + result["serverName"] = from_str(self.server_name) return result @dataclass -class PermissionDecisionApproveForSessionApproval: - """The approval to add as a session-scoped rule - - Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type. +class PermissionDecisionApproveForLocationApprovalMemory: + """Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.""" - Schema for the `PermissionDecisionApproveForSessionApprovalRead` type. + kind: PermissionDecisionApproveForLocationApprovalMemoryKind + """Approval covering writes to long-term memory.""" - Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalMemory': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalMemory(kind) - Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) + return result - Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type. +@dataclass +class PermissionDecisionApproveForSessionApprovalMemory: + """Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.""" - Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type. + kind: PermissionDecisionApproveForLocationApprovalMemoryKind + """Approval covering writes to long-term memory.""" - Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalMemory': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalMemory(kind) - Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) + return result - Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` - type. - """ - kind: ApprovalKind - """Approval scoped to specific command identifiers. +@dataclass +class UserToolSessionApprovalMemory: + """Schema for the `UserToolSessionApprovalMemory` type.""" - Approval covering read-only filesystem operations. + kind: PermissionDecisionApproveForLocationApprovalMemoryKind + """Memory approval kind""" - Approval covering filesystem write operations. + @staticmethod + def from_dict(obj: Any) -> 'UserToolSessionApprovalMemory': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalMemoryKind(obj.get("kind")) + return UserToolSessionApprovalMemory(kind) - Approval covering an MCP tool. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalMemoryKind, self.kind) + return result - Approval covering MCP sampling requests for a server. +@dataclass +class PermissionDecisionApproveForLocationApprovalRead: + """Schema for the `PermissionDecisionApproveForLocationApprovalRead` type.""" - Approval covering writes to long-term memory. + kind: PermissionDecisionApproveForLocationApprovalReadKind + """Approval covering read-only filesystem operations.""" - Approval covering a custom tool. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalRead': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalRead(kind) - Approval covering extension lifecycle operations such as enable, disable, or reload. + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) + return result - Approval covering an extension's request to access a permission-gated capability. - """ - command_identifiers: list[str] | None = None - """Command identifiers covered by this approval.""" +@dataclass +class PermissionDecisionApproveForSessionApprovalRead: + """Schema for the `PermissionDecisionApproveForSessionApprovalRead` type.""" - server_name: str | None = None - """MCP server name.""" + kind: PermissionDecisionApproveForLocationApprovalReadKind + """Approval covering read-only filesystem operations.""" - tool_name: str | None = None - """MCP tool name, or null to cover every tool on the server. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalRead': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalRead(kind) - Custom tool name. - """ - operation: str | None = None - """Optional operation identifier; when omitted, the approval covers all extension management - operations. - """ - extension_name: str | None = None - """Extension name.""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) + return result + +@dataclass +class UserToolSessionApprovalRead: + """Schema for the `UserToolSessionApprovalRead` type.""" + + kind: PermissionDecisionApproveForLocationApprovalReadKind + """Read approval kind""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApproval': + def from_dict(obj: Any) -> 'UserToolSessionApprovalRead': assert isinstance(obj, dict) - kind = ApprovalKind(obj.get("kind")) - command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) - server_name = from_union([from_str, from_none], obj.get("serverName")) - tool_name = from_union([from_none, from_str], obj.get("toolName")) - operation = from_union([from_str, from_none], obj.get("operation")) - extension_name = from_union([from_str, from_none], obj.get("extensionName")) - return PermissionDecisionApproveForSessionApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) + kind = PermissionDecisionApproveForLocationApprovalReadKind(obj.get("kind")) + return UserToolSessionApprovalRead(kind) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(ApprovalKind, self.kind) - if self.command_identifiers is not None: - result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) - if self.server_name is not None: - result["serverName"] = from_union([from_str, from_none], self.server_name) - if self.tool_name is not None: - result["toolName"] = from_union([from_none, from_str], self.tool_name) - if self.operation is not None: - result["operation"] = from_union([from_str, from_none], self.operation) - if self.extension_name is not None: - result["extensionName"] = from_union([from_str, from_none], self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalReadKind, self.kind) return result @dataclass -class ExternalToolTextResultForLlm: - """Expanded external tool result payload""" +class PermissionDecisionApproveForLocationApprovalWrite: + """Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type.""" - text_result_for_llm: str - """Text result returned to the model""" + kind: PermissionDecisionApproveForLocationApprovalWriteKind + """Approval covering filesystem write operations.""" - binary_results_for_llm: list[ExternalToolTextResultForLlmBinaryResultsForLlm] | None = None - """Base64-encoded binary results returned to the model""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalWrite': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalWrite(kind) - contents: list[ExternalToolTextResultForLlmContent] | None = None - """Structured content blocks from the tool""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) + return result - error: str | None = None - """Optional error message for failed executions""" +@dataclass +class PermissionDecisionApproveForSessionApprovalWrite: + """Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type.""" - result_type: str | None = None - """Execution outcome classification. Optional for back-compat; normalized to 'success' (or - 'failure' when error is present) when missing or unrecognized. - """ - session_log: str | None = None - """Detailed log content for timeline display""" + kind: PermissionDecisionApproveForLocationApprovalWriteKind + """Approval covering filesystem write operations.""" - tool_telemetry: dict[str, Any] | None = None - """Optional tool-specific telemetry""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalWrite': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalWrite(kind) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) + return result + +@dataclass +class UserToolSessionApprovalWrite: + """Schema for the `UserToolSessionApprovalWrite` type.""" + + kind: PermissionDecisionApproveForLocationApprovalWriteKind + """Write approval kind""" @staticmethod - def from_dict(obj: Any) -> 'ExternalToolTextResultForLlm': + def from_dict(obj: Any) -> 'UserToolSessionApprovalWrite': assert isinstance(obj, dict) - text_result_for_llm = from_str(obj.get("textResultForLlm")) - binary_results_for_llm = from_union([lambda x: from_list(ExternalToolTextResultForLlmBinaryResultsForLlm.from_dict, x), from_none], obj.get("binaryResultsForLlm")) - contents = from_union([lambda x: from_list(ExternalToolTextResultForLlmContent.from_dict, x), from_none], obj.get("contents")) - error = from_union([from_str, from_none], obj.get("error")) - result_type = from_union([from_str, from_none], obj.get("resultType")) - session_log = from_union([from_str, from_none], obj.get("sessionLog")) - tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry")) - return ExternalToolTextResultForLlm(text_result_for_llm, binary_results_for_llm, contents, error, result_type, session_log, tool_telemetry) + kind = PermissionDecisionApproveForLocationApprovalWriteKind(obj.get("kind")) + return UserToolSessionApprovalWrite(kind) def to_dict(self) -> dict: result: dict = {} - result["textResultForLlm"] = from_str(self.text_result_for_llm) - if self.binary_results_for_llm is not None: - result["binaryResultsForLlm"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmBinaryResultsForLlm, x), x), from_none], self.binary_results_for_llm) - if self.contents is not None: - result["contents"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContent, x), x), from_none], self.contents) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result_type is not None: - result["resultType"] = from_union([from_str, from_none], self.result_type) - if self.session_log is not None: - result["sessionLog"] = from_union([from_str, from_none], self.session_log) - if self.tool_telemetry is not None: - result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalWriteKind, self.kind) return result @dataclass -class UIElicitationSchema: - """JSON Schema describing the form fields to present to the user""" +class PermissionDecisionApproveOnce: + """Schema for the `PermissionDecisionApproveOnce` type.""" - properties: dict[str, UIElicitationSchemaProperty] - """Form field definitions, keyed by field name""" + kind: PermissionDecisionApproveOnceKind + """Approve this single request only""" - type: UIElicitationSchemaType - """Schema type indicator (always 'object')""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveOnce': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveOnceKind(obj.get("kind")) + return PermissionDecisionApproveOnce(kind) - required: list[str] | None = None - """List of required field names""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveOnceKind, self.kind) + return result + +@dataclass +class PermissionDecisionApprovePermanently: + """Schema for the `PermissionDecisionApprovePermanently` type.""" + + domain: str + """URL domain to approve permanently""" + + kind: PermissionDecisionApprovePermanentlyKind + """Approve and persist across sessions (URL prompts only)""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationSchema': + def from_dict(obj: Any) -> 'PermissionDecisionApprovePermanently': assert isinstance(obj, dict) - properties = from_dict(UIElicitationSchemaProperty.from_dict, obj.get("properties")) - type = UIElicitationSchemaType(obj.get("type")) - required = from_union([lambda x: from_list(from_str, x), from_none], obj.get("required")) - return UIElicitationSchema(properties, type, required) + domain = from_str(obj.get("domain")) + kind = PermissionDecisionApprovePermanentlyKind(obj.get("kind")) + return PermissionDecisionApprovePermanently(domain, kind) def to_dict(self) -> dict: result: dict = {} - result["properties"] = from_dict(lambda x: to_class(UIElicitationSchemaProperty, x), self.properties) - result["type"] = to_enum(UIElicitationSchemaType, self.type) - if self.required is not None: - result["required"] = from_union([lambda x: from_list(from_str, x), from_none], self.required) + result["domain"] = from_str(self.domain) + result["kind"] = to_enum(PermissionDecisionApprovePermanentlyKind, self.kind) return result @dataclass -class PermissionDecisionApproveForLocation: - """Schema for the `PermissionDecisionApproveForLocation` type.""" +class PermissionDecisionApproved: + """Schema for the `PermissionDecisionApproved` type.""" - approval: PermissionDecisionApproveForLocationApproval + kind: PermissionDecisionApprovedKind + """The permission request was approved""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproved': + assert isinstance(obj, dict) + kind = PermissionDecisionApprovedKind(obj.get("kind")) + return PermissionDecisionApproved(kind) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApprovedKind, self.kind) + return result + +@dataclass +class PermissionDecisionApprovedForLocation: + """Schema for the `PermissionDecisionApprovedForLocation` type.""" + + approval: UserToolSessionApproval """The approval to persist for this location""" - kind: PermissionDecisionApproveForLocationKind + kind: PermissionDecisionApprovedForLocationKind """Approved and persisted for this project location""" location_key: str """The location key (git root or cwd) to persist the approval to""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocation': + def from_dict(obj: Any) -> 'PermissionDecisionApprovedForLocation': assert isinstance(obj, dict) - approval = PermissionDecisionApproveForLocationApproval.from_dict(obj.get("approval")) - kind = PermissionDecisionApproveForLocationKind(obj.get("kind")) + approval = UserToolSessionApproval.from_dict(obj.get("approval")) + kind = PermissionDecisionApprovedForLocationKind(obj.get("kind")) location_key = from_str(obj.get("locationKey")) - return PermissionDecisionApproveForLocation(approval, kind, location_key) + return PermissionDecisionApprovedForLocation(approval, kind, location_key) def to_dict(self) -> dict: result: dict = {} - result["approval"] = to_class(PermissionDecisionApproveForLocationApproval, self.approval) - result["kind"] = to_enum(PermissionDecisionApproveForLocationKind, self.kind) + result["approval"] = to_class(UserToolSessionApproval, self.approval) + result["kind"] = to_enum(PermissionDecisionApprovedForLocationKind, self.kind) result["locationKey"] = from_str(self.location_key) return result @dataclass -class PermissionDecisionApproveForSession: - """Schema for the `PermissionDecisionApproveForSession` type.""" +class PermissionDecisionApprovedForSession: + """Schema for the `PermissionDecisionApprovedForSession` type.""" - kind: PermissionDecisionApproveForSessionKind - """Approved and remembered for the rest of the session""" - - approval: PermissionDecisionApproveForSessionApproval | None = None + approval: UserToolSessionApproval """The approval to add as a session-scoped rule""" - domain: str | None = None - """The URL domain to approve for this session""" + kind: PermissionDecisionApprovedForSessionKind + """Approved and remembered for the rest of the session""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionApproveForSession': + def from_dict(obj: Any) -> 'PermissionDecisionApprovedForSession': assert isinstance(obj, dict) - kind = PermissionDecisionApproveForSessionKind(obj.get("kind")) - approval = from_union([PermissionDecisionApproveForSessionApproval.from_dict, from_none], obj.get("approval")) - domain = from_union([from_str, from_none], obj.get("domain")) - return PermissionDecisionApproveForSession(kind, approval, domain) + approval = UserToolSessionApproval.from_dict(obj.get("approval")) + kind = PermissionDecisionApprovedForSessionKind(obj.get("kind")) + return PermissionDecisionApprovedForSession(approval, kind) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionApproveForSessionKind, self.kind) - if self.approval is not None: - result["approval"] = from_union([lambda x: to_class(PermissionDecisionApproveForSessionApproval, x), from_none], self.approval) - if self.domain is not None: - result["domain"] = from_union([from_str, from_none], self.domain) + result["approval"] = to_class(UserToolSessionApproval, self.approval) + result["kind"] = to_enum(PermissionDecisionApprovedForSessionKind, self.kind) return result @dataclass -class HandlePendingToolCallRequest: - """Pending external tool call request ID, with the tool result or an error describing why it - failed. - """ - request_id: str - """Request ID of the pending tool call""" +class PermissionDecisionCancelled: + """Schema for the `PermissionDecisionCancelled` type.""" - error: str | None = None - """Error message if the tool call failed""" + kind: PermissionDecisionCancelledKind + """The permission request was cancelled before a response was used""" - result: ExternalToolTextResultForLlm | str | None = None - """Tool call result (string or expanded result object)""" + reason: str | None = None + """Optional explanation of why the request was cancelled""" @staticmethod - def from_dict(obj: Any) -> 'HandlePendingToolCallRequest': + def from_dict(obj: Any) -> 'PermissionDecisionCancelled': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - error = from_union([from_str, from_none], obj.get("error")) - result = from_union([ExternalToolTextResultForLlm.from_dict, from_str, from_none], obj.get("result")) - return HandlePendingToolCallRequest(request_id, error, result) + kind = PermissionDecisionCancelledKind(obj.get("kind")) + reason = from_union([from_str, from_none], obj.get("reason")) + return PermissionDecisionCancelled(kind, reason) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.result is not None: - result["result"] = from_union([lambda x: to_class(ExternalToolTextResultForLlm, x), from_str, from_none], self.result) + result["kind"] = to_enum(PermissionDecisionCancelledKind, self.kind) + if self.reason is not None: + result["reason"] = from_union([from_str, from_none], self.reason) return result @dataclass -class UIElicitationRequest: - """Prompt message and JSON schema describing the form fields to elicit from the user.""" +class PermissionDecisionDeniedByContentExclusionPolicy: + """Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type.""" + + kind: PermissionDecisionDeniedByContentExclusionPolicyKind + """Denied by the organization's content exclusion policy""" message: str - """Message describing what information is needed from the user""" + """Human-readable explanation of why the path was excluded""" - requested_schema: UIElicitationSchema - """JSON Schema describing the form fields to present to the user""" + path: str + """File path that triggered the exclusion""" @staticmethod - def from_dict(obj: Any) -> 'UIElicitationRequest': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedByContentExclusionPolicy': assert isinstance(obj, dict) + kind = PermissionDecisionDeniedByContentExclusionPolicyKind(obj.get("kind")) message = from_str(obj.get("message")) - requested_schema = UIElicitationSchema.from_dict(obj.get("requestedSchema")) - return UIElicitationRequest(message, requested_schema) + path = from_str(obj.get("path")) + return PermissionDecisionDeniedByContentExclusionPolicy(kind, message, path) def to_dict(self) -> dict: result: dict = {} + result["kind"] = to_enum(PermissionDecisionDeniedByContentExclusionPolicyKind, self.kind) result["message"] = from_str(self.message) - result["requestedSchema"] = to_class(UIElicitationSchema, self.requested_schema) + result["path"] = from_str(self.path) return result @dataclass -class PermissionDecision: - """Decision to apply to a pending permission request. - - Schema for the `PermissionDecisionApproveOnce` type. +class PermissionDecisionDeniedByPermissionRequestHook: + """Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type.""" - Schema for the `PermissionDecisionApproveForSession` type. + kind: PermissionDecisionDeniedByPermissionRequestHookKind + """Denied by a permission request hook registered by an extension or plugin""" - Schema for the `PermissionDecisionApproveForLocation` type. + interrupt: bool | None = None + """Whether to interrupt the current agent turn""" - Schema for the `PermissionDecisionApprovePermanently` type. + message: str | None = None + """Optional message from the hook explaining the denial""" - Schema for the `PermissionDecisionReject` type. + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionDeniedByPermissionRequestHook': + assert isinstance(obj, dict) + kind = PermissionDecisionDeniedByPermissionRequestHookKind(obj.get("kind")) + interrupt = from_union([from_bool, from_none], obj.get("interrupt")) + message = from_union([from_str, from_none], obj.get("message")) + return PermissionDecisionDeniedByPermissionRequestHook(kind, interrupt, message) - Schema for the `PermissionDecisionUserNotAvailable` type. - """ - kind: PermissionDecisionKind - """The permission request was approved for this one instance + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionDeniedByPermissionRequestHookKind, self.kind) + if self.interrupt is not None: + result["interrupt"] = from_union([from_bool, from_none], self.interrupt) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + return result - Approved and remembered for the rest of the session +@dataclass +class PermissionDecisionDeniedByRules: + """Schema for the `PermissionDecisionDeniedByRules` type.""" - Approved and persisted for this project location + kind: PermissionDecisionDeniedByRulesKind + """Denied because approval rules explicitly blocked it""" - Approved and persisted across sessions + rules: list[PermissionRule] + """Rules that denied the request""" - Denied by the user during an interactive prompt + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionDeniedByRules': + assert isinstance(obj, dict) + kind = PermissionDecisionDeniedByRulesKind(obj.get("kind")) + rules = from_list(PermissionRule.from_dict, obj.get("rules")) + return PermissionDecisionDeniedByRules(kind, rules) - Denied because user confirmation was unavailable - """ - approval: PermissionDecisionApproveForIonApproval | None = None - """The approval to add as a session-scoped rule + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionDeniedByRulesKind, self.kind) + result["rules"] = from_list(lambda x: to_class(PermissionRule, x), self.rules) + return result - The approval to persist for this location - """ - domain: str | None = None - """The URL domain to approve for this session +@dataclass +class PermissionDecisionDeniedInteractivelyByUser: + """Schema for the `PermissionDecisionDeniedInteractivelyByUser` type.""" - The URL domain to approve permanently - """ - location_key: str | None = None - """The location key (git root or cwd) to persist the approval to""" + kind: PermissionDecisionDeniedInteractivelyByUserKind + """Denied by the user during an interactive prompt""" feedback: str | None = None """Optional feedback from the user explaining the denial""" + force_reject: bool | None = None + """Whether to force-reject the current agent turn""" + @staticmethod - def from_dict(obj: Any) -> 'PermissionDecision': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedInteractivelyByUser': assert isinstance(obj, dict) - kind = PermissionDecisionKind(obj.get("kind")) - approval = from_union([PermissionDecisionApproveForIonApproval.from_dict, from_none], obj.get("approval")) - domain = from_union([from_str, from_none], obj.get("domain")) - location_key = from_union([from_str, from_none], obj.get("locationKey")) + kind = PermissionDecisionDeniedInteractivelyByUserKind(obj.get("kind")) feedback = from_union([from_str, from_none], obj.get("feedback")) - return PermissionDecision(kind, approval, domain, location_key, feedback) + force_reject = from_union([from_bool, from_none], obj.get("forceReject")) + return PermissionDecisionDeniedInteractivelyByUser(kind, feedback, force_reject) def to_dict(self) -> dict: result: dict = {} - result["kind"] = to_enum(PermissionDecisionKind, self.kind) - if self.approval is not None: - result["approval"] = from_union([lambda x: to_class(PermissionDecisionApproveForIonApproval, x), from_none], self.approval) - if self.domain is not None: - result["domain"] = from_union([from_str, from_none], self.domain) - if self.location_key is not None: - result["locationKey"] = from_union([from_str, from_none], self.location_key) + result["kind"] = to_enum(PermissionDecisionDeniedInteractivelyByUserKind, self.kind) if self.feedback is not None: result["feedback"] = from_union([from_str, from_none], self.feedback) + if self.force_reject is not None: + result["forceReject"] = from_union([from_bool, from_none], self.force_reject) return result @dataclass -class PermissionDecisionRequest: - """Pending permission request ID and the decision to apply (approve/reject and scope).""" - - request_id: str - """Request ID of the pending permission request""" +class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser: + """Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type.""" - result: PermissionDecision - """Decision to apply to a pending permission request.""" + kind: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind + """Denied because no approval rule matched and user confirmation was unavailable""" @staticmethod - def from_dict(obj: Any) -> 'PermissionDecisionRequest': + def from_dict(obj: Any) -> 'PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser': assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - result = PermissionDecision.from_dict(obj.get("result")) - return PermissionDecisionRequest(request_id, result) + kind = PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind(obj.get("kind")) + return PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser(kind) def to_dict(self) -> dict: result: dict = {} - result["requestId"] = from_str(self.request_id) - result["result"] = to_class(PermissionDecision, self.result) + result["kind"] = to_enum(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUserKind, self.kind) return result @dataclass -class ModelCapabilities: - """Model capabilities and limits""" +class PermissionDecisionReject: + """Schema for the `PermissionDecisionReject` type.""" - limits: ModelCapabilitiesLimits | None = None - """Token limits for prompts, outputs, and context window""" + kind: PermissionDecisionRejectKind + """Reject the request""" - supports: ModelCapabilitiesSupports | None = None - """Feature flags indicating what the model supports""" + feedback: str | None = None + """Optional feedback explaining the rejection""" @staticmethod - def from_dict(obj: Any) -> 'ModelCapabilities': + def from_dict(obj: Any) -> 'PermissionDecisionReject': assert isinstance(obj, dict) - limits = from_union([ModelCapabilitiesLimits.from_dict, from_none], obj.get("limits")) - supports = from_union([ModelCapabilitiesSupports.from_dict, from_none], obj.get("supports")) - return ModelCapabilities(limits, supports) + kind = PermissionDecisionRejectKind(obj.get("kind")) + feedback = from_union([from_str, from_none], obj.get("feedback")) + return PermissionDecisionReject(kind, feedback) def to_dict(self) -> dict: result: dict = {} - if self.limits is not None: - result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesLimits, x), from_none], self.limits) - if self.supports is not None: - result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesSupports, x), from_none], self.supports) + result["kind"] = to_enum(PermissionDecisionRejectKind, self.kind) + if self.feedback is not None: + result["feedback"] = from_union([from_str, from_none], self.feedback) return result -class ModelPickerCategory(Enum): - """Model capability category for grouping in the model picker""" +@dataclass +class PermissionDecisionUserNotAvailable: + """Schema for the `PermissionDecisionUserNotAvailable` type.""" - LIGHTWEIGHT = "lightweight" - POWERFUL = "powerful" - VERSATILE = "versatile" + kind: PermissionDecisionUserNotAvailableKind + """No user is available to confirm the request""" -@dataclass -class Model: - """Schema for the `Model` type.""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionUserNotAvailable': + assert isinstance(obj, dict) + kind = PermissionDecisionUserNotAvailableKind(obj.get("kind")) + return PermissionDecisionUserNotAvailable(kind) - capabilities: ModelCapabilities - """Model capabilities and limits""" + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionUserNotAvailableKind, self.kind) + return result - id: str - """Model identifier (e.g., "claude-sonnet-4.5")""" +@dataclass +class PermissionsConfigureAdditionalContentExclusionPolicyRule: + """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRule` type.""" - name: str - """Display name""" + paths: list[str] + source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource + """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.""" - billing: ModelBilling | None = None - """Billing information""" + if_any_match: list[str] | None = None + if_none_match: list[str] | None = None - default_reasoning_effort: str | None = None - """Default reasoning effort level (only present if model supports reasoning effort)""" + @staticmethod + def from_dict(obj: Any) -> 'PermissionsConfigureAdditionalContentExclusionPolicyRule': + assert isinstance(obj, dict) + paths = from_list(from_str, obj.get("paths")) + source = PermissionsConfigureAdditionalContentExclusionPolicyRuleSource.from_dict(obj.get("source")) + if_any_match = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ifAnyMatch")) + if_none_match = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ifNoneMatch")) + return PermissionsConfigureAdditionalContentExclusionPolicyRule(paths, source, if_any_match, if_none_match) - model_picker_category: ModelPickerCategory | None = None - """Model capability category for grouping in the model picker""" + def to_dict(self) -> dict: + result: dict = {} + result["paths"] = from_list(from_str, self.paths) + result["source"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicyRuleSource, self.source) + if self.if_any_match is not None: + result["ifAnyMatch"] = from_union([lambda x: from_list(from_str, x), from_none], self.if_any_match) + if self.if_none_match is not None: + result["ifNoneMatch"] = from_union([lambda x: from_list(from_str, x), from_none], self.if_none_match) + return result - model_picker_price_category: ModelPickerPriceCategory | None = None - """Relative cost tier for token-based billing users""" +@dataclass +class PermissionsModifyRulesParams: + """Scope and add/remove instructions for modifying session- or location-scoped permission + rules. + """ + scope: PermissionsModifyRulesScope + """Whether the change applies to ephemeral session-scoped rules (cleared at session end) or + to location-scoped rules persisted via the location-permissions config file. + """ + add: list[PermissionRule] | None = None + """Rules to add to the scope. Applied before `remove`/`removeAll`.""" - policy: ModelPolicy | None = None - """Policy state (if applicable)""" + remove: list[PermissionRule] | None = None + """Specific rules to remove from the scope. Ignored when `removeAll` is true.""" - supported_reasoning_efforts: list[str] | None = None - """Supported reasoning effort levels (only present if model supports reasoning effort)""" + remove_all: bool | None = None + """When true, removes every rule currently in the scope (after any `add` is applied). Useful + for clearing the location scope wholesale. + """ @staticmethod - def from_dict(obj: Any) -> 'Model': + def from_dict(obj: Any) -> 'PermissionsModifyRulesParams': assert isinstance(obj, dict) - capabilities = ModelCapabilities.from_dict(obj.get("capabilities")) - id = from_str(obj.get("id")) - name = from_str(obj.get("name")) - billing = from_union([ModelBilling.from_dict, from_none], obj.get("billing")) - default_reasoning_effort = from_union([from_str, from_none], obj.get("defaultReasoningEffort")) - model_picker_category = from_union([ModelPickerCategory, from_none], obj.get("modelPickerCategory")) - model_picker_price_category = from_union([ModelPickerPriceCategory, from_none], obj.get("modelPickerPriceCategory")) - policy = from_union([ModelPolicy.from_dict, from_none], obj.get("policy")) - supported_reasoning_efforts = from_union([lambda x: from_list(from_str, x), from_none], obj.get("supportedReasoningEfforts")) - return Model(capabilities, id, name, billing, default_reasoning_effort, model_picker_category, model_picker_price_category, policy, supported_reasoning_efforts) + scope = PermissionsModifyRulesScope(obj.get("scope")) + add = from_union([lambda x: from_list(PermissionRule.from_dict, x), from_none], obj.get("add")) + remove = from_union([lambda x: from_list(PermissionRule.from_dict, x), from_none], obj.get("remove")) + remove_all = from_union([from_bool, from_none], obj.get("removeAll")) + return PermissionsModifyRulesParams(scope, add, remove, remove_all) def to_dict(self) -> dict: result: dict = {} - result["capabilities"] = to_class(ModelCapabilities, self.capabilities) - result["id"] = from_str(self.id) - result["name"] = from_str(self.name) - if self.billing is not None: - result["billing"] = from_union([lambda x: to_class(ModelBilling, x), from_none], self.billing) - if self.default_reasoning_effort is not None: - result["defaultReasoningEffort"] = from_union([from_str, from_none], self.default_reasoning_effort) - if self.model_picker_category is not None: - result["modelPickerCategory"] = from_union([lambda x: to_enum(ModelPickerCategory, x), from_none], self.model_picker_category) - if self.model_picker_price_category is not None: - result["modelPickerPriceCategory"] = from_union([lambda x: to_enum(ModelPickerPriceCategory, x), from_none], self.model_picker_price_category) - if self.policy is not None: - result["policy"] = from_union([lambda x: to_class(ModelPolicy, x), from_none], self.policy) - if self.supported_reasoning_efforts is not None: - result["supportedReasoningEfforts"] = from_union([lambda x: from_list(from_str, x), from_none], self.supported_reasoning_efforts) + result["scope"] = to_enum(PermissionsModifyRulesScope, self.scope) + if self.add is not None: + result["add"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRule, x), x), from_none], self.add) + if self.remove is not None: + result["remove"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRule, x), x), from_none], self.remove) + if self.remove_all is not None: + result["removeAll"] = from_union([from_bool, from_none], self.remove_all) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelList: - """List of Copilot models available to the resolved user, including capabilities and billing - metadata. - """ - models: list[Model] - """List of available models with full metadata""" +class PluginList: + """Plugins installed for the session, with their enabled state and version metadata.""" + + plugins: list[Plugin] + """Installed plugins""" @staticmethod - def from_dict(obj: Any) -> 'ModelList': + def from_dict(obj: Any) -> 'PluginList': assert isinstance(obj, dict) - models = from_list(Model.from_dict, obj.get("models")) - return ModelList(models) + plugins = from_list(Plugin.from_dict, obj.get("plugins")) + return PluginList(plugins) def to_dict(self) -> dict: result: dict = {} - result["models"] = from_list(lambda x: to_class(Model, x), self.models) + result["plugins"] = from_list(lambda x: to_class(Plugin, x), self.plugins) return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class ModelSwitchToRequest: - """Target model identifier and optional reasoning effort, summary, and capability overrides.""" - - model_id: str - """Model identifier to switch to""" - - model_capabilities: ModelCapabilitiesOverride | None = None - """Override individual model capabilities resolved by the runtime""" +class QueuePendingItems: + """Schema for the `QueuePendingItems` type.""" - reasoning_effort: str | None = None - """Reasoning effort level to use for the model. "none" disables reasoning.""" + display_text: str + """Human-readable text to display for this queue entry in the UI""" - reasoning_summary: ReasoningSummary | None = None - """Reasoning summary mode to request for supported model clients""" + kind: QueuePendingItemsKind + """Whether this item is a queued user message or a queued slash command / model change""" @staticmethod - def from_dict(obj: Any) -> 'ModelSwitchToRequest': + def from_dict(obj: Any) -> 'QueuePendingItems': assert isinstance(obj, dict) - model_id = from_str(obj.get("modelId")) - model_capabilities = from_union([ModelCapabilitiesOverride.from_dict, from_none], obj.get("modelCapabilities")) - reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) - reasoning_summary = from_union([ReasoningSummary, from_none], obj.get("reasoningSummary")) - return ModelSwitchToRequest(model_id, model_capabilities, reasoning_effort, reasoning_summary) + display_text = from_str(obj.get("displayText")) + kind = QueuePendingItemsKind(obj.get("kind")) + return QueuePendingItems(display_text, kind) def to_dict(self) -> dict: result: dict = {} - result["modelId"] = from_str(self.model_id) - if self.model_capabilities is not None: - result["modelCapabilities"] = from_union([lambda x: to_class(ModelCapabilitiesOverride, x), from_none], self.model_capabilities) - if self.reasoning_effort is not None: - result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) - if self.reasoning_summary is not None: - result["reasoningSummary"] = from_union([lambda x: to_enum(ReasoningSummary, x), from_none], self.reasoning_summary) + result["displayText"] = from_str(self.display_text) + result["kind"] = to_enum(QueuePendingItemsKind, self.kind) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskAgentInfo: - """Schema for the `TaskAgentInfo` type.""" +class QueuedCommandResult: + """Result of the queued command execution. - agent_type: str - """Type of agent running this task""" + Schema for the `QueuedCommandHandled` type. - description: str - """Short description of the task""" + Schema for the `QueuedCommandNotHandled` type. + """ + handled: bool + """The host actually executed the queued command. - id: str - """Unique task identifier""" + The host did not execute the queued command. Unblocks the queue without claiming the + command was processed (e.g. when the handler threw before completing). + """ + stop_processing_queue: bool | None = None + """When true, the runtime will not process subsequent queued commands until a new request + comes in. + """ - prompt: str - """Prompt passed to the agent""" + @staticmethod + def from_dict(obj: Any) -> 'QueuedCommandResult': + assert isinstance(obj, dict) + handled = from_bool(obj.get("handled")) + stop_processing_queue = from_union([from_bool, from_none], obj.get("stopProcessingQueue")) + return QueuedCommandResult(handled, stop_processing_queue) - started_at: datetime - """ISO 8601 timestamp when the task was started""" + def to_dict(self) -> dict: + result: dict = {} + result["handled"] = from_bool(self.handled) + if self.stop_processing_queue is not None: + result["stopProcessingQueue"] = from_union([from_bool, from_none], self.stop_processing_queue) + return result - status: TaskStatus - """Current lifecycle status of the task""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class RemoteEnableRequest: + """Optional remote session mode ("off", "export", or "on"); defaults to enabling both export + and remote steering. + """ + mode: RemoteSessionMode | None = None + """Per-session remote mode. "off" disables remote, "export" exports session events to GitHub + without enabling remote steering, "on" enables both export and remote steering. + """ - tool_call_id: str - """Tool call ID associated with this agent task""" + @staticmethod + def from_dict(obj: Any) -> 'RemoteEnableRequest': + assert isinstance(obj, dict) + mode = from_union([RemoteSessionMode, from_none], obj.get("mode")) + return RemoteEnableRequest(mode) - type: TaskAgentInfoType - """Task kind""" + def to_dict(self) -> dict: + result: dict = {} + if self.mode is not None: + result["mode"] = from_union([lambda x: to_enum(RemoteSessionMode, x), from_none], self.mode) + return result - active_started_at: datetime | None = None - """ISO 8601 timestamp when the current active period began""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ScheduleList: + """Snapshot of the currently active recurring prompts for this session.""" - active_time_ms: int | None = None - """Accumulated active execution time in milliseconds""" + entries: list[ScheduleEntry] + """Active scheduled prompts, ordered by id.""" - can_promote_to_background: bool | None = None - """Whether the task is currently in the original sync wait and can be moved to background - mode. False once it is already backgrounded, idle, finished, or no longer has a - promotable sync waiter. - """ - completed_at: datetime | None = None - """ISO 8601 timestamp when the task finished""" + @staticmethod + def from_dict(obj: Any) -> 'ScheduleList': + assert isinstance(obj, dict) + entries = from_list(ScheduleEntry.from_dict, obj.get("entries")) + return ScheduleList(entries) - error: str | None = None - """Error message when the task failed""" + def to_dict(self) -> dict: + result: dict = {} + result["entries"] = from_list(lambda x: to_class(ScheduleEntry, x), self.entries) + return result - execution_mode: TaskExecutionMode | None = None - """Whether task execution is synchronously awaited or managed in the background""" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ScheduleStopResult: + """Remove a scheduled prompt by id. The result entry is omitted if the id was unknown.""" - idle_since: datetime | None = None - """ISO 8601 timestamp when the agent entered idle state""" + entry: ScheduleEntry | None = None + """The removed entry, or omitted if no entry matched.""" - latest_response: str | None = None - """Most recent response text from the agent""" + @staticmethod + def from_dict(obj: Any) -> 'ScheduleStopResult': + assert isinstance(obj, dict) + entry = from_union([ScheduleEntry.from_dict, from_none], obj.get("entry")) + return ScheduleStopResult(entry) - model: str | None = None - """Model used for the task when specified""" + def to_dict(self) -> dict: + result: dict = {} + if self.entry is not None: + result["entry"] = from_union([lambda x: to_class(ScheduleEntry, x), from_none], self.entry) + return result - result: str | None = None - """Result text from the task when available""" +@dataclass +class SendAttachmentSelectionDetails: + """Position range of the selection within the file""" + + end: SendAttachmentSelectionDetailsEnd + """End position of the selection""" + + start: SendAttachmentSelectionDetailsStart + """Start position of the selection""" @staticmethod - def from_dict(obj: Any) -> 'TaskAgentInfo': + def from_dict(obj: Any) -> 'SendAttachmentSelectionDetails': assert isinstance(obj, dict) - agent_type = from_str(obj.get("agentType")) - description = from_str(obj.get("description")) - id = from_str(obj.get("id")) - prompt = from_str(obj.get("prompt")) - started_at = from_datetime(obj.get("startedAt")) - status = TaskStatus(obj.get("status")) - tool_call_id = from_str(obj.get("toolCallId")) - type = TaskAgentInfoType(obj.get("type")) - active_started_at = from_union([from_datetime, from_none], obj.get("activeStartedAt")) - active_time_ms = from_union([from_int, from_none], obj.get("activeTimeMs")) - can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) - completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) - error = from_union([from_str, from_none], obj.get("error")) - execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) - idle_since = from_union([from_datetime, from_none], obj.get("idleSince")) - latest_response = from_union([from_str, from_none], obj.get("latestResponse")) - model = from_union([from_str, from_none], obj.get("model")) - result = from_union([from_str, from_none], obj.get("result")) - return TaskAgentInfo(agent_type, description, id, prompt, started_at, status, tool_call_id, type, active_started_at, active_time_ms, can_promote_to_background, completed_at, error, execution_mode, idle_since, latest_response, model, result) + end = SendAttachmentSelectionDetailsEnd.from_dict(obj.get("end")) + start = SendAttachmentSelectionDetailsStart.from_dict(obj.get("start")) + return SendAttachmentSelectionDetails(end, start) def to_dict(self) -> dict: result: dict = {} - result["agentType"] = from_str(self.agent_type) - result["description"] = from_str(self.description) - result["id"] = from_str(self.id) - result["prompt"] = from_str(self.prompt) - result["startedAt"] = self.started_at.isoformat() - result["status"] = to_enum(TaskStatus, self.status) - result["toolCallId"] = from_str(self.tool_call_id) - result["type"] = to_enum(TaskAgentInfoType, self.type) - if self.active_started_at is not None: - result["activeStartedAt"] = from_union([lambda x: x.isoformat(), from_none], self.active_started_at) - if self.active_time_ms is not None: - result["activeTimeMs"] = from_union([from_int, from_none], self.active_time_ms) - if self.can_promote_to_background is not None: - result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) - if self.completed_at is not None: - result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.execution_mode is not None: - result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) - if self.idle_since is not None: - result["idleSince"] = from_union([lambda x: x.isoformat(), from_none], self.idle_since) - if self.latest_response is not None: - result["latestResponse"] = from_union([from_str, from_none], self.latest_response) - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) - if self.result is not None: - result["result"] = from_union([from_str, from_none], self.result) + result["end"] = to_class(SendAttachmentSelectionDetailsEnd, self.end) + result["start"] = to_class(SendAttachmentSelectionDetailsStart, self.start) return result -# Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskInfo: - """Schema for the `TaskInfo` type. +class SendAttachmentBlob: + """Blob attachment with inline base64-encoded data""" - Schema for the `TaskAgentInfo` type. + data: str + """Base64-encoded content""" - Schema for the `TaskShellInfo` type. - """ - description: str - """Short description of the task""" + mime_type: str + """MIME type of the inline data""" - id: str - """Unique task identifier""" + type: SendAttachmentBlobType + """Attachment type discriminator""" - started_at: datetime - """ISO 8601 timestamp when the task was started""" + display_name: str | None = None + """User-facing display name for the attachment""" - status: TaskStatus - """Current lifecycle status of the task""" + @staticmethod + def from_dict(obj: Any) -> 'SendAttachmentBlob': + assert isinstance(obj, dict) + data = from_str(obj.get("data")) + mime_type = from_str(obj.get("mimeType")) + type = SendAttachmentBlobType(obj.get("type")) + display_name = from_union([from_str, from_none], obj.get("displayName")) + return SendAttachmentBlob(data, mime_type, type, display_name) - type: TaskInfoType - """Task kind""" + def to_dict(self) -> dict: + result: dict = {} + result["data"] = from_str(self.data) + result["mimeType"] = from_str(self.mime_type) + result["type"] = to_enum(SendAttachmentBlobType, self.type) + if self.display_name is not None: + result["displayName"] = from_union([from_str, from_none], self.display_name) + return result - active_started_at: datetime | None = None - """ISO 8601 timestamp when the current active period began""" +@dataclass +class SendAttachmentFile: + """File attachment""" - active_time_ms: int | None = None - """Accumulated active execution time in milliseconds""" + display_name: str + """User-facing display name for the attachment""" - agent_type: str | None = None - """Type of agent running this task""" + path: str + """Absolute file path""" - can_promote_to_background: bool | None = None - """Whether the task is currently in the original sync wait and can be moved to background - mode. False once it is already backgrounded, idle, finished, or no longer has a - promotable sync waiter. + type: SendAttachmentFileType + """Attachment type discriminator""" - Whether this shell task can be promoted to background mode - """ - completed_at: datetime | None = None - """ISO 8601 timestamp when the task finished""" + line_range: SendAttachmentFileLineRange | None = None + """Optional line range to scope the attachment to a specific section of the file""" - error: str | None = None - """Error message when the task failed""" + @staticmethod + def from_dict(obj: Any) -> 'SendAttachmentFile': + assert isinstance(obj, dict) + display_name = from_str(obj.get("displayName")) + path = from_str(obj.get("path")) + type = SendAttachmentFileType(obj.get("type")) + line_range = from_union([SendAttachmentFileLineRange.from_dict, from_none], obj.get("lineRange")) + return SendAttachmentFile(display_name, path, type, line_range) - execution_mode: TaskExecutionMode | None = None - """Whether task execution is synchronously awaited or managed in the background""" + def to_dict(self) -> dict: + result: dict = {} + result["displayName"] = from_str(self.display_name) + result["path"] = from_str(self.path) + result["type"] = to_enum(SendAttachmentFileType, self.type) + if self.line_range is not None: + result["lineRange"] = from_union([lambda x: to_class(SendAttachmentFileLineRange, x), from_none], self.line_range) + return result - idle_since: datetime | None = None - """ISO 8601 timestamp when the agent entered idle state""" +@dataclass +class SendAttachmentGithubReference: + """GitHub issue, pull request, or discussion reference""" - latest_response: str | None = None - """Most recent response text from the agent""" + number: int + """Issue, pull request, or discussion number""" - model: str | None = None - """Model used for the task when specified""" + reference_type: SendAttachmentGithubReferenceTypeEnum + """Type of GitHub reference""" - prompt: str | None = None - """Prompt passed to the agent""" + state: str + """Current state of the referenced item (e.g., open, closed, merged)""" - result: str | None = None - """Result text from the task when available""" + title: str + """Title of the referenced item""" - tool_call_id: str | None = None - """Tool call ID associated with this agent task""" + type: SendAttachmentGithubReferenceType + """Attachment type discriminator""" - attachment_mode: TaskShellInfoAttachmentMode | None = None - """Whether the shell runs inside a managed PTY session or as an independent background - process - """ - command: str | None = None - """Command being executed""" + url: str + """URL to the referenced item on GitHub""" - log_path: str | None = None - """Path to the detached shell log, when available""" + @staticmethod + def from_dict(obj: Any) -> 'SendAttachmentGithubReference': + assert isinstance(obj, dict) + number = from_int(obj.get("number")) + reference_type = SendAttachmentGithubReferenceTypeEnum(obj.get("referenceType")) + state = from_str(obj.get("state")) + title = from_str(obj.get("title")) + type = SendAttachmentGithubReferenceType(obj.get("type")) + url = from_str(obj.get("url")) + return SendAttachmentGithubReference(number, reference_type, state, title, type, url) - pid: int | None = None - """Process ID when available""" + def to_dict(self) -> dict: + result: dict = {} + result["number"] = from_int(self.number) + result["referenceType"] = to_enum(SendAttachmentGithubReferenceTypeEnum, self.reference_type) + result["state"] = from_str(self.state) + result["title"] = from_str(self.title) + result["type"] = to_enum(SendAttachmentGithubReferenceType, self.type) + result["url"] = from_str(self.url) + return result + +@dataclass +class ServerSkillList: + """Skills discovered across global and project sources.""" + + skills: list[ServerSkill] + """All discovered skills across all sources""" @staticmethod - def from_dict(obj: Any) -> 'TaskInfo': + def from_dict(obj: Any) -> 'ServerSkillList': assert isinstance(obj, dict) - description = from_str(obj.get("description")) - id = from_str(obj.get("id")) - started_at = from_datetime(obj.get("startedAt")) - status = TaskStatus(obj.get("status")) - type = TaskInfoType(obj.get("type")) - active_started_at = from_union([from_datetime, from_none], obj.get("activeStartedAt")) - active_time_ms = from_union([from_int, from_none], obj.get("activeTimeMs")) - agent_type = from_union([from_str, from_none], obj.get("agentType")) - can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) - completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) - error = from_union([from_str, from_none], obj.get("error")) - execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) - idle_since = from_union([from_datetime, from_none], obj.get("idleSince")) - latest_response = from_union([from_str, from_none], obj.get("latestResponse")) - model = from_union([from_str, from_none], obj.get("model")) - prompt = from_union([from_str, from_none], obj.get("prompt")) - result = from_union([from_str, from_none], obj.get("result")) - tool_call_id = from_union([from_str, from_none], obj.get("toolCallId")) - attachment_mode = from_union([TaskShellInfoAttachmentMode, from_none], obj.get("attachmentMode")) - command = from_union([from_str, from_none], obj.get("command")) - log_path = from_union([from_str, from_none], obj.get("logPath")) - pid = from_union([from_int, from_none], obj.get("pid")) - return TaskInfo(description, id, started_at, status, type, active_started_at, active_time_ms, agent_type, can_promote_to_background, completed_at, error, execution_mode, idle_since, latest_response, model, prompt, result, tool_call_id, attachment_mode, command, log_path, pid) + skills = from_list(ServerSkill.from_dict, obj.get("skills")) + return ServerSkillList(skills) def to_dict(self) -> dict: result: dict = {} - result["description"] = from_str(self.description) - result["id"] = from_str(self.id) - result["startedAt"] = self.started_at.isoformat() - result["status"] = to_enum(TaskStatus, self.status) - result["type"] = to_enum(TaskInfoType, self.type) - if self.active_started_at is not None: - result["activeStartedAt"] = from_union([lambda x: x.isoformat(), from_none], self.active_started_at) - if self.active_time_ms is not None: - result["activeTimeMs"] = from_union([from_int, from_none], self.active_time_ms) - if self.agent_type is not None: - result["agentType"] = from_union([from_str, from_none], self.agent_type) - if self.can_promote_to_background is not None: - result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) - if self.completed_at is not None: - result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) - if self.error is not None: - result["error"] = from_union([from_str, from_none], self.error) - if self.execution_mode is not None: - result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) - if self.idle_since is not None: - result["idleSince"] = from_union([lambda x: x.isoformat(), from_none], self.idle_since) - if self.latest_response is not None: - result["latestResponse"] = from_union([from_str, from_none], self.latest_response) - if self.model is not None: - result["model"] = from_union([from_str, from_none], self.model) - if self.prompt is not None: - result["prompt"] = from_union([from_str, from_none], self.prompt) - if self.result is not None: - result["result"] = from_union([from_str, from_none], self.result) - if self.tool_call_id is not None: - result["toolCallId"] = from_union([from_str, from_none], self.tool_call_id) - if self.attachment_mode is not None: - result["attachmentMode"] = from_union([lambda x: to_enum(TaskShellInfoAttachmentMode, x), from_none], self.attachment_mode) - if self.command is not None: - result["command"] = from_union([from_str, from_none], self.command) - if self.log_path is not None: - result["logPath"] = from_union([from_str, from_none], self.log_path) - if self.pid is not None: - result["pid"] = from_union([from_int, from_none], self.pid) + result["skills"] = from_list(lambda x: to_class(ServerSkill, x), self.skills) + return result + +@dataclass +class SessionFSError: + """Describes a filesystem error.""" + + code: SessionFSErrorCode + """Error classification""" + + message: str | None = None + """Free-form detail about the error, for logging/diagnostics""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSError': + assert isinstance(obj, dict) + code = SessionFSErrorCode(obj.get("code")) + message = from_union([from_str, from_none], obj.get("message")) + return SessionFSError(code, message) + + def to_dict(self) -> dict: + result: dict = {} + result["code"] = to_enum(SessionFSErrorCode, self.code) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + return result + +@dataclass +class SessionFSReaddirWithTypesEntry: + """Schema for the `SessionFsReaddirWithTypesEntry` type.""" + + name: str + """Entry name""" + + type: SessionFSReaddirWithTypesEntryType + """Entry type""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesEntry': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + type = SessionFSReaddirWithTypesEntryType(obj.get("type")) + return SessionFSReaddirWithTypesEntry(name, type) + + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + result["type"] = to_enum(SessionFSReaddirWithTypesEntryType, self.type) + return result + +@dataclass +class SessionFSSetProviderRequest: + """Initial working directory, session-state path layout, and path conventions used to + register the calling SDK client as the session filesystem provider. + """ + conventions: SessionFSSetProviderConventions + """Path conventions used by this filesystem""" + + initial_cwd: str + """Initial working directory for sessions""" + + session_state_path: str + """Path within each session's SessionFs where the runtime stores files for that session""" + + capabilities: SessionFSSetProviderCapabilities | None = None + """Optional capabilities declared by the provider""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSetProviderRequest': + assert isinstance(obj, dict) + conventions = SessionFSSetProviderConventions(obj.get("conventions")) + initial_cwd = from_str(obj.get("initialCwd")) + session_state_path = from_str(obj.get("sessionStatePath")) + capabilities = from_union([SessionFSSetProviderCapabilities.from_dict, from_none], obj.get("capabilities")) + return SessionFSSetProviderRequest(conventions, initial_cwd, session_state_path, capabilities) + + def to_dict(self) -> dict: + result: dict = {} + result["conventions"] = to_enum(SessionFSSetProviderConventions, self.conventions) + result["initialCwd"] = from_str(self.initial_cwd) + result["sessionStatePath"] = from_str(self.session_state_path) + if self.capabilities is not None: + result["capabilities"] = from_union([lambda x: to_class(SessionFSSetProviderCapabilities, x), from_none], self.capabilities) + return result + +@dataclass +class SessionFSSqliteQueryRequest: + """SQL query, query type, and optional bind parameters for executing a SQLite query against + the per-session database. + """ + query: str + """SQL query to execute""" + + query_type: SessionFSSqliteQueryType + """How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT + (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected) + """ + session_id: str + """Target session identifier""" + + params: dict[str, float | str | None] | None = None + """Optional named bind parameters""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSqliteQueryRequest': + assert isinstance(obj, dict) + query = from_str(obj.get("query")) + query_type = SessionFSSqliteQueryType(obj.get("queryType")) + session_id = from_str(obj.get("sessionId")) + params = from_union([lambda x: from_dict(lambda x: from_union([from_none, from_float, from_str], x), x), from_none], obj.get("params")) + return SessionFSSqliteQueryRequest(query, query_type, session_id, params) + + def to_dict(self) -> dict: + result: dict = {} + result["query"] = from_str(self.query) + result["queryType"] = to_enum(SessionFSSqliteQueryType, self.query_type) + result["sessionId"] = from_str(self.session_id) + if self.params is not None: + result["params"] = from_union([lambda x: from_dict(lambda x: from_union([from_none, to_float, from_str], x), x), from_none], self.params) return result # Experimental: this type is part of an experimental API and may change or be removed. @dataclass -class TaskList: - """Background tasks currently tracked by the session.""" +class SessionsListRequest: + """Optional metadata-load limit and context filter applied to the returned sessions.""" - tasks: list[TaskInfo] - """Currently tracked tasks""" + filter: Filter | None = None + """Optional filter applied to the returned sessions""" + + metadata_limit: int | None = None + """When provided, only the first N sessions (sorted by modification time, newest first) load + full metadata; remaining sessions return basic info only. Use 0 to return only basic info + for every session. + """ @staticmethod - def from_dict(obj: Any) -> 'TaskList': + def from_dict(obj: Any) -> 'SessionsListRequest': assert isinstance(obj, dict) - tasks = from_list(TaskInfo.from_dict, obj.get("tasks")) - return TaskList(tasks) + filter = from_union([Filter.from_dict, from_none], obj.get("filter")) + metadata_limit = from_union([from_int, from_none], obj.get("metadataLimit")) + return SessionsListRequest(filter, metadata_limit) def to_dict(self) -> dict: result: dict = {} - result["tasks"] = from_list(lambda x: to_class(TaskInfo, x), self.tasks) + if self.filter is not None: + result["filter"] = from_union([lambda x: to_class(Filter, x), from_none], self.filter) + if self.metadata_limit is not None: + result["metadataLimit"] = from_union([from_int, from_none], self.metadata_limit) return result @dataclass -class RPC: - account_get_quota_request: AccountGetQuotaRequest - account_get_quota_result: AccountGetQuotaResult - account_quota_snapshot: AccountQuotaSnapshot - agent_get_current_result: AgentGetCurrentResult - agent_info: AgentInfo - agent_list: AgentList - agent_reload_result: AgentReloadResult - agent_select_request: AgentSelectRequest - agent_select_result: AgentSelectResult - auth_info_type: AuthInfoType - command_list: CommandList - commands_handle_pending_command_request: CommandsHandlePendingCommandRequest - commands_handle_pending_command_result: CommandsHandlePendingCommandResult - commands_invoke_request: CommandsInvokeRequest - commands_list_request: CommandsListRequest - commands_respond_to_queued_command_request: CommandsRespondToQueuedCommandRequest - commands_respond_to_queued_command_result: CommandsRespondToQueuedCommandResult - connected_remote_session_metadata: ConnectedRemoteSessionMetadata - connected_remote_session_metadata_kind: ConnectedRemoteSessionMetadataKind - connected_remote_session_metadata_repository: ConnectedRemoteSessionMetadataRepository - connect_remote_session_params: ConnectRemoteSessionParams - connect_request: ConnectRequest - connect_result: ConnectResult - content_filter_mode: ContentFilterMode - current_model: CurrentModel - discovered_mcp_server: DiscoveredMCPServer - discovered_mcp_server_type: DiscoveredMCPServerType - extension: Extension - extension_list: ExtensionList - extensions_disable_request: ExtensionsDisableRequest - extensions_enable_request: ExtensionsEnableRequest - extension_source: ExtensionSource - extension_status: ExtensionStatus - external_tool_result: ExternalToolTextResultForLlm | str - external_tool_text_result_for_llm: ExternalToolTextResultForLlm - external_tool_text_result_for_llm_binary_results_for_llm: ExternalToolTextResultForLlmBinaryResultsForLlm - external_tool_text_result_for_llm_binary_results_for_llm_type: ExternalToolTextResultForLlmBinaryResultsForLlmType - external_tool_text_result_for_llm_content: ExternalToolTextResultForLlmContent - external_tool_text_result_for_llm_content_audio: ExternalToolTextResultForLlmContentAudio - external_tool_text_result_for_llm_content_image: ExternalToolTextResultForLlmContentImage - external_tool_text_result_for_llm_content_resource: ExternalToolTextResultForLlmContentResource - external_tool_text_result_for_llm_content_resource_details: ExternalToolTextResultForLlmContentResourceDetails - external_tool_text_result_for_llm_content_resource_link: ExternalToolTextResultForLlmContentResourceLink - external_tool_text_result_for_llm_content_resource_link_icon: ExternalToolTextResultForLlmContentResourceLinkIcon - external_tool_text_result_for_llm_content_resource_link_icon_theme: ExternalToolTextResultForLlmContentResourceLinkIconTheme - external_tool_text_result_for_llm_content_terminal: ExternalToolTextResultForLlmContentTerminal - external_tool_text_result_for_llm_content_text: ExternalToolTextResultForLlmContentText - filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode - fleet_start_request: FleetStartRequest - fleet_start_result: FleetStartResult - handle_pending_tool_call_request: HandlePendingToolCallRequest - handle_pending_tool_call_result: HandlePendingToolCallResult - history_compact_context_window: HistoryCompactContextWindow - history_compact_result: HistoryCompactResult - history_truncate_request: HistoryTruncateRequest - history_truncate_result: HistoryTruncateResult - instructions_get_sources_result: InstructionsGetSourcesResult - instructions_sources: InstructionsSources - instructions_sources_location: InstructionsSourcesLocation - instructions_sources_type: InstructionsSourcesType - log_request: LogRequest - log_result: LogResult - mcp_config_add_request: MCPConfigAddRequest - mcp_config_disable_request: MCPConfigDisableRequest - mcp_config_enable_request: MCPConfigEnableRequest - mcp_config_list: MCPConfigList - mcp_config_remove_request: MCPConfigRemoveRequest - mcp_config_update_request: MCPConfigUpdateRequest - mcp_disable_request: MCPDisableRequest - mcp_discover_request: MCPDiscoverRequest - mcp_discover_result: MCPDiscoverResult - mcp_enable_request: MCPEnableRequest - mcp_oauth_login_request: MCPOauthLoginRequest - mcp_oauth_login_result: MCPOauthLoginResult - mcp_server: MCPServer - mcp_server_config: MCPServerConfig - mcp_server_config_http: MCPServerConfigHTTP - mcp_server_config_http_auth: MCPServerConfigHTTPAuth - mcp_server_config_http_oauth_grant_type: MCPServerConfigHTTPOauthGrantType - mcp_server_config_http_type: MCPServerConfigHTTPType - mcp_server_config_stdio: MCPServerConfigStdio - mcp_server_list: MCPServerList - model: Model - model_billing: ModelBilling - model_billing_token_prices: ModelBillingTokenPrices - model_capabilities: ModelCapabilities - model_capabilities_limits: ModelCapabilitiesLimits - model_capabilities_limits_vision: ModelCapabilitiesLimitsVision +class ShellKillRequest: + """Identifier of a process previously returned by "shell.exec" and the signal to send.""" + + process_id: str + """Process identifier returned by shell.exec""" + + signal: ShellKillSignal | None = None + """Signal to send (default: SIGTERM)""" + + @staticmethod + def from_dict(obj: Any) -> 'ShellKillRequest': + assert isinstance(obj, dict) + process_id = from_str(obj.get("processId")) + signal = from_union([ShellKillSignal, from_none], obj.get("signal")) + return ShellKillRequest(process_id, signal) + + def to_dict(self) -> dict: + result: dict = {} + result["processId"] = from_str(self.process_id) + if self.signal is not None: + result["signal"] = from_union([lambda x: to_enum(ShellKillSignal, x), from_none], self.signal) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AgentInfo: + """Schema for the `AgentInfo` type. + + The newly selected custom agent + """ + description: str + """Description of the agent's purpose""" + + display_name: str + """Human-readable display name""" + + id: str + """Stable identifier for selection. For most agents this is the same as `name`; for + plugin/builtin agents it may differ. Always populated; defaults to `name` when no + distinct id was assigned. + """ + name: str + """Unique identifier of the custom agent""" + + mcp_servers: dict[str, Any] | None = None + """MCP server configurations attached to this agent, keyed by server name. Server config + shape mirrors the MCP `mcpServers` schema. + """ + model: str | None = None + """Preferred model id for this agent. When omitted, inherits the outer agent's model.""" + + path: str | None = None + """Absolute local file path of the agent definition. Only set for file-based agents loaded + from disk; remote agents do not have a path. + """ + skills: list[str] | None = None + """Skill names preloaded into this agent's context. Omitted means none.""" + + source: AgentInfoSource | None = None + """Where the agent definition was loaded from""" + + tools: list[str] | None = None + """Allowed tool names for this agent. Empty array means none; omitted means inherit defaults.""" + + user_invocable: bool | None = None + """Whether the agent can be selected directly by the user. Agents marked `false` are + subagent-only. + """ + + @staticmethod + def from_dict(obj: Any) -> 'AgentInfo': + assert isinstance(obj, dict) + description = from_str(obj.get("description")) + display_name = from_str(obj.get("displayName")) + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + mcp_servers = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("mcpServers")) + model = from_union([from_str, from_none], obj.get("model")) + path = from_union([from_str, from_none], obj.get("path")) + skills = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skills")) + source = from_union([AgentInfoSource, from_none], obj.get("source")) + tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) + user_invocable = from_union([from_bool, from_none], obj.get("userInvocable")) + return AgentInfo(description, display_name, id, name, mcp_servers, model, path, skills, source, tools, user_invocable) + + def to_dict(self) -> dict: + result: dict = {} + result["description"] = from_str(self.description) + result["displayName"] = from_str(self.display_name) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + if self.mcp_servers is not None: + result["mcpServers"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.mcp_servers) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.skills is not None: + result["skills"] = from_union([lambda x: from_list(from_str, x), from_none], self.skills) + if self.source is not None: + result["source"] = from_union([lambda x: to_enum(AgentInfoSource, x), from_none], self.source) + if self.tools is not None: + result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) + if self.user_invocable is not None: + result["userInvocable"] = from_union([from_bool, from_none], self.user_invocable) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SkillList: + """Skills available to the session, with their enabled state.""" + + skills: list[Skill] + """Available skills""" + + @staticmethod + def from_dict(obj: Any) -> 'SkillList': + assert isinstance(obj, dict) + skills = from_list(Skill.from_dict, obj.get("skills")) + return SkillList(skills) + + def to_dict(self) -> dict: + result: dict = {} + result["skills"] = from_list(lambda x: to_class(Skill, x), self.skills) + return result + +@dataclass +class SkillsConfigSetDisabledSkillsRequest: + """Skill names to mark as disabled in global configuration, replacing any previous list.""" + + disabled_skills: list[str] + """List of skill names to disable""" + + @staticmethod + def from_dict(obj: Any) -> 'SkillsConfigSetDisabledSkillsRequest': + assert isinstance(obj, dict) + disabled_skills = from_list(from_str, obj.get("disabledSkills")) + return SkillsConfigSetDisabledSkillsRequest(disabled_skills) + + def to_dict(self) -> dict: + result: dict = {} + result["disabledSkills"] = from_list(from_str, self.disabled_skills) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SkillsGetInvokedResult: + """Skills invoked during this session, ordered by invocation time (most recent last).""" + + skills: list[SkillsInvokedSkill] + """Skills invoked during this session, ordered by invocation time (most recent last)""" + + @staticmethod + def from_dict(obj: Any) -> 'SkillsGetInvokedResult': + assert isinstance(obj, dict) + skills = from_list(SkillsInvokedSkill.from_dict, obj.get("skills")) + return SkillsGetInvokedResult(skills) + + def to_dict(self) -> dict: + result: dict = {} + result["skills"] = from_list(lambda x: to_class(SkillsInvokedSkill, x), self.skills) + return result + +@dataclass +class SlashCommandAgentPromptResult: + """Schema for the `SlashCommandAgentPromptResult` type.""" + + display_prompt: str + """Prompt text to display to the user""" + + kind: SlashCommandAgentPromptResultKind + """Agent prompt result discriminator""" + + prompt: str + """Prompt to submit to the agent""" + + mode: SessionMode | None = None + """Optional target session mode for the agent prompt""" + + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh + """ + + @staticmethod + def from_dict(obj: Any) -> 'SlashCommandAgentPromptResult': + assert isinstance(obj, dict) + display_prompt = from_str(obj.get("displayPrompt")) + kind = SlashCommandAgentPromptResultKind(obj.get("kind")) + prompt = from_str(obj.get("prompt")) + mode = from_union([SessionMode, from_none], obj.get("mode")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + return SlashCommandAgentPromptResult(display_prompt, kind, prompt, mode, runtime_settings_changed) + + def to_dict(self) -> dict: + result: dict = {} + result["displayPrompt"] = from_str(self.display_prompt) + result["kind"] = to_enum(SlashCommandAgentPromptResultKind, self.kind) + result["prompt"] = from_str(self.prompt) + if self.mode is not None: + result["mode"] = from_union([lambda x: to_enum(SessionMode, x), from_none], self.mode) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + return result + +@dataclass +class SlashCommandCompletedResult: + """Schema for the `SlashCommandCompletedResult` type.""" + + kind: SlashCommandCompletedResultKind + """Completed result discriminator""" + + message: str | None = None + """Optional user-facing message describing the completed command""" + + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh + """ + + @staticmethod + def from_dict(obj: Any) -> 'SlashCommandCompletedResult': + assert isinstance(obj, dict) + kind = SlashCommandCompletedResultKind(obj.get("kind")) + message = from_union([from_str, from_none], obj.get("message")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + return SlashCommandCompletedResult(kind, message, runtime_settings_changed) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(SlashCommandCompletedResultKind, self.kind) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TaskAgentProgress: + """Schema for the `TaskAgentProgress` type.""" + + type: TaskAgentProgressType + """Progress kind""" + + latest_intent: str | None = None + """The most recent intent reported by the agent""" + + recent_activity: list[RecentActivity] | None = None + """Recent tool execution events converted to display lines""" + + pid: int | None = None + """Process ID when available""" + + recent_output: str | None = None + """Recent stdout/stderr lines from the running shell command""" + + @staticmethod + def from_dict(obj: Any) -> 'TaskAgentProgress': + assert isinstance(obj, dict) + type = TaskAgentProgressType(obj.get("type")) + latest_intent = from_union([from_str, from_none], obj.get("latestIntent")) + recent_activity = from_union([lambda x: from_list(RecentActivity.from_dict, x), from_none], obj.get("recentActivity")) + pid = from_union([from_int, from_none], obj.get("pid")) + recent_output = from_union([from_str, from_none], obj.get("recentOutput")) + return TaskAgentProgress(type, latest_intent, recent_activity, pid, recent_output) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(TaskAgentProgressType, self.type) + if self.latest_intent is not None: + result["latestIntent"] = from_union([from_str, from_none], self.latest_intent) + if self.recent_activity is not None: + result["recentActivity"] = from_union([lambda x: from_list(lambda x: to_class(RecentActivity, x), x), from_none], self.recent_activity) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) + if self.recent_output is not None: + result["recentOutput"] = from_union([from_str, from_none], self.recent_output) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TaskProgressClass: + type: TaskAgentProgressType + """Progress kind""" + + latest_intent: str | None = None + """The most recent intent reported by the agent""" + + recent_activity: list[RecentActivity] | None = None + """Recent tool execution events converted to display lines""" + + pid: int | None = None + """Process ID when available""" + + recent_output: str | None = None + """Recent stdout/stderr lines from the running shell command""" + + @staticmethod + def from_dict(obj: Any) -> 'TaskProgressClass': + assert isinstance(obj, dict) + type = TaskAgentProgressType(obj.get("type")) + latest_intent = from_union([from_str, from_none], obj.get("latestIntent")) + recent_activity = from_union([lambda x: from_list(RecentActivity.from_dict, x), from_none], obj.get("recentActivity")) + pid = from_union([from_int, from_none], obj.get("pid")) + recent_output = from_union([from_str, from_none], obj.get("recentOutput")) + return TaskProgressClass(type, latest_intent, recent_activity, pid, recent_output) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(TaskAgentProgressType, self.type) + if self.latest_intent is not None: + result["latestIntent"] = from_union([from_str, from_none], self.latest_intent) + if self.recent_activity is not None: + result["recentActivity"] = from_union([lambda x: from_list(lambda x: to_class(RecentActivity, x), x), from_none], self.recent_activity) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) + if self.recent_output is not None: + result["recentOutput"] = from_union([from_str, from_none], self.recent_output) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TaskShellInfo: + """Schema for the `TaskShellInfo` type.""" + + attachment_mode: TaskShellInfoAttachmentMode + """Whether the shell runs inside a managed PTY session or as an independent background + process + """ + command: str + """Command being executed""" + + description: str + """Short description of the task""" + + id: str + """Unique task identifier""" + + started_at: datetime + """ISO 8601 timestamp when the task was started""" + + status: TaskStatus + """Current lifecycle status of the task""" + + type: TaskShellInfoType + """Task kind""" + + can_promote_to_background: bool | None = None + """Whether this shell task can be promoted to background mode""" + + completed_at: datetime | None = None + """ISO 8601 timestamp when the task finished""" + + execution_mode: TaskExecutionMode | None = None + """Whether task execution is synchronously awaited or managed in the background""" + + log_path: str | None = None + """Path to the detached shell log, when available""" + + pid: int | None = None + """Process ID when available""" + + @staticmethod + def from_dict(obj: Any) -> 'TaskShellInfo': + assert isinstance(obj, dict) + attachment_mode = TaskShellInfoAttachmentMode(obj.get("attachmentMode")) + command = from_str(obj.get("command")) + description = from_str(obj.get("description")) + id = from_str(obj.get("id")) + started_at = from_datetime(obj.get("startedAt")) + status = TaskStatus(obj.get("status")) + type = TaskShellInfoType(obj.get("type")) + can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) + completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) + execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) + log_path = from_union([from_str, from_none], obj.get("logPath")) + pid = from_union([from_int, from_none], obj.get("pid")) + return TaskShellInfo(attachment_mode, command, description, id, started_at, status, type, can_promote_to_background, completed_at, execution_mode, log_path, pid) + + def to_dict(self) -> dict: + result: dict = {} + result["attachmentMode"] = to_enum(TaskShellInfoAttachmentMode, self.attachment_mode) + result["command"] = from_str(self.command) + result["description"] = from_str(self.description) + result["id"] = from_str(self.id) + result["startedAt"] = self.started_at.isoformat() + result["status"] = to_enum(TaskStatus, self.status) + result["type"] = to_enum(TaskShellInfoType, self.type) + if self.can_promote_to_background is not None: + result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) + if self.completed_at is not None: + result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) + if self.execution_mode is not None: + result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) + if self.log_path is not None: + result["logPath"] = from_union([from_str, from_none], self.log_path) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) + return result + +@dataclass +class ToolList: + """Built-in tools available for the requested model, with their parameters and instructions.""" + + tools: list[Tool] + """List of available built-in tools with metadata""" + + @staticmethod + def from_dict(obj: Any) -> 'ToolList': + assert isinstance(obj, dict) + tools = from_list(Tool.from_dict, obj.get("tools")) + return ToolList(tools) + + def to_dict(self) -> dict: + result: dict = {} + result["tools"] = from_list(lambda x: to_class(Tool, x), self.tools) + return result + +@dataclass +class UIHandlePendingAutoModeSwitchRequest: + """Request ID of a pending `auto_mode_switch.requested` event and the user's response.""" + + request_id: str + """The unique request ID from the auto_mode_switch.requested event""" + + response: UIAutoModeSwitchResponse + """User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist + as setting), or no (decline). + """ + + @staticmethod + def from_dict(obj: Any) -> 'UIHandlePendingAutoModeSwitchRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + response = UIAutoModeSwitchResponse(obj.get("response")) + return UIHandlePendingAutoModeSwitchRequest(request_id, response) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["response"] = to_enum(UIAutoModeSwitchResponse, self.response) + return result + +@dataclass +class UIElicitationArrayAnyOfFieldItems: + """Schema applied to each item in the array.""" + + any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] + """Selectable options, each with a value and a display label.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfFieldItems': + assert isinstance(obj, dict) + any_of = from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, obj.get("anyOf")) + return UIElicitationArrayAnyOfFieldItems(any_of) + + def to_dict(self) -> dict: + result: dict = {} + result["anyOf"] = from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), self.any_of) + return result + +@dataclass +class UIElicitationArrayEnumFieldItems: + """Schema applied to each item in the array.""" + + enum: list[str] + """Allowed string values for each selected item.""" + + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayEnumFieldItems': + assert isinstance(obj, dict) + enum = from_list(from_str, obj.get("enum")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + return UIElicitationArrayEnumFieldItems(enum, type) + + def to_dict(self) -> dict: + result: dict = {} + result["enum"] = from_list(from_str, self.enum) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + return result + +@dataclass +class UIElicitationArrayFieldItems: + """Schema applied to each item in the array.""" + + enum: list[str] | None = None + """Allowed string values for each selected item.""" + + type: UIElicitationArrayEnumFieldItemsType | None = None + """Type discriminator. Always "string".""" + + any_of: list[UIElicitationArrayAnyOfFieldItemsAnyOf] | None = None + """Selectable options, each with a value and a display label.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayFieldItems': + assert isinstance(obj, dict) + enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) + type = from_union([UIElicitationArrayEnumFieldItemsType, from_none], obj.get("type")) + any_of = from_union([lambda x: from_list(UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict, x), from_none], obj.get("anyOf")) + return UIElicitationArrayFieldItems(enum, type, any_of) + + def to_dict(self) -> dict: + result: dict = {} + if self.enum is not None: + result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) + if self.type is not None: + result["type"] = from_union([lambda x: to_enum(UIElicitationArrayEnumFieldItemsType, x), from_none], self.type) + if self.any_of is not None: + result["anyOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, x), x), from_none], self.any_of) + return result + +@dataclass +class UIElicitationStringEnumField: + """Single-select string field whose allowed values are defined inline.""" + + enum: list[str] + """Allowed string values.""" + + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" + + default: str | None = None + """Default value selected when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + enum_names: list[str] | None = None + """Optional display labels for each enum value, in the same order as `enum`.""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationStringEnumField': + assert isinstance(obj, dict) + enum = from_list(from_str, obj.get("enum")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationStringEnumField(enum, type, default, description, enum_names, title) + + def to_dict(self) -> dict: + result: dict = {} + result["enum"] = from_list(from_str, self.enum) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.enum_names is not None: + result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationSchemaPropertyString: + """Free-text string field with optional length and format constraints.""" + + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" + + default: str | None = None + """Default value populated in the input when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + format: UIElicitationSchemaPropertyStringFormat | None = None + """Optional format hint that constrains the accepted input.""" + + max_length: int | None = None + """Maximum number of characters allowed.""" + + min_length: int | None = None + """Minimum number of characters required.""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyString': + assert isinstance(obj, dict) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) + max_length = from_union([from_int, from_none], obj.get("maxLength")) + min_length = from_union([from_int, from_none], obj.get("minLength")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyString(type, default, description, format, max_length, min_length, title) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.format is not None: + result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) + if self.max_length is not None: + result["maxLength"] = from_union([from_int, from_none], self.max_length) + if self.min_length is not None: + result["minLength"] = from_union([from_int, from_none], self.min_length) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationStringOneOfField: + """Single-select string field where each option pairs a value with a display label.""" + + one_of: list[UIElicitationStringOneOfFieldOneOf] + """Selectable options, each with a value and a display label.""" + + type: UIElicitationArrayEnumFieldItemsType + """Type discriminator. Always "string".""" + + default: str | None = None + """Default value selected when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationStringOneOfField': + assert isinstance(obj, dict) + one_of = from_list(UIElicitationStringOneOfFieldOneOf.from_dict, obj.get("oneOf")) + type = UIElicitationArrayEnumFieldItemsType(obj.get("type")) + default = from_union([from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationStringOneOfField(one_of, type, default, description, title) + + def to_dict(self) -> dict: + result: dict = {} + result["oneOf"] = from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), self.one_of) + result["type"] = to_enum(UIElicitationArrayEnumFieldItemsType, self.type) + if self.default is not None: + result["default"] = from_union([from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationResponse: + """The elicitation response (accept with form values, decline, or cancel)""" + + action: UIElicitationResponseAction + """The user's response: accept (submitted), decline (rejected), or cancel (dismissed)""" + + content: dict[str, float | bool | list[str] | str] | None = None + """The form values submitted by the user (present when action is 'accept')""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationResponse': + assert isinstance(obj, dict) + action = UIElicitationResponseAction(obj.get("action")) + content = from_union([lambda x: from_dict(lambda x: from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], obj.get("content")) + return UIElicitationResponse(action, content) + + def to_dict(self) -> dict: + result: dict = {} + result["action"] = to_enum(UIElicitationResponseAction, self.action) + if self.content is not None: + result["content"] = from_union([lambda x: from_dict(lambda x: from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str], x), x), from_none], self.content) + return result + +@dataclass +class UIElicitationSchemaPropertyBoolean: + """Boolean field rendered as a yes/no toggle.""" + + type: UIElicitationSchemaPropertyBooleanType + """Type discriminator. Always "boolean".""" + + default: bool | None = None + """Default value selected when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyBoolean': + assert isinstance(obj, dict) + type = UIElicitationSchemaPropertyBooleanType(obj.get("type")) + default = from_union([from_bool, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyBoolean(type, default, description, title) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(UIElicitationSchemaPropertyBooleanType, self.type) + if self.default is not None: + result["default"] = from_union([from_bool, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationSchemaPropertyNumber: + """Numeric field accepting either a number or an integer.""" + + type: UIElicitationSchemaPropertyNumberType + """Numeric type accepted by the field.""" + + default: float | None = None + """Default value populated in the input when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + maximum: float | None = None + """Maximum allowed value (inclusive).""" + + minimum: float | None = None + """Minimum allowed value (inclusive).""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationSchemaPropertyNumber': + assert isinstance(obj, dict) + type = UIElicitationSchemaPropertyNumberType(obj.get("type")) + default = from_union([from_float, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + maximum = from_union([from_float, from_none], obj.get("maximum")) + minimum = from_union([from_float, from_none], obj.get("minimum")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationSchemaPropertyNumber(type, default, description, maximum, minimum, title) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(UIElicitationSchemaPropertyNumberType, self.type) + if self.default is not None: + result["default"] = from_union([to_float, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.maximum is not None: + result["maximum"] = from_union([to_float, from_none], self.maximum) + if self.minimum is not None: + result["minimum"] = from_union([to_float, from_none], self.minimum) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIExitPlanModeResponse: + """Schema for the `UIExitPlanModeResponse` type.""" + + approved: bool + """Whether the plan was approved.""" + + auto_approve_edits: bool | None = None + """Whether subsequent edits should be auto-approved without confirmation.""" + + feedback: str | None = None + """Feedback from the user when they declined the plan or requested changes.""" + + selected_action: UIExitPlanModeAction | None = None + """The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, + otherwise 'interactive'. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UIExitPlanModeResponse': + assert isinstance(obj, dict) + approved = from_bool(obj.get("approved")) + auto_approve_edits = from_union([from_bool, from_none], obj.get("autoApproveEdits")) + feedback = from_union([from_str, from_none], obj.get("feedback")) + selected_action = from_union([UIExitPlanModeAction, from_none], obj.get("selectedAction")) + return UIExitPlanModeResponse(approved, auto_approve_edits, feedback, selected_action) + + def to_dict(self) -> dict: + result: dict = {} + result["approved"] = from_bool(self.approved) + if self.auto_approve_edits is not None: + result["autoApproveEdits"] = from_union([from_bool, from_none], self.auto_approve_edits) + if self.feedback is not None: + result["feedback"] = from_union([from_str, from_none], self.feedback) + if self.selected_action is not None: + result["selectedAction"] = from_union([lambda x: to_enum(UIExitPlanModeAction, x), from_none], self.selected_action) + return result + +@dataclass +class UIHandlePendingUserInputRequest: + """Request ID of a pending `user_input.requested` event and the user's response.""" + + request_id: str + """The unique request ID from the user_input.requested event""" + + response: UIUserInputResponse + """Schema for the `UIUserInputResponse` type.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIHandlePendingUserInputRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + response = UIUserInputResponse.from_dict(obj.get("response")) + return UIHandlePendingUserInputRequest(request_id, response) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["response"] = to_class(UIUserInputResponse, self.response) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UsageMetricsModelMetric: + """Schema for the `UsageMetricsModelMetric` type.""" + + requests: UsageMetricsModelMetricRequests + """Request count and cost metrics for this model""" + + usage: UsageMetricsModelMetricUsage + """Token usage metrics for this model""" + + token_details: dict[str, UsageMetricsModelMetricTokenDetail] | None = None + """Token count details per type""" + + total_nano_aiu: int | None = None + """Accumulated nano-AI units cost for this model""" + + @staticmethod + def from_dict(obj: Any) -> 'UsageMetricsModelMetric': + assert isinstance(obj, dict) + requests = UsageMetricsModelMetricRequests.from_dict(obj.get("requests")) + usage = UsageMetricsModelMetricUsage.from_dict(obj.get("usage")) + token_details = from_union([lambda x: from_dict(UsageMetricsModelMetricTokenDetail.from_dict, x), from_none], obj.get("tokenDetails")) + total_nano_aiu = from_union([from_int, from_none], obj.get("totalNanoAiu")) + return UsageMetricsModelMetric(requests, usage, token_details, total_nano_aiu) + + def to_dict(self) -> dict: + result: dict = {} + result["requests"] = to_class(UsageMetricsModelMetricRequests, self.requests) + result["usage"] = to_class(UsageMetricsModelMetricUsage, self.usage) + if self.token_details is not None: + result["tokenDetails"] = from_union([lambda x: from_dict(lambda x: to_class(UsageMetricsModelMetricTokenDetail, x), x), from_none], self.token_details) + if self.total_nano_aiu is not None: + result["totalNanoAiu"] = from_union([from_int, from_none], self.total_nano_aiu) + return result + +@dataclass +class WorkspacesSaveLargePasteResult: + """Descriptor for the saved paste file, or null when the workspace is unavailable.""" + + saved: Saved | None = None + """Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, + non-infinite sessions, remote sessions) + """ + + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesSaveLargePasteResult': + assert isinstance(obj, dict) + saved = from_union([Saved.from_dict, from_none], obj.get("saved")) + return WorkspacesSaveLargePasteResult(saved) + + def to_dict(self) -> dict: + result: dict = {} + result["saved"] = from_union([lambda x: to_class(Saved, x), from_none], self.saved) + return result + +@dataclass +class SlashCommandInfo: + """Schema for the `SlashCommandInfo` type.""" + + allow_during_agent_execution: bool + """Whether the command may run while an agent turn is active""" + + description: str + """Human-readable command description""" + + kind: SlashCommandKind + """Coarse command category for grouping and behavior: runtime built-in, skill-backed + command, or SDK/client-owned command + """ + name: str + """Canonical command name without a leading slash""" + + aliases: list[str] | None = None + """Canonical aliases without leading slashes""" + + experimental: bool | None = None + """Whether the command is experimental""" + + input: SlashCommandInput | None = None + """Optional unstructured input hint""" + + @staticmethod + def from_dict(obj: Any) -> 'SlashCommandInfo': + assert isinstance(obj, dict) + allow_during_agent_execution = from_bool(obj.get("allowDuringAgentExecution")) + description = from_str(obj.get("description")) + kind = SlashCommandKind(obj.get("kind")) + name = from_str(obj.get("name")) + aliases = from_union([lambda x: from_list(from_str, x), from_none], obj.get("aliases")) + experimental = from_union([from_bool, from_none], obj.get("experimental")) + input = from_union([SlashCommandInput.from_dict, from_none], obj.get("input")) + return SlashCommandInfo(allow_during_agent_execution, description, kind, name, aliases, experimental, input) + + def to_dict(self) -> dict: + result: dict = {} + result["allowDuringAgentExecution"] = from_bool(self.allow_during_agent_execution) + result["description"] = from_str(self.description) + result["kind"] = to_enum(SlashCommandKind, self.kind) + result["name"] = from_str(self.name) + if self.aliases is not None: + result["aliases"] = from_union([lambda x: from_list(from_str, x), from_none], self.aliases) + if self.experimental is not None: + result["experimental"] = from_union([from_bool, from_none], self.experimental) + if self.input is not None: + result["input"] = from_union([lambda x: to_class(SlashCommandInput, x), from_none], self.input) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class RemoteSessionConnectionResult: + """Remote session connection result.""" + + metadata: ConnectedRemoteSessionMetadata + """Metadata for a connected remote session.""" + + session_id: str + """SDK session ID for the connected remote session.""" + + @staticmethod + def from_dict(obj: Any) -> 'RemoteSessionConnectionResult': + assert isinstance(obj, dict) + metadata = ConnectedRemoteSessionMetadata.from_dict(obj.get("metadata")) + session_id = from_str(obj.get("sessionId")) + return RemoteSessionConnectionResult(metadata, session_id) + + def to_dict(self) -> dict: + result: dict = {} + result["metadata"] = to_class(ConnectedRemoteSessionMetadata, self.metadata) + result["sessionId"] = from_str(self.session_id) + return result + +@dataclass +class CopilotUserResponse: + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + access_type_sku: str | None = None + analytics_tracking_id: str | None = None + assigned_date: Any = None + can_signup_for_limited: bool | None = None + chat_enabled: bool | None = None + cli_remote_control_enabled: bool | None = None + cloud_session_storage_enabled: bool | None = None + codex_agent_enabled: bool | None = None + copilot_plan: str | None = None + copilotignore_enabled: bool | None = None + endpoints: CopilotUserResponseEndpoints | None = None + """Schema for the `CopilotUserResponseEndpoints` type.""" + + is_mcp_enabled: Any = None + limited_user_quotas: dict[str, float] | None = None + limited_user_reset_date: str | None = None + login: str | None = None + monthly_quotas: dict[str, float] | None = None + organization_list: Any = None + organization_login_list: list[str] | None = None + quota_reset_date: str | None = None + quota_reset_date_utc: str | None = None + quota_snapshots: dict[str, CopilotUserResponseQuotaSnapshots | None] | None = None + """Schema for the `CopilotUserResponseQuotaSnapshots` type.""" + + restricted_telemetry: bool | None = None + token_based_billing: bool | None = None + + @staticmethod + def from_dict(obj: Any) -> 'CopilotUserResponse': + assert isinstance(obj, dict) + access_type_sku = from_union([from_str, from_none], obj.get("access_type_sku")) + analytics_tracking_id = from_union([from_str, from_none], obj.get("analytics_tracking_id")) + assigned_date = obj.get("assigned_date") + can_signup_for_limited = from_union([from_bool, from_none], obj.get("can_signup_for_limited")) + chat_enabled = from_union([from_bool, from_none], obj.get("chat_enabled")) + cli_remote_control_enabled = from_union([from_bool, from_none], obj.get("cli_remote_control_enabled")) + cloud_session_storage_enabled = from_union([from_bool, from_none], obj.get("cloud_session_storage_enabled")) + codex_agent_enabled = from_union([from_bool, from_none], obj.get("codex_agent_enabled")) + copilot_plan = from_union([from_str, from_none], obj.get("copilot_plan")) + copilotignore_enabled = from_union([from_bool, from_none], obj.get("copilotignore_enabled")) + endpoints = from_union([CopilotUserResponseEndpoints.from_dict, from_none], obj.get("endpoints")) + is_mcp_enabled = obj.get("is_mcp_enabled") + limited_user_quotas = from_union([lambda x: from_dict(from_float, x), from_none], obj.get("limited_user_quotas")) + limited_user_reset_date = from_union([from_str, from_none], obj.get("limited_user_reset_date")) + login = from_union([from_str, from_none], obj.get("login")) + monthly_quotas = from_union([lambda x: from_dict(from_float, x), from_none], obj.get("monthly_quotas")) + organization_list = obj.get("organization_list") + organization_login_list = from_union([lambda x: from_list(from_str, x), from_none], obj.get("organization_login_list")) + quota_reset_date = from_union([from_str, from_none], obj.get("quota_reset_date")) + quota_reset_date_utc = from_union([from_str, from_none], obj.get("quota_reset_date_utc")) + quota_snapshots = from_union([lambda x: from_dict(lambda x: from_union([CopilotUserResponseQuotaSnapshots.from_dict, from_none], x), x), from_none], obj.get("quota_snapshots")) + restricted_telemetry = from_union([from_bool, from_none], obj.get("restricted_telemetry")) + token_based_billing = from_union([from_bool, from_none], obj.get("token_based_billing")) + return CopilotUserResponse(access_type_sku, analytics_tracking_id, assigned_date, can_signup_for_limited, chat_enabled, cli_remote_control_enabled, cloud_session_storage_enabled, codex_agent_enabled, copilot_plan, copilotignore_enabled, endpoints, is_mcp_enabled, limited_user_quotas, limited_user_reset_date, login, monthly_quotas, organization_list, organization_login_list, quota_reset_date, quota_reset_date_utc, quota_snapshots, restricted_telemetry, token_based_billing) + + def to_dict(self) -> dict: + result: dict = {} + if self.access_type_sku is not None: + result["access_type_sku"] = from_union([from_str, from_none], self.access_type_sku) + if self.analytics_tracking_id is not None: + result["analytics_tracking_id"] = from_union([from_str, from_none], self.analytics_tracking_id) + if self.assigned_date is not None: + result["assigned_date"] = self.assigned_date + if self.can_signup_for_limited is not None: + result["can_signup_for_limited"] = from_union([from_bool, from_none], self.can_signup_for_limited) + if self.chat_enabled is not None: + result["chat_enabled"] = from_union([from_bool, from_none], self.chat_enabled) + if self.cli_remote_control_enabled is not None: + result["cli_remote_control_enabled"] = from_union([from_bool, from_none], self.cli_remote_control_enabled) + if self.cloud_session_storage_enabled is not None: + result["cloud_session_storage_enabled"] = from_union([from_bool, from_none], self.cloud_session_storage_enabled) + if self.codex_agent_enabled is not None: + result["codex_agent_enabled"] = from_union([from_bool, from_none], self.codex_agent_enabled) + if self.copilot_plan is not None: + result["copilot_plan"] = from_union([from_str, from_none], self.copilot_plan) + if self.copilotignore_enabled is not None: + result["copilotignore_enabled"] = from_union([from_bool, from_none], self.copilotignore_enabled) + if self.endpoints is not None: + result["endpoints"] = from_union([lambda x: to_class(CopilotUserResponseEndpoints, x), from_none], self.endpoints) + if self.is_mcp_enabled is not None: + result["is_mcp_enabled"] = self.is_mcp_enabled + if self.limited_user_quotas is not None: + result["limited_user_quotas"] = from_union([lambda x: from_dict(to_float, x), from_none], self.limited_user_quotas) + if self.limited_user_reset_date is not None: + result["limited_user_reset_date"] = from_union([from_str, from_none], self.limited_user_reset_date) + if self.login is not None: + result["login"] = from_union([from_str, from_none], self.login) + if self.monthly_quotas is not None: + result["monthly_quotas"] = from_union([lambda x: from_dict(to_float, x), from_none], self.monthly_quotas) + if self.organization_list is not None: + result["organization_list"] = self.organization_list + if self.organization_login_list is not None: + result["organization_login_list"] = from_union([lambda x: from_list(from_str, x), from_none], self.organization_login_list) + if self.quota_reset_date is not None: + result["quota_reset_date"] = from_union([from_str, from_none], self.quota_reset_date) + if self.quota_reset_date_utc is not None: + result["quota_reset_date_utc"] = from_union([from_str, from_none], self.quota_reset_date_utc) + if self.quota_snapshots is not None: + result["quota_snapshots"] = from_union([lambda x: from_dict(lambda x: from_union([lambda x: to_class(CopilotUserResponseQuotaSnapshots, x), from_none], x), x), from_none], self.quota_snapshots) + if self.restricted_telemetry is not None: + result["restricted_telemetry"] = from_union([from_bool, from_none], self.restricted_telemetry) + if self.token_based_billing is not None: + result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) + return result + +@dataclass +class MCPDiscoverResult: + """MCP servers discovered from user, workspace, plugin, and built-in sources.""" + + servers: list[DiscoveredMCPServer] + """MCP servers discovered from all sources""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPDiscoverResult': + assert isinstance(obj, dict) + servers = from_list(DiscoveredMCPServer.from_dict, obj.get("servers")) + return MCPDiscoverResult(servers) + + def to_dict(self) -> dict: + result: dict = {} + result["servers"] = from_list(lambda x: to_class(DiscoveredMCPServer, x), self.servers) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ExtensionList: + """Extensions discovered for the session, with their current status.""" + + extensions: list[Extension] + """Discovered extensions and their current status""" + + @staticmethod + def from_dict(obj: Any) -> 'ExtensionList': + assert isinstance(obj, dict) + extensions = from_list(Extension.from_dict, obj.get("extensions")) + return ExtensionList(extensions) + + def to_dict(self) -> dict: + result: dict = {} + result["extensions"] = from_list(lambda x: to_class(Extension, x), self.extensions) + return result + +@dataclass +class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess: + """Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` + type. + """ + extension_name: str + """Extension name.""" + + kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind + """Approval covering an extension's request to access a permission-gated capability.""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess': + assert isinstance(obj, dict) + extension_name = from_str(obj.get("extensionName")) + kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) + return PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess(extension_name, kind) + + def to_dict(self) -> dict: + result: dict = {} + result["extensionName"] = from_str(self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + return result + +@dataclass +class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess: + """Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` + type. + """ + extension_name: str + """Extension name.""" + + kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind + """Approval covering an extension's request to access a permission-gated capability.""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess': + assert isinstance(obj, dict) + extension_name = from_str(obj.get("extensionName")) + kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) + return PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess(extension_name, kind) + + def to_dict(self) -> dict: + result: dict = {} + result["extensionName"] = from_str(self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + return result + +@dataclass +class UserToolSessionApprovalExtensionManagement: + """Schema for the `UserToolSessionApprovalExtensionManagement` type.""" + + kind: PermissionDecisionApproveForLocationApprovalExtensionManagementKind + """Extension management approval kind""" + + operation: str | None = None + """Optional operation identifier""" + + @staticmethod + def from_dict(obj: Any) -> 'UserToolSessionApprovalExtensionManagement': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForLocationApprovalExtensionManagementKind(obj.get("kind")) + operation = from_union([from_str, from_none], obj.get("operation")) + return UserToolSessionApprovalExtensionManagement(kind, operation) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionManagementKind, self.kind) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) + return result + +@dataclass +class UserToolSessionApprovalExtensionPermissionAccess: + """Schema for the `UserToolSessionApprovalExtensionPermissionAccess` type.""" + + extension_name: str + """Extension name""" + + kind: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind + """Extension permission access approval kind""" + + @staticmethod + def from_dict(obj: Any) -> 'UserToolSessionApprovalExtensionPermissionAccess': + assert isinstance(obj, dict) + extension_name = from_str(obj.get("extensionName")) + kind = PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind(obj.get("kind")) + return UserToolSessionApprovalExtensionPermissionAccess(extension_name, kind) + + def to_dict(self) -> dict: + result: dict = {} + result["extensionName"] = from_str(self.extension_name) + result["kind"] = to_enum(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind, self.kind) + return result + +@dataclass +class ExternalToolTextResultForLlmContent: + """A content block within a tool result, which may be text, terminal output, image, audio, + or a resource + + Plain text content block + + Terminal/shell output content block with optional exit code and working directory + + Image content block with base64-encoded data + + Audio content block with base64-encoded data + + Resource link content block referencing an external resource + + Embedded resource content block with inline text or binary data + """ + type: ExternalToolTextResultForLlmContentType + """Content block type discriminator""" + + text: str | None = None + """The text content + + Terminal/shell output text + """ + cwd: str | None = None + """Working directory where the command was executed""" + + exit_code: int | None = None + """Process exit code, if the command has completed""" + + data: str | None = None + """Base64-encoded image data + + Base64-encoded audio data + """ + mime_type: str | None = None + """MIME type of the image (e.g., image/png, image/jpeg) + + MIME type of the audio (e.g., audio/wav, audio/mpeg) + + MIME type of the resource content + """ + description: str | None = None + """Human-readable description of the resource""" + + icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None + """Icons associated with this resource""" + + name: str | None = None + """Resource name identifier""" + + size: int | None = None + """Size of the resource in bytes""" + + title: str | None = None + """Human-readable display title for the resource""" + + uri: str | None = None + """URI identifying the resource""" + + resource: ExternalToolTextResultForLlmContentResourceDetails | None = None + """The embedded resource contents, either text or base64-encoded binary""" + + @staticmethod + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContent': + assert isinstance(obj, dict) + type = ExternalToolTextResultForLlmContentType(obj.get("type")) + text = from_union([from_str, from_none], obj.get("text")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + exit_code = from_union([from_int, from_none], obj.get("exitCode")) + data = from_union([from_str, from_none], obj.get("data")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + description = from_union([from_str, from_none], obj.get("description")) + icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) + name = from_union([from_str, from_none], obj.get("name")) + size = from_union([from_int, from_none], obj.get("size")) + title = from_union([from_str, from_none], obj.get("title")) + uri = from_union([from_str, from_none], obj.get("uri")) + resource = from_union([(lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x)), from_none], obj.get("resource")) + return ExternalToolTextResultForLlmContent(type, text, cwd, exit_code, data, mime_type, description, icons, name, size, title, uri, resource) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(ExternalToolTextResultForLlmContentType, self.type) + if self.text is not None: + result["text"] = from_union([from_str, from_none], self.text) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.exit_code is not None: + result["exitCode"] = from_union([from_int, from_none], self.exit_code) + if self.data is not None: + result["data"] = from_union([from_str, from_none], self.data) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.icons is not None: + result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.size is not None: + result["size"] = from_union([from_int, from_none], self.size) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + if self.uri is not None: + result["uri"] = from_union([from_str, from_none], self.uri) + if self.resource is not None: + result["resource"] = from_union([lambda x: from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], x), from_none], self.resource) + return result + +@dataclass +class ExternalToolTextResultForLlmContentResourceLink: + """Resource link content block referencing an external resource""" + + name: str + """Resource name identifier""" + + type: ExternalToolTextResultForLlmContentResourceLinkType + """Content block type discriminator""" + + uri: str + """URI identifying the resource""" + + description: str | None = None + """Human-readable description of the resource""" + + icons: list[ExternalToolTextResultForLlmContentResourceLinkIcon] | None = None + """Icons associated with this resource""" + + mime_type: str | None = None + """MIME type of the resource content""" + + size: int | None = None + """Size of the resource in bytes""" + + title: str | None = None + """Human-readable display title for the resource""" + + @staticmethod + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlmContentResourceLink': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + type = ExternalToolTextResultForLlmContentResourceLinkType(obj.get("type")) + uri = from_str(obj.get("uri")) + description = from_union([from_str, from_none], obj.get("description")) + icons = from_union([lambda x: from_list(ExternalToolTextResultForLlmContentResourceLinkIcon.from_dict, x), from_none], obj.get("icons")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + size = from_union([from_int, from_none], obj.get("size")) + title = from_union([from_str, from_none], obj.get("title")) + return ExternalToolTextResultForLlmContentResourceLink(name, type, uri, description, icons, mime_type, size, title) + + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + result["type"] = to_enum(ExternalToolTextResultForLlmContentResourceLinkType, self.type) + result["uri"] = from_str(self.uri) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.icons is not None: + result["icons"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContentResourceLinkIcon, x), x), from_none], self.icons) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + if self.size is not None: + result["size"] = from_union([from_int, from_none], self.size) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class InstalledPluginSource: + """Schema for the `InstalledPluginSourceGithub` type. + + Schema for the `InstalledPluginSourceUrl` type. + + Schema for the `InstalledPluginSourceLocal` type. + """ + source: PurpleSource + """Constant value. Always "github". + + Constant value. Always "url". + + Constant value. Always "local". + """ + path: str | None = None + ref: str | None = None + repo: str | None = None + url: str | None = None + + @staticmethod + def from_dict(obj: Any) -> 'InstalledPluginSource': + assert isinstance(obj, dict) + source = PurpleSource(obj.get("source")) + path = from_union([from_str, from_none], obj.get("path")) + ref = from_union([from_str, from_none], obj.get("ref")) + repo = from_union([from_str, from_none], obj.get("repo")) + url = from_union([from_str, from_none], obj.get("url")) + return InstalledPluginSource(source, path, ref, repo, url) + + def to_dict(self) -> dict: + result: dict = {} + result["source"] = to_enum(PurpleSource, self.source) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.ref is not None: + result["ref"] = from_union([from_str, from_none], self.ref) + if self.repo is not None: + result["repo"] = from_union([from_str, from_none], self.repo) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionInstalledPluginSource: + """Schema for the `SessionInstalledPluginSourceGithub` type. + + Schema for the `SessionInstalledPluginSourceUrl` type. + + Schema for the `SessionInstalledPluginSourceLocal` type. + """ + source: PurpleSource + """Constant value. Always "github". + + Constant value. Always "url". + + Constant value. Always "local". + """ + path: str | None = None + ref: str | None = None + repo: str | None = None + url: str | None = None + + @staticmethod + def from_dict(obj: Any) -> 'SessionInstalledPluginSource': + assert isinstance(obj, dict) + source = PurpleSource(obj.get("source")) + path = from_union([from_str, from_none], obj.get("path")) + ref = from_union([from_str, from_none], obj.get("ref")) + repo = from_union([from_str, from_none], obj.get("repo")) + url = from_union([from_str, from_none], obj.get("url")) + return SessionInstalledPluginSource(source, path, ref, repo, url) + + def to_dict(self) -> dict: + result: dict = {} + result["source"] = to_enum(PurpleSource, self.source) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.ref is not None: + result["ref"] = from_union([from_str, from_none], self.ref) + if self.repo is not None: + result["repo"] = from_union([from_str, from_none], self.repo) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) + return result + +@dataclass +class InstructionsGetSourcesResult: + """Instruction sources loaded for the session, in merge order.""" + + sources: list[InstructionsSources] + """Instruction sources for the session""" + + @staticmethod + def from_dict(obj: Any) -> 'InstructionsGetSourcesResult': + assert isinstance(obj, dict) + sources = from_list(InstructionsSources.from_dict, obj.get("sources")) + return InstructionsGetSourcesResult(sources) + + def to_dict(self) -> dict: + result: dict = {} + result["sources"] = from_list(lambda x: to_class(InstructionsSources, x), self.sources) + return result + +@dataclass +class MCPConfigAddRequest: + """MCP server name and configuration to add to user configuration.""" + + config: MCPServerConfig + """MCP server configuration (stdio process or remote HTTP/SSE)""" + + name: str + """Unique name for the MCP server""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPConfigAddRequest': + assert isinstance(obj, dict) + config = MCPServerConfig.from_dict(obj.get("config")) + name = from_str(obj.get("name")) + return MCPConfigAddRequest(config, name) + + def to_dict(self) -> dict: + result: dict = {} + result["config"] = to_class(MCPServerConfig, self.config) + result["name"] = from_str(self.name) + return result + +@dataclass +class MCPConfigList: + """User-configured MCP servers, keyed by server name.""" + + servers: dict[str, MCPServerConfig] + """All MCP servers from user config, keyed by name""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPConfigList': + assert isinstance(obj, dict) + servers = from_dict(MCPServerConfig.from_dict, obj.get("servers")) + return MCPConfigList(servers) + + def to_dict(self) -> dict: + result: dict = {} + result["servers"] = from_dict(lambda x: to_class(MCPServerConfig, x), self.servers) + return result + +@dataclass +class MCPConfigUpdateRequest: + """MCP server name and replacement configuration to write to user configuration.""" + + config: MCPServerConfig + """MCP server configuration (stdio process or remote HTTP/SSE)""" + + name: str + """Name of the MCP server to update""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPConfigUpdateRequest': + assert isinstance(obj, dict) + config = MCPServerConfig.from_dict(obj.get("config")) + name = from_str(obj.get("name")) + return MCPConfigUpdateRequest(config, name) + + def to_dict(self) -> dict: + result: dict = {} + result["config"] = to_class(MCPServerConfig, self.config) + result["name"] = from_str(self.name) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataRecordContextChangeRequest: + """Updated working-directory/git context to record on the session.""" + + context: SessionWorkingDirectoryContext + """Updated working directory and git context. Emitted as the new payload of + `session.context_changed`. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MetadataRecordContextChangeRequest': + assert isinstance(obj, dict) + context = SessionWorkingDirectoryContext.from_dict(obj.get("context")) + return MetadataRecordContextChangeRequest(context) + + def to_dict(self) -> dict: + result: dict = {} + result["context"] = to_class(SessionWorkingDirectoryContext, self.context) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionMetadata: + """Schema for the `SessionMetadata` type.""" + + is_remote: bool + """True for remote (GitHub) sessions; false for local""" + + modified_time: str + """Last-modified time of the session's persisted state, as ISO 8601""" + + session_id: str + """Stable session identifier""" + + start_time: str + """Session creation time as an ISO 8601 timestamp""" + + context: SessionContext | None = None + """Schema for the `SessionContext` type.""" + + mc_task_id: str | None = None + """GitHub task ID, when this local session is bound to one. Only present for local sessions + exported to remote control. + """ + name: str | None = None + """Optional human-friendly name set via /rename""" + + summary: str | None = None + """Short summary of the session, when one has been derived""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionMetadata': + assert isinstance(obj, dict) + is_remote = from_bool(obj.get("isRemote")) + modified_time = from_str(obj.get("modifiedTime")) + session_id = from_str(obj.get("sessionId")) + start_time = from_str(obj.get("startTime")) + context = from_union([SessionContext.from_dict, from_none], obj.get("context")) + mc_task_id = from_union([from_str, from_none], obj.get("mcTaskId")) + name = from_union([from_str, from_none], obj.get("name")) + summary = from_union([from_str, from_none], obj.get("summary")) + return SessionMetadata(is_remote, modified_time, session_id, start_time, context, mc_task_id, name, summary) + + def to_dict(self) -> dict: + result: dict = {} + result["isRemote"] = from_bool(self.is_remote) + result["modifiedTime"] = from_str(self.modified_time) + result["sessionId"] = from_str(self.session_id) + result["startTime"] = from_str(self.start_time) + if self.context is not None: + result["context"] = from_union([lambda x: to_class(SessionContext, x), from_none], self.context) + if self.mc_task_id is not None: + result["mcTaskId"] = from_union([from_str, from_none], self.mc_task_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.summary is not None: + result["summary"] = from_union([from_str, from_none], self.summary) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsGetLastForContextRequest: + """Optional working-directory context used to score session relevance.""" + + context: SessionContext | None = None + """Optional working-directory context used to score session relevance. When omitted the + most-recently-modified session wins. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionsGetLastForContextRequest': + assert isinstance(obj, dict) + context = from_union([SessionContext.from_dict, from_none], obj.get("context")) + return SessionsGetLastForContextRequest(context) + + def to_dict(self) -> dict: + result: dict = {} + if self.context is not None: + result["context"] = from_union([lambda x: to_class(SessionContext, x), from_none], self.context) + return result + +@dataclass +class PermissionPathsConfig: + """If specified, replaces the session's path-permission policy. The runtime constructs the + appropriate PathManager based on these inputs (rooted at the session's working + directory). Omit to leave the current path policy unchanged. + """ + additional_directories: list[str] | None = None + """Additional directories to allow tool access to (in addition to the session's working + directory). When `unrestricted` is true, these are still pre-populated on the + UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention + completion). + """ + include_temp_directory: bool | None = None + """Whether to include the system temp directory in the allowed list (defaults to true). + Ignored when `unrestricted` is true. + """ + unrestricted: bool | None = None + """If true, the runtime allows access to all paths without prompting. Equivalent to + constructing an UnrestrictedPathManager. + """ + workspace_path: str | None = None + """Workspace root path (special-cased to be allowed even before the directory exists). + Ignored when `unrestricted` is true. + """ + + @staticmethod + def from_dict(obj: Any) -> 'PermissionPathsConfig': + assert isinstance(obj, dict) + additional_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("additionalDirectories")) + include_temp_directory = from_union([from_bool, from_none], obj.get("includeTempDirectory")) + unrestricted = from_union([from_bool, from_none], obj.get("unrestricted")) + workspace_path = from_union([from_str, from_none], obj.get("workspacePath")) + return PermissionPathsConfig(additional_directories, include_temp_directory, unrestricted, workspace_path) + + def to_dict(self) -> dict: + result: dict = {} + if self.additional_directories is not None: + result["additionalDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.additional_directories) + if self.include_temp_directory is not None: + result["includeTempDirectory"] = from_union([from_bool, from_none], self.include_temp_directory) + if self.unrestricted is not None: + result["unrestricted"] = from_union([from_bool, from_none], self.unrestricted) + if self.workspace_path is not None: + result["workspacePath"] = from_union([from_str, from_none], self.workspace_path) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class WorkspaceSummary: + """Public-facing projection of workspace metadata for SDK / TUI consumers""" + + id: UUID + """Workspace identifier (1:1 with sessionId)""" + + branch: str | None = None + """Branch checked out at session start, if any""" + + created_at: datetime | None = None + """ISO 8601 timestamp when the workspace was created""" + + cwd: str | None = None + """Current working directory at session start""" + + git_root: str | None = None + """Resolved git root for cwd, if any""" + + host_type: SessionContextHostType | None = None + """Repository host type, if known""" + + name: str | None = None + """Display name for the session, if set""" + + repository: str | None = None + """Repository identifier in 'owner/repo' or 'org/project/repo' format, if any""" + + updated_at: datetime | None = None + """ISO 8601 timestamp when the workspace was last updated""" + + @staticmethod + def from_dict(obj: Any) -> 'WorkspaceSummary': + assert isinstance(obj, dict) + id = UUID(obj.get("id")) + branch = from_union([from_str, from_none], obj.get("branch")) + created_at = from_union([from_datetime, from_none], obj.get("created_at")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + git_root = from_union([from_str, from_none], obj.get("git_root")) + host_type = from_union([SessionContextHostType, from_none], obj.get("host_type")) + name = from_union([from_str, from_none], obj.get("name")) + repository = from_union([from_str, from_none], obj.get("repository")) + updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) + return WorkspaceSummary(id, branch, created_at, cwd, git_root, host_type, name, repository, updated_at) + + def to_dict(self) -> dict: + result: dict = {} + result["id"] = str(self.id) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.created_at is not None: + result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.git_root is not None: + result["git_root"] = from_union([from_str, from_none], self.git_root) + if self.host_type is not None: + result["host_type"] = from_union([lambda x: to_enum(SessionContextHostType, x), from_none], self.host_type) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + if self.updated_at is not None: + result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + return result + +@dataclass +class WorkspacesGetWorkspaceResult: + """Current workspace metadata for the session, including its absolute filesystem path when + available. + """ + path: str | None = None + """Absolute filesystem path to the workspace directory. Omitted when the session has no + workspace (e.g. remote sessions). + """ + workspace: Workspace | None = None + """Current workspace metadata, or null if not available""" + + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': + assert isinstance(obj, dict) + path = from_union([from_str, from_none], obj.get("path")) + workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) + return WorkspacesGetWorkspaceResult(path, workspace) + + def to_dict(self) -> dict: + result: dict = {} + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) + return result + +@dataclass +class WorkspacesListCheckpointsResult: + """Workspace checkpoints in chronological order; empty when the workspace is not enabled.""" + + checkpoints: list[WorkspacesCheckpoints] + """Workspace checkpoints in chronological order. Empty when workspace is not enabled.""" + + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesListCheckpointsResult': + assert isinstance(obj, dict) + checkpoints = from_list(WorkspacesCheckpoints.from_dict, obj.get("checkpoints")) + return WorkspacesListCheckpointsResult(checkpoints) + + def to_dict(self) -> dict: + result: dict = {} + result["checkpoints"] = from_list(lambda x: to_class(WorkspacesCheckpoints, x), self.checkpoints) + return result + +@dataclass +class ModelCapabilitiesOverride: + """Override individual model capabilities resolved by the runtime""" + + limits: ModelCapabilitiesOverrideLimits | None = None + """Token limits for prompts, outputs, and context window""" + + supports: ModelCapabilitiesOverrideSupports | None = None + """Feature flags indicating what the model supports""" + + @staticmethod + def from_dict(obj: Any) -> 'ModelCapabilitiesOverride': + assert isinstance(obj, dict) + limits = from_union([ModelCapabilitiesOverrideLimits.from_dict, from_none], obj.get("limits")) + supports = from_union([ModelCapabilitiesOverrideSupports.from_dict, from_none], obj.get("supports")) + return ModelCapabilitiesOverride(limits, supports) + + def to_dict(self) -> dict: + result: dict = {} + if self.limits is not None: + result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideLimits, x), from_none], self.limits) + if self.supports is not None: + result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesOverrideSupports, x), from_none], self.supports) + return result + +@dataclass +class PermissionsConfigureAdditionalContentExclusionPolicy: + """Schema for the `PermissionsConfigureAdditionalContentExclusionPolicy` type.""" + + last_updated_at: float | str + rules: list[PermissionsConfigureAdditionalContentExclusionPolicyRule] + scope: PermissionsConfigureAdditionalContentExclusionPolicyScope + """Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` + enumeration. + """ + + @staticmethod + def from_dict(obj: Any) -> 'PermissionsConfigureAdditionalContentExclusionPolicy': + assert isinstance(obj, dict) + last_updated_at = from_union([from_float, from_str], obj.get("last_updated_at")) + rules = from_list(PermissionsConfigureAdditionalContentExclusionPolicyRule.from_dict, obj.get("rules")) + scope = PermissionsConfigureAdditionalContentExclusionPolicyScope(obj.get("scope")) + return PermissionsConfigureAdditionalContentExclusionPolicy(last_updated_at, rules, scope) + + def to_dict(self) -> dict: + result: dict = {} + result["last_updated_at"] = from_union([to_float, from_str], self.last_updated_at) + result["rules"] = from_list(lambda x: to_class(PermissionsConfigureAdditionalContentExclusionPolicyRule, x), self.rules) + result["scope"] = to_enum(PermissionsConfigureAdditionalContentExclusionPolicyScope, self.scope) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class QueuePendingItemsResult: + """Snapshot of the session's pending queued items and immediate-steering messages.""" + + items: list[QueuePendingItems] + """Pending queued items in submission order. Includes user messages, queued slash commands, + and queued model changes; omits internal system items. + """ + steering_messages: list[str] + """Display text for messages currently in the immediate steering queue (interjections sent + during a running turn). + """ + + @staticmethod + def from_dict(obj: Any) -> 'QueuePendingItemsResult': + assert isinstance(obj, dict) + items = from_list(QueuePendingItems.from_dict, obj.get("items")) + steering_messages = from_list(from_str, obj.get("steeringMessages")) + return QueuePendingItemsResult(items, steering_messages) + + def to_dict(self) -> dict: + result: dict = {} + result["items"] = from_list(lambda x: to_class(QueuePendingItems, x), self.items) + result["steeringMessages"] = from_list(from_str, self.steering_messages) + return result + +@dataclass +class CommandsRespondToQueuedCommandRequest: + """Queued-command request ID and the result indicating whether the host executed it (and + whether to stop processing further queued commands). + """ + request_id: str + """Request ID from the `command.queued` event the host is responding to.""" + + result: QueuedCommandResult + """Result of the queued command execution.""" + + @staticmethod + def from_dict(obj: Any) -> 'CommandsRespondToQueuedCommandRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + result = QueuedCommandResult.from_dict(obj.get("result")) + return CommandsRespondToQueuedCommandRequest(request_id, result) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(QueuedCommandResult, self.result) + return result + +@dataclass +class SendAttachment: + """A user message attachment — a file, directory, code selection, blob, or GitHub reference + + File attachment + + Directory attachment + + Code selection attachment from an editor + + GitHub issue, pull request, or discussion reference + + Blob attachment with inline base64-encoded data + """ + type: SendAttachmentType + """Attachment type discriminator""" + + display_name: str | None = None + """User-facing display name for the attachment + + User-facing display name for the selection + """ + line_range: SendAttachmentFileLineRange | None = None + """Optional line range to scope the attachment to a specific section of the file""" + + path: str | None = None + """Absolute file path + + Absolute directory path + """ + file_path: str | None = None + """Absolute path to the file containing the selection""" + + selection: SendAttachmentSelectionDetails | None = None + """Position range of the selection within the file""" + + text: str | None = None + """The selected text content""" + + number: int | None = None + """Issue, pull request, or discussion number""" + + reference_type: SendAttachmentGithubReferenceTypeEnum | None = None + """Type of GitHub reference""" + + state: str | None = None + """Current state of the referenced item (e.g., open, closed, merged)""" + + title: str | None = None + """Title of the referenced item""" + + url: str | None = None + """URL to the referenced item on GitHub""" + + data: str | None = None + """Base64-encoded content""" + + mime_type: str | None = None + """MIME type of the inline data""" + + @staticmethod + def from_dict(obj: Any) -> 'SendAttachment': + assert isinstance(obj, dict) + type = SendAttachmentType(obj.get("type")) + display_name = from_union([from_str, from_none], obj.get("displayName")) + line_range = from_union([SendAttachmentFileLineRange.from_dict, from_none], obj.get("lineRange")) + path = from_union([from_str, from_none], obj.get("path")) + file_path = from_union([from_str, from_none], obj.get("filePath")) + selection = from_union([SendAttachmentSelectionDetails.from_dict, from_none], obj.get("selection")) + text = from_union([from_str, from_none], obj.get("text")) + number = from_union([from_int, from_none], obj.get("number")) + reference_type = from_union([SendAttachmentGithubReferenceTypeEnum, from_none], obj.get("referenceType")) + state = from_union([from_str, from_none], obj.get("state")) + title = from_union([from_str, from_none], obj.get("title")) + url = from_union([from_str, from_none], obj.get("url")) + data = from_union([from_str, from_none], obj.get("data")) + mime_type = from_union([from_str, from_none], obj.get("mimeType")) + return SendAttachment(type, display_name, line_range, path, file_path, selection, text, number, reference_type, state, title, url, data, mime_type) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(SendAttachmentType, self.type) + if self.display_name is not None: + result["displayName"] = from_union([from_str, from_none], self.display_name) + if self.line_range is not None: + result["lineRange"] = from_union([lambda x: to_class(SendAttachmentFileLineRange, x), from_none], self.line_range) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.file_path is not None: + result["filePath"] = from_union([from_str, from_none], self.file_path) + if self.selection is not None: + result["selection"] = from_union([lambda x: to_class(SendAttachmentSelectionDetails, x), from_none], self.selection) + if self.text is not None: + result["text"] = from_union([from_str, from_none], self.text) + if self.number is not None: + result["number"] = from_union([from_int, from_none], self.number) + if self.reference_type is not None: + result["referenceType"] = from_union([lambda x: to_enum(SendAttachmentGithubReferenceTypeEnum, x), from_none], self.reference_type) + if self.state is not None: + result["state"] = from_union([from_str, from_none], self.state) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + if self.url is not None: + result["url"] = from_union([from_str, from_none], self.url) + if self.data is not None: + result["data"] = from_union([from_str, from_none], self.data) + if self.mime_type is not None: + result["mimeType"] = from_union([from_str, from_none], self.mime_type) + return result + +@dataclass +class SendAttachmentSelection: + """Code selection attachment from an editor""" + + display_name: str + """User-facing display name for the selection""" + + file_path: str + """Absolute path to the file containing the selection""" + + selection: SendAttachmentSelectionDetails + """Position range of the selection within the file""" + + text: str + """The selected text content""" + + type: SendAttachmentSelectionType + """Attachment type discriminator""" + + @staticmethod + def from_dict(obj: Any) -> 'SendAttachmentSelection': + assert isinstance(obj, dict) + display_name = from_str(obj.get("displayName")) + file_path = from_str(obj.get("filePath")) + selection = SendAttachmentSelectionDetails.from_dict(obj.get("selection")) + text = from_str(obj.get("text")) + type = SendAttachmentSelectionType(obj.get("type")) + return SendAttachmentSelection(display_name, file_path, selection, text, type) + + def to_dict(self) -> dict: + result: dict = {} + result["displayName"] = from_str(self.display_name) + result["filePath"] = from_str(self.file_path) + result["selection"] = to_class(SendAttachmentSelectionDetails, self.selection) + result["text"] = from_str(self.text) + result["type"] = to_enum(SendAttachmentSelectionType, self.type) + return result + +@dataclass +class SessionFSReadFileResult: + """File content as a UTF-8 string, or a filesystem error if the read failed.""" + + content: str + """File content as UTF-8 string""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSReadFileResult': + assert isinstance(obj, dict) + content = from_str(obj.get("content")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSReadFileResult(content, error) + + def to_dict(self) -> dict: + result: dict = {} + result["content"] = from_str(self.content) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + return result + +@dataclass +class SessionFSReaddirResult: + """Names of entries in the requested directory, or a filesystem error if the read failed.""" + + entries: list[str] + """Entry names in the directory""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSReaddirResult': + assert isinstance(obj, dict) + entries = from_list(from_str, obj.get("entries")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSReaddirResult(entries, error) + + def to_dict(self) -> dict: + result: dict = {} + result["entries"] = from_list(from_str, self.entries) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + return result + +@dataclass +class SessionFSSqliteQueryResult: + """Query results including rows, columns, and rows affected, or a filesystem error if + execution failed. + """ + columns: list[str] + """Column names from the result set""" + + rows: list[dict[str, Any]] + """For SELECT: array of row objects. For others: empty array.""" + + rows_affected: int + """Number of rows affected (for INSERT/UPDATE/DELETE)""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" + + last_insert_rowid: int | None = None + """SQLite last_insert_rowid() value for INSERT.""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSSqliteQueryResult': + assert isinstance(obj, dict) + columns = from_list(from_str, obj.get("columns")) + rows = from_list(lambda x: from_dict(lambda x: x, x), obj.get("rows")) + rows_affected = from_int(obj.get("rowsAffected")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + last_insert_rowid = from_union([from_int, from_none], obj.get("lastInsertRowid")) + return SessionFSSqliteQueryResult(columns, rows, rows_affected, error, last_insert_rowid) + + def to_dict(self) -> dict: + result: dict = {} + result["columns"] = from_list(from_str, self.columns) + result["rows"] = from_list(lambda x: from_dict(lambda x: x, x), self.rows) + result["rowsAffected"] = from_int(self.rows_affected) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + if self.last_insert_rowid is not None: + result["lastInsertRowid"] = from_union([from_int, from_none], self.last_insert_rowid) + return result + +@dataclass +class SessionFSStatResult: + """Filesystem metadata for the requested path, or a filesystem error if the stat failed.""" + + birthtime: datetime + """ISO 8601 timestamp of creation""" + + is_directory: bool + """Whether the path is a directory""" + + is_file: bool + """Whether the path is a file""" + + mtime: datetime + """ISO 8601 timestamp of last modification""" + + size: int + """File size in bytes""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSStatResult': + assert isinstance(obj, dict) + birthtime = from_datetime(obj.get("birthtime")) + is_directory = from_bool(obj.get("isDirectory")) + is_file = from_bool(obj.get("isFile")) + mtime = from_datetime(obj.get("mtime")) + size = from_int(obj.get("size")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSStatResult(birthtime, is_directory, is_file, mtime, size, error) + + def to_dict(self) -> dict: + result: dict = {} + result["birthtime"] = self.birthtime.isoformat() + result["isDirectory"] = from_bool(self.is_directory) + result["isFile"] = from_bool(self.is_file) + result["mtime"] = self.mtime.isoformat() + result["size"] = from_int(self.size) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + return result + +@dataclass +class SessionFSReaddirWithTypesResult: + """Entries in the requested directory paired with file/directory type information, or a + filesystem error if the read failed. + """ + entries: list[SessionFSReaddirWithTypesEntry] + """Directory entries with type information""" + + error: SessionFSError | None = None + """Describes a filesystem error.""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionFSReaddirWithTypesResult': + assert isinstance(obj, dict) + entries = from_list(SessionFSReaddirWithTypesEntry.from_dict, obj.get("entries")) + error = from_union([SessionFSError.from_dict, from_none], obj.get("error")) + return SessionFSReaddirWithTypesResult(entries, error) + + def to_dict(self) -> dict: + result: dict = {} + result["entries"] = from_list(lambda x: to_class(SessionFSReaddirWithTypesEntry, x), self.entries) + if self.error is not None: + result["error"] = from_union([lambda x: to_class(SessionFSError, x), from_none], self.error) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AgentGetCurrentResult: + """The currently selected custom agent, or null when using the default agent.""" + + agent: AgentInfo | None = None + """Currently selected custom agent, or null if using the default agent""" + + @staticmethod + def from_dict(obj: Any) -> 'AgentGetCurrentResult': + assert isinstance(obj, dict) + agent = from_union([AgentInfo.from_dict, from_none], obj.get("agent")) + return AgentGetCurrentResult(agent) + + def to_dict(self) -> dict: + result: dict = {} + if self.agent is not None: + result["agent"] = from_union([lambda x: to_class(AgentInfo, x), from_none], self.agent) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AgentList: + """Custom agents available to the session.""" + + agents: list[AgentInfo] + """Available custom agents""" + + @staticmethod + def from_dict(obj: Any) -> 'AgentList': + assert isinstance(obj, dict) + agents = from_list(AgentInfo.from_dict, obj.get("agents")) + return AgentList(agents) + + def to_dict(self) -> dict: + result: dict = {} + result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AgentReloadResult: + """Custom agents available to the session after reloading definitions from disk.""" + + agents: list[AgentInfo] + """Reloaded custom agents""" + + @staticmethod + def from_dict(obj: Any) -> 'AgentReloadResult': + assert isinstance(obj, dict) + agents = from_list(AgentInfo.from_dict, obj.get("agents")) + return AgentReloadResult(agents) + + def to_dict(self) -> dict: + result: dict = {} + result["agents"] = from_list(lambda x: to_class(AgentInfo, x), self.agents) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AgentSelectResult: + """The newly selected custom agent.""" + + agent: AgentInfo + """The newly selected custom agent""" + + @staticmethod + def from_dict(obj: Any) -> 'AgentSelectResult': + assert isinstance(obj, dict) + agent = AgentInfo.from_dict(obj.get("agent")) + return AgentSelectResult(agent) + + def to_dict(self) -> dict: + result: dict = {} + result["agent"] = to_class(AgentInfo, self.agent) + return result + +@dataclass +class SlashCommandInvocationResult: + """Result of invoking the slash command (text output, prompt to send to the agent, or + completion). + + Schema for the `SlashCommandTextResult` type. + + Schema for the `SlashCommandAgentPromptResult` type. + + Schema for the `SlashCommandCompletedResult` type. + """ + kind: SlashCommandInvocationResultKind + """Text result discriminator + + Agent prompt result discriminator + + Completed result discriminator + """ + markdown: bool | None = None + """Whether text contains Markdown""" + + preserve_ansi: bool | None = None + """Whether ANSI sequences should be preserved""" + + runtime_settings_changed: bool | None = None + """True when the invocation mutated user runtime settings; consumers caching settings should + refresh + """ + text: str | None = None + """Text output for the client to render""" + + display_prompt: str | None = None + """Prompt text to display to the user""" + + mode: SessionMode | None = None + """Optional target session mode for the agent prompt""" + + prompt: str | None = None + """Prompt to submit to the agent""" + + message: str | None = None + """Optional user-facing message describing the completed command""" + + @staticmethod + def from_dict(obj: Any) -> 'SlashCommandInvocationResult': + assert isinstance(obj, dict) + kind = SlashCommandInvocationResultKind(obj.get("kind")) + markdown = from_union([from_bool, from_none], obj.get("markdown")) + preserve_ansi = from_union([from_bool, from_none], obj.get("preserveAnsi")) + runtime_settings_changed = from_union([from_bool, from_none], obj.get("runtimeSettingsChanged")) + text = from_union([from_str, from_none], obj.get("text")) + display_prompt = from_union([from_str, from_none], obj.get("displayPrompt")) + mode = from_union([SessionMode, from_none], obj.get("mode")) + prompt = from_union([from_str, from_none], obj.get("prompt")) + message = from_union([from_str, from_none], obj.get("message")) + return SlashCommandInvocationResult(kind, markdown, preserve_ansi, runtime_settings_changed, text, display_prompt, mode, prompt, message) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(SlashCommandInvocationResultKind, self.kind) + if self.markdown is not None: + result["markdown"] = from_union([from_bool, from_none], self.markdown) + if self.preserve_ansi is not None: + result["preserveAnsi"] = from_union([from_bool, from_none], self.preserve_ansi) + if self.runtime_settings_changed is not None: + result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) + if self.text is not None: + result["text"] = from_union([from_str, from_none], self.text) + if self.display_prompt is not None: + result["displayPrompt"] = from_union([from_str, from_none], self.display_prompt) + if self.mode is not None: + result["mode"] = from_union([lambda x: to_enum(SessionMode, x), from_none], self.mode) + if self.prompt is not None: + result["prompt"] = from_union([from_str, from_none], self.prompt) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TasksGetProgressResult: + """Progress information for the task, or null when no task with that ID is tracked.""" + + progress: TaskProgressClass | None = None + """Progress information for the task, discriminated by type. Returns null when no task with + this ID is currently tracked. + """ + + @staticmethod + def from_dict(obj: Any) -> 'TasksGetProgressResult': + assert isinstance(obj, dict) + progress = from_union([TaskProgressClass.from_dict, from_none], obj.get("progress")) + return TasksGetProgressResult(progress) + + def to_dict(self) -> dict: + result: dict = {} + if self.progress is not None: + result["progress"] = from_union([lambda x: to_class(TaskProgressClass, x), from_none], self.progress) + return result + +@dataclass +class UIElicitationArrayAnyOfField: + """Multi-select string field where each option pairs a value with a display label.""" + + items: UIElicitationArrayAnyOfFieldItems + """Schema applied to each item in the array.""" + + type: UIElicitationArrayAnyOfFieldType + """Type discriminator. Always "array".""" + + default: list[str] | None = None + """Default values selected when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + max_items: int | None = None + """Maximum number of items the user may select.""" + + min_items: int | None = None + """Minimum number of items the user must select.""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayAnyOfField': + assert isinstance(obj, dict) + items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("items")) + type = UIElicitationArrayAnyOfFieldType(obj.get("type")) + default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + max_items = from_union([from_int, from_none], obj.get("maxItems")) + min_items = from_union([from_int, from_none], obj.get("minItems")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationArrayAnyOfField(items, type, default, description, max_items, min_items, title) + + def to_dict(self) -> dict: + result: dict = {} + result["items"] = to_class(UIElicitationArrayAnyOfFieldItems, self.items) + result["type"] = to_enum(UIElicitationArrayAnyOfFieldType, self.type) + if self.default is not None: + result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.max_items is not None: + result["maxItems"] = from_union([from_int, from_none], self.max_items) + if self.min_items is not None: + result["minItems"] = from_union([from_int, from_none], self.min_items) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationArrayEnumField: + """Multi-select string field whose allowed values are defined inline.""" + + items: UIElicitationArrayEnumFieldItems + """Schema applied to each item in the array.""" + + type: UIElicitationArrayAnyOfFieldType + """Type discriminator. Always "array".""" + + default: list[str] | None = None + """Default values selected when the form is first shown.""" + + description: str | None = None + """Help text describing the field.""" + + max_items: int | None = None + """Maximum number of items the user may select.""" + + min_items: int | None = None + """Minimum number of items the user must select.""" + + title: str | None = None + """Human-readable label for the field.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationArrayEnumField': + assert isinstance(obj, dict) + items = UIElicitationArrayEnumFieldItems.from_dict(obj.get("items")) + type = UIElicitationArrayAnyOfFieldType(obj.get("type")) + default = from_union([lambda x: from_list(from_str, x), from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + max_items = from_union([from_int, from_none], obj.get("maxItems")) + min_items = from_union([from_int, from_none], obj.get("minItems")) + title = from_union([from_str, from_none], obj.get("title")) + return UIElicitationArrayEnumField(items, type, default, description, max_items, min_items, title) + + def to_dict(self) -> dict: + result: dict = {} + result["items"] = to_class(UIElicitationArrayEnumFieldItems, self.items) + result["type"] = to_enum(UIElicitationArrayAnyOfFieldType, self.type) + if self.default is not None: + result["default"] = from_union([lambda x: from_list(from_str, x), from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.max_items is not None: + result["maxItems"] = from_union([from_int, from_none], self.max_items) + if self.min_items is not None: + result["minItems"] = from_union([from_int, from_none], self.min_items) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + return result + +@dataclass +class UIElicitationSchemaProperty: + """Definition for a single elicitation form field. + + Single-select string field whose allowed values are defined inline. + + Single-select string field where each option pairs a value with a display label. + + Multi-select string field whose allowed values are defined inline. + + Multi-select string field where each option pairs a value with a display label. + + Boolean field rendered as a yes/no toggle. + + Free-text string field with optional length and format constraints. + + Numeric field accepting either a number or an integer. + """ + type: UIElicitationSchemaPropertyType + """Type discriminator. Always "string". + + Type discriminator. Always "array". + + Type discriminator. Always "boolean". + + Numeric type accepted by the field. + """ + default: float | bool | list[str] | str | None = None + """Default value selected when the form is first shown. + + Default values selected when the form is first shown. + + Default value populated in the input when the form is first shown. + """ + description: str | None = None + """Help text describing the field.""" + + enum: list[str] | None = None + """Allowed string values.""" + + enum_names: list[str] | None = None + """Optional display labels for each enum value, in the same order as `enum`.""" + + title: str | None = None + """Human-readable label for the field.""" + + one_of: list[UIElicitationStringOneOfFieldOneOf] | None = None + """Selectable options, each with a value and a display label.""" + + items: UIElicitationArrayFieldItems | None = None + """Schema applied to each item in the array.""" + + max_items: int | None = None + """Maximum number of items the user may select.""" + + min_items: int | None = None + """Minimum number of items the user must select.""" + + format: UIElicitationSchemaPropertyStringFormat | None = None + """Optional format hint that constrains the accepted input.""" + + max_length: int | None = None + """Maximum number of characters allowed.""" + + min_length: int | None = None + """Minimum number of characters required.""" + + maximum: float | None = None + """Maximum allowed value (inclusive).""" + + minimum: float | None = None + """Minimum allowed value (inclusive).""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationSchemaProperty': + assert isinstance(obj, dict) + type = UIElicitationSchemaPropertyType(obj.get("type")) + default = from_union([from_float, from_bool, lambda x: from_list(from_str, x), from_str, from_none], obj.get("default")) + description = from_union([from_str, from_none], obj.get("description")) + enum = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enum")) + enum_names = from_union([lambda x: from_list(from_str, x), from_none], obj.get("enumNames")) + title = from_union([from_str, from_none], obj.get("title")) + one_of = from_union([lambda x: from_list(UIElicitationStringOneOfFieldOneOf.from_dict, x), from_none], obj.get("oneOf")) + items = from_union([UIElicitationArrayFieldItems.from_dict, from_none], obj.get("items")) + max_items = from_union([from_int, from_none], obj.get("maxItems")) + min_items = from_union([from_int, from_none], obj.get("minItems")) + format = from_union([UIElicitationSchemaPropertyStringFormat, from_none], obj.get("format")) + max_length = from_union([from_int, from_none], obj.get("maxLength")) + min_length = from_union([from_int, from_none], obj.get("minLength")) + maximum = from_union([from_float, from_none], obj.get("maximum")) + minimum = from_union([from_float, from_none], obj.get("minimum")) + return UIElicitationSchemaProperty(type, default, description, enum, enum_names, title, one_of, items, max_items, min_items, format, max_length, min_length, maximum, minimum) + + def to_dict(self) -> dict: + result: dict = {} + result["type"] = to_enum(UIElicitationSchemaPropertyType, self.type) + if self.default is not None: + result["default"] = from_union([to_float, from_bool, lambda x: from_list(from_str, x), from_str, from_none], self.default) + if self.description is not None: + result["description"] = from_union([from_str, from_none], self.description) + if self.enum is not None: + result["enum"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum) + if self.enum_names is not None: + result["enumNames"] = from_union([lambda x: from_list(from_str, x), from_none], self.enum_names) + if self.title is not None: + result["title"] = from_union([from_str, from_none], self.title) + if self.one_of is not None: + result["oneOf"] = from_union([lambda x: from_list(lambda x: to_class(UIElicitationStringOneOfFieldOneOf, x), x), from_none], self.one_of) + if self.items is not None: + result["items"] = from_union([lambda x: to_class(UIElicitationArrayFieldItems, x), from_none], self.items) + if self.max_items is not None: + result["maxItems"] = from_union([from_int, from_none], self.max_items) + if self.min_items is not None: + result["minItems"] = from_union([from_int, from_none], self.min_items) + if self.format is not None: + result["format"] = from_union([lambda x: to_enum(UIElicitationSchemaPropertyStringFormat, x), from_none], self.format) + if self.max_length is not None: + result["maxLength"] = from_union([from_int, from_none], self.max_length) + if self.min_length is not None: + result["minLength"] = from_union([from_int, from_none], self.min_length) + if self.maximum is not None: + result["maximum"] = from_union([to_float, from_none], self.maximum) + if self.minimum is not None: + result["minimum"] = from_union([to_float, from_none], self.minimum) + return result + +@dataclass +class UIHandlePendingElicitationRequest: + """Pending elicitation request ID and the user's response (accept/decline/cancel + form + values). + """ + request_id: str + """The unique request ID from the elicitation.requested event""" + + result: UIElicitationResponse + """The elicitation response (accept with form values, decline, or cancel)""" + + @staticmethod + def from_dict(obj: Any) -> 'UIHandlePendingElicitationRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + result = UIElicitationResponse.from_dict(obj.get("result")) + return UIHandlePendingElicitationRequest(request_id, result) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(UIElicitationResponse, self.result) + return result + +@dataclass +class UIHandlePendingExitPlanModeRequest: + """Request ID of a pending `exit_plan_mode.requested` event and the user's response.""" + + request_id: str + """The unique request ID from the exit_plan_mode.requested event""" + + response: UIExitPlanModeResponse + """Schema for the `UIExitPlanModeResponse` type.""" + + @staticmethod + def from_dict(obj: Any) -> 'UIHandlePendingExitPlanModeRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + response = UIExitPlanModeResponse.from_dict(obj.get("response")) + return UIHandlePendingExitPlanModeRequest(request_id, response) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["response"] = to_class(UIExitPlanModeResponse, self.response) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UsageGetMetricsResult: + """Accumulated session usage metrics, including premium request cost, token counts, model + breakdown, and code-change totals. + """ + code_changes: UsageMetricsCodeChanges + """Aggregated code change metrics""" + + last_call_input_tokens: int + """Input tokens from the most recent main-agent API call""" + + last_call_output_tokens: int + """Output tokens from the most recent main-agent API call""" + + model_metrics: dict[str, UsageMetricsModelMetric] + """Per-model token and request metrics, keyed by model identifier""" + + session_start_time: datetime + """ISO 8601 timestamp when the session started""" + + total_api_duration_ms: int + """Total time spent in model API calls (milliseconds)""" + + total_premium_request_cost: float + """Total user-initiated premium request cost across all models (may be fractional due to + multipliers) + """ + total_user_requests: int + """Raw count of user-initiated API requests""" + + current_model: str | None = None + """Currently active model identifier""" + + token_details: dict[str, UsageMetricsTokenDetail] | None = None + """Session-wide per-token-type accumulated token counts""" + + total_nano_aiu: int | None = None + """Session-wide accumulated nano-AI units cost""" + + @staticmethod + def from_dict(obj: Any) -> 'UsageGetMetricsResult': + assert isinstance(obj, dict) + code_changes = UsageMetricsCodeChanges.from_dict(obj.get("codeChanges")) + last_call_input_tokens = from_int(obj.get("lastCallInputTokens")) + last_call_output_tokens = from_int(obj.get("lastCallOutputTokens")) + model_metrics = from_dict(UsageMetricsModelMetric.from_dict, obj.get("modelMetrics")) + session_start_time = from_datetime(obj.get("sessionStartTime")) + total_api_duration_ms = from_int(obj.get("totalApiDurationMs")) + total_premium_request_cost = from_float(obj.get("totalPremiumRequestCost")) + total_user_requests = from_int(obj.get("totalUserRequests")) + current_model = from_union([from_str, from_none], obj.get("currentModel")) + token_details = from_union([lambda x: from_dict(UsageMetricsTokenDetail.from_dict, x), from_none], obj.get("tokenDetails")) + total_nano_aiu = from_union([from_int, from_none], obj.get("totalNanoAiu")) + return UsageGetMetricsResult(code_changes, last_call_input_tokens, last_call_output_tokens, model_metrics, session_start_time, total_api_duration_ms, total_premium_request_cost, total_user_requests, current_model, token_details, total_nano_aiu) + + def to_dict(self) -> dict: + result: dict = {} + result["codeChanges"] = to_class(UsageMetricsCodeChanges, self.code_changes) + result["lastCallInputTokens"] = from_int(self.last_call_input_tokens) + result["lastCallOutputTokens"] = from_int(self.last_call_output_tokens) + result["modelMetrics"] = from_dict(lambda x: to_class(UsageMetricsModelMetric, x), self.model_metrics) + result["sessionStartTime"] = self.session_start_time.isoformat() + result["totalApiDurationMs"] = from_int(self.total_api_duration_ms) + result["totalPremiumRequestCost"] = to_float(self.total_premium_request_cost) + result["totalUserRequests"] = from_int(self.total_user_requests) + if self.current_model is not None: + result["currentModel"] = from_union([from_str, from_none], self.current_model) + if self.token_details is not None: + result["tokenDetails"] = from_union([lambda x: from_dict(lambda x: to_class(UsageMetricsTokenDetail, x), x), from_none], self.token_details) + if self.total_nano_aiu is not None: + result["totalNanoAiu"] = from_union([from_int, from_none], self.total_nano_aiu) + return result + +@dataclass +class CommandList: + """Slash commands available in the session, after applying any include/exclude filters.""" + + commands: list[SlashCommandInfo] + """Commands available in this session""" + + @staticmethod + def from_dict(obj: Any) -> 'CommandList': + assert isinstance(obj, dict) + commands = from_list(SlashCommandInfo.from_dict, obj.get("commands")) + return CommandList(commands) + + def to_dict(self) -> dict: + result: dict = {} + result["commands"] = from_list(lambda x: to_class(SlashCommandInfo, x), self.commands) + return result + +@dataclass +class APIKeyAuthInfo: + """Schema for the `ApiKeyAuthInfo` type.""" + + api_key: str + """The API key. Treat as a secret.""" + + host: str + """Authentication host.""" + + type: APIKeyAuthInfoType + """API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style).""" + + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + + @staticmethod + def from_dict(obj: Any) -> 'APIKeyAuthInfo': + assert isinstance(obj, dict) + api_key = from_str(obj.get("apiKey")) + host = from_str(obj.get("host")) + type = APIKeyAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + return APIKeyAuthInfo(api_key, host, type, copilot_user) + + def to_dict(self) -> dict: + result: dict = {} + result["apiKey"] = from_str(self.api_key) + result["host"] = from_str(self.host) + result["type"] = to_enum(APIKeyAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + return result + +@dataclass +class CopilotAPITokenAuthInfo: + """Schema for the `CopilotApiTokenAuthInfo` type.""" + + host: Host + """Authentication host (always the public GitHub host).""" + + type: CopilotAPITokenAuthInfoType + """Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` + environment-variable pair. The token itself is read from the environment by the runtime, + not carried in this struct. + """ + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + + @staticmethod + def from_dict(obj: Any) -> 'CopilotAPITokenAuthInfo': + assert isinstance(obj, dict) + host = Host(obj.get("host")) + type = CopilotAPITokenAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + return CopilotAPITokenAuthInfo(host, type, copilot_user) + + def to_dict(self) -> dict: + result: dict = {} + result["host"] = to_enum(Host, self.host) + result["type"] = to_enum(CopilotAPITokenAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + return result + +@dataclass +class EnvAuthInfo: + """Schema for the `EnvAuthInfo` type.""" + + env_var: str + """Name of the environment variable the token was sourced from.""" + + host: str + """Authentication host (e.g. https://github.com or a GHES host).""" + + token: str + """The token value itself. Treat as a secret.""" + + type: EnvAuthInfoType + """Personal access token (PAT) or server-to-server token sourced from an environment + variable. + """ + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + login: str | None = None + """User login associated with the token. Undefined for server-to-server tokens (those + starting with `ghs_`). + """ + + @staticmethod + def from_dict(obj: Any) -> 'EnvAuthInfo': + assert isinstance(obj, dict) + env_var = from_str(obj.get("envVar")) + host = from_str(obj.get("host")) + token = from_str(obj.get("token")) + type = EnvAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + login = from_union([from_str, from_none], obj.get("login")) + return EnvAuthInfo(env_var, host, token, type, copilot_user, login) + + def to_dict(self) -> dict: + result: dict = {} + result["envVar"] = from_str(self.env_var) + result["host"] = from_str(self.host) + result["token"] = from_str(self.token) + result["type"] = to_enum(EnvAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + if self.login is not None: + result["login"] = from_union([from_str, from_none], self.login) + return result + +@dataclass +class GhCLIAuthInfo: + """Schema for the `GhCliAuthInfo` type.""" + + host: str + """Authentication host.""" + + login: str + """User login as reported by `gh auth status`.""" + + token: str + """The token returned by `gh auth token`. Treat as a secret.""" + + type: GhCLIAuthInfoType + """Authentication via the `gh` CLI's saved credentials.""" + + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + + @staticmethod + def from_dict(obj: Any) -> 'GhCLIAuthInfo': + assert isinstance(obj, dict) + host = from_str(obj.get("host")) + login = from_str(obj.get("login")) + token = from_str(obj.get("token")) + type = GhCLIAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + return GhCLIAuthInfo(host, login, token, type, copilot_user) + + def to_dict(self) -> dict: + result: dict = {} + result["host"] = from_str(self.host) + result["login"] = from_str(self.login) + result["token"] = from_str(self.token) + result["type"] = to_enum(GhCLIAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + return result + +@dataclass +class HMACAuthInfo: + """Schema for the `HMACAuthInfo` type.""" + + hmac: str + """HMAC secret used to sign requests.""" + + host: Host + """Authentication host. HMAC auth always targets the public GitHub host.""" + + type: HMACAuthInfoType + """HMAC-based authentication used by GitHub-internal services.""" + + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + + @staticmethod + def from_dict(obj: Any) -> 'HMACAuthInfo': + assert isinstance(obj, dict) + hmac = from_str(obj.get("hmac")) + host = Host(obj.get("host")) + type = HMACAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + return HMACAuthInfo(hmac, host, type, copilot_user) + + def to_dict(self) -> dict: + result: dict = {} + result["hmac"] = from_str(self.hmac) + result["host"] = to_enum(Host, self.host) + result["type"] = to_enum(HMACAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + return result + +@dataclass +class TokenAuthInfo: + """Schema for the `TokenAuthInfo` type.""" + + host: str + """Authentication host.""" + + token: str + """The token value itself. Treat as a secret.""" + + type: TokenAuthInfoType + """SDK-side token authentication; the host configured the token directly via the SDK.""" + + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + + @staticmethod + def from_dict(obj: Any) -> 'TokenAuthInfo': + assert isinstance(obj, dict) + host = from_str(obj.get("host")) + token = from_str(obj.get("token")) + type = TokenAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + return TokenAuthInfo(host, token, type, copilot_user) + + def to_dict(self) -> dict: + result: dict = {} + result["host"] = from_str(self.host) + result["token"] = from_str(self.token) + result["type"] = to_enum(TokenAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + return result + +@dataclass +class UserAuthInfo: + """Schema for the `UserAuthInfo` type.""" + + host: str + """Authentication host.""" + + login: str + """OAuth user login.""" + + type: UserAuthInfoType + """OAuth user authentication. The token itself is held in the runtime's secret token store + (keyed by host+login) and is NOT carried in this struct. + """ + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserAuthInfo': + assert isinstance(obj, dict) + host = from_str(obj.get("host")) + login = from_str(obj.get("login")) + type = UserAuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + return UserAuthInfo(host, login, type, copilot_user) + + def to_dict(self) -> dict: + result: dict = {} + result["host"] = from_str(self.host) + result["login"] = from_str(self.login) + result["type"] = to_enum(UserAuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + return result + +@dataclass +class PermissionDecisionApproveForLocationApproval: + """Approval to persist for this location + + Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalRead` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` + type. + """ + kind: ApprovalKind + """Approval scoped to specific command identifiers. + + Approval covering read-only filesystem operations. + + Approval covering filesystem write operations. + + Approval covering an MCP tool. + + Approval covering MCP sampling requests for a server. + + Approval covering writes to long-term memory. + + Approval covering a custom tool. + + Approval covering extension lifecycle operations such as enable, disable, or reload. + + Approval covering an extension's request to access a permission-gated capability. + """ + command_identifiers: list[str] | None = None + """Command identifiers covered by this approval.""" + + server_name: str | None = None + """MCP server name.""" + + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server. + + Custom tool name. + """ + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. + """ + extension_name: str | None = None + """Extension name.""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocationApproval': + assert isinstance(obj, dict) + kind = ApprovalKind(obj.get("kind")) + command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) + server_name = from_union([from_str, from_none], obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + operation = from_union([from_str, from_none], obj.get("operation")) + extension_name = from_union([from_str, from_none], obj.get("extensionName")) + return PermissionDecisionApproveForLocationApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(ApprovalKind, self.kind) + if self.command_identifiers is not None: + result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) + if self.server_name is not None: + result["serverName"] = from_union([from_str, from_none], self.server_name) + if self.tool_name is not None: + result["toolName"] = from_union([from_none, from_str], self.tool_name) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) + if self.extension_name is not None: + result["extensionName"] = from_union([from_str, from_none], self.extension_name) + return result + +@dataclass +class PermissionDecisionApproveForIonApproval: + """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) + + Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalRead` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` + type. + + Approval to persist for this location + + Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalRead` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type. + + Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` + type. + + The approval to add as a session-scoped rule + + The approval to persist for this location + """ + command_identifiers: list[str] | None = None + """Command identifiers covered by this approval.""" + + kind: ApprovalKind | None = None + """Approval scoped to specific command identifiers. + + Approval covering read-only filesystem operations. + + Approval covering filesystem write operations. + + Approval covering an MCP tool. + + Approval covering MCP sampling requests for a server. + + Approval covering writes to long-term memory. + + Approval covering a custom tool. + + Approval covering extension lifecycle operations such as enable, disable, or reload. + + Approval covering an extension's request to access a permission-gated capability. + """ + server_name: str | None = None + """MCP server name.""" + + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server. + + Custom tool name. + """ + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. + """ + extension_name: str | None = None + """Extension name.""" + + external_ref_marker_external_ref_user_tool_session_approval: str | None = None + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForIonApproval': + assert isinstance(obj, dict) + command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) + kind = from_union([ApprovalKind, from_none], obj.get("kind")) + server_name = from_union([from_str, from_none], obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + operation = from_union([from_str, from_none], obj.get("operation")) + extension_name = from_union([from_str, from_none], obj.get("extensionName")) + external_ref_marker_external_ref_user_tool_session_approval = from_union([from_str, from_none], obj.get("__externalRefMarker___ExternalRef_UserToolSessionApproval")) + return PermissionDecisionApproveForIonApproval(command_identifiers, kind, server_name, tool_name, operation, extension_name, external_ref_marker_external_ref_user_tool_session_approval) + + def to_dict(self) -> dict: + result: dict = {} + if self.command_identifiers is not None: + result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) + if self.kind is not None: + result["kind"] = from_union([lambda x: to_enum(ApprovalKind, x), from_none], self.kind) + if self.server_name is not None: + result["serverName"] = from_union([from_str, from_none], self.server_name) + if self.tool_name is not None: + result["toolName"] = from_union([from_none, from_str], self.tool_name) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) + if self.extension_name is not None: + result["extensionName"] = from_union([from_str, from_none], self.extension_name) + if self.external_ref_marker_external_ref_user_tool_session_approval is not None: + result["__externalRefMarker___ExternalRef_UserToolSessionApproval"] = from_union([from_str, from_none], self.external_ref_marker_external_ref_user_tool_session_approval) + return result + +@dataclass +class PermissionDecisionApproveForSessionApproval: + """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) + + Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalRead` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type. + + Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` + type. + """ + kind: ApprovalKind + """Approval scoped to specific command identifiers. + + Approval covering read-only filesystem operations. + + Approval covering filesystem write operations. + + Approval covering an MCP tool. + + Approval covering MCP sampling requests for a server. + + Approval covering writes to long-term memory. + + Approval covering a custom tool. + + Approval covering extension lifecycle operations such as enable, disable, or reload. + + Approval covering an extension's request to access a permission-gated capability. + """ + command_identifiers: list[str] | None = None + """Command identifiers covered by this approval.""" + + server_name: str | None = None + """MCP server name.""" + + tool_name: str | None = None + """MCP tool name, or null to cover every tool on the server. + + Custom tool name. + """ + operation: str | None = None + """Optional operation identifier; when omitted, the approval covers all extension management + operations. + """ + extension_name: str | None = None + """Extension name.""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSessionApproval': + assert isinstance(obj, dict) + kind = ApprovalKind(obj.get("kind")) + command_identifiers = from_union([lambda x: from_list(from_str, x), from_none], obj.get("commandIdentifiers")) + server_name = from_union([from_str, from_none], obj.get("serverName")) + tool_name = from_union([from_none, from_str], obj.get("toolName")) + operation = from_union([from_str, from_none], obj.get("operation")) + extension_name = from_union([from_str, from_none], obj.get("extensionName")) + return PermissionDecisionApproveForSessionApproval(kind, command_identifiers, server_name, tool_name, operation, extension_name) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(ApprovalKind, self.kind) + if self.command_identifiers is not None: + result["commandIdentifiers"] = from_union([lambda x: from_list(from_str, x), from_none], self.command_identifiers) + if self.server_name is not None: + result["serverName"] = from_union([from_str, from_none], self.server_name) + if self.tool_name is not None: + result["toolName"] = from_union([from_none, from_str], self.tool_name) + if self.operation is not None: + result["operation"] = from_union([from_str, from_none], self.operation) + if self.extension_name is not None: + result["extensionName"] = from_union([from_str, from_none], self.extension_name) + return result + +@dataclass +class ExternalToolTextResultForLlm: + """Expanded external tool result payload""" + + text_result_for_llm: str + """Text result returned to the model""" + + binary_results_for_llm: list[ExternalToolTextResultForLlmBinaryResultsForLlm] | None = None + """Base64-encoded binary results returned to the model""" + + contents: list[ExternalToolTextResultForLlmContent] | None = None + """Structured content blocks from the tool""" + + error: str | None = None + """Optional error message for failed executions""" + + result_type: str | None = None + """Execution outcome classification. Optional for back-compat; normalized to 'success' (or + 'failure' when error is present) when missing or unrecognized. + """ + session_log: str | None = None + """Detailed log content for timeline display""" + + tool_telemetry: dict[str, Any] | None = None + """Optional tool-specific telemetry""" + + @staticmethod + def from_dict(obj: Any) -> 'ExternalToolTextResultForLlm': + assert isinstance(obj, dict) + text_result_for_llm = from_str(obj.get("textResultForLlm")) + binary_results_for_llm = from_union([lambda x: from_list(ExternalToolTextResultForLlmBinaryResultsForLlm.from_dict, x), from_none], obj.get("binaryResultsForLlm")) + contents = from_union([lambda x: from_list(ExternalToolTextResultForLlmContent.from_dict, x), from_none], obj.get("contents")) + error = from_union([from_str, from_none], obj.get("error")) + result_type = from_union([from_str, from_none], obj.get("resultType")) + session_log = from_union([from_str, from_none], obj.get("sessionLog")) + tool_telemetry = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("toolTelemetry")) + return ExternalToolTextResultForLlm(text_result_for_llm, binary_results_for_llm, contents, error, result_type, session_log, tool_telemetry) + + def to_dict(self) -> dict: + result: dict = {} + result["textResultForLlm"] = from_str(self.text_result_for_llm) + if self.binary_results_for_llm is not None: + result["binaryResultsForLlm"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmBinaryResultsForLlm, x), x), from_none], self.binary_results_for_llm) + if self.contents is not None: + result["contents"] = from_union([lambda x: from_list(lambda x: to_class(ExternalToolTextResultForLlmContent, x), x), from_none], self.contents) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result_type is not None: + result["resultType"] = from_union([from_str, from_none], self.result_type) + if self.session_log is not None: + result["sessionLog"] = from_union([from_str, from_none], self.session_log) + if self.tool_telemetry is not None: + result["toolTelemetry"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.tool_telemetry) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class InstalledPlugin: + """Schema for the `InstalledPlugin` type.""" + + enabled: bool + """Whether the plugin is currently enabled""" + + installed_at: str + """Installation timestamp""" + + marketplace: str + """Marketplace the plugin came from (empty string for direct repo installs)""" + + name: str + """Plugin name""" + + cache_path: str | None = None + """Path where the plugin is cached locally""" + + source: InstalledPluginSource | str | None = None + """Source for direct repo installs (when marketplace is empty)""" + + version: str | None = None + """Version installed (if available)""" + + @staticmethod + def from_dict(obj: Any) -> 'InstalledPlugin': + assert isinstance(obj, dict) + enabled = from_bool(obj.get("enabled")) + installed_at = from_str(obj.get("installed_at")) + marketplace = from_str(obj.get("marketplace")) + name = from_str(obj.get("name")) + cache_path = from_union([from_str, from_none], obj.get("cache_path")) + source = from_union([InstalledPluginSource.from_dict, from_str, from_none], obj.get("source")) + version = from_union([from_str, from_none], obj.get("version")) + return InstalledPlugin(enabled, installed_at, marketplace, name, cache_path, source, version) + + def to_dict(self) -> dict: + result: dict = {} + result["enabled"] = from_bool(self.enabled) + result["installed_at"] = from_str(self.installed_at) + result["marketplace"] = from_str(self.marketplace) + result["name"] = from_str(self.name) + if self.cache_path is not None: + result["cache_path"] = from_union([from_str, from_none], self.cache_path) + if self.source is not None: + result["source"] = from_union([lambda x: to_class(InstalledPluginSource, x), from_str, from_none], self.source) + if self.version is not None: + result["version"] = from_union([from_str, from_none], self.version) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionInstalledPlugin: + """Schema for the `SessionInstalledPlugin` type.""" + + enabled: bool + """Whether the plugin is currently enabled""" + + installed_at: str + """Installation timestamp (ISO-8601)""" + + marketplace: str + """Marketplace the plugin came from (empty string for direct repo installs)""" + + name: str + """Plugin name""" + + cache_path: str | None = None + """Path where the plugin is cached locally""" + + source: SessionInstalledPluginSource | str | None = None + """Source descriptor for direct repo installs (when marketplace is empty)""" + + version: str | None = None + """Installed version, if known""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionInstalledPlugin': + assert isinstance(obj, dict) + enabled = from_bool(obj.get("enabled")) + installed_at = from_str(obj.get("installed_at")) + marketplace = from_str(obj.get("marketplace")) + name = from_str(obj.get("name")) + cache_path = from_union([from_str, from_none], obj.get("cache_path")) + source = from_union([SessionInstalledPluginSource.from_dict, from_str, from_none], obj.get("source")) + version = from_union([from_str, from_none], obj.get("version")) + return SessionInstalledPlugin(enabled, installed_at, marketplace, name, cache_path, source, version) + + def to_dict(self) -> dict: + result: dict = {} + result["enabled"] = from_bool(self.enabled) + result["installed_at"] = from_str(self.installed_at) + result["marketplace"] = from_str(self.marketplace) + result["name"] = from_str(self.name) + if self.cache_path is not None: + result["cache_path"] = from_union([from_str, from_none], self.cache_path) + if self.source is not None: + result["source"] = from_union([lambda x: to_class(SessionInstalledPluginSource, x), from_str, from_none], self.source) + if self.version is not None: + result["version"] = from_union([from_str, from_none], self.version) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionEnrichMetadataResult: + """The same metadata records, with summary and context fields backfilled where available.""" + + sessions: list[SessionMetadata] + """Same records, with summary and context backfilled""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionEnrichMetadataResult': + assert isinstance(obj, dict) + sessions = from_list(SessionMetadata.from_dict, obj.get("sessions")) + return SessionEnrichMetadataResult(sessions) + + def to_dict(self) -> dict: + result: dict = {} + result["sessions"] = from_list(lambda x: to_class(SessionMetadata, x), self.sessions) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionList: + """Persisted sessions matching the filter, ordered most-recently-modified first.""" + + sessions: list[SessionMetadata] + """Sessions ordered most-recently-modified first""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionList': + assert isinstance(obj, dict) + sessions = from_list(SessionMetadata.from_dict, obj.get("sessions")) + return SessionList(sessions) + + def to_dict(self) -> dict: + result: dict = {} + result["sessions"] = from_list(lambda x: to_class(SessionMetadata, x), self.sessions) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsEnrichMetadataRequest: + """Session metadata records to enrich with summary and context information.""" + + sessions: list[SessionMetadata] + """Session metadata records to enrich. Records that already have summary and context are + returned unchanged. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionsEnrichMetadataRequest': + assert isinstance(obj, dict) + sessions = from_list(SessionMetadata.from_dict, obj.get("sessions")) + return SessionsEnrichMetadataRequest(sessions) + + def to_dict(self) -> dict: + result: dict = {} + result["sessions"] = from_list(lambda x: to_class(SessionMetadata, x), self.sessions) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionMetadataSnapshot: + """Point-in-time snapshot of slow-changing session identifier and state fields""" + + already_in_use: bool + """True when the session was detected to be in use by another process at construction time. + Local consumers may surface a confirmation prompt before fully attaching. Always false + for new sessions. + """ + current_mode: MetadataSnapshotCurrentMode + """The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot')""" + + is_remote: bool + """Whether this is a remote session (i.e., one whose runtime executes elsewhere and is + steered through this process) + """ + modified_time: datetime + """ISO 8601 timestamp of when the session's persisted state was last modified on disk. For + new sessions, equals startTime. For resumed sessions, reflects the previous modification + time at construction. + """ + session_id: str + """The unique identifier of the session""" + + start_time: datetime + """ISO 8601 timestamp of when the session started""" + + working_directory: str + """Absolute path to the session's current working directory""" + + initial_name: str | None = None + """User-provided name supplied at session construction (via `--name`), if any. Immutable + after construction. + """ + remote_metadata: MetadataSnapshotRemoteMetadata | None = None + """Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are + immutable for the lifetime of the session. + """ + selected_model: str | None = None + """Currently selected model identifier, if any""" + + summary: str | None = None + """Short human-readable summary of the session, if known. Omitted when no summary has been + generated. + """ + workspace: WorkspaceSummary | None = None + """Public-facing workspace metadata for this session, or null if the session has no + associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, + internal flags). + """ + workspace_path: str | None = None + """Absolute path to the session's workspace directory on disk, or null if the session has no + associated workspace + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionMetadataSnapshot': + assert isinstance(obj, dict) + already_in_use = from_bool(obj.get("alreadyInUse")) + current_mode = MetadataSnapshotCurrentMode(obj.get("currentMode")) + is_remote = from_bool(obj.get("isRemote")) + modified_time = from_datetime(obj.get("modifiedTime")) + session_id = from_str(obj.get("sessionId")) + start_time = from_datetime(obj.get("startTime")) + working_directory = from_str(obj.get("workingDirectory")) + initial_name = from_union([from_str, from_none], obj.get("initialName")) + remote_metadata = from_union([MetadataSnapshotRemoteMetadata.from_dict, from_none], obj.get("remoteMetadata")) + selected_model = from_union([from_str, from_none], obj.get("selectedModel")) + summary = from_union([from_str, from_none], obj.get("summary")) + workspace = from_union([WorkspaceSummary.from_dict, from_none], obj.get("workspace")) + workspace_path = from_union([from_none, from_str], obj.get("workspacePath")) + return SessionMetadataSnapshot(already_in_use, current_mode, is_remote, modified_time, session_id, start_time, working_directory, initial_name, remote_metadata, selected_model, summary, workspace, workspace_path) + + def to_dict(self) -> dict: + result: dict = {} + result["alreadyInUse"] = from_bool(self.already_in_use) + result["currentMode"] = to_enum(MetadataSnapshotCurrentMode, self.current_mode) + result["isRemote"] = from_bool(self.is_remote) + result["modifiedTime"] = self.modified_time.isoformat() + result["sessionId"] = from_str(self.session_id) + result["startTime"] = self.start_time.isoformat() + result["workingDirectory"] = from_str(self.working_directory) + if self.initial_name is not None: + result["initialName"] = from_union([from_str, from_none], self.initial_name) + if self.remote_metadata is not None: + result["remoteMetadata"] = from_union([lambda x: to_class(MetadataSnapshotRemoteMetadata, x), from_none], self.remote_metadata) + if self.selected_model is not None: + result["selectedModel"] = from_union([from_str, from_none], self.selected_model) + if self.summary is not None: + result["summary"] = from_union([from_str, from_none], self.summary) + if self.workspace is not None: + result["workspace"] = from_union([lambda x: to_class(WorkspaceSummary, x), from_none], self.workspace) + result["workspacePath"] = from_union([from_none, from_str], self.workspace_path) + return result + +@dataclass +class PermissionsConfigureParams: + """Patch of permission policy fields to apply (omit a field to leave it unchanged).""" + + additional_content_exclusion_policies: list[PermissionsConfigureAdditionalContentExclusionPolicy] | None = None + """If specified, replaces the host-supplied GitHub Content Exclusion policies on the session + (combined with natively-discovered policies when evaluating tool/file access). Omit to + leave the current policies unchanged. + """ + approve_all_read_permission_requests: bool | None = None + """If specified, sets whether path/URL read permission requests are auto-approved. Omit to + leave the current value unchanged. + """ + approve_all_tool_permission_requests: bool | None = None + """If specified, sets whether tool permission requests are auto-approved without prompting. + Omit to leave the current value unchanged. + """ + paths: PermissionPathsConfig | None = None + """If specified, replaces the session's path-permission policy. The runtime constructs the + appropriate PathManager based on these inputs (rooted at the session's working + directory). Omit to leave the current path policy unchanged. + """ + rules: PermissionRulesSet | None = None + """If specified, replaces the session's approved/denied permission rules. Omit to leave the + current rules unchanged. + """ + urls: PermissionUrlsConfig | None = None + """If specified, replaces the session's URL-permission policy. The runtime constructs a + fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy + unchanged. + """ + + @staticmethod + def from_dict(obj: Any) -> 'PermissionsConfigureParams': + assert isinstance(obj, dict) + additional_content_exclusion_policies = from_union([lambda x: from_list(PermissionsConfigureAdditionalContentExclusionPolicy.from_dict, x), from_none], obj.get("additionalContentExclusionPolicies")) + approve_all_read_permission_requests = from_union([from_bool, from_none], obj.get("approveAllReadPermissionRequests")) + approve_all_tool_permission_requests = from_union([from_bool, from_none], obj.get("approveAllToolPermissionRequests")) + paths = from_union([PermissionPathsConfig.from_dict, from_none], obj.get("paths")) + rules = from_union([PermissionRulesSet.from_dict, from_none], obj.get("rules")) + urls = from_union([PermissionUrlsConfig.from_dict, from_none], obj.get("urls")) + return PermissionsConfigureParams(additional_content_exclusion_policies, approve_all_read_permission_requests, approve_all_tool_permission_requests, paths, rules, urls) + + def to_dict(self) -> dict: + result: dict = {} + if self.additional_content_exclusion_policies is not None: + result["additionalContentExclusionPolicies"] = from_union([lambda x: from_list(lambda x: to_class(PermissionsConfigureAdditionalContentExclusionPolicy, x), x), from_none], self.additional_content_exclusion_policies) + if self.approve_all_read_permission_requests is not None: + result["approveAllReadPermissionRequests"] = from_union([from_bool, from_none], self.approve_all_read_permission_requests) + if self.approve_all_tool_permission_requests is not None: + result["approveAllToolPermissionRequests"] = from_union([from_bool, from_none], self.approve_all_tool_permission_requests) + if self.paths is not None: + result["paths"] = from_union([lambda x: to_class(PermissionPathsConfig, x), from_none], self.paths) + if self.rules is not None: + result["rules"] = from_union([lambda x: to_class(PermissionRulesSet, x), from_none], self.rules) + if self.urls is not None: + result["urls"] = from_union([lambda x: to_class(PermissionUrlsConfig, x), from_none], self.urls) + return result + +@dataclass +class SendRequest: + """Parameters for sending a user message to the session""" + + prompt: str + """The user message text""" + + agent_mode: SendAgentMode | None = None + """The UI mode the agent was in when this message was sent. Defaults to the session's + current mode. + """ + attachments: list[SendAttachment] | None = None + """Optional attachments (files, directories, selections, blobs, GitHub references) to + include with the message + """ + billable: bool | None = None + """If false, this message will not trigger a Premium Request Unit charge. User messages + default to billable. + """ + display_prompt: str | None = None + """If provided, this is shown in the timeline instead of `prompt`""" + + mode: SendMode | None = None + """How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` + interjects during an in-progress turn. + """ + prepend: bool | None = None + """If true, adds the message to the front of the queue instead of the end""" + + request_headers: dict[str, str] | None = None + """Custom HTTP headers to include in outbound model requests for this turn. Merged with + session-level provider headers; per-turn headers augment and overwrite session-level + headers with the same key. + """ + required_tool: str | None = None + """If set, the request will fail if the named tool is not available when this message is + among the user messages at the start of the current exchange + """ + source: Any = None + """Optional provenance tag copied to the resulting user.message event. Supported values are + `system`, `command-*`, and `schedule-*`. + """ + traceparent: str | None = None + """W3C Trace Context traceparent header for distributed tracing of this agent turn""" + + tracestate: str | None = None + """W3C Trace Context tracestate header for distributed tracing""" + + wait: bool | None = None + """If true, await completion of the agentic loop for this message before returning. Defaults + to false (fire-and-forget). When true, the result still contains the same `messageId`; + the caller can rely on the agent having processed the message before the call resolves. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SendRequest': + assert isinstance(obj, dict) + prompt = from_str(obj.get("prompt")) + agent_mode = from_union([SendAgentMode, from_none], obj.get("agentMode")) + attachments = from_union([lambda x: from_list(SendAttachment.from_dict, x), from_none], obj.get("attachments")) + billable = from_union([from_bool, from_none], obj.get("billable")) + display_prompt = from_union([from_str, from_none], obj.get("displayPrompt")) + mode = from_union([SendMode, from_none], obj.get("mode")) + prepend = from_union([from_bool, from_none], obj.get("prepend")) + request_headers = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("requestHeaders")) + required_tool = from_union([from_str, from_none], obj.get("requiredTool")) + source = obj.get("source") + traceparent = from_union([from_str, from_none], obj.get("traceparent")) + tracestate = from_union([from_str, from_none], obj.get("tracestate")) + wait = from_union([from_bool, from_none], obj.get("wait")) + return SendRequest(prompt, agent_mode, attachments, billable, display_prompt, mode, prepend, request_headers, required_tool, source, traceparent, tracestate, wait) + + def to_dict(self) -> dict: + result: dict = {} + result["prompt"] = from_str(self.prompt) + if self.agent_mode is not None: + result["agentMode"] = from_union([lambda x: to_enum(SendAgentMode, x), from_none], self.agent_mode) + if self.attachments is not None: + result["attachments"] = from_union([lambda x: from_list(lambda x: to_class(SendAttachment, x), x), from_none], self.attachments) + if self.billable is not None: + result["billable"] = from_union([from_bool, from_none], self.billable) + if self.display_prompt is not None: + result["displayPrompt"] = from_union([from_str, from_none], self.display_prompt) + if self.mode is not None: + result["mode"] = from_union([lambda x: to_enum(SendMode, x), from_none], self.mode) + if self.prepend is not None: + result["prepend"] = from_union([from_bool, from_none], self.prepend) + if self.request_headers is not None: + result["requestHeaders"] = from_union([lambda x: from_dict(from_str, x), from_none], self.request_headers) + if self.required_tool is not None: + result["requiredTool"] = from_union([from_str, from_none], self.required_tool) + if self.source is not None: + result["source"] = self.source + if self.traceparent is not None: + result["traceparent"] = from_union([from_str, from_none], self.traceparent) + if self.tracestate is not None: + result["tracestate"] = from_union([from_str, from_none], self.tracestate) + if self.wait is not None: + result["wait"] = from_union([from_bool, from_none], self.wait) + return result + +@dataclass +class UIElicitationSchema: + """JSON Schema describing the form fields to present to the user""" + + properties: dict[str, UIElicitationSchemaProperty] + """Form field definitions, keyed by field name""" + + type: UIElicitationSchemaType + """Schema type indicator (always 'object')""" + + required: list[str] | None = None + """List of required field names""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationSchema': + assert isinstance(obj, dict) + properties = from_dict(UIElicitationSchemaProperty.from_dict, obj.get("properties")) + type = UIElicitationSchemaType(obj.get("type")) + required = from_union([lambda x: from_list(from_str, x), from_none], obj.get("required")) + return UIElicitationSchema(properties, type, required) + + def to_dict(self) -> dict: + result: dict = {} + result["properties"] = from_dict(lambda x: to_class(UIElicitationSchemaProperty, x), self.properties) + result["type"] = to_enum(UIElicitationSchemaType, self.type) + if self.required is not None: + result["required"] = from_union([lambda x: from_list(from_str, x), from_none], self.required) + return result + +@dataclass +class AuthInfo: + """The new auth credentials to install on the session. When omitted or `undefined`, the call + is a no-op and the session's existing credentials are preserved. The runtime stores the + value verbatim and uses it for outbound model/API requests; it does NOT re-validate or + re-fetch the associated Copilot user response. Several variants carry secret material; + treat this method's params as containing secrets at rest and in transit. + + Schema for the `HMACAuthInfo` type. + + Schema for the `EnvAuthInfo` type. + + Schema for the `TokenAuthInfo` type. + + Schema for the `CopilotApiTokenAuthInfo` type. + + Schema for the `UserAuthInfo` type. + + Schema for the `GhCliAuthInfo` type. + + Schema for the `ApiKeyAuthInfo` type. + """ + host: str + """Authentication host. HMAC auth always targets the public GitHub host. + + Authentication host (e.g. https://github.com or a GHES host). + + Authentication host. + + Authentication host (always the public GitHub host). + """ + type: AuthInfoType + """HMAC-based authentication used by GitHub-internal services. + + Personal access token (PAT) or server-to-server token sourced from an environment + variable. + + SDK-side token authentication; the host configured the token directly via the SDK. + + Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` + environment-variable pair. The token itself is read from the environment by the runtime, + not carried in this struct. + + OAuth user authentication. The token itself is held in the runtime's secret token store + (keyed by host+login) and is NOT carried in this struct. + + Authentication via the `gh` CLI's saved credentials. + + API-key authentication for non-GitHub LLM providers (e.g. when running BYOM-style). + """ + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the + GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this + verbatim and does not re-fetch when set. + """ + hmac: str | None = None + """HMAC secret used to sign requests.""" + + env_var: str | None = None + """Name of the environment variable the token was sourced from.""" + + login: str | None = None + """User login associated with the token. Undefined for server-to-server tokens (those + starting with `ghs_`). + + OAuth user login. + + User login as reported by `gh auth status`. + """ + token: str | None = None + """The token value itself. Treat as a secret. + + The token returned by `gh auth token`. Treat as a secret. + """ + api_key: str | None = None + """The API key. Treat as a secret.""" + + @staticmethod + def from_dict(obj: Any) -> 'AuthInfo': + assert isinstance(obj, dict) + host = from_str(obj.get("host")) + type = AuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + hmac = from_union([from_str, from_none], obj.get("hmac")) + env_var = from_union([from_str, from_none], obj.get("envVar")) + login = from_union([from_str, from_none], obj.get("login")) + token = from_union([from_str, from_none], obj.get("token")) + api_key = from_union([from_str, from_none], obj.get("apiKey")) + return AuthInfo(host, type, copilot_user, hmac, env_var, login, token, api_key) + + def to_dict(self) -> dict: + result: dict = {} + result["host"] = from_str(self.host) + result["type"] = to_enum(AuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + if self.hmac is not None: + result["hmac"] = from_union([from_str, from_none], self.hmac) + if self.env_var is not None: + result["envVar"] = from_union([from_str, from_none], self.env_var) + if self.login is not None: + result["login"] = from_union([from_str, from_none], self.login) + if self.token is not None: + result["token"] = from_union([from_str, from_none], self.token) + if self.api_key is not None: + result["apiKey"] = from_union([from_str, from_none], self.api_key) + return result + +@dataclass +class PermissionDecisionApproveForLocation: + """Schema for the `PermissionDecisionApproveForLocation` type.""" + + approval: PermissionDecisionApproveForLocationApproval + """Approval to persist for this location""" + + kind: PermissionDecisionApproveForLocationKind + """Approve and persist for this project location""" + + location_key: str + """Location key (git root or cwd) to persist the approval to""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForLocation': + assert isinstance(obj, dict) + approval = PermissionDecisionApproveForLocationApproval.from_dict(obj.get("approval")) + kind = PermissionDecisionApproveForLocationKind(obj.get("kind")) + location_key = from_str(obj.get("locationKey")) + return PermissionDecisionApproveForLocation(approval, kind, location_key) + + def to_dict(self) -> dict: + result: dict = {} + result["approval"] = to_class(PermissionDecisionApproveForLocationApproval, self.approval) + result["kind"] = to_enum(PermissionDecisionApproveForLocationKind, self.kind) + result["locationKey"] = from_str(self.location_key) + return result + +@dataclass +class PermissionDecisionApproveForSession: + """Schema for the `PermissionDecisionApproveForSession` type.""" + + kind: PermissionDecisionApproveForSessionKind + """Approve and remember for the rest of the session""" + + approval: PermissionDecisionApproveForSessionApproval | None = None + """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts)""" + + domain: str | None = None + """URL domain to approve for the rest of the session (URL prompts only)""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionApproveForSession': + assert isinstance(obj, dict) + kind = PermissionDecisionApproveForSessionKind(obj.get("kind")) + approval = from_union([PermissionDecisionApproveForSessionApproval.from_dict, from_none], obj.get("approval")) + domain = from_union([from_str, from_none], obj.get("domain")) + return PermissionDecisionApproveForSession(kind, approval, domain) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionApproveForSessionKind, self.kind) + if self.approval is not None: + result["approval"] = from_union([lambda x: to_class(PermissionDecisionApproveForSessionApproval, x), from_none], self.approval) + if self.domain is not None: + result["domain"] = from_union([from_str, from_none], self.domain) + return result + +@dataclass +class HandlePendingToolCallRequest: + """Pending external tool call request ID, with the tool result or an error describing why it + failed. + """ + request_id: str + """Request ID of the pending tool call""" + + error: str | None = None + """Error message if the tool call failed""" + + result: ExternalToolTextResultForLlm | str | None = None + """Tool call result (string or expanded result object)""" + + @staticmethod + def from_dict(obj: Any) -> 'HandlePendingToolCallRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + error = from_union([from_str, from_none], obj.get("error")) + result = from_union([ExternalToolTextResultForLlm.from_dict, from_str, from_none], obj.get("result")) + return HandlePendingToolCallRequest(request_id, error, result) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.result is not None: + result["result"] = from_union([lambda x: to_class(ExternalToolTextResultForLlm, x), from_str, from_none], self.result) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionsSetAdditionalPluginsRequest: + """Manager-wide additional plugins to register; replaces any previously-configured set.""" + + plugins: list[InstalledPlugin] + """Manager-wide additional plugins to register. Replaces any previously-configured set. Pass + an empty array to clear. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionsSetAdditionalPluginsRequest': + assert isinstance(obj, dict) + plugins = from_list(InstalledPlugin.from_dict, obj.get("plugins")) + return SessionsSetAdditionalPluginsRequest(plugins) + + def to_dict(self) -> dict: + result: dict = {} + result["plugins"] = from_list(lambda x: to_class(InstalledPlugin, x), self.plugins) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionUpdateOptionsParams: + """Patch of mutable session options to apply to the running session.""" + + additional_content_exclusion_policies: list[Any] | None = None + """Additional content-exclusion policies to merge into the session's policy set. Opaque + shape; see `ContentExclusionApiResponse` in the runtime. + """ + agent_context: str | None = None + """Runtime context discriminator (e.g., `cli`, `actions`).""" + + ask_user_disabled: bool | None = None + """Whether to disable the `ask_user` tool (encourages autonomous behavior).""" + + available_tools: list[str] | None = None + """Allowlist of tool names available to this session.""" + + client_name: str | None = None + """Identifier of the client driving the session.""" + + coauthor_enabled: bool | None = None + """Whether to include the `Co-authored-by` trailer in commit messages.""" + + continue_on_auto_mode: bool | None = None + """Whether to allow auto-mode continuation across turns.""" + + copilot_url: str | None = None + """Override URL for the Copilot API endpoint.""" + + custom_agents_local_only: bool | None = None + """Whether to default custom agents to local-only execution.""" + + disabled_instruction_sources: list[str] | None = None + """Instruction source IDs to exclude from the system prompt.""" + + disabled_skills: list[str] | None = None + """Skill IDs that should be excluded from this session.""" + + enable_on_demand_instruction_discovery: bool | None = None + """Whether to discover custom instructions on demand after successful file views (AGENTS.md + / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with + `skipCustomInstructions` and the runtime-side `ON_DEMAND_INSTRUCTIONS` feature flag. + """ + enable_reasoning_summaries: bool | None = None + """Whether to surface reasoning-summary events from the model.""" + + enable_script_safety: bool | None = None + """Whether shell-script safety heuristics are enabled.""" + + enable_streaming: bool | None = None + """Whether to stream model responses.""" + + env_value_mode: MCPSetEnvValueModeDetails | None = None + """How env values are passed to MCP servers (`direct` inlines literal values; `indirect` + resolves at launch). + """ + events_log_directory: str | None = None + """Override directory for the session-events log. When unset, the runtime's default events + log directory is used. + """ + excluded_tools: list[str] | None = None + """Denylist of tool names for this session.""" + + feature_flags: dict[str, bool] | None = None + """Map of feature-flag IDs to their boolean enabled state.""" + + installed_plugins: list[SessionInstalledPlugin] | None = None + """Full set of installed plugins for the session. Replaces the existing list; the runtime + invalidates the skills cache only when the list materially changes. + """ + integration_id: str | None = None + """Stable integration identifier used for analytics and rate-limit attribution.""" + + is_experimental_mode: bool | None = None + """Whether experimental capabilities are enabled.""" + + log_interactive_shells: bool | None = None + """Whether interactive shell sessions are logged.""" + + lsp_client_name: str | None = None + """Identifier sent to LSP-style integrations.""" + + manage_schedule_enabled: bool | None = None + """Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the + per-session schedule registry; this flag only controls tool exposure (typically gated to + staff users). + """ + model: str | None = None + """The model ID to use for assistant turns.""" + + provider: Any = None + """Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the + runtime. + """ + reasoning_effort: str | None = None + """Reasoning effort for the selected model (model-defined enum).""" + + running_in_interactive_mode: bool | None = None + """Whether the session is running in an interactive UI.""" + + sandbox_config: Any = None + """Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime.""" + + shell_init_profile: str | None = None + """Shell init profile (`None` or `NonInteractive`).""" + + shell_process_flags: list[str] | None = None + """Per-shell process flags (e.g., `pwsh` arguments).""" + + skill_directories: list[str] | None = None + """Additional directories to search for skills.""" + + skip_custom_instructions: bool | None = None + """Whether to skip loading custom instruction sources.""" + + trajectory_file: str | None = None + """Optional path for trajectory output.""" + + working_directory: str | None = None + """Absolute working-directory path for shell tools.""" + + @staticmethod + def from_dict(obj: Any) -> 'SessionUpdateOptionsParams': + assert isinstance(obj, dict) + additional_content_exclusion_policies = from_union([lambda x: from_list(lambda x: x, x), from_none], obj.get("additionalContentExclusionPolicies")) + agent_context = from_union([from_str, from_none], obj.get("agentContext")) + ask_user_disabled = from_union([from_bool, from_none], obj.get("askUserDisabled")) + available_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("availableTools")) + client_name = from_union([from_str, from_none], obj.get("clientName")) + coauthor_enabled = from_union([from_bool, from_none], obj.get("coauthorEnabled")) + continue_on_auto_mode = from_union([from_bool, from_none], obj.get("continueOnAutoMode")) + copilot_url = from_union([from_str, from_none], obj.get("copilotUrl")) + custom_agents_local_only = from_union([from_bool, from_none], obj.get("customAgentsLocalOnly")) + disabled_instruction_sources = from_union([lambda x: from_list(from_str, x), from_none], obj.get("disabledInstructionSources")) + disabled_skills = from_union([lambda x: from_list(from_str, x), from_none], obj.get("disabledSkills")) + enable_on_demand_instruction_discovery = from_union([from_bool, from_none], obj.get("enableOnDemandInstructionDiscovery")) + enable_reasoning_summaries = from_union([from_bool, from_none], obj.get("enableReasoningSummaries")) + enable_script_safety = from_union([from_bool, from_none], obj.get("enableScriptSafety")) + enable_streaming = from_union([from_bool, from_none], obj.get("enableStreaming")) + env_value_mode = from_union([MCPSetEnvValueModeDetails, from_none], obj.get("envValueMode")) + events_log_directory = from_union([from_str, from_none], obj.get("eventsLogDirectory")) + excluded_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludedTools")) + feature_flags = from_union([lambda x: from_dict(from_bool, x), from_none], obj.get("featureFlags")) + installed_plugins = from_union([lambda x: from_list(SessionInstalledPlugin.from_dict, x), from_none], obj.get("installedPlugins")) + integration_id = from_union([from_str, from_none], obj.get("integrationId")) + is_experimental_mode = from_union([from_bool, from_none], obj.get("isExperimentalMode")) + log_interactive_shells = from_union([from_bool, from_none], obj.get("logInteractiveShells")) + lsp_client_name = from_union([from_str, from_none], obj.get("lspClientName")) + manage_schedule_enabled = from_union([from_bool, from_none], obj.get("manageScheduleEnabled")) + model = from_union([from_str, from_none], obj.get("model")) + provider = obj.get("provider") + reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) + running_in_interactive_mode = from_union([from_bool, from_none], obj.get("runningInInteractiveMode")) + sandbox_config = obj.get("sandboxConfig") + shell_init_profile = from_union([from_str, from_none], obj.get("shellInitProfile")) + shell_process_flags = from_union([lambda x: from_list(from_str, x), from_none], obj.get("shellProcessFlags")) + skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) + skip_custom_instructions = from_union([from_bool, from_none], obj.get("skipCustomInstructions")) + trajectory_file = from_union([from_str, from_none], obj.get("trajectoryFile")) + working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) + return SessionUpdateOptionsParams(additional_content_exclusion_policies, agent_context, ask_user_disabled, available_tools, client_name, coauthor_enabled, continue_on_auto_mode, copilot_url, custom_agents_local_only, disabled_instruction_sources, disabled_skills, enable_on_demand_instruction_discovery, enable_reasoning_summaries, enable_script_safety, enable_streaming, env_value_mode, events_log_directory, excluded_tools, feature_flags, installed_plugins, integration_id, is_experimental_mode, log_interactive_shells, lsp_client_name, manage_schedule_enabled, model, provider, reasoning_effort, running_in_interactive_mode, sandbox_config, shell_init_profile, shell_process_flags, skill_directories, skip_custom_instructions, trajectory_file, working_directory) + + def to_dict(self) -> dict: + result: dict = {} + if self.additional_content_exclusion_policies is not None: + result["additionalContentExclusionPolicies"] = from_union([lambda x: from_list(lambda x: x, x), from_none], self.additional_content_exclusion_policies) + if self.agent_context is not None: + result["agentContext"] = from_union([from_str, from_none], self.agent_context) + if self.ask_user_disabled is not None: + result["askUserDisabled"] = from_union([from_bool, from_none], self.ask_user_disabled) + if self.available_tools is not None: + result["availableTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.available_tools) + if self.client_name is not None: + result["clientName"] = from_union([from_str, from_none], self.client_name) + if self.coauthor_enabled is not None: + result["coauthorEnabled"] = from_union([from_bool, from_none], self.coauthor_enabled) + if self.continue_on_auto_mode is not None: + result["continueOnAutoMode"] = from_union([from_bool, from_none], self.continue_on_auto_mode) + if self.copilot_url is not None: + result["copilotUrl"] = from_union([from_str, from_none], self.copilot_url) + if self.custom_agents_local_only is not None: + result["customAgentsLocalOnly"] = from_union([from_bool, from_none], self.custom_agents_local_only) + if self.disabled_instruction_sources is not None: + result["disabledInstructionSources"] = from_union([lambda x: from_list(from_str, x), from_none], self.disabled_instruction_sources) + if self.disabled_skills is not None: + result["disabledSkills"] = from_union([lambda x: from_list(from_str, x), from_none], self.disabled_skills) + if self.enable_on_demand_instruction_discovery is not None: + result["enableOnDemandInstructionDiscovery"] = from_union([from_bool, from_none], self.enable_on_demand_instruction_discovery) + if self.enable_reasoning_summaries is not None: + result["enableReasoningSummaries"] = from_union([from_bool, from_none], self.enable_reasoning_summaries) + if self.enable_script_safety is not None: + result["enableScriptSafety"] = from_union([from_bool, from_none], self.enable_script_safety) + if self.enable_streaming is not None: + result["enableStreaming"] = from_union([from_bool, from_none], self.enable_streaming) + if self.env_value_mode is not None: + result["envValueMode"] = from_union([lambda x: to_enum(MCPSetEnvValueModeDetails, x), from_none], self.env_value_mode) + if self.events_log_directory is not None: + result["eventsLogDirectory"] = from_union([from_str, from_none], self.events_log_directory) + if self.excluded_tools is not None: + result["excludedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.excluded_tools) + if self.feature_flags is not None: + result["featureFlags"] = from_union([lambda x: from_dict(from_bool, x), from_none], self.feature_flags) + if self.installed_plugins is not None: + result["installedPlugins"] = from_union([lambda x: from_list(lambda x: to_class(SessionInstalledPlugin, x), x), from_none], self.installed_plugins) + if self.integration_id is not None: + result["integrationId"] = from_union([from_str, from_none], self.integration_id) + if self.is_experimental_mode is not None: + result["isExperimentalMode"] = from_union([from_bool, from_none], self.is_experimental_mode) + if self.log_interactive_shells is not None: + result["logInteractiveShells"] = from_union([from_bool, from_none], self.log_interactive_shells) + if self.lsp_client_name is not None: + result["lspClientName"] = from_union([from_str, from_none], self.lsp_client_name) + if self.manage_schedule_enabled is not None: + result["manageScheduleEnabled"] = from_union([from_bool, from_none], self.manage_schedule_enabled) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) + if self.provider is not None: + result["provider"] = self.provider + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) + if self.running_in_interactive_mode is not None: + result["runningInInteractiveMode"] = from_union([from_bool, from_none], self.running_in_interactive_mode) + if self.sandbox_config is not None: + result["sandboxConfig"] = self.sandbox_config + if self.shell_init_profile is not None: + result["shellInitProfile"] = from_union([from_str, from_none], self.shell_init_profile) + if self.shell_process_flags is not None: + result["shellProcessFlags"] = from_union([lambda x: from_list(from_str, x), from_none], self.shell_process_flags) + if self.skill_directories is not None: + result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) + if self.skip_custom_instructions is not None: + result["skipCustomInstructions"] = from_union([from_bool, from_none], self.skip_custom_instructions) + if self.trajectory_file is not None: + result["trajectoryFile"] = from_union([from_str, from_none], self.trajectory_file) + if self.working_directory is not None: + result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) + return result + +@dataclass +class UIElicitationRequest: + """Prompt message and JSON schema describing the form fields to elicit from the user.""" + + message: str + """Message describing what information is needed from the user""" + + requested_schema: UIElicitationSchema + """JSON Schema describing the form fields to present to the user""" + + @staticmethod + def from_dict(obj: Any) -> 'UIElicitationRequest': + assert isinstance(obj, dict) + message = from_str(obj.get("message")) + requested_schema = UIElicitationSchema.from_dict(obj.get("requestedSchema")) + return UIElicitationRequest(message, requested_schema) + + def to_dict(self) -> dict: + result: dict = {} + result["message"] = from_str(self.message) + result["requestedSchema"] = to_class(UIElicitationSchema, self.requested_schema) + return result + +@dataclass +class SessionSetCredentialsParams: + """New auth credentials to install on the session. Omit to leave credentials unchanged.""" + + credentials: AuthInfo | None = None + """The new auth credentials to install on the session. When omitted or `undefined`, the call + is a no-op and the session's existing credentials are preserved. The runtime stores the + value verbatim and uses it for outbound model/API requests; it does NOT re-validate or + re-fetch the associated Copilot user response. Several variants carry secret material; + treat this method's params as containing secrets at rest and in transit. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionSetCredentialsParams': + assert isinstance(obj, dict) + credentials = from_union([AuthInfo.from_dict, from_none], obj.get("credentials")) + return SessionSetCredentialsParams(credentials) + + def to_dict(self) -> dict: + result: dict = {} + if self.credentials is not None: + result["credentials"] = from_union([lambda x: to_class(AuthInfo, x), from_none], self.credentials) + return result + +@dataclass +class PermissionDecision: + """The client's response to the pending permission prompt + + Schema for the `PermissionDecisionApproveOnce` type. + + Schema for the `PermissionDecisionApproveForSession` type. + + Schema for the `PermissionDecisionApproveForLocation` type. + + Schema for the `PermissionDecisionApprovePermanently` type. + + Schema for the `PermissionDecisionReject` type. + + Schema for the `PermissionDecisionUserNotAvailable` type. + + Schema for the `PermissionDecisionApproved` type. + + Schema for the `PermissionDecisionApprovedForSession` type. + + Schema for the `PermissionDecisionApprovedForLocation` type. + + Schema for the `PermissionDecisionCancelled` type. + + Schema for the `PermissionDecisionDeniedByRules` type. + + Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type. + + Schema for the `PermissionDecisionDeniedInteractivelyByUser` type. + + Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type. + + Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type. + """ + kind: PermissionDecisionKind + """Approve this single request only + + Approve and remember for the rest of the session + + Approve and persist for this project location + + Approve and persist across sessions (URL prompts only) + + Reject the request + + No user is available to confirm the request + + The permission request was approved + + Approved and remembered for the rest of the session + + Approved and persisted for this project location + + The permission request was cancelled before a response was used + + Denied because approval rules explicitly blocked it + + Denied because no approval rule matched and user confirmation was unavailable + + Denied by the user during an interactive prompt + + Denied by the organization's content exclusion policy + + Denied by a permission request hook registered by an extension or plugin + """ + approval: PermissionDecisionApproveForIonApproval | None = None + """Session-scoped approval to remember (tool prompts only; omitted for path/url prompts) + + Approval to persist for this location + + The approval to add as a session-scoped rule + + The approval to persist for this location + """ + domain: str | None = None + """URL domain to approve for the rest of the session (URL prompts only) + + URL domain to approve permanently + """ + location_key: str | None = None + """Location key (git root or cwd) to persist the approval to + + The location key (git root or cwd) to persist the approval to + """ + feedback: str | None = None + """Optional feedback explaining the rejection + + Optional feedback from the user explaining the denial + """ + reason: str | None = None + """Optional explanation of why the request was cancelled""" + + rules: list[PermissionRule] | None = None + """Rules that denied the request""" + + force_reject: bool | None = None + """Whether to force-reject the current agent turn""" + + message: str | None = None + """Human-readable explanation of why the path was excluded + + Optional message from the hook explaining the denial + """ + path: str | None = None + """File path that triggered the exclusion""" + + interrupt: bool | None = None + """Whether to interrupt the current agent turn""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecision': + assert isinstance(obj, dict) + kind = PermissionDecisionKind(obj.get("kind")) + approval = from_union([PermissionDecisionApproveForIonApproval.from_dict, from_none], obj.get("approval")) + domain = from_union([from_str, from_none], obj.get("domain")) + location_key = from_union([from_str, from_none], obj.get("locationKey")) + feedback = from_union([from_str, from_none], obj.get("feedback")) + reason = from_union([from_str, from_none], obj.get("reason")) + rules = from_union([lambda x: from_list(PermissionRule.from_dict, x), from_none], obj.get("rules")) + force_reject = from_union([from_bool, from_none], obj.get("forceReject")) + message = from_union([from_str, from_none], obj.get("message")) + path = from_union([from_str, from_none], obj.get("path")) + interrupt = from_union([from_bool, from_none], obj.get("interrupt")) + return PermissionDecision(kind, approval, domain, location_key, feedback, reason, rules, force_reject, message, path, interrupt) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(PermissionDecisionKind, self.kind) + if self.approval is not None: + result["approval"] = from_union([lambda x: to_class(PermissionDecisionApproveForIonApproval, x), from_none], self.approval) + if self.domain is not None: + result["domain"] = from_union([from_str, from_none], self.domain) + if self.location_key is not None: + result["locationKey"] = from_union([from_str, from_none], self.location_key) + if self.feedback is not None: + result["feedback"] = from_union([from_str, from_none], self.feedback) + if self.reason is not None: + result["reason"] = from_union([from_str, from_none], self.reason) + if self.rules is not None: + result["rules"] = from_union([lambda x: from_list(lambda x: to_class(PermissionRule, x), x), from_none], self.rules) + if self.force_reject is not None: + result["forceReject"] = from_union([from_bool, from_none], self.force_reject) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + if self.path is not None: + result["path"] = from_union([from_str, from_none], self.path) + if self.interrupt is not None: + result["interrupt"] = from_union([from_bool, from_none], self.interrupt) + return result + +@dataclass +class PermissionDecisionRequest: + """Pending permission request ID and the decision to apply (approve/reject and scope).""" + + request_id: str + """Request ID of the pending permission request""" + + result: PermissionDecision + """The client's response to the pending permission prompt""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionDecisionRequest': + assert isinstance(obj, dict) + request_id = from_str(obj.get("requestId")) + result = PermissionDecision.from_dict(obj.get("result")) + return PermissionDecisionRequest(request_id, result) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_str(self.request_id) + result["result"] = to_class(PermissionDecision, self.result) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MCPExecuteSamplingParams: + """Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference.""" + + mcp_request_id: float | str + """The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate + the inference with the originating MCP request for telemetry; this is distinct from + `requestId` (which is the schema-level cancellation handle). + """ + request: dict[str, Any] + """Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. + Treated as opaque at the schema layer; the runtime converts the embedded MCP messages + into the OpenAI chat-completion shape internally. + """ + request_id: str + """Caller-provided unique identifier for this sampling execution. Use this same ID with + cancelSamplingExecution to cancel the in-flight call. Must be unique within the session + for the lifetime of the call. + """ + server_name: str + """Name of the MCP server that initiated the sampling request""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPExecuteSamplingParams': + assert isinstance(obj, dict) + mcp_request_id = from_union([from_float, from_str], obj.get("mcpRequestId")) + request = from_dict(lambda x: x, obj.get("request")) + request_id = from_str(obj.get("requestId")) + server_name = from_str(obj.get("serverName")) + return MCPExecuteSamplingParams(mcp_request_id, request, request_id, server_name) + + def to_dict(self) -> dict: + result: dict = {} + result["mcpRequestId"] = from_union([to_float, from_str], self.mcp_request_id) + result["request"] = from_dict(lambda x: x, self.request) + result["requestId"] = from_str(self.request_id) + result["serverName"] = from_str(self.server_name) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataContextInfoRequest: + """Model identifier and token limits used to compute the context-info breakdown.""" + + output_token_limit: int + """Maximum output tokens allowed by the target model. Pass 0 if unknown.""" + + prompt_token_limit: int + """Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default.""" + + selected_model: str | None = None + """Model identifier used for tokenization. Omit to use the session default. Used both for + token counting and to compute display values. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MetadataContextInfoRequest': + assert isinstance(obj, dict) + output_token_limit = from_int(obj.get("outputTokenLimit")) + prompt_token_limit = from_int(obj.get("promptTokenLimit")) + selected_model = from_union([from_str, from_none], obj.get("selectedModel")) + return MetadataContextInfoRequest(output_token_limit, prompt_token_limit, selected_model) + + def to_dict(self) -> dict: + result: dict = {} + result["outputTokenLimit"] = from_int(self.output_token_limit) + result["promptTokenLimit"] = from_int(self.prompt_token_limit) + if self.selected_model is not None: + result["selectedModel"] = from_union([from_str, from_none], self.selected_model) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class MetadataRecomputeContextTokensRequest: + """Model identifier to use when re-tokenizing the session's existing messages.""" + + model_id: str + """Model identifier used for tokenization. The runtime token-counts both chat-context and + system-context messages against this model. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MetadataRecomputeContextTokensRequest': + assert isinstance(obj, dict) + model_id = from_str(obj.get("modelId")) + return MetadataRecomputeContextTokensRequest(model_id) + + def to_dict(self) -> dict: + result: dict = {} + result["modelId"] = from_str(self.model_id) + return result + +@dataclass +class ModelCapabilities: + """Model capabilities and limits""" + + limits: ModelCapabilitiesLimits | None = None + """Token limits for prompts, outputs, and context window""" + + supports: ModelCapabilitiesSupports | None = None + """Feature flags indicating what the model supports""" + + @staticmethod + def from_dict(obj: Any) -> 'ModelCapabilities': + assert isinstance(obj, dict) + limits = from_union([ModelCapabilitiesLimits.from_dict, from_none], obj.get("limits")) + supports = from_union([ModelCapabilitiesSupports.from_dict, from_none], obj.get("supports")) + return ModelCapabilities(limits, supports) + + def to_dict(self) -> dict: + result: dict = {} + if self.limits is not None: + result["limits"] = from_union([lambda x: to_class(ModelCapabilitiesLimits, x), from_none], self.limits) + if self.supports is not None: + result["supports"] = from_union([lambda x: to_class(ModelCapabilitiesSupports, x), from_none], self.supports) + return result + +class ModelPickerCategory(Enum): + """Model capability category for grouping in the model picker""" + + LIGHTWEIGHT = "lightweight" + POWERFUL = "powerful" + VERSATILE = "versatile" + +@dataclass +class Model: + """Schema for the `Model` type.""" + + capabilities: ModelCapabilities + """Model capabilities and limits""" + + id: str + """Model identifier (e.g., "claude-sonnet-4.5")""" + + name: str + """Display name""" + + billing: ModelBilling | None = None + """Billing information""" + + default_reasoning_effort: str | None = None + """Default reasoning effort level (only present if model supports reasoning effort)""" + + model_picker_category: ModelPickerCategory | None = None + """Model capability category for grouping in the model picker""" + + model_picker_price_category: ModelPickerPriceCategory | None = None + """Relative cost tier for token-based billing users""" + + policy: ModelPolicy | None = None + """Policy state (if applicable)""" + + supported_reasoning_efforts: list[str] | None = None + """Supported reasoning effort levels (only present if model supports reasoning effort)""" + + @staticmethod + def from_dict(obj: Any) -> 'Model': + assert isinstance(obj, dict) + capabilities = ModelCapabilities.from_dict(obj.get("capabilities")) + id = from_str(obj.get("id")) + name = from_str(obj.get("name")) + billing = from_union([ModelBilling.from_dict, from_none], obj.get("billing")) + default_reasoning_effort = from_union([from_str, from_none], obj.get("defaultReasoningEffort")) + model_picker_category = from_union([ModelPickerCategory, from_none], obj.get("modelPickerCategory")) + model_picker_price_category = from_union([ModelPickerPriceCategory, from_none], obj.get("modelPickerPriceCategory")) + policy = from_union([ModelPolicy.from_dict, from_none], obj.get("policy")) + supported_reasoning_efforts = from_union([lambda x: from_list(from_str, x), from_none], obj.get("supportedReasoningEfforts")) + return Model(capabilities, id, name, billing, default_reasoning_effort, model_picker_category, model_picker_price_category, policy, supported_reasoning_efforts) + + def to_dict(self) -> dict: + result: dict = {} + result["capabilities"] = to_class(ModelCapabilities, self.capabilities) + result["id"] = from_str(self.id) + result["name"] = from_str(self.name) + if self.billing is not None: + result["billing"] = from_union([lambda x: to_class(ModelBilling, x), from_none], self.billing) + if self.default_reasoning_effort is not None: + result["defaultReasoningEffort"] = from_union([from_str, from_none], self.default_reasoning_effort) + if self.model_picker_category is not None: + result["modelPickerCategory"] = from_union([lambda x: to_enum(ModelPickerCategory, x), from_none], self.model_picker_category) + if self.model_picker_price_category is not None: + result["modelPickerPriceCategory"] = from_union([lambda x: to_enum(ModelPickerPriceCategory, x), from_none], self.model_picker_price_category) + if self.policy is not None: + result["policy"] = from_union([lambda x: to_class(ModelPolicy, x), from_none], self.policy) + if self.supported_reasoning_efforts is not None: + result["supportedReasoningEfforts"] = from_union([lambda x: from_list(from_str, x), from_none], self.supported_reasoning_efforts) + return result + +@dataclass +class ModelList: + """List of Copilot models available to the resolved user, including capabilities and billing + metadata. + """ + models: list[Model] + """List of available models with full metadata""" + + @staticmethod + def from_dict(obj: Any) -> 'ModelList': + assert isinstance(obj, dict) + models = from_list(Model.from_dict, obj.get("models")) + return ModelList(models) + + def to_dict(self) -> dict: + result: dict = {} + result["models"] = from_list(lambda x: to_class(Model, x), self.models) + return result + +@dataclass +class ModelSwitchToRequest: + """Target model identifier and optional reasoning effort, summary, and capability overrides.""" + + model_id: str + """Model identifier to switch to""" + + model_capabilities: ModelCapabilitiesOverride | None = None + """Override individual model capabilities resolved by the runtime""" + + reasoning_effort: str | None = None + """Reasoning effort level to use for the model. "none" disables reasoning.""" + + reasoning_summary: ReasoningSummary | None = None + """Reasoning summary mode to request for supported model clients""" + + @staticmethod + def from_dict(obj: Any) -> 'ModelSwitchToRequest': + assert isinstance(obj, dict) + model_id = from_str(obj.get("modelId")) + model_capabilities = from_union([ModelCapabilitiesOverride.from_dict, from_none], obj.get("modelCapabilities")) + reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) + reasoning_summary = from_union([ReasoningSummary, from_none], obj.get("reasoningSummary")) + return ModelSwitchToRequest(model_id, model_capabilities, reasoning_effort, reasoning_summary) + + def to_dict(self) -> dict: + result: dict = {} + result["modelId"] = from_str(self.model_id) + if self.model_capabilities is not None: + result["modelCapabilities"] = from_union([lambda x: to_class(ModelCapabilitiesOverride, x), from_none], self.model_capabilities) + if self.reasoning_effort is not None: + result["reasoningEffort"] = from_union([from_str, from_none], self.reasoning_effort) + if self.reasoning_summary is not None: + result["reasoningSummary"] = from_union([lambda x: to_enum(ReasoningSummary, x), from_none], self.reasoning_summary) + return result + +class PermissionsSetApproveAllSource(Enum): + """Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.""" + + AUTOPILOT_CONFIRMATION = "autopilot_confirmation" + CLI_FLAG = "cli_flag" + RPC = "rpc" + SLASH_COMMAND = "slash_command" + +@dataclass +class PermissionsSetApproveAllRequest: + """Allow-all toggle for tool permission requests, with an optional telemetry source.""" + + enabled: bool + """Whether to auto-approve all tool permission requests""" + + source: PermissionsSetApproveAllSource | None = None + """Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.""" + + @staticmethod + def from_dict(obj: Any) -> 'PermissionsSetApproveAllRequest': + assert isinstance(obj, dict) + enabled = from_bool(obj.get("enabled")) + source = from_union([PermissionsSetApproveAllSource, from_none], obj.get("source")) + return PermissionsSetApproveAllRequest(enabled, source) + + def to_dict(self) -> dict: + result: dict = {} + result["enabled"] = from_bool(self.enabled) + if self.source is not None: + result["source"] = from_union([lambda x: to_enum(PermissionsSetApproveAllSource, x), from_none], self.source) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TaskAgentInfo: + """Schema for the `TaskAgentInfo` type.""" + + agent_type: str + """Type of agent running this task""" + + description: str + """Short description of the task""" + + id: str + """Unique task identifier""" + + prompt: str + """Prompt passed to the agent""" + + started_at: datetime + """ISO 8601 timestamp when the task was started""" + + status: TaskStatus + """Current lifecycle status of the task""" + + tool_call_id: str + """Tool call ID associated with this agent task""" + + type: TaskAgentInfoType + """Task kind""" + + active_started_at: datetime | None = None + """ISO 8601 timestamp when the current active period began""" + + active_time_ms: int | None = None + """Accumulated active execution time in milliseconds""" + + can_promote_to_background: bool | None = None + """Whether the task is currently in the original sync wait and can be moved to background + mode. False once it is already backgrounded, idle, finished, or no longer has a + promotable sync waiter. + """ + completed_at: datetime | None = None + """ISO 8601 timestamp when the task finished""" + + error: str | None = None + """Error message when the task failed""" + + execution_mode: TaskExecutionMode | None = None + """Whether task execution is synchronously awaited or managed in the background""" + + idle_since: datetime | None = None + """ISO 8601 timestamp when the agent entered idle state""" + + latest_response: str | None = None + """Most recent response text from the agent""" + + model: str | None = None + """Model used for the task when specified""" + + result: str | None = None + """Result text from the task when available""" + + @staticmethod + def from_dict(obj: Any) -> 'TaskAgentInfo': + assert isinstance(obj, dict) + agent_type = from_str(obj.get("agentType")) + description = from_str(obj.get("description")) + id = from_str(obj.get("id")) + prompt = from_str(obj.get("prompt")) + started_at = from_datetime(obj.get("startedAt")) + status = TaskStatus(obj.get("status")) + tool_call_id = from_str(obj.get("toolCallId")) + type = TaskAgentInfoType(obj.get("type")) + active_started_at = from_union([from_datetime, from_none], obj.get("activeStartedAt")) + active_time_ms = from_union([from_int, from_none], obj.get("activeTimeMs")) + can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) + completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) + error = from_union([from_str, from_none], obj.get("error")) + execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) + idle_since = from_union([from_datetime, from_none], obj.get("idleSince")) + latest_response = from_union([from_str, from_none], obj.get("latestResponse")) + model = from_union([from_str, from_none], obj.get("model")) + result = from_union([from_str, from_none], obj.get("result")) + return TaskAgentInfo(agent_type, description, id, prompt, started_at, status, tool_call_id, type, active_started_at, active_time_ms, can_promote_to_background, completed_at, error, execution_mode, idle_since, latest_response, model, result) + + def to_dict(self) -> dict: + result: dict = {} + result["agentType"] = from_str(self.agent_type) + result["description"] = from_str(self.description) + result["id"] = from_str(self.id) + result["prompt"] = from_str(self.prompt) + result["startedAt"] = self.started_at.isoformat() + result["status"] = to_enum(TaskStatus, self.status) + result["toolCallId"] = from_str(self.tool_call_id) + result["type"] = to_enum(TaskAgentInfoType, self.type) + if self.active_started_at is not None: + result["activeStartedAt"] = from_union([lambda x: x.isoformat(), from_none], self.active_started_at) + if self.active_time_ms is not None: + result["activeTimeMs"] = from_union([from_int, from_none], self.active_time_ms) + if self.can_promote_to_background is not None: + result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) + if self.completed_at is not None: + result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.execution_mode is not None: + result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) + if self.idle_since is not None: + result["idleSince"] = from_union([lambda x: x.isoformat(), from_none], self.idle_since) + if self.latest_response is not None: + result["latestResponse"] = from_union([from_str, from_none], self.latest_response) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) + if self.result is not None: + result["result"] = from_union([from_str, from_none], self.result) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TaskInfo: + """Schema for the `TaskInfo` type. + + The first sync-waiting task (agent first, then shell) that can currently be promoted to + background mode. Omitted if no such task exists. The returned task is guaranteed to have + executionMode='sync' and canPromoteToBackground=true at the time of the call. + + The promoted task as it now exists in background mode, omitted if no promotable task was + waiting. Atomic operation: avoids the race window of getCurrentPromotable + + promoteToBackground. + + Schema for the `TaskAgentInfo` type. + + Schema for the `TaskShellInfo` type. + """ + description: str + """Short description of the task""" + + id: str + """Unique task identifier""" + + started_at: datetime + """ISO 8601 timestamp when the task was started""" + + status: TaskStatus + """Current lifecycle status of the task""" + + type: TaskAgentProgressType + """Task kind""" + + active_started_at: datetime | None = None + """ISO 8601 timestamp when the current active period began""" + + active_time_ms: int | None = None + """Accumulated active execution time in milliseconds""" + + agent_type: str | None = None + """Type of agent running this task""" + + can_promote_to_background: bool | None = None + """Whether the task is currently in the original sync wait and can be moved to background + mode. False once it is already backgrounded, idle, finished, or no longer has a + promotable sync waiter. + + Whether this shell task can be promoted to background mode + """ + completed_at: datetime | None = None + """ISO 8601 timestamp when the task finished""" + + error: str | None = None + """Error message when the task failed""" + + execution_mode: TaskExecutionMode | None = None + """Whether task execution is synchronously awaited or managed in the background""" + + idle_since: datetime | None = None + """ISO 8601 timestamp when the agent entered idle state""" + + latest_response: str | None = None + """Most recent response text from the agent""" + + model: str | None = None + """Model used for the task when specified""" + + prompt: str | None = None + """Prompt passed to the agent""" + + result: str | None = None + """Result text from the task when available""" + + tool_call_id: str | None = None + """Tool call ID associated with this agent task""" + + attachment_mode: TaskShellInfoAttachmentMode | None = None + """Whether the shell runs inside a managed PTY session or as an independent background + process + """ + command: str | None = None + """Command being executed""" + + log_path: str | None = None + """Path to the detached shell log, when available""" + + pid: int | None = None + """Process ID when available""" + + @staticmethod + def from_dict(obj: Any) -> 'TaskInfo': + assert isinstance(obj, dict) + description = from_str(obj.get("description")) + id = from_str(obj.get("id")) + started_at = from_datetime(obj.get("startedAt")) + status = TaskStatus(obj.get("status")) + type = TaskAgentProgressType(obj.get("type")) + active_started_at = from_union([from_datetime, from_none], obj.get("activeStartedAt")) + active_time_ms = from_union([from_int, from_none], obj.get("activeTimeMs")) + agent_type = from_union([from_str, from_none], obj.get("agentType")) + can_promote_to_background = from_union([from_bool, from_none], obj.get("canPromoteToBackground")) + completed_at = from_union([from_datetime, from_none], obj.get("completedAt")) + error = from_union([from_str, from_none], obj.get("error")) + execution_mode = from_union([TaskExecutionMode, from_none], obj.get("executionMode")) + idle_since = from_union([from_datetime, from_none], obj.get("idleSince")) + latest_response = from_union([from_str, from_none], obj.get("latestResponse")) + model = from_union([from_str, from_none], obj.get("model")) + prompt = from_union([from_str, from_none], obj.get("prompt")) + result = from_union([from_str, from_none], obj.get("result")) + tool_call_id = from_union([from_str, from_none], obj.get("toolCallId")) + attachment_mode = from_union([TaskShellInfoAttachmentMode, from_none], obj.get("attachmentMode")) + command = from_union([from_str, from_none], obj.get("command")) + log_path = from_union([from_str, from_none], obj.get("logPath")) + pid = from_union([from_int, from_none], obj.get("pid")) + return TaskInfo(description, id, started_at, status, type, active_started_at, active_time_ms, agent_type, can_promote_to_background, completed_at, error, execution_mode, idle_since, latest_response, model, prompt, result, tool_call_id, attachment_mode, command, log_path, pid) + + def to_dict(self) -> dict: + result: dict = {} + result["description"] = from_str(self.description) + result["id"] = from_str(self.id) + result["startedAt"] = self.started_at.isoformat() + result["status"] = to_enum(TaskStatus, self.status) + result["type"] = to_enum(TaskAgentProgressType, self.type) + if self.active_started_at is not None: + result["activeStartedAt"] = from_union([lambda x: x.isoformat(), from_none], self.active_started_at) + if self.active_time_ms is not None: + result["activeTimeMs"] = from_union([from_int, from_none], self.active_time_ms) + if self.agent_type is not None: + result["agentType"] = from_union([from_str, from_none], self.agent_type) + if self.can_promote_to_background is not None: + result["canPromoteToBackground"] = from_union([from_bool, from_none], self.can_promote_to_background) + if self.completed_at is not None: + result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + if self.execution_mode is not None: + result["executionMode"] = from_union([lambda x: to_enum(TaskExecutionMode, x), from_none], self.execution_mode) + if self.idle_since is not None: + result["idleSince"] = from_union([lambda x: x.isoformat(), from_none], self.idle_since) + if self.latest_response is not None: + result["latestResponse"] = from_union([from_str, from_none], self.latest_response) + if self.model is not None: + result["model"] = from_union([from_str, from_none], self.model) + if self.prompt is not None: + result["prompt"] = from_union([from_str, from_none], self.prompt) + if self.result is not None: + result["result"] = from_union([from_str, from_none], self.result) + if self.tool_call_id is not None: + result["toolCallId"] = from_union([from_str, from_none], self.tool_call_id) + if self.attachment_mode is not None: + result["attachmentMode"] = from_union([lambda x: to_enum(TaskShellInfoAttachmentMode, x), from_none], self.attachment_mode) + if self.command is not None: + result["command"] = from_union([from_str, from_none], self.command) + if self.log_path is not None: + result["logPath"] = from_union([from_str, from_none], self.log_path) + if self.pid is not None: + result["pid"] = from_union([from_int, from_none], self.pid) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TaskList: + """Background tasks currently tracked by the session.""" + + tasks: list[TaskInfo] + """Currently tracked tasks""" + + @staticmethod + def from_dict(obj: Any) -> 'TaskList': + assert isinstance(obj, dict) + tasks = from_list(TaskInfo.from_dict, obj.get("tasks")) + return TaskList(tasks) + + def to_dict(self) -> dict: + result: dict = {} + result["tasks"] = from_list(lambda x: to_class(TaskInfo, x), self.tasks) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TasksGetCurrentPromotableResult: + """The first sync-waiting task that can currently be promoted to background mode.""" + + task: TaskInfo | None = None + """The first sync-waiting task (agent first, then shell) that can currently be promoted to + background mode. Omitted if no such task exists. The returned task is guaranteed to have + executionMode='sync' and canPromoteToBackground=true at the time of the call. + """ + + @staticmethod + def from_dict(obj: Any) -> 'TasksGetCurrentPromotableResult': + assert isinstance(obj, dict) + task = from_union([TaskInfo.from_dict, from_none], obj.get("task")) + return TasksGetCurrentPromotableResult(task) + + def to_dict(self) -> dict: + result: dict = {} + if self.task is not None: + result["task"] = from_union([lambda x: to_class(TaskInfo, x), from_none], self.task) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class TasksPromoteCurrentToBackgroundResult: + """The promoted task as it now exists in background mode, omitted if no promotable task was + waiting. + """ + task: TaskInfo | None = None + """The promoted task as it now exists in background mode, omitted if no promotable task was + waiting. Atomic operation: avoids the race window of getCurrentPromotable + + promoteToBackground. + """ + + @staticmethod + def from_dict(obj: Any) -> 'TasksPromoteCurrentToBackgroundResult': + assert isinstance(obj, dict) + task = from_union([TaskInfo.from_dict, from_none], obj.get("task")) + return TasksPromoteCurrentToBackgroundResult(task) + + def to_dict(self) -> dict: + result: dict = {} + if self.task is not None: + result["task"] = from_union([lambda x: to_class(TaskInfo, x), from_none], self.task) + return result + +@dataclass +class RPC: + abort_request: AbortRequest + abort_result: AbortResult + account_get_quota_request: AccountGetQuotaRequest + account_get_quota_result: AccountGetQuotaResult + account_quota_snapshot: AccountQuotaSnapshot + agent_get_current_result: AgentGetCurrentResult + agent_info: AgentInfo + agent_info_source: AgentInfoSource + agent_list: AgentList + agent_reload_result: AgentReloadResult + agent_select_request: AgentSelectRequest + agent_select_result: AgentSelectResult + api_key_auth_info: APIKeyAuthInfo + auth_info: AuthInfo + auth_info_type: AuthInfoType + command_list: CommandList + commands_handle_pending_command_request: CommandsHandlePendingCommandRequest + commands_handle_pending_command_result: CommandsHandlePendingCommandResult + commands_invoke_request: CommandsInvokeRequest + commands_list_request: CommandsListRequest + commands_respond_to_queued_command_request: CommandsRespondToQueuedCommandRequest + commands_respond_to_queued_command_result: CommandsRespondToQueuedCommandResult + connected_remote_session_metadata: ConnectedRemoteSessionMetadata + connected_remote_session_metadata_kind: ConnectedRemoteSessionMetadataKind + connected_remote_session_metadata_repository: ConnectedRemoteSessionMetadataRepository + connect_remote_session_params: ConnectRemoteSessionParams + connect_request: ConnectRequest + connect_result: ConnectResult + content_filter_mode: ContentFilterMode + copilot_api_token_auth_info: CopilotAPITokenAuthInfo + copilot_user_response: CopilotUserResponse + copilot_user_response_endpoints: CopilotUserResponseEndpoints + copilot_user_response_quota_snapshots: dict[str, CopilotUserResponseQuotaSnapshots | None] + copilot_user_response_quota_snapshots_chat: CopilotUserResponseQuotaSnapshotsChat + copilot_user_response_quota_snapshots_completions: CopilotUserResponseQuotaSnapshotsCompletions + copilot_user_response_quota_snapshots_premium_interactions: CopilotUserResponseQuotaSnapshotsPremiumInteractions + current_model: CurrentModel + discovered_mcp_server: DiscoveredMCPServer + discovered_mcp_server_type: DiscoveredMCPServerType + enqueue_command_params: EnqueueCommandParams + enqueue_command_result: EnqueueCommandResult + env_auth_info: EnvAuthInfo + event_log_read_request: EventLogReadRequest + event_log_release_interest_result: EventLogReleaseInterestResult + event_log_tail_result: EventLogTailResult + event_log_types: list[str] | EventLogTypes + events_agent_scope: EventsAgentScope + events_cursor_status: EventsCursorStatus + events_read_result: EventsReadResult + execute_command_params: ExecuteCommandParams + execute_command_result: ExecuteCommandResult + extension: Extension + extension_list: ExtensionList + extensions_disable_request: ExtensionsDisableRequest + extensions_enable_request: ExtensionsEnableRequest + extension_source: ExtensionSource + extension_status: ExtensionStatus + external_tool_result: ExternalToolTextResultForLlm | str + external_tool_text_result_for_llm: ExternalToolTextResultForLlm + external_tool_text_result_for_llm_binary_results_for_llm: ExternalToolTextResultForLlmBinaryResultsForLlm + external_tool_text_result_for_llm_binary_results_for_llm_type: ExternalToolTextResultForLlmBinaryResultsForLlmType + external_tool_text_result_for_llm_content: ExternalToolTextResultForLlmContent + external_tool_text_result_for_llm_content_audio: ExternalToolTextResultForLlmContentAudio + external_tool_text_result_for_llm_content_image: ExternalToolTextResultForLlmContentImage + external_tool_text_result_for_llm_content_resource: ExternalToolTextResultForLlmContentResource + external_tool_text_result_for_llm_content_resource_details: ExternalToolTextResultForLlmContentResourceDetails + external_tool_text_result_for_llm_content_resource_link: ExternalToolTextResultForLlmContentResourceLink + external_tool_text_result_for_llm_content_resource_link_icon: ExternalToolTextResultForLlmContentResourceLinkIcon + external_tool_text_result_for_llm_content_resource_link_icon_theme: ExternalToolTextResultForLlmContentResourceLinkIconTheme + external_tool_text_result_for_llm_content_terminal: ExternalToolTextResultForLlmContentTerminal + external_tool_text_result_for_llm_content_text: ExternalToolTextResultForLlmContentText + filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode + fleet_start_request: FleetStartRequest + fleet_start_result: FleetStartResult + gh_cli_auth_info: GhCLIAuthInfo + handle_pending_tool_call_request: HandlePendingToolCallRequest + handle_pending_tool_call_result: HandlePendingToolCallResult + history_abort_manual_compaction_result: HistoryAbortManualCompactionResult + history_cancel_background_compaction_result: HistoryCancelBackgroundCompactionResult + history_compact_context_window: HistoryCompactContextWindow + history_compact_result: HistoryCompactResult + history_summarize_for_handoff_result: HistorySummarizeForHandoffResult + history_truncate_request: HistoryTruncateRequest + history_truncate_result: HistoryTruncateResult + hmac_auth_info: HMACAuthInfo + installed_plugin: InstalledPlugin + installed_plugin_source: InstalledPluginSource | str + installed_plugin_source_github: InstalledPluginSourceGithub + installed_plugin_source_local: InstalledPluginSourceLocal + installed_plugin_source_url: InstalledPluginSourceURL + instructions_get_sources_result: InstructionsGetSourcesResult + instructions_sources: InstructionsSources + instructions_sources_location: InstructionsSourcesLocation + instructions_sources_type: InstructionsSourcesType + log_request: LogRequest + log_result: LogResult + lsp_initialize_request: LspInitializeRequest + mcp_cancel_sampling_execution_params: MCPCancelSamplingExecutionParams + mcp_cancel_sampling_execution_result: MCPCancelSamplingExecutionResult + mcp_config_add_request: MCPConfigAddRequest + mcp_config_disable_request: MCPConfigDisableRequest + mcp_config_enable_request: MCPConfigEnableRequest + mcp_config_list: MCPConfigList + mcp_config_remove_request: MCPConfigRemoveRequest + mcp_config_update_request: MCPConfigUpdateRequest + mcp_disable_request: MCPDisableRequest + mcp_discover_request: MCPDiscoverRequest + mcp_discover_result: MCPDiscoverResult + mcp_enable_request: MCPEnableRequest + mcp_execute_sampling_params: MCPExecuteSamplingParams + mcp_execute_sampling_request: dict[str, Any] + mcp_execute_sampling_result: dict[str, Any] + mcp_oauth_login_request: MCPOauthLoginRequest + mcp_oauth_login_result: MCPOauthLoginResult + mcp_remove_git_hub_result: MCPRemoveGitHubResult + mcp_sampling_execution_action: MCPSamplingExecutionAction + mcp_sampling_execution_result: MCPSamplingExecutionResult + mcp_server: MCPServer + mcp_server_config: MCPServerConfig + mcp_server_config_http: MCPServerConfigHTTP + mcp_server_config_http_auth: MCPServerConfigHTTPAuth + mcp_server_config_http_oauth_grant_type: MCPServerConfigHTTPOauthGrantType + mcp_server_config_http_type: MCPServerConfigHTTPType + mcp_server_config_stdio: MCPServerConfigStdio + mcp_server_list: MCPServerList + mcp_set_env_value_mode_details: MCPSetEnvValueModeDetails + mcp_set_env_value_mode_params: MCPSetEnvValueModeParams + mcp_set_env_value_mode_result: MCPSetEnvValueModeResult + metadata_context_info_request: MetadataContextInfoRequest + metadata_context_info_result: MetadataContextInfoResult + metadata_is_processing_result: MetadataIsProcessingResult + metadata_recompute_context_tokens_request: MetadataRecomputeContextTokensRequest + metadata_recompute_context_tokens_result: MetadataRecomputeContextTokensResult + metadata_record_context_change_request: MetadataRecordContextChangeRequest + metadata_record_context_change_result: MetadataRecordContextChangeResult + metadata_set_working_directory_request: MetadataSetWorkingDirectoryRequest + metadata_set_working_directory_result: MetadataSetWorkingDirectoryResult + metadata_snapshot_current_mode: MetadataSnapshotCurrentMode + metadata_snapshot_remote_metadata: MetadataSnapshotRemoteMetadata + metadata_snapshot_remote_metadata_repository: MetadataSnapshotRemoteMetadataRepository + metadata_snapshot_remote_metadata_task_type: MetadataSnapshotRemoteMetadataTaskType + model: Model + model_billing: ModelBilling + model_billing_token_prices: ModelBillingTokenPrices + model_capabilities: ModelCapabilities + model_capabilities_limits: ModelCapabilitiesLimits + model_capabilities_limits_vision: ModelCapabilitiesLimitsVision model_capabilities_override: ModelCapabilitiesOverride model_capabilities_override_limits: ModelCapabilitiesOverrideLimits model_capabilities_override_limits_vision: ModelCapabilitiesOverrideLimitsVision @@ -7592,13 +14187,23 @@ class RPC: model_picker_price_category: ModelPickerPriceCategory model_policy: ModelPolicy model_policy_state: ModelPolicyState + model_set_reasoning_effort_request: ModelSetReasoningEffortRequest + model_set_reasoning_effort_result: ModelSetReasoningEffortResult models_list_request: ModelsListRequest model_switch_to_request: ModelSwitchToRequest model_switch_to_result: ModelSwitchToResult mode_set_request: ModeSetRequest name_get_result: NameGetResult + name_set_auto_request: NameSetAutoRequest + name_set_auto_result: NameSetAutoResult name_set_request: NameSetRequest + options_update_env_value_mode: MCPSetEnvValueModeDetails + pending_permission_request: PendingPermissionRequest + pending_permission_request_list: PendingPermissionRequestList permission_decision: PermissionDecision + permission_decision_approved: PermissionDecisionApproved + permission_decision_approved_for_location: PermissionDecisionApprovedForLocation + permission_decision_approved_for_session: PermissionDecisionApprovedForSession permission_decision_approve_for_location: PermissionDecisionApproveForLocation permission_decision_approve_for_location_approval: PermissionDecisionApproveForLocationApproval permission_decision_approve_for_location_approval_commands: PermissionDecisionApproveForLocationApprovalCommands @@ -7623,14 +14228,50 @@ class RPC: permission_decision_approve_for_session_approval_write: PermissionDecisionApproveForSessionApprovalWrite permission_decision_approve_once: PermissionDecisionApproveOnce permission_decision_approve_permanently: PermissionDecisionApprovePermanently + permission_decision_cancelled: PermissionDecisionCancelled + permission_decision_denied_by_content_exclusion_policy: PermissionDecisionDeniedByContentExclusionPolicy + permission_decision_denied_by_permission_request_hook: PermissionDecisionDeniedByPermissionRequestHook + permission_decision_denied_by_rules: PermissionDecisionDeniedByRules + permission_decision_denied_interactively_by_user: PermissionDecisionDeniedInteractivelyByUser + permission_decision_denied_no_approval_rule_and_could_not_request_from_user: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser permission_decision_reject: PermissionDecisionReject permission_decision_request: PermissionDecisionRequest permission_decision_user_not_available: PermissionDecisionUserNotAvailable + permission_paths_add_params: PermissionPathsAddParams + permission_paths_allowed_check_params: PermissionPathsAllowedCheckParams + permission_paths_allowed_check_result: PermissionPathsAllowedCheckResult + permission_paths_config: PermissionPathsConfig + permission_paths_list: PermissionPathsList + permission_paths_update_primary_params: PermissionPathsUpdatePrimaryParams + permission_paths_workspace_check_params: PermissionPathsWorkspaceCheckParams + permission_paths_workspace_check_result: PermissionPathsWorkspaceCheckResult + permission_prompt_shown_notification: PermissionPromptShownNotification permission_request_result: PermissionRequestResult + permission_rules_set: PermissionRulesSet + permissions_configure_additional_content_exclusion_policy: PermissionsConfigureAdditionalContentExclusionPolicy + permissions_configure_additional_content_exclusion_policy_rule: PermissionsConfigureAdditionalContentExclusionPolicyRule + permissions_configure_additional_content_exclusion_policy_rule_source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource + permissions_configure_additional_content_exclusion_policy_scope: PermissionsConfigureAdditionalContentExclusionPolicyScope + permissions_configure_params: PermissionsConfigureParams + permissions_configure_result: PermissionsConfigureResult + permissions_modify_rules_params: PermissionsModifyRulesParams + permissions_modify_rules_result: PermissionsModifyRulesResult + permissions_modify_rules_scope: PermissionsModifyRulesScope + permissions_notify_prompt_shown_result: PermissionsNotifyPromptShownResult + permissions_paths_add_result: PermissionsPathsAddResult + permissions_paths_list_request: PermissionsPathsListRequest + permissions_paths_update_primary_result: PermissionsPathsUpdatePrimaryResult + permissions_pending_requests_request: PermissionsPendingRequestsRequest permissions_reset_session_approvals_request: PermissionsResetSessionApprovalsRequest permissions_reset_session_approvals_result: PermissionsResetSessionApprovalsResult permissions_set_approve_all_request: PermissionsSetApproveAllRequest permissions_set_approve_all_result: PermissionsSetApproveAllResult + permissions_set_approve_all_source: PermissionsSetApproveAllSource + permissions_set_required_request: PermissionsSetRequiredRequest + permissions_set_required_result: PermissionsSetRequiredResult + permissions_urls_set_unrestricted_mode_result: PermissionsUrlsSetUnrestrictedModeResult + permission_urls_config: PermissionUrlsConfig + permission_urls_set_unrestricted_mode_params: PermissionUrlsSetUnrestrictedModeParams ping_request: PingRequest ping_result: PingResult plan_read_result: PlanReadResult @@ -7640,13 +14281,45 @@ class RPC: queued_command_handled: QueuedCommandHandled queued_command_not_handled: QueuedCommandNotHandled queued_command_result: QueuedCommandResult + queue_pending_items: QueuePendingItems + queue_pending_items_kind: QueuePendingItemsKind + queue_pending_items_result: QueuePendingItemsResult + queue_remove_most_recent_result: QueueRemoveMostRecentResult + register_event_interest_params: RegisterEventInterestParams + register_event_interest_result: RegisterEventInterestResult + release_event_interest_params: ReleaseEventInterestParams remote_enable_request: RemoteEnableRequest remote_enable_result: RemoteEnableResult + remote_notify_steerable_changed_request: RemoteNotifySteerableChangedRequest + remote_notify_steerable_changed_result: RemoteNotifySteerableChangedResult remote_session_connection_result: RemoteSessionConnectionResult remote_session_mode: RemoteSessionMode + schedule_entry: ScheduleEntry + schedule_list: ScheduleList + schedule_stop_request: ScheduleStopRequest + schedule_stop_result: ScheduleStopResult + send_agent_mode: SendAgentMode + send_attachment: SendAttachment + send_attachment_blob: SendAttachmentBlob + send_attachment_directory: SendAttachmentDirectory + send_attachment_file: SendAttachmentFile + send_attachment_file_line_range: SendAttachmentFileLineRange + send_attachment_github_reference: SendAttachmentGithubReference + send_attachment_github_reference_type: SendAttachmentGithubReferenceTypeEnum + send_attachment_selection: SendAttachmentSelection + send_attachment_selection_details: SendAttachmentSelectionDetails + send_attachment_selection_details_end: SendAttachmentSelectionDetailsEnd + send_attachment_selection_details_start: SendAttachmentSelectionDetailsStart + send_mode: SendMode + send_request: SendRequest + send_result: SendResult server_skill: ServerSkill server_skill_list: ServerSkillList session_auth_status: SessionAuthStatus + session_bulk_delete_result: SessionBulkDeleteResult + session_context: SessionContext + session_context_host_type: SessionContextHostType + session_enrich_metadata_result: SessionEnrichMetadataResult session_fs_append_file_request: SessionFSAppendFileRequest session_fs_error: SessionFSError session_fs_error_code: SessionFSErrorCode @@ -7675,21 +14348,68 @@ class RPC: session_fs_stat_request: SessionFSStatRequest session_fs_stat_result: SessionFSStatResult session_fs_write_file_request: SessionFSWriteFileRequest + session_installed_plugin: SessionInstalledPlugin + session_installed_plugin_source: SessionInstalledPluginSource | str + session_installed_plugin_source_github: SessionInstalledPluginSourceGithub + session_installed_plugin_source_local: SessionInstalledPluginSourceLocal + session_installed_plugin_source_url: SessionInstalledPluginSourceURL + session_list: SessionList + session_load_deferred_repo_hooks_result: SessionLoadDeferredRepoHooksResult session_log_level: SessionLogLevel + session_metadata: SessionMetadata + session_metadata_snapshot: SessionMetadataSnapshot session_mode: SessionMode + session_prune_result: SessionPruneResult + sessions_bulk_delete_request: SessionsBulkDeleteRequest + sessions_check_in_use_request: SessionsCheckInUseRequest + sessions_check_in_use_result: SessionsCheckInUseResult + sessions_close_request: SessionsCloseRequest + sessions_close_result: SessionsCloseResult + sessions_enrich_metadata_request: SessionsEnrichMetadataRequest + session_set_credentials_params: SessionSetCredentialsParams + session_set_credentials_result: SessionSetCredentialsResult + sessions_find_by_prefix_request: SessionsFindByPrefixRequest + sessions_find_by_prefix_result: SessionsFindByPrefixResult + sessions_find_by_task_id_request: SessionsFindByTaskIDRequest + sessions_find_by_task_id_result: SessionsFindByTaskIDResult sessions_fork_request: SessionsForkRequest sessions_fork_result: SessionsForkResult + sessions_get_event_file_path_request: SessionsGetEventFilePathRequest + sessions_get_event_file_path_result: SessionsGetEventFilePathResult + sessions_get_last_for_context_request: SessionsGetLastForContextRequest + sessions_get_last_for_context_result: SessionsGetLastForContextResult + sessions_get_persisted_remote_steerable_request: SessionsGetPersistedRemoteSteerableRequest + sessions_get_persisted_remote_steerable_result: SessionsGetPersistedRemoteSteerableResult + session_sizes: SessionSizes + sessions_list_request: SessionsListRequest + sessions_load_deferred_repo_hooks_request: SessionsLoadDeferredRepoHooksRequest + sessions_prune_old_request: SessionsPruneOldRequest + sessions_release_lock_request: SessionsReleaseLockRequest + sessions_release_lock_result: SessionsReleaseLockResult + sessions_reload_plugin_hooks_request: SessionsReloadPluginHooksRequest + sessions_reload_plugin_hooks_result: SessionsReloadPluginHooksResult + sessions_save_request: SessionsSaveRequest + sessions_save_result: SessionsSaveResult + sessions_set_additional_plugins_request: SessionsSetAdditionalPluginsRequest + sessions_set_additional_plugins_result: SessionsSetAdditionalPluginsResult + session_update_options_params: SessionUpdateOptionsParams + session_update_options_result: SessionUpdateOptionsResult + session_working_directory_context: SessionWorkingDirectoryContext + session_working_directory_context_host_type: SessionContextHostType shell_exec_request: ShellExecRequest shell_exec_result: ShellExecResult shell_kill_request: ShellKillRequest shell_kill_result: ShellKillResult shell_kill_signal: ShellKillSignal + shutdown_request: ShutdownRequest skill: Skill skill_list: SkillList skills_config_set_disabled_skills_request: SkillsConfigSetDisabledSkillsRequest skills_disable_request: SkillsDisableRequest skills_discover_request: SkillsDiscoverRequest skills_enable_request: SkillsEnableRequest + skills_get_invoked_result: SkillsGetInvokedResult + skills_invoked_skill: SkillsInvokedSkill skills_load_diagnostics: SkillsLoadDiagnostics slash_command_agent_prompt_result: SlashCommandAgentPromptResult slash_command_completed_result: SlashCommandCompletedResult @@ -7700,15 +14420,22 @@ class RPC: slash_command_kind: SlashCommandKind slash_command_text_result: SlashCommandTextResult task_agent_info: TaskAgentInfo + task_agent_progress: TaskAgentProgress task_execution_mode: TaskExecutionMode task_info: TaskInfo task_list: TaskList tasks_cancel_request: TasksCancelRequest tasks_cancel_result: TasksCancelResult + tasks_get_current_promotable_result: TasksGetCurrentPromotableResult + tasks_get_progress_request: TasksGetProgressRequest + tasks_get_progress_result: TasksGetProgressResult task_shell_info: TaskShellInfo task_shell_info_attachment_mode: TaskShellInfoAttachmentMode + task_shell_progress: None + tasks_promote_current_to_background_result: TasksPromoteCurrentToBackgroundResult tasks_promote_to_background_request: TasksPromoteToBackgroundRequest tasks_promote_to_background_result: TasksPromoteToBackgroundResult + tasks_refresh_result: TasksRefreshResult tasks_remove_request: TasksRemoveRequest tasks_remove_result: TasksRemoveResult tasks_send_message_request: TasksSendMessageRequest @@ -7716,9 +14443,14 @@ class RPC: tasks_start_agent_request: TasksStartAgentRequest tasks_start_agent_result: TasksStartAgentResult task_status: TaskStatus + tasks_wait_for_pending_result: TasksWaitForPendingResult + telemetry_set_feature_overrides_request: TelemetrySetFeatureOverridesRequest + token_auth_info: TokenAuthInfo tool: Tool tool_list: ToolList + tools_initialize_and_validate_result: ToolsInitializeAndValidateResult tools_list_request: ToolsListRequest + ui_auto_mode_switch_response: UIAutoModeSwitchResponse ui_elicitation_array_any_of_field: UIElicitationArrayAnyOfField ui_elicitation_array_any_of_field_items: UIElicitationArrayAnyOfFieldItems ui_elicitation_array_any_of_field_items_any_of: UIElicitationArrayAnyOfFieldItemsAnyOf @@ -7740,7 +14472,19 @@ class RPC: ui_elicitation_string_enum_field: UIElicitationStringEnumField ui_elicitation_string_one_of_field: UIElicitationStringOneOfField ui_elicitation_string_one_of_field_one_of: UIElicitationStringOneOfFieldOneOf + ui_exit_plan_mode_action: UIExitPlanModeAction + ui_exit_plan_mode_response: UIExitPlanModeResponse + ui_handle_pending_auto_mode_switch_request: UIHandlePendingAutoModeSwitchRequest ui_handle_pending_elicitation_request: UIHandlePendingElicitationRequest + ui_handle_pending_exit_plan_mode_request: UIHandlePendingExitPlanModeRequest + ui_handle_pending_result: UIHandlePendingResult + ui_handle_pending_sampling_request: UIHandlePendingSamplingRequest + ui_handle_pending_sampling_response: dict[str, Any] + ui_handle_pending_user_input_request: UIHandlePendingUserInputRequest + ui_register_direct_auto_mode_switch_handler_result: UIRegisterDirectAutoModeSwitchHandlerResult + ui_unregister_direct_auto_mode_switch_handler_request: UIUnregisterDirectAutoModeSwitchHandlerRequest + ui_unregister_direct_auto_mode_switch_handler_result: UIUnregisterDirectAutoModeSwitchHandlerResult + ui_user_input_response: UIUserInputResponse usage_get_metrics_result: UsageGetMetricsResult usage_metrics_code_changes: UsageMetricsCodeChanges usage_metrics_model_metric: UsageMetricsModelMetric @@ -7748,24 +14492,47 @@ class RPC: usage_metrics_model_metric_token_detail: UsageMetricsModelMetricTokenDetail usage_metrics_model_metric_usage: UsageMetricsModelMetricUsage usage_metrics_token_detail: UsageMetricsTokenDetail + user_auth_info: UserAuthInfo + user_tool_session_approval_commands: UserToolSessionApprovalCommands + user_tool_session_approval_custom_tool: UserToolSessionApprovalCustomTool + user_tool_session_approval_extension_management: UserToolSessionApprovalExtensionManagement + user_tool_session_approval_extension_permission_access: UserToolSessionApprovalExtensionPermissionAccess + user_tool_session_approval_mcp: UserToolSessionApprovalMCP + user_tool_session_approval_memory: UserToolSessionApprovalMemory + user_tool_session_approval_read: UserToolSessionApprovalRead + user_tool_session_approval_write: UserToolSessionApprovalWrite + workspaces_checkpoints: WorkspacesCheckpoints workspaces_create_file_request: WorkspacesCreateFileRequest workspaces_get_workspace_result: WorkspacesGetWorkspaceResult + workspaces_list_checkpoints_result: WorkspacesListCheckpointsResult workspaces_list_files_result: WorkspacesListFilesResult + workspaces_read_checkpoint_request: WorkspacesReadCheckpointRequest + workspaces_read_checkpoint_result: WorkspacesReadCheckpointResult workspaces_read_file_request: WorkspacesReadFileRequest workspaces_read_file_result: WorkspacesReadFileResult + workspaces_save_large_paste_request: WorkspacesSaveLargePasteRequest + workspaces_save_large_paste_result: WorkspacesSaveLargePasteResult + session_context_info: SessionContextInfo | None = None + task_progress: TaskProgressClass | None = None + workspace_summary: WorkspaceSummary | None = None @staticmethod def from_dict(obj: Any) -> 'RPC': assert isinstance(obj, dict) + abort_request = AbortRequest.from_dict(obj.get("AbortRequest")) + abort_result = AbortResult.from_dict(obj.get("AbortResult")) account_get_quota_request = AccountGetQuotaRequest.from_dict(obj.get("AccountGetQuotaRequest")) account_get_quota_result = AccountGetQuotaResult.from_dict(obj.get("AccountGetQuotaResult")) account_quota_snapshot = AccountQuotaSnapshot.from_dict(obj.get("AccountQuotaSnapshot")) agent_get_current_result = AgentGetCurrentResult.from_dict(obj.get("AgentGetCurrentResult")) agent_info = AgentInfo.from_dict(obj.get("AgentInfo")) + agent_info_source = AgentInfoSource(obj.get("AgentInfoSource")) agent_list = AgentList.from_dict(obj.get("AgentList")) agent_reload_result = AgentReloadResult.from_dict(obj.get("AgentReloadResult")) agent_select_request = AgentSelectRequest.from_dict(obj.get("AgentSelectRequest")) agent_select_result = AgentSelectResult.from_dict(obj.get("AgentSelectResult")) + api_key_auth_info = APIKeyAuthInfo.from_dict(obj.get("ApiKeyAuthInfo")) + auth_info = AuthInfo.from_dict(obj.get("AuthInfo")) auth_info_type = AuthInfoType(obj.get("AuthInfoType")) command_list = CommandList.from_dict(obj.get("CommandList")) commands_handle_pending_command_request = CommandsHandlePendingCommandRequest.from_dict(obj.get("CommandsHandlePendingCommandRequest")) @@ -7781,9 +14548,28 @@ def from_dict(obj: Any) -> 'RPC': connect_request = ConnectRequest.from_dict(obj.get("ConnectRequest")) connect_result = ConnectResult.from_dict(obj.get("ConnectResult")) content_filter_mode = ContentFilterMode(obj.get("ContentFilterMode")) + copilot_api_token_auth_info = CopilotAPITokenAuthInfo.from_dict(obj.get("CopilotApiTokenAuthInfo")) + copilot_user_response = CopilotUserResponse.from_dict(obj.get("CopilotUserResponse")) + copilot_user_response_endpoints = CopilotUserResponseEndpoints.from_dict(obj.get("CopilotUserResponseEndpoints")) + copilot_user_response_quota_snapshots = from_dict(lambda x: from_union([CopilotUserResponseQuotaSnapshots.from_dict, from_none], x), obj.get("CopilotUserResponseQuotaSnapshots")) + copilot_user_response_quota_snapshots_chat = CopilotUserResponseQuotaSnapshotsChat.from_dict(obj.get("CopilotUserResponseQuotaSnapshotsChat")) + copilot_user_response_quota_snapshots_completions = CopilotUserResponseQuotaSnapshotsCompletions.from_dict(obj.get("CopilotUserResponseQuotaSnapshotsCompletions")) + copilot_user_response_quota_snapshots_premium_interactions = CopilotUserResponseQuotaSnapshotsPremiumInteractions.from_dict(obj.get("CopilotUserResponseQuotaSnapshotsPremiumInteractions")) current_model = CurrentModel.from_dict(obj.get("CurrentModel")) discovered_mcp_server = DiscoveredMCPServer.from_dict(obj.get("DiscoveredMcpServer")) discovered_mcp_server_type = DiscoveredMCPServerType(obj.get("DiscoveredMcpServerType")) + enqueue_command_params = EnqueueCommandParams.from_dict(obj.get("EnqueueCommandParams")) + enqueue_command_result = EnqueueCommandResult.from_dict(obj.get("EnqueueCommandResult")) + env_auth_info = EnvAuthInfo.from_dict(obj.get("EnvAuthInfo")) + event_log_read_request = EventLogReadRequest.from_dict(obj.get("EventLogReadRequest")) + event_log_release_interest_result = EventLogReleaseInterestResult.from_dict(obj.get("EventLogReleaseInterestResult")) + event_log_tail_result = EventLogTailResult.from_dict(obj.get("EventLogTailResult")) + event_log_types = from_union([lambda x: from_list(from_str, x), EventLogTypes], obj.get("EventLogTypes")) + events_agent_scope = EventsAgentScope(obj.get("EventsAgentScope")) + events_cursor_status = EventsCursorStatus(obj.get("EventsCursorStatus")) + events_read_result = EventsReadResult.from_dict(obj.get("EventsReadResult")) + execute_command_params = ExecuteCommandParams.from_dict(obj.get("ExecuteCommandParams")) + execute_command_result = ExecuteCommandResult.from_dict(obj.get("ExecuteCommandResult")) extension = Extension.from_dict(obj.get("Extension")) extension_list = ExtensionList.from_dict(obj.get("ExtensionList")) extensions_disable_request = ExtensionsDisableRequest.from_dict(obj.get("ExtensionsDisableRequest")) @@ -7807,18 +14593,31 @@ def from_dict(obj: Any) -> 'RPC': filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode], obj.get("FilterMapping")) fleet_start_request = FleetStartRequest.from_dict(obj.get("FleetStartRequest")) fleet_start_result = FleetStartResult.from_dict(obj.get("FleetStartResult")) + gh_cli_auth_info = GhCLIAuthInfo.from_dict(obj.get("GhCliAuthInfo")) handle_pending_tool_call_request = HandlePendingToolCallRequest.from_dict(obj.get("HandlePendingToolCallRequest")) handle_pending_tool_call_result = HandlePendingToolCallResult.from_dict(obj.get("HandlePendingToolCallResult")) + history_abort_manual_compaction_result = HistoryAbortManualCompactionResult.from_dict(obj.get("HistoryAbortManualCompactionResult")) + history_cancel_background_compaction_result = HistoryCancelBackgroundCompactionResult.from_dict(obj.get("HistoryCancelBackgroundCompactionResult")) history_compact_context_window = HistoryCompactContextWindow.from_dict(obj.get("HistoryCompactContextWindow")) history_compact_result = HistoryCompactResult.from_dict(obj.get("HistoryCompactResult")) + history_summarize_for_handoff_result = HistorySummarizeForHandoffResult.from_dict(obj.get("HistorySummarizeForHandoffResult")) history_truncate_request = HistoryTruncateRequest.from_dict(obj.get("HistoryTruncateRequest")) history_truncate_result = HistoryTruncateResult.from_dict(obj.get("HistoryTruncateResult")) + hmac_auth_info = HMACAuthInfo.from_dict(obj.get("HMACAuthInfo")) + installed_plugin = InstalledPlugin.from_dict(obj.get("InstalledPlugin")) + installed_plugin_source = from_union([InstalledPluginSource.from_dict, from_str], obj.get("InstalledPluginSource")) + installed_plugin_source_github = InstalledPluginSourceGithub.from_dict(obj.get("InstalledPluginSourceGithub")) + installed_plugin_source_local = InstalledPluginSourceLocal.from_dict(obj.get("InstalledPluginSourceLocal")) + installed_plugin_source_url = InstalledPluginSourceURL.from_dict(obj.get("InstalledPluginSourceUrl")) instructions_get_sources_result = InstructionsGetSourcesResult.from_dict(obj.get("InstructionsGetSourcesResult")) instructions_sources = InstructionsSources.from_dict(obj.get("InstructionsSources")) instructions_sources_location = InstructionsSourcesLocation(obj.get("InstructionsSourcesLocation")) instructions_sources_type = InstructionsSourcesType(obj.get("InstructionsSourcesType")) log_request = LogRequest.from_dict(obj.get("LogRequest")) log_result = LogResult.from_dict(obj.get("LogResult")) + lsp_initialize_request = LspInitializeRequest.from_dict(obj.get("LspInitializeRequest")) + mcp_cancel_sampling_execution_params = MCPCancelSamplingExecutionParams.from_dict(obj.get("McpCancelSamplingExecutionParams")) + mcp_cancel_sampling_execution_result = MCPCancelSamplingExecutionResult.from_dict(obj.get("McpCancelSamplingExecutionResult")) mcp_config_add_request = MCPConfigAddRequest.from_dict(obj.get("McpConfigAddRequest")) mcp_config_disable_request = MCPConfigDisableRequest.from_dict(obj.get("McpConfigDisableRequest")) mcp_config_enable_request = MCPConfigEnableRequest.from_dict(obj.get("McpConfigEnableRequest")) @@ -7829,8 +14628,14 @@ def from_dict(obj: Any) -> 'RPC': mcp_discover_request = MCPDiscoverRequest.from_dict(obj.get("McpDiscoverRequest")) mcp_discover_result = MCPDiscoverResult.from_dict(obj.get("McpDiscoverResult")) mcp_enable_request = MCPEnableRequest.from_dict(obj.get("McpEnableRequest")) + mcp_execute_sampling_params = MCPExecuteSamplingParams.from_dict(obj.get("McpExecuteSamplingParams")) + mcp_execute_sampling_request = from_dict(lambda x: x, obj.get("McpExecuteSamplingRequest")) + mcp_execute_sampling_result = from_dict(lambda x: x, obj.get("McpExecuteSamplingResult")) mcp_oauth_login_request = MCPOauthLoginRequest.from_dict(obj.get("McpOauthLoginRequest")) mcp_oauth_login_result = MCPOauthLoginResult.from_dict(obj.get("McpOauthLoginResult")) + mcp_remove_git_hub_result = MCPRemoveGitHubResult.from_dict(obj.get("McpRemoveGitHubResult")) + mcp_sampling_execution_action = MCPSamplingExecutionAction(obj.get("McpSamplingExecutionAction")) + mcp_sampling_execution_result = MCPSamplingExecutionResult.from_dict(obj.get("McpSamplingExecutionResult")) mcp_server = MCPServer.from_dict(obj.get("McpServer")) mcp_server_config = MCPServerConfig.from_dict(obj.get("McpServerConfig")) mcp_server_config_http = MCPServerConfigHTTP.from_dict(obj.get("McpServerConfigHttp")) @@ -7839,6 +14644,22 @@ def from_dict(obj: Any) -> 'RPC': mcp_server_config_http_type = MCPServerConfigHTTPType(obj.get("McpServerConfigHttpType")) mcp_server_config_stdio = MCPServerConfigStdio.from_dict(obj.get("McpServerConfigStdio")) mcp_server_list = MCPServerList.from_dict(obj.get("McpServerList")) + mcp_set_env_value_mode_details = MCPSetEnvValueModeDetails(obj.get("McpSetEnvValueModeDetails")) + mcp_set_env_value_mode_params = MCPSetEnvValueModeParams.from_dict(obj.get("McpSetEnvValueModeParams")) + mcp_set_env_value_mode_result = MCPSetEnvValueModeResult.from_dict(obj.get("McpSetEnvValueModeResult")) + metadata_context_info_request = MetadataContextInfoRequest.from_dict(obj.get("MetadataContextInfoRequest")) + metadata_context_info_result = MetadataContextInfoResult.from_dict(obj.get("MetadataContextInfoResult")) + metadata_is_processing_result = MetadataIsProcessingResult.from_dict(obj.get("MetadataIsProcessingResult")) + metadata_recompute_context_tokens_request = MetadataRecomputeContextTokensRequest.from_dict(obj.get("MetadataRecomputeContextTokensRequest")) + metadata_recompute_context_tokens_result = MetadataRecomputeContextTokensResult.from_dict(obj.get("MetadataRecomputeContextTokensResult")) + metadata_record_context_change_request = MetadataRecordContextChangeRequest.from_dict(obj.get("MetadataRecordContextChangeRequest")) + metadata_record_context_change_result = MetadataRecordContextChangeResult.from_dict(obj.get("MetadataRecordContextChangeResult")) + metadata_set_working_directory_request = MetadataSetWorkingDirectoryRequest.from_dict(obj.get("MetadataSetWorkingDirectoryRequest")) + metadata_set_working_directory_result = MetadataSetWorkingDirectoryResult.from_dict(obj.get("MetadataSetWorkingDirectoryResult")) + metadata_snapshot_current_mode = MetadataSnapshotCurrentMode(obj.get("MetadataSnapshotCurrentMode")) + metadata_snapshot_remote_metadata = MetadataSnapshotRemoteMetadata.from_dict(obj.get("MetadataSnapshotRemoteMetadata")) + metadata_snapshot_remote_metadata_repository = MetadataSnapshotRemoteMetadataRepository.from_dict(obj.get("MetadataSnapshotRemoteMetadataRepository")) + metadata_snapshot_remote_metadata_task_type = MetadataSnapshotRemoteMetadataTaskType(obj.get("MetadataSnapshotRemoteMetadataTaskType")) model = Model.from_dict(obj.get("Model")) model_billing = ModelBilling.from_dict(obj.get("ModelBilling")) model_billing_token_prices = ModelBillingTokenPrices.from_dict(obj.get("ModelBillingTokenPrices")) @@ -7855,13 +14676,23 @@ def from_dict(obj: Any) -> 'RPC': model_picker_price_category = ModelPickerPriceCategory(obj.get("ModelPickerPriceCategory")) model_policy = ModelPolicy.from_dict(obj.get("ModelPolicy")) model_policy_state = ModelPolicyState(obj.get("ModelPolicyState")) + model_set_reasoning_effort_request = ModelSetReasoningEffortRequest.from_dict(obj.get("ModelSetReasoningEffortRequest")) + model_set_reasoning_effort_result = ModelSetReasoningEffortResult.from_dict(obj.get("ModelSetReasoningEffortResult")) models_list_request = ModelsListRequest.from_dict(obj.get("ModelsListRequest")) model_switch_to_request = ModelSwitchToRequest.from_dict(obj.get("ModelSwitchToRequest")) model_switch_to_result = ModelSwitchToResult.from_dict(obj.get("ModelSwitchToResult")) mode_set_request = ModeSetRequest.from_dict(obj.get("ModeSetRequest")) name_get_result = NameGetResult.from_dict(obj.get("NameGetResult")) + name_set_auto_request = NameSetAutoRequest.from_dict(obj.get("NameSetAutoRequest")) + name_set_auto_result = NameSetAutoResult.from_dict(obj.get("NameSetAutoResult")) name_set_request = NameSetRequest.from_dict(obj.get("NameSetRequest")) + options_update_env_value_mode = MCPSetEnvValueModeDetails(obj.get("OptionsUpdateEnvValueMode")) + pending_permission_request = PendingPermissionRequest.from_dict(obj.get("PendingPermissionRequest")) + pending_permission_request_list = PendingPermissionRequestList.from_dict(obj.get("PendingPermissionRequestList")) permission_decision = PermissionDecision.from_dict(obj.get("PermissionDecision")) + permission_decision_approved = PermissionDecisionApproved.from_dict(obj.get("PermissionDecisionApproved")) + permission_decision_approved_for_location = PermissionDecisionApprovedForLocation.from_dict(obj.get("PermissionDecisionApprovedForLocation")) + permission_decision_approved_for_session = PermissionDecisionApprovedForSession.from_dict(obj.get("PermissionDecisionApprovedForSession")) permission_decision_approve_for_location = PermissionDecisionApproveForLocation.from_dict(obj.get("PermissionDecisionApproveForLocation")) permission_decision_approve_for_location_approval = PermissionDecisionApproveForLocationApproval.from_dict(obj.get("PermissionDecisionApproveForLocationApproval")) permission_decision_approve_for_location_approval_commands = PermissionDecisionApproveForLocationApprovalCommands.from_dict(obj.get("PermissionDecisionApproveForLocationApprovalCommands")) @@ -7886,14 +14717,50 @@ def from_dict(obj: Any) -> 'RPC': permission_decision_approve_for_session_approval_write = PermissionDecisionApproveForSessionApprovalWrite.from_dict(obj.get("PermissionDecisionApproveForSessionApprovalWrite")) permission_decision_approve_once = PermissionDecisionApproveOnce.from_dict(obj.get("PermissionDecisionApproveOnce")) permission_decision_approve_permanently = PermissionDecisionApprovePermanently.from_dict(obj.get("PermissionDecisionApprovePermanently")) + permission_decision_cancelled = PermissionDecisionCancelled.from_dict(obj.get("PermissionDecisionCancelled")) + permission_decision_denied_by_content_exclusion_policy = PermissionDecisionDeniedByContentExclusionPolicy.from_dict(obj.get("PermissionDecisionDeniedByContentExclusionPolicy")) + permission_decision_denied_by_permission_request_hook = PermissionDecisionDeniedByPermissionRequestHook.from_dict(obj.get("PermissionDecisionDeniedByPermissionRequestHook")) + permission_decision_denied_by_rules = PermissionDecisionDeniedByRules.from_dict(obj.get("PermissionDecisionDeniedByRules")) + permission_decision_denied_interactively_by_user = PermissionDecisionDeniedInteractivelyByUser.from_dict(obj.get("PermissionDecisionDeniedInteractivelyByUser")) + permission_decision_denied_no_approval_rule_and_could_not_request_from_user = PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser.from_dict(obj.get("PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser")) permission_decision_reject = PermissionDecisionReject.from_dict(obj.get("PermissionDecisionReject")) permission_decision_request = PermissionDecisionRequest.from_dict(obj.get("PermissionDecisionRequest")) permission_decision_user_not_available = PermissionDecisionUserNotAvailable.from_dict(obj.get("PermissionDecisionUserNotAvailable")) + permission_paths_add_params = PermissionPathsAddParams.from_dict(obj.get("PermissionPathsAddParams")) + permission_paths_allowed_check_params = PermissionPathsAllowedCheckParams.from_dict(obj.get("PermissionPathsAllowedCheckParams")) + permission_paths_allowed_check_result = PermissionPathsAllowedCheckResult.from_dict(obj.get("PermissionPathsAllowedCheckResult")) + permission_paths_config = PermissionPathsConfig.from_dict(obj.get("PermissionPathsConfig")) + permission_paths_list = PermissionPathsList.from_dict(obj.get("PermissionPathsList")) + permission_paths_update_primary_params = PermissionPathsUpdatePrimaryParams.from_dict(obj.get("PermissionPathsUpdatePrimaryParams")) + permission_paths_workspace_check_params = PermissionPathsWorkspaceCheckParams.from_dict(obj.get("PermissionPathsWorkspaceCheckParams")) + permission_paths_workspace_check_result = PermissionPathsWorkspaceCheckResult.from_dict(obj.get("PermissionPathsWorkspaceCheckResult")) + permission_prompt_shown_notification = PermissionPromptShownNotification.from_dict(obj.get("PermissionPromptShownNotification")) permission_request_result = PermissionRequestResult.from_dict(obj.get("PermissionRequestResult")) + permission_rules_set = PermissionRulesSet.from_dict(obj.get("PermissionRulesSet")) + permissions_configure_additional_content_exclusion_policy = PermissionsConfigureAdditionalContentExclusionPolicy.from_dict(obj.get("PermissionsConfigureAdditionalContentExclusionPolicy")) + permissions_configure_additional_content_exclusion_policy_rule = PermissionsConfigureAdditionalContentExclusionPolicyRule.from_dict(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyRule")) + permissions_configure_additional_content_exclusion_policy_rule_source = PermissionsConfigureAdditionalContentExclusionPolicyRuleSource.from_dict(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyRuleSource")) + permissions_configure_additional_content_exclusion_policy_scope = PermissionsConfigureAdditionalContentExclusionPolicyScope(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyScope")) + permissions_configure_params = PermissionsConfigureParams.from_dict(obj.get("PermissionsConfigureParams")) + permissions_configure_result = PermissionsConfigureResult.from_dict(obj.get("PermissionsConfigureResult")) + permissions_modify_rules_params = PermissionsModifyRulesParams.from_dict(obj.get("PermissionsModifyRulesParams")) + permissions_modify_rules_result = PermissionsModifyRulesResult.from_dict(obj.get("PermissionsModifyRulesResult")) + permissions_modify_rules_scope = PermissionsModifyRulesScope(obj.get("PermissionsModifyRulesScope")) + permissions_notify_prompt_shown_result = PermissionsNotifyPromptShownResult.from_dict(obj.get("PermissionsNotifyPromptShownResult")) + permissions_paths_add_result = PermissionsPathsAddResult.from_dict(obj.get("PermissionsPathsAddResult")) + permissions_paths_list_request = PermissionsPathsListRequest.from_dict(obj.get("PermissionsPathsListRequest")) + permissions_paths_update_primary_result = PermissionsPathsUpdatePrimaryResult.from_dict(obj.get("PermissionsPathsUpdatePrimaryResult")) + permissions_pending_requests_request = PermissionsPendingRequestsRequest.from_dict(obj.get("PermissionsPendingRequestsRequest")) permissions_reset_session_approvals_request = PermissionsResetSessionApprovalsRequest.from_dict(obj.get("PermissionsResetSessionApprovalsRequest")) permissions_reset_session_approvals_result = PermissionsResetSessionApprovalsResult.from_dict(obj.get("PermissionsResetSessionApprovalsResult")) permissions_set_approve_all_request = PermissionsSetApproveAllRequest.from_dict(obj.get("PermissionsSetApproveAllRequest")) permissions_set_approve_all_result = PermissionsSetApproveAllResult.from_dict(obj.get("PermissionsSetApproveAllResult")) + permissions_set_approve_all_source = PermissionsSetApproveAllSource(obj.get("PermissionsSetApproveAllSource")) + permissions_set_required_request = PermissionsSetRequiredRequest.from_dict(obj.get("PermissionsSetRequiredRequest")) + permissions_set_required_result = PermissionsSetRequiredResult.from_dict(obj.get("PermissionsSetRequiredResult")) + permissions_urls_set_unrestricted_mode_result = PermissionsUrlsSetUnrestrictedModeResult.from_dict(obj.get("PermissionsUrlsSetUnrestrictedModeResult")) + permission_urls_config = PermissionUrlsConfig.from_dict(obj.get("PermissionUrlsConfig")) + permission_urls_set_unrestricted_mode_params = PermissionUrlsSetUnrestrictedModeParams.from_dict(obj.get("PermissionUrlsSetUnrestrictedModeParams")) ping_request = PingRequest.from_dict(obj.get("PingRequest")) ping_result = PingResult.from_dict(obj.get("PingResult")) plan_read_result = PlanReadResult.from_dict(obj.get("PlanReadResult")) @@ -7903,13 +14770,45 @@ def from_dict(obj: Any) -> 'RPC': queued_command_handled = QueuedCommandHandled.from_dict(obj.get("QueuedCommandHandled")) queued_command_not_handled = QueuedCommandNotHandled.from_dict(obj.get("QueuedCommandNotHandled")) queued_command_result = QueuedCommandResult.from_dict(obj.get("QueuedCommandResult")) + queue_pending_items = QueuePendingItems.from_dict(obj.get("QueuePendingItems")) + queue_pending_items_kind = QueuePendingItemsKind(obj.get("QueuePendingItemsKind")) + queue_pending_items_result = QueuePendingItemsResult.from_dict(obj.get("QueuePendingItemsResult")) + queue_remove_most_recent_result = QueueRemoveMostRecentResult.from_dict(obj.get("QueueRemoveMostRecentResult")) + register_event_interest_params = RegisterEventInterestParams.from_dict(obj.get("RegisterEventInterestParams")) + register_event_interest_result = RegisterEventInterestResult.from_dict(obj.get("RegisterEventInterestResult")) + release_event_interest_params = ReleaseEventInterestParams.from_dict(obj.get("ReleaseEventInterestParams")) remote_enable_request = RemoteEnableRequest.from_dict(obj.get("RemoteEnableRequest")) remote_enable_result = RemoteEnableResult.from_dict(obj.get("RemoteEnableResult")) + remote_notify_steerable_changed_request = RemoteNotifySteerableChangedRequest.from_dict(obj.get("RemoteNotifySteerableChangedRequest")) + remote_notify_steerable_changed_result = RemoteNotifySteerableChangedResult.from_dict(obj.get("RemoteNotifySteerableChangedResult")) remote_session_connection_result = RemoteSessionConnectionResult.from_dict(obj.get("RemoteSessionConnectionResult")) remote_session_mode = RemoteSessionMode(obj.get("RemoteSessionMode")) + schedule_entry = ScheduleEntry.from_dict(obj.get("ScheduleEntry")) + schedule_list = ScheduleList.from_dict(obj.get("ScheduleList")) + schedule_stop_request = ScheduleStopRequest.from_dict(obj.get("ScheduleStopRequest")) + schedule_stop_result = ScheduleStopResult.from_dict(obj.get("ScheduleStopResult")) + send_agent_mode = SendAgentMode(obj.get("SendAgentMode")) + send_attachment = SendAttachment.from_dict(obj.get("SendAttachment")) + send_attachment_blob = SendAttachmentBlob.from_dict(obj.get("SendAttachmentBlob")) + send_attachment_directory = SendAttachmentDirectory.from_dict(obj.get("SendAttachmentDirectory")) + send_attachment_file = SendAttachmentFile.from_dict(obj.get("SendAttachmentFile")) + send_attachment_file_line_range = SendAttachmentFileLineRange.from_dict(obj.get("SendAttachmentFileLineRange")) + send_attachment_github_reference = SendAttachmentGithubReference.from_dict(obj.get("SendAttachmentGithubReference")) + send_attachment_github_reference_type = SendAttachmentGithubReferenceTypeEnum(obj.get("SendAttachmentGithubReferenceType")) + send_attachment_selection = SendAttachmentSelection.from_dict(obj.get("SendAttachmentSelection")) + send_attachment_selection_details = SendAttachmentSelectionDetails.from_dict(obj.get("SendAttachmentSelectionDetails")) + send_attachment_selection_details_end = SendAttachmentSelectionDetailsEnd.from_dict(obj.get("SendAttachmentSelectionDetailsEnd")) + send_attachment_selection_details_start = SendAttachmentSelectionDetailsStart.from_dict(obj.get("SendAttachmentSelectionDetailsStart")) + send_mode = SendMode(obj.get("SendMode")) + send_request = SendRequest.from_dict(obj.get("SendRequest")) + send_result = SendResult.from_dict(obj.get("SendResult")) server_skill = ServerSkill.from_dict(obj.get("ServerSkill")) server_skill_list = ServerSkillList.from_dict(obj.get("ServerSkillList")) session_auth_status = SessionAuthStatus.from_dict(obj.get("SessionAuthStatus")) + session_bulk_delete_result = SessionBulkDeleteResult.from_dict(obj.get("SessionBulkDeleteResult")) + session_context = SessionContext.from_dict(obj.get("SessionContext")) + session_context_host_type = SessionContextHostType(obj.get("SessionContextHostType")) + session_enrich_metadata_result = SessionEnrichMetadataResult.from_dict(obj.get("SessionEnrichMetadataResult")) session_fs_append_file_request = SessionFSAppendFileRequest.from_dict(obj.get("SessionFsAppendFileRequest")) session_fs_error = SessionFSError.from_dict(obj.get("SessionFsError")) session_fs_error_code = SessionFSErrorCode(obj.get("SessionFsErrorCode")) @@ -7938,21 +14837,68 @@ def from_dict(obj: Any) -> 'RPC': session_fs_stat_request = SessionFSStatRequest.from_dict(obj.get("SessionFsStatRequest")) session_fs_stat_result = SessionFSStatResult.from_dict(obj.get("SessionFsStatResult")) session_fs_write_file_request = SessionFSWriteFileRequest.from_dict(obj.get("SessionFsWriteFileRequest")) + session_installed_plugin = SessionInstalledPlugin.from_dict(obj.get("SessionInstalledPlugin")) + session_installed_plugin_source = from_union([SessionInstalledPluginSource.from_dict, from_str], obj.get("SessionInstalledPluginSource")) + session_installed_plugin_source_github = SessionInstalledPluginSourceGithub.from_dict(obj.get("SessionInstalledPluginSourceGithub")) + session_installed_plugin_source_local = SessionInstalledPluginSourceLocal.from_dict(obj.get("SessionInstalledPluginSourceLocal")) + session_installed_plugin_source_url = SessionInstalledPluginSourceURL.from_dict(obj.get("SessionInstalledPluginSourceUrl")) + session_list = SessionList.from_dict(obj.get("SessionList")) + session_load_deferred_repo_hooks_result = SessionLoadDeferredRepoHooksResult.from_dict(obj.get("SessionLoadDeferredRepoHooksResult")) session_log_level = SessionLogLevel(obj.get("SessionLogLevel")) + session_metadata = SessionMetadata.from_dict(obj.get("SessionMetadata")) + session_metadata_snapshot = SessionMetadataSnapshot.from_dict(obj.get("SessionMetadataSnapshot")) session_mode = SessionMode(obj.get("SessionMode")) + session_prune_result = SessionPruneResult.from_dict(obj.get("SessionPruneResult")) + sessions_bulk_delete_request = SessionsBulkDeleteRequest.from_dict(obj.get("SessionsBulkDeleteRequest")) + sessions_check_in_use_request = SessionsCheckInUseRequest.from_dict(obj.get("SessionsCheckInUseRequest")) + sessions_check_in_use_result = SessionsCheckInUseResult.from_dict(obj.get("SessionsCheckInUseResult")) + sessions_close_request = SessionsCloseRequest.from_dict(obj.get("SessionsCloseRequest")) + sessions_close_result = SessionsCloseResult.from_dict(obj.get("SessionsCloseResult")) + sessions_enrich_metadata_request = SessionsEnrichMetadataRequest.from_dict(obj.get("SessionsEnrichMetadataRequest")) + session_set_credentials_params = SessionSetCredentialsParams.from_dict(obj.get("SessionSetCredentialsParams")) + session_set_credentials_result = SessionSetCredentialsResult.from_dict(obj.get("SessionSetCredentialsResult")) + sessions_find_by_prefix_request = SessionsFindByPrefixRequest.from_dict(obj.get("SessionsFindByPrefixRequest")) + sessions_find_by_prefix_result = SessionsFindByPrefixResult.from_dict(obj.get("SessionsFindByPrefixResult")) + sessions_find_by_task_id_request = SessionsFindByTaskIDRequest.from_dict(obj.get("SessionsFindByTaskIDRequest")) + sessions_find_by_task_id_result = SessionsFindByTaskIDResult.from_dict(obj.get("SessionsFindByTaskIDResult")) sessions_fork_request = SessionsForkRequest.from_dict(obj.get("SessionsForkRequest")) sessions_fork_result = SessionsForkResult.from_dict(obj.get("SessionsForkResult")) + sessions_get_event_file_path_request = SessionsGetEventFilePathRequest.from_dict(obj.get("SessionsGetEventFilePathRequest")) + sessions_get_event_file_path_result = SessionsGetEventFilePathResult.from_dict(obj.get("SessionsGetEventFilePathResult")) + sessions_get_last_for_context_request = SessionsGetLastForContextRequest.from_dict(obj.get("SessionsGetLastForContextRequest")) + sessions_get_last_for_context_result = SessionsGetLastForContextResult.from_dict(obj.get("SessionsGetLastForContextResult")) + sessions_get_persisted_remote_steerable_request = SessionsGetPersistedRemoteSteerableRequest.from_dict(obj.get("SessionsGetPersistedRemoteSteerableRequest")) + sessions_get_persisted_remote_steerable_result = SessionsGetPersistedRemoteSteerableResult.from_dict(obj.get("SessionsGetPersistedRemoteSteerableResult")) + session_sizes = SessionSizes.from_dict(obj.get("SessionSizes")) + sessions_list_request = SessionsListRequest.from_dict(obj.get("SessionsListRequest")) + sessions_load_deferred_repo_hooks_request = SessionsLoadDeferredRepoHooksRequest.from_dict(obj.get("SessionsLoadDeferredRepoHooksRequest")) + sessions_prune_old_request = SessionsPruneOldRequest.from_dict(obj.get("SessionsPruneOldRequest")) + sessions_release_lock_request = SessionsReleaseLockRequest.from_dict(obj.get("SessionsReleaseLockRequest")) + sessions_release_lock_result = SessionsReleaseLockResult.from_dict(obj.get("SessionsReleaseLockResult")) + sessions_reload_plugin_hooks_request = SessionsReloadPluginHooksRequest.from_dict(obj.get("SessionsReloadPluginHooksRequest")) + sessions_reload_plugin_hooks_result = SessionsReloadPluginHooksResult.from_dict(obj.get("SessionsReloadPluginHooksResult")) + sessions_save_request = SessionsSaveRequest.from_dict(obj.get("SessionsSaveRequest")) + sessions_save_result = SessionsSaveResult.from_dict(obj.get("SessionsSaveResult")) + sessions_set_additional_plugins_request = SessionsSetAdditionalPluginsRequest.from_dict(obj.get("SessionsSetAdditionalPluginsRequest")) + sessions_set_additional_plugins_result = SessionsSetAdditionalPluginsResult.from_dict(obj.get("SessionsSetAdditionalPluginsResult")) + session_update_options_params = SessionUpdateOptionsParams.from_dict(obj.get("SessionUpdateOptionsParams")) + session_update_options_result = SessionUpdateOptionsResult.from_dict(obj.get("SessionUpdateOptionsResult")) + session_working_directory_context = SessionWorkingDirectoryContext.from_dict(obj.get("SessionWorkingDirectoryContext")) + session_working_directory_context_host_type = SessionContextHostType(obj.get("SessionWorkingDirectoryContextHostType")) shell_exec_request = ShellExecRequest.from_dict(obj.get("ShellExecRequest")) shell_exec_result = ShellExecResult.from_dict(obj.get("ShellExecResult")) shell_kill_request = ShellKillRequest.from_dict(obj.get("ShellKillRequest")) shell_kill_result = ShellKillResult.from_dict(obj.get("ShellKillResult")) shell_kill_signal = ShellKillSignal(obj.get("ShellKillSignal")) + shutdown_request = ShutdownRequest.from_dict(obj.get("ShutdownRequest")) skill = Skill.from_dict(obj.get("Skill")) skill_list = SkillList.from_dict(obj.get("SkillList")) skills_config_set_disabled_skills_request = SkillsConfigSetDisabledSkillsRequest.from_dict(obj.get("SkillsConfigSetDisabledSkillsRequest")) skills_disable_request = SkillsDisableRequest.from_dict(obj.get("SkillsDisableRequest")) skills_discover_request = SkillsDiscoverRequest.from_dict(obj.get("SkillsDiscoverRequest")) skills_enable_request = SkillsEnableRequest.from_dict(obj.get("SkillsEnableRequest")) + skills_get_invoked_result = SkillsGetInvokedResult.from_dict(obj.get("SkillsGetInvokedResult")) + skills_invoked_skill = SkillsInvokedSkill.from_dict(obj.get("SkillsInvokedSkill")) skills_load_diagnostics = SkillsLoadDiagnostics.from_dict(obj.get("SkillsLoadDiagnostics")) slash_command_agent_prompt_result = SlashCommandAgentPromptResult.from_dict(obj.get("SlashCommandAgentPromptResult")) slash_command_completed_result = SlashCommandCompletedResult.from_dict(obj.get("SlashCommandCompletedResult")) @@ -7963,15 +14909,22 @@ def from_dict(obj: Any) -> 'RPC': slash_command_kind = SlashCommandKind(obj.get("SlashCommandKind")) slash_command_text_result = SlashCommandTextResult.from_dict(obj.get("SlashCommandTextResult")) task_agent_info = TaskAgentInfo.from_dict(obj.get("TaskAgentInfo")) + task_agent_progress = TaskAgentProgress.from_dict(obj.get("TaskAgentProgress")) task_execution_mode = TaskExecutionMode(obj.get("TaskExecutionMode")) task_info = TaskInfo.from_dict(obj.get("TaskInfo")) task_list = TaskList.from_dict(obj.get("TaskList")) tasks_cancel_request = TasksCancelRequest.from_dict(obj.get("TasksCancelRequest")) tasks_cancel_result = TasksCancelResult.from_dict(obj.get("TasksCancelResult")) + tasks_get_current_promotable_result = TasksGetCurrentPromotableResult.from_dict(obj.get("TasksGetCurrentPromotableResult")) + tasks_get_progress_request = TasksGetProgressRequest.from_dict(obj.get("TasksGetProgressRequest")) + tasks_get_progress_result = TasksGetProgressResult.from_dict(obj.get("TasksGetProgressResult")) task_shell_info = TaskShellInfo.from_dict(obj.get("TaskShellInfo")) task_shell_info_attachment_mode = TaskShellInfoAttachmentMode(obj.get("TaskShellInfoAttachmentMode")) + task_shell_progress = from_none(obj.get("TaskShellProgress")) + tasks_promote_current_to_background_result = TasksPromoteCurrentToBackgroundResult.from_dict(obj.get("TasksPromoteCurrentToBackgroundResult")) tasks_promote_to_background_request = TasksPromoteToBackgroundRequest.from_dict(obj.get("TasksPromoteToBackgroundRequest")) tasks_promote_to_background_result = TasksPromoteToBackgroundResult.from_dict(obj.get("TasksPromoteToBackgroundResult")) + tasks_refresh_result = TasksRefreshResult.from_dict(obj.get("TasksRefreshResult")) tasks_remove_request = TasksRemoveRequest.from_dict(obj.get("TasksRemoveRequest")) tasks_remove_result = TasksRemoveResult.from_dict(obj.get("TasksRemoveResult")) tasks_send_message_request = TasksSendMessageRequest.from_dict(obj.get("TasksSendMessageRequest")) @@ -7979,9 +14932,14 @@ def from_dict(obj: Any) -> 'RPC': tasks_start_agent_request = TasksStartAgentRequest.from_dict(obj.get("TasksStartAgentRequest")) tasks_start_agent_result = TasksStartAgentResult.from_dict(obj.get("TasksStartAgentResult")) task_status = TaskStatus(obj.get("TaskStatus")) + tasks_wait_for_pending_result = TasksWaitForPendingResult.from_dict(obj.get("TasksWaitForPendingResult")) + telemetry_set_feature_overrides_request = TelemetrySetFeatureOverridesRequest.from_dict(obj.get("TelemetrySetFeatureOverridesRequest")) + token_auth_info = TokenAuthInfo.from_dict(obj.get("TokenAuthInfo")) tool = Tool.from_dict(obj.get("Tool")) tool_list = ToolList.from_dict(obj.get("ToolList")) + tools_initialize_and_validate_result = ToolsInitializeAndValidateResult.from_dict(obj.get("ToolsInitializeAndValidateResult")) tools_list_request = ToolsListRequest.from_dict(obj.get("ToolsListRequest")) + ui_auto_mode_switch_response = UIAutoModeSwitchResponse(obj.get("UIAutoModeSwitchResponse")) ui_elicitation_array_any_of_field = UIElicitationArrayAnyOfField.from_dict(obj.get("UIElicitationArrayAnyOfField")) ui_elicitation_array_any_of_field_items = UIElicitationArrayAnyOfFieldItems.from_dict(obj.get("UIElicitationArrayAnyOfFieldItems")) ui_elicitation_array_any_of_field_items_any_of = UIElicitationArrayAnyOfFieldItemsAnyOf.from_dict(obj.get("UIElicitationArrayAnyOfFieldItemsAnyOf")) @@ -8003,7 +14961,19 @@ def from_dict(obj: Any) -> 'RPC': ui_elicitation_string_enum_field = UIElicitationStringEnumField.from_dict(obj.get("UIElicitationStringEnumField")) ui_elicitation_string_one_of_field = UIElicitationStringOneOfField.from_dict(obj.get("UIElicitationStringOneOfField")) ui_elicitation_string_one_of_field_one_of = UIElicitationStringOneOfFieldOneOf.from_dict(obj.get("UIElicitationStringOneOfFieldOneOf")) + ui_exit_plan_mode_action = UIExitPlanModeAction(obj.get("UIExitPlanModeAction")) + ui_exit_plan_mode_response = UIExitPlanModeResponse.from_dict(obj.get("UIExitPlanModeResponse")) + ui_handle_pending_auto_mode_switch_request = UIHandlePendingAutoModeSwitchRequest.from_dict(obj.get("UIHandlePendingAutoModeSwitchRequest")) ui_handle_pending_elicitation_request = UIHandlePendingElicitationRequest.from_dict(obj.get("UIHandlePendingElicitationRequest")) + ui_handle_pending_exit_plan_mode_request = UIHandlePendingExitPlanModeRequest.from_dict(obj.get("UIHandlePendingExitPlanModeRequest")) + ui_handle_pending_result = UIHandlePendingResult.from_dict(obj.get("UIHandlePendingResult")) + ui_handle_pending_sampling_request = UIHandlePendingSamplingRequest.from_dict(obj.get("UIHandlePendingSamplingRequest")) + ui_handle_pending_sampling_response = from_dict(lambda x: x, obj.get("UIHandlePendingSamplingResponse")) + ui_handle_pending_user_input_request = UIHandlePendingUserInputRequest.from_dict(obj.get("UIHandlePendingUserInputRequest")) + ui_register_direct_auto_mode_switch_handler_result = UIRegisterDirectAutoModeSwitchHandlerResult.from_dict(obj.get("UIRegisterDirectAutoModeSwitchHandlerResult")) + ui_unregister_direct_auto_mode_switch_handler_request = UIUnregisterDirectAutoModeSwitchHandlerRequest.from_dict(obj.get("UIUnregisterDirectAutoModeSwitchHandlerRequest")) + ui_unregister_direct_auto_mode_switch_handler_result = UIUnregisterDirectAutoModeSwitchHandlerResult.from_dict(obj.get("UIUnregisterDirectAutoModeSwitchHandlerResult")) + ui_user_input_response = UIUserInputResponse.from_dict(obj.get("UIUserInputResponse")) usage_get_metrics_result = UsageGetMetricsResult.from_dict(obj.get("UsageGetMetricsResult")) usage_metrics_code_changes = UsageMetricsCodeChanges.from_dict(obj.get("UsageMetricsCodeChanges")) usage_metrics_model_metric = UsageMetricsModelMetric.from_dict(obj.get("UsageMetricsModelMetric")) @@ -8011,24 +14981,47 @@ def from_dict(obj: Any) -> 'RPC': usage_metrics_model_metric_token_detail = UsageMetricsModelMetricTokenDetail.from_dict(obj.get("UsageMetricsModelMetricTokenDetail")) usage_metrics_model_metric_usage = UsageMetricsModelMetricUsage.from_dict(obj.get("UsageMetricsModelMetricUsage")) usage_metrics_token_detail = UsageMetricsTokenDetail.from_dict(obj.get("UsageMetricsTokenDetail")) + user_auth_info = UserAuthInfo.from_dict(obj.get("UserAuthInfo")) + user_tool_session_approval_commands = UserToolSessionApprovalCommands.from_dict(obj.get("UserToolSessionApprovalCommands")) + user_tool_session_approval_custom_tool = UserToolSessionApprovalCustomTool.from_dict(obj.get("UserToolSessionApprovalCustomTool")) + user_tool_session_approval_extension_management = UserToolSessionApprovalExtensionManagement.from_dict(obj.get("UserToolSessionApprovalExtensionManagement")) + user_tool_session_approval_extension_permission_access = UserToolSessionApprovalExtensionPermissionAccess.from_dict(obj.get("UserToolSessionApprovalExtensionPermissionAccess")) + user_tool_session_approval_mcp = UserToolSessionApprovalMCP.from_dict(obj.get("UserToolSessionApprovalMcp")) + user_tool_session_approval_memory = UserToolSessionApprovalMemory.from_dict(obj.get("UserToolSessionApprovalMemory")) + user_tool_session_approval_read = UserToolSessionApprovalRead.from_dict(obj.get("UserToolSessionApprovalRead")) + user_tool_session_approval_write = UserToolSessionApprovalWrite.from_dict(obj.get("UserToolSessionApprovalWrite")) + workspaces_checkpoints = WorkspacesCheckpoints.from_dict(obj.get("WorkspacesCheckpoints")) workspaces_create_file_request = WorkspacesCreateFileRequest.from_dict(obj.get("WorkspacesCreateFileRequest")) workspaces_get_workspace_result = WorkspacesGetWorkspaceResult.from_dict(obj.get("WorkspacesGetWorkspaceResult")) + workspaces_list_checkpoints_result = WorkspacesListCheckpointsResult.from_dict(obj.get("WorkspacesListCheckpointsResult")) workspaces_list_files_result = WorkspacesListFilesResult.from_dict(obj.get("WorkspacesListFilesResult")) + workspaces_read_checkpoint_request = WorkspacesReadCheckpointRequest.from_dict(obj.get("WorkspacesReadCheckpointRequest")) + workspaces_read_checkpoint_result = WorkspacesReadCheckpointResult.from_dict(obj.get("WorkspacesReadCheckpointResult")) workspaces_read_file_request = WorkspacesReadFileRequest.from_dict(obj.get("WorkspacesReadFileRequest")) workspaces_read_file_result = WorkspacesReadFileResult.from_dict(obj.get("WorkspacesReadFileResult")) - return RPC(account_get_quota_request, account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_list, agent_reload_result, agent_select_request, agent_select_result, auth_info_type, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, current_model, discovered_mcp_server, discovered_mcp_server_type, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, handle_pending_tool_call_request, handle_pending_tool_call_result, history_compact_context_window, history_compact_result, history_truncate_request, history_truncate_result, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_oauth_login_request, mcp_oauth_login_result, mcp_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_auth, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_list, model, model_billing, model_billing_token_prices, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_picker_category, model_picker_price_category, model_policy, model_policy_state, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_request, permission_decision, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_request_result, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, queued_command_handled, queued_command_not_handled, queued_command_result, remote_enable_request, remote_enable_result, remote_session_connection_result, remote_session_mode, server_skill, server_skill_list, session_auth_status, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_log_level, session_mode, sessions_fork_request, sessions_fork_result, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_text_result, task_agent_info, task_execution_mode, task_info, task_list, tasks_cancel_request, tasks_cancel_result, task_shell_info, task_shell_info_attachment_mode, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tool, tool_list, tools_list_request, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_handle_pending_elicitation_request, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_files_result, workspaces_read_file_request, workspaces_read_file_result) + workspaces_save_large_paste_request = WorkspacesSaveLargePasteRequest.from_dict(obj.get("WorkspacesSaveLargePasteRequest")) + workspaces_save_large_paste_result = WorkspacesSaveLargePasteResult.from_dict(obj.get("WorkspacesSaveLargePasteResult")) + session_context_info = from_union([SessionContextInfo.from_dict, from_none], obj.get("SessionContextInfo")) + task_progress = from_union([TaskProgressClass.from_dict, from_none], obj.get("TaskProgress")) + workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) + return RPC(abort_request, abort_result, account_get_quota_request, account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_reload_result, agent_select_request, agent_select_result, api_key_auth_info, auth_info, auth_info_type, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, discovered_mcp_server, discovered_mcp_server_type, enqueue_command_params, enqueue_command_result, env_auth_info, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_result, execute_command_params, execute_command_result, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, gh_cli_auth_info, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_compact_context_window, history_compact_result, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, installed_plugin, installed_plugin_source, installed_plugin_source_github, installed_plugin_source_local, installed_plugin_source_url, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, lsp_initialize_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_oauth_login_request, mcp_oauth_login_result, mcp_remove_git_hub_result, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_auth, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_list, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, model, model_billing, model_billing_token_prices, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_picker_category, model_picker_price_category, model_policy, model_policy_state, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, options_update_env_value_mode, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_cancelled, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, queued_command_handled, queued_command_not_handled, queued_command_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_most_recent_result, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_mode, schedule_entry, schedule_list, schedule_stop_request, schedule_stop_result, send_agent_mode, send_attachment, send_attachment_blob, send_attachment_directory, send_attachment_file, send_attachment_file_line_range, send_attachment_github_reference, send_attachment_github_reference_type, send_attachment_selection, send_attachment_selection_details, send_attachment_selection_details_end, send_attachment_selection_details_start, send_mode, send_request, send_result, server_skill, server_skill_list, session_auth_status, session_bulk_delete_result, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_github, session_installed_plugin_source_local, session_installed_plugin_source_url, session_list, session_load_deferred_repo_hooks_result, session_log_level, session_metadata, session_metadata_snapshot, session_mode, session_prune_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_close_request, sessions_close_result, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_prune_old_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, session_update_options_params, session_update_options_result, session_working_directory_context, session_working_directory_context_host_type, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, shutdown_request, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_text_result, task_agent_info, task_agent_progress, task_execution_mode, task_info, task_list, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, tool, tool_list, tools_initialize_and_validate_result, tools_list_request, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, user_auth_info, user_tool_session_approval_commands, user_tool_session_approval_custom_tool, user_tool_session_approval_extension_management, user_tool_session_approval_extension_permission_access, user_tool_session_approval_mcp, user_tool_session_approval_memory, user_tool_session_approval_read, user_tool_session_approval_write, workspaces_checkpoints, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_save_large_paste_request, workspaces_save_large_paste_result, session_context_info, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} + result["AbortRequest"] = to_class(AbortRequest, self.abort_request) + result["AbortResult"] = to_class(AbortResult, self.abort_result) result["AccountGetQuotaRequest"] = to_class(AccountGetQuotaRequest, self.account_get_quota_request) result["AccountGetQuotaResult"] = to_class(AccountGetQuotaResult, self.account_get_quota_result) result["AccountQuotaSnapshot"] = to_class(AccountQuotaSnapshot, self.account_quota_snapshot) result["AgentGetCurrentResult"] = to_class(AgentGetCurrentResult, self.agent_get_current_result) result["AgentInfo"] = to_class(AgentInfo, self.agent_info) + result["AgentInfoSource"] = to_enum(AgentInfoSource, self.agent_info_source) result["AgentList"] = to_class(AgentList, self.agent_list) result["AgentReloadResult"] = to_class(AgentReloadResult, self.agent_reload_result) result["AgentSelectRequest"] = to_class(AgentSelectRequest, self.agent_select_request) result["AgentSelectResult"] = to_class(AgentSelectResult, self.agent_select_result) + result["ApiKeyAuthInfo"] = to_class(APIKeyAuthInfo, self.api_key_auth_info) + result["AuthInfo"] = to_class(AuthInfo, self.auth_info) result["AuthInfoType"] = to_enum(AuthInfoType, self.auth_info_type) result["CommandList"] = to_class(CommandList, self.command_list) result["CommandsHandlePendingCommandRequest"] = to_class(CommandsHandlePendingCommandRequest, self.commands_handle_pending_command_request) @@ -8044,9 +15037,28 @@ def to_dict(self) -> dict: result["ConnectRequest"] = to_class(ConnectRequest, self.connect_request) result["ConnectResult"] = to_class(ConnectResult, self.connect_result) result["ContentFilterMode"] = to_enum(ContentFilterMode, self.content_filter_mode) + result["CopilotApiTokenAuthInfo"] = to_class(CopilotAPITokenAuthInfo, self.copilot_api_token_auth_info) + result["CopilotUserResponse"] = to_class(CopilotUserResponse, self.copilot_user_response) + result["CopilotUserResponseEndpoints"] = to_class(CopilotUserResponseEndpoints, self.copilot_user_response_endpoints) + result["CopilotUserResponseQuotaSnapshots"] = from_dict(lambda x: from_union([lambda x: to_class(CopilotUserResponseQuotaSnapshots, x), from_none], x), self.copilot_user_response_quota_snapshots) + result["CopilotUserResponseQuotaSnapshotsChat"] = to_class(CopilotUserResponseQuotaSnapshotsChat, self.copilot_user_response_quota_snapshots_chat) + result["CopilotUserResponseQuotaSnapshotsCompletions"] = to_class(CopilotUserResponseQuotaSnapshotsCompletions, self.copilot_user_response_quota_snapshots_completions) + result["CopilotUserResponseQuotaSnapshotsPremiumInteractions"] = to_class(CopilotUserResponseQuotaSnapshotsPremiumInteractions, self.copilot_user_response_quota_snapshots_premium_interactions) result["CurrentModel"] = to_class(CurrentModel, self.current_model) result["DiscoveredMcpServer"] = to_class(DiscoveredMCPServer, self.discovered_mcp_server) result["DiscoveredMcpServerType"] = to_enum(DiscoveredMCPServerType, self.discovered_mcp_server_type) + result["EnqueueCommandParams"] = to_class(EnqueueCommandParams, self.enqueue_command_params) + result["EnqueueCommandResult"] = to_class(EnqueueCommandResult, self.enqueue_command_result) + result["EnvAuthInfo"] = to_class(EnvAuthInfo, self.env_auth_info) + result["EventLogReadRequest"] = to_class(EventLogReadRequest, self.event_log_read_request) + result["EventLogReleaseInterestResult"] = to_class(EventLogReleaseInterestResult, self.event_log_release_interest_result) + result["EventLogTailResult"] = to_class(EventLogTailResult, self.event_log_tail_result) + result["EventLogTypes"] = from_union([lambda x: from_list(from_str, x), lambda x: to_enum(EventLogTypes, x)], self.event_log_types) + result["EventsAgentScope"] = to_enum(EventsAgentScope, self.events_agent_scope) + result["EventsCursorStatus"] = to_enum(EventsCursorStatus, self.events_cursor_status) + result["EventsReadResult"] = to_class(EventsReadResult, self.events_read_result) + result["ExecuteCommandParams"] = to_class(ExecuteCommandParams, self.execute_command_params) + result["ExecuteCommandResult"] = to_class(ExecuteCommandResult, self.execute_command_result) result["Extension"] = to_class(Extension, self.extension) result["ExtensionList"] = to_class(ExtensionList, self.extension_list) result["ExtensionsDisableRequest"] = to_class(ExtensionsDisableRequest, self.extensions_disable_request) @@ -8070,18 +15082,31 @@ def to_dict(self) -> dict: result["FilterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x)], self.filter_mapping) result["FleetStartRequest"] = to_class(FleetStartRequest, self.fleet_start_request) result["FleetStartResult"] = to_class(FleetStartResult, self.fleet_start_result) + result["GhCliAuthInfo"] = to_class(GhCLIAuthInfo, self.gh_cli_auth_info) result["HandlePendingToolCallRequest"] = to_class(HandlePendingToolCallRequest, self.handle_pending_tool_call_request) result["HandlePendingToolCallResult"] = to_class(HandlePendingToolCallResult, self.handle_pending_tool_call_result) + result["HistoryAbortManualCompactionResult"] = to_class(HistoryAbortManualCompactionResult, self.history_abort_manual_compaction_result) + result["HistoryCancelBackgroundCompactionResult"] = to_class(HistoryCancelBackgroundCompactionResult, self.history_cancel_background_compaction_result) result["HistoryCompactContextWindow"] = to_class(HistoryCompactContextWindow, self.history_compact_context_window) result["HistoryCompactResult"] = to_class(HistoryCompactResult, self.history_compact_result) + result["HistorySummarizeForHandoffResult"] = to_class(HistorySummarizeForHandoffResult, self.history_summarize_for_handoff_result) result["HistoryTruncateRequest"] = to_class(HistoryTruncateRequest, self.history_truncate_request) result["HistoryTruncateResult"] = to_class(HistoryTruncateResult, self.history_truncate_result) + result["HMACAuthInfo"] = to_class(HMACAuthInfo, self.hmac_auth_info) + result["InstalledPlugin"] = to_class(InstalledPlugin, self.installed_plugin) + result["InstalledPluginSource"] = from_union([lambda x: to_class(InstalledPluginSource, x), from_str], self.installed_plugin_source) + result["InstalledPluginSourceGithub"] = to_class(InstalledPluginSourceGithub, self.installed_plugin_source_github) + result["InstalledPluginSourceLocal"] = to_class(InstalledPluginSourceLocal, self.installed_plugin_source_local) + result["InstalledPluginSourceUrl"] = to_class(InstalledPluginSourceURL, self.installed_plugin_source_url) result["InstructionsGetSourcesResult"] = to_class(InstructionsGetSourcesResult, self.instructions_get_sources_result) result["InstructionsSources"] = to_class(InstructionsSources, self.instructions_sources) result["InstructionsSourcesLocation"] = to_enum(InstructionsSourcesLocation, self.instructions_sources_location) result["InstructionsSourcesType"] = to_enum(InstructionsSourcesType, self.instructions_sources_type) result["LogRequest"] = to_class(LogRequest, self.log_request) result["LogResult"] = to_class(LogResult, self.log_result) + result["LspInitializeRequest"] = to_class(LspInitializeRequest, self.lsp_initialize_request) + result["McpCancelSamplingExecutionParams"] = to_class(MCPCancelSamplingExecutionParams, self.mcp_cancel_sampling_execution_params) + result["McpCancelSamplingExecutionResult"] = to_class(MCPCancelSamplingExecutionResult, self.mcp_cancel_sampling_execution_result) result["McpConfigAddRequest"] = to_class(MCPConfigAddRequest, self.mcp_config_add_request) result["McpConfigDisableRequest"] = to_class(MCPConfigDisableRequest, self.mcp_config_disable_request) result["McpConfigEnableRequest"] = to_class(MCPConfigEnableRequest, self.mcp_config_enable_request) @@ -8092,8 +15117,14 @@ def to_dict(self) -> dict: result["McpDiscoverRequest"] = to_class(MCPDiscoverRequest, self.mcp_discover_request) result["McpDiscoverResult"] = to_class(MCPDiscoverResult, self.mcp_discover_result) result["McpEnableRequest"] = to_class(MCPEnableRequest, self.mcp_enable_request) + result["McpExecuteSamplingParams"] = to_class(MCPExecuteSamplingParams, self.mcp_execute_sampling_params) + result["McpExecuteSamplingRequest"] = from_dict(lambda x: x, self.mcp_execute_sampling_request) + result["McpExecuteSamplingResult"] = from_dict(lambda x: x, self.mcp_execute_sampling_result) result["McpOauthLoginRequest"] = to_class(MCPOauthLoginRequest, self.mcp_oauth_login_request) result["McpOauthLoginResult"] = to_class(MCPOauthLoginResult, self.mcp_oauth_login_result) + result["McpRemoveGitHubResult"] = to_class(MCPRemoveGitHubResult, self.mcp_remove_git_hub_result) + result["McpSamplingExecutionAction"] = to_enum(MCPSamplingExecutionAction, self.mcp_sampling_execution_action) + result["McpSamplingExecutionResult"] = to_class(MCPSamplingExecutionResult, self.mcp_sampling_execution_result) result["McpServer"] = to_class(MCPServer, self.mcp_server) result["McpServerConfig"] = to_class(MCPServerConfig, self.mcp_server_config) result["McpServerConfigHttp"] = to_class(MCPServerConfigHTTP, self.mcp_server_config_http) @@ -8102,6 +15133,22 @@ def to_dict(self) -> dict: result["McpServerConfigHttpType"] = to_enum(MCPServerConfigHTTPType, self.mcp_server_config_http_type) result["McpServerConfigStdio"] = to_class(MCPServerConfigStdio, self.mcp_server_config_stdio) result["McpServerList"] = to_class(MCPServerList, self.mcp_server_list) + result["McpSetEnvValueModeDetails"] = to_enum(MCPSetEnvValueModeDetails, self.mcp_set_env_value_mode_details) + result["McpSetEnvValueModeParams"] = to_class(MCPSetEnvValueModeParams, self.mcp_set_env_value_mode_params) + result["McpSetEnvValueModeResult"] = to_class(MCPSetEnvValueModeResult, self.mcp_set_env_value_mode_result) + result["MetadataContextInfoRequest"] = to_class(MetadataContextInfoRequest, self.metadata_context_info_request) + result["MetadataContextInfoResult"] = to_class(MetadataContextInfoResult, self.metadata_context_info_result) + result["MetadataIsProcessingResult"] = to_class(MetadataIsProcessingResult, self.metadata_is_processing_result) + result["MetadataRecomputeContextTokensRequest"] = to_class(MetadataRecomputeContextTokensRequest, self.metadata_recompute_context_tokens_request) + result["MetadataRecomputeContextTokensResult"] = to_class(MetadataRecomputeContextTokensResult, self.metadata_recompute_context_tokens_result) + result["MetadataRecordContextChangeRequest"] = to_class(MetadataRecordContextChangeRequest, self.metadata_record_context_change_request) + result["MetadataRecordContextChangeResult"] = to_class(MetadataRecordContextChangeResult, self.metadata_record_context_change_result) + result["MetadataSetWorkingDirectoryRequest"] = to_class(MetadataSetWorkingDirectoryRequest, self.metadata_set_working_directory_request) + result["MetadataSetWorkingDirectoryResult"] = to_class(MetadataSetWorkingDirectoryResult, self.metadata_set_working_directory_result) + result["MetadataSnapshotCurrentMode"] = to_enum(MetadataSnapshotCurrentMode, self.metadata_snapshot_current_mode) + result["MetadataSnapshotRemoteMetadata"] = to_class(MetadataSnapshotRemoteMetadata, self.metadata_snapshot_remote_metadata) + result["MetadataSnapshotRemoteMetadataRepository"] = to_class(MetadataSnapshotRemoteMetadataRepository, self.metadata_snapshot_remote_metadata_repository) + result["MetadataSnapshotRemoteMetadataTaskType"] = to_enum(MetadataSnapshotRemoteMetadataTaskType, self.metadata_snapshot_remote_metadata_task_type) result["Model"] = to_class(Model, self.model) result["ModelBilling"] = to_class(ModelBilling, self.model_billing) result["ModelBillingTokenPrices"] = to_class(ModelBillingTokenPrices, self.model_billing_token_prices) @@ -8118,13 +15165,23 @@ def to_dict(self) -> dict: result["ModelPickerPriceCategory"] = to_enum(ModelPickerPriceCategory, self.model_picker_price_category) result["ModelPolicy"] = to_class(ModelPolicy, self.model_policy) result["ModelPolicyState"] = to_enum(ModelPolicyState, self.model_policy_state) + result["ModelSetReasoningEffortRequest"] = to_class(ModelSetReasoningEffortRequest, self.model_set_reasoning_effort_request) + result["ModelSetReasoningEffortResult"] = to_class(ModelSetReasoningEffortResult, self.model_set_reasoning_effort_result) result["ModelsListRequest"] = to_class(ModelsListRequest, self.models_list_request) result["ModelSwitchToRequest"] = to_class(ModelSwitchToRequest, self.model_switch_to_request) result["ModelSwitchToResult"] = to_class(ModelSwitchToResult, self.model_switch_to_result) result["ModeSetRequest"] = to_class(ModeSetRequest, self.mode_set_request) result["NameGetResult"] = to_class(NameGetResult, self.name_get_result) + result["NameSetAutoRequest"] = to_class(NameSetAutoRequest, self.name_set_auto_request) + result["NameSetAutoResult"] = to_class(NameSetAutoResult, self.name_set_auto_result) result["NameSetRequest"] = to_class(NameSetRequest, self.name_set_request) + result["OptionsUpdateEnvValueMode"] = to_enum(MCPSetEnvValueModeDetails, self.options_update_env_value_mode) + result["PendingPermissionRequest"] = to_class(PendingPermissionRequest, self.pending_permission_request) + result["PendingPermissionRequestList"] = to_class(PendingPermissionRequestList, self.pending_permission_request_list) result["PermissionDecision"] = to_class(PermissionDecision, self.permission_decision) + result["PermissionDecisionApproved"] = to_class(PermissionDecisionApproved, self.permission_decision_approved) + result["PermissionDecisionApprovedForLocation"] = to_class(PermissionDecisionApprovedForLocation, self.permission_decision_approved_for_location) + result["PermissionDecisionApprovedForSession"] = to_class(PermissionDecisionApprovedForSession, self.permission_decision_approved_for_session) result["PermissionDecisionApproveForLocation"] = to_class(PermissionDecisionApproveForLocation, self.permission_decision_approve_for_location) result["PermissionDecisionApproveForLocationApproval"] = to_class(PermissionDecisionApproveForLocationApproval, self.permission_decision_approve_for_location_approval) result["PermissionDecisionApproveForLocationApprovalCommands"] = to_class(PermissionDecisionApproveForLocationApprovalCommands, self.permission_decision_approve_for_location_approval_commands) @@ -8149,14 +15206,50 @@ def to_dict(self) -> dict: result["PermissionDecisionApproveForSessionApprovalWrite"] = to_class(PermissionDecisionApproveForSessionApprovalWrite, self.permission_decision_approve_for_session_approval_write) result["PermissionDecisionApproveOnce"] = to_class(PermissionDecisionApproveOnce, self.permission_decision_approve_once) result["PermissionDecisionApprovePermanently"] = to_class(PermissionDecisionApprovePermanently, self.permission_decision_approve_permanently) + result["PermissionDecisionCancelled"] = to_class(PermissionDecisionCancelled, self.permission_decision_cancelled) + result["PermissionDecisionDeniedByContentExclusionPolicy"] = to_class(PermissionDecisionDeniedByContentExclusionPolicy, self.permission_decision_denied_by_content_exclusion_policy) + result["PermissionDecisionDeniedByPermissionRequestHook"] = to_class(PermissionDecisionDeniedByPermissionRequestHook, self.permission_decision_denied_by_permission_request_hook) + result["PermissionDecisionDeniedByRules"] = to_class(PermissionDecisionDeniedByRules, self.permission_decision_denied_by_rules) + result["PermissionDecisionDeniedInteractivelyByUser"] = to_class(PermissionDecisionDeniedInteractivelyByUser, self.permission_decision_denied_interactively_by_user) + result["PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser"] = to_class(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser, self.permission_decision_denied_no_approval_rule_and_could_not_request_from_user) result["PermissionDecisionReject"] = to_class(PermissionDecisionReject, self.permission_decision_reject) result["PermissionDecisionRequest"] = to_class(PermissionDecisionRequest, self.permission_decision_request) result["PermissionDecisionUserNotAvailable"] = to_class(PermissionDecisionUserNotAvailable, self.permission_decision_user_not_available) + result["PermissionPathsAddParams"] = to_class(PermissionPathsAddParams, self.permission_paths_add_params) + result["PermissionPathsAllowedCheckParams"] = to_class(PermissionPathsAllowedCheckParams, self.permission_paths_allowed_check_params) + result["PermissionPathsAllowedCheckResult"] = to_class(PermissionPathsAllowedCheckResult, self.permission_paths_allowed_check_result) + result["PermissionPathsConfig"] = to_class(PermissionPathsConfig, self.permission_paths_config) + result["PermissionPathsList"] = to_class(PermissionPathsList, self.permission_paths_list) + result["PermissionPathsUpdatePrimaryParams"] = to_class(PermissionPathsUpdatePrimaryParams, self.permission_paths_update_primary_params) + result["PermissionPathsWorkspaceCheckParams"] = to_class(PermissionPathsWorkspaceCheckParams, self.permission_paths_workspace_check_params) + result["PermissionPathsWorkspaceCheckResult"] = to_class(PermissionPathsWorkspaceCheckResult, self.permission_paths_workspace_check_result) + result["PermissionPromptShownNotification"] = to_class(PermissionPromptShownNotification, self.permission_prompt_shown_notification) result["PermissionRequestResult"] = to_class(PermissionRequestResult, self.permission_request_result) + result["PermissionRulesSet"] = to_class(PermissionRulesSet, self.permission_rules_set) + result["PermissionsConfigureAdditionalContentExclusionPolicy"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicy, self.permissions_configure_additional_content_exclusion_policy) + result["PermissionsConfigureAdditionalContentExclusionPolicyRule"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicyRule, self.permissions_configure_additional_content_exclusion_policy_rule) + result["PermissionsConfigureAdditionalContentExclusionPolicyRuleSource"] = to_class(PermissionsConfigureAdditionalContentExclusionPolicyRuleSource, self.permissions_configure_additional_content_exclusion_policy_rule_source) + result["PermissionsConfigureAdditionalContentExclusionPolicyScope"] = to_enum(PermissionsConfigureAdditionalContentExclusionPolicyScope, self.permissions_configure_additional_content_exclusion_policy_scope) + result["PermissionsConfigureParams"] = to_class(PermissionsConfigureParams, self.permissions_configure_params) + result["PermissionsConfigureResult"] = to_class(PermissionsConfigureResult, self.permissions_configure_result) + result["PermissionsModifyRulesParams"] = to_class(PermissionsModifyRulesParams, self.permissions_modify_rules_params) + result["PermissionsModifyRulesResult"] = to_class(PermissionsModifyRulesResult, self.permissions_modify_rules_result) + result["PermissionsModifyRulesScope"] = to_enum(PermissionsModifyRulesScope, self.permissions_modify_rules_scope) + result["PermissionsNotifyPromptShownResult"] = to_class(PermissionsNotifyPromptShownResult, self.permissions_notify_prompt_shown_result) + result["PermissionsPathsAddResult"] = to_class(PermissionsPathsAddResult, self.permissions_paths_add_result) + result["PermissionsPathsListRequest"] = to_class(PermissionsPathsListRequest, self.permissions_paths_list_request) + result["PermissionsPathsUpdatePrimaryResult"] = to_class(PermissionsPathsUpdatePrimaryResult, self.permissions_paths_update_primary_result) + result["PermissionsPendingRequestsRequest"] = to_class(PermissionsPendingRequestsRequest, self.permissions_pending_requests_request) result["PermissionsResetSessionApprovalsRequest"] = to_class(PermissionsResetSessionApprovalsRequest, self.permissions_reset_session_approvals_request) result["PermissionsResetSessionApprovalsResult"] = to_class(PermissionsResetSessionApprovalsResult, self.permissions_reset_session_approvals_result) result["PermissionsSetApproveAllRequest"] = to_class(PermissionsSetApproveAllRequest, self.permissions_set_approve_all_request) result["PermissionsSetApproveAllResult"] = to_class(PermissionsSetApproveAllResult, self.permissions_set_approve_all_result) + result["PermissionsSetApproveAllSource"] = to_enum(PermissionsSetApproveAllSource, self.permissions_set_approve_all_source) + result["PermissionsSetRequiredRequest"] = to_class(PermissionsSetRequiredRequest, self.permissions_set_required_request) + result["PermissionsSetRequiredResult"] = to_class(PermissionsSetRequiredResult, self.permissions_set_required_result) + result["PermissionsUrlsSetUnrestrictedModeResult"] = to_class(PermissionsUrlsSetUnrestrictedModeResult, self.permissions_urls_set_unrestricted_mode_result) + result["PermissionUrlsConfig"] = to_class(PermissionUrlsConfig, self.permission_urls_config) + result["PermissionUrlsSetUnrestrictedModeParams"] = to_class(PermissionUrlsSetUnrestrictedModeParams, self.permission_urls_set_unrestricted_mode_params) result["PingRequest"] = to_class(PingRequest, self.ping_request) result["PingResult"] = to_class(PingResult, self.ping_result) result["PlanReadResult"] = to_class(PlanReadResult, self.plan_read_result) @@ -8166,13 +15259,45 @@ def to_dict(self) -> dict: result["QueuedCommandHandled"] = to_class(QueuedCommandHandled, self.queued_command_handled) result["QueuedCommandNotHandled"] = to_class(QueuedCommandNotHandled, self.queued_command_not_handled) result["QueuedCommandResult"] = to_class(QueuedCommandResult, self.queued_command_result) + result["QueuePendingItems"] = to_class(QueuePendingItems, self.queue_pending_items) + result["QueuePendingItemsKind"] = to_enum(QueuePendingItemsKind, self.queue_pending_items_kind) + result["QueuePendingItemsResult"] = to_class(QueuePendingItemsResult, self.queue_pending_items_result) + result["QueueRemoveMostRecentResult"] = to_class(QueueRemoveMostRecentResult, self.queue_remove_most_recent_result) + result["RegisterEventInterestParams"] = to_class(RegisterEventInterestParams, self.register_event_interest_params) + result["RegisterEventInterestResult"] = to_class(RegisterEventInterestResult, self.register_event_interest_result) + result["ReleaseEventInterestParams"] = to_class(ReleaseEventInterestParams, self.release_event_interest_params) result["RemoteEnableRequest"] = to_class(RemoteEnableRequest, self.remote_enable_request) result["RemoteEnableResult"] = to_class(RemoteEnableResult, self.remote_enable_result) + result["RemoteNotifySteerableChangedRequest"] = to_class(RemoteNotifySteerableChangedRequest, self.remote_notify_steerable_changed_request) + result["RemoteNotifySteerableChangedResult"] = to_class(RemoteNotifySteerableChangedResult, self.remote_notify_steerable_changed_result) result["RemoteSessionConnectionResult"] = to_class(RemoteSessionConnectionResult, self.remote_session_connection_result) result["RemoteSessionMode"] = to_enum(RemoteSessionMode, self.remote_session_mode) + result["ScheduleEntry"] = to_class(ScheduleEntry, self.schedule_entry) + result["ScheduleList"] = to_class(ScheduleList, self.schedule_list) + result["ScheduleStopRequest"] = to_class(ScheduleStopRequest, self.schedule_stop_request) + result["ScheduleStopResult"] = to_class(ScheduleStopResult, self.schedule_stop_result) + result["SendAgentMode"] = to_enum(SendAgentMode, self.send_agent_mode) + result["SendAttachment"] = to_class(SendAttachment, self.send_attachment) + result["SendAttachmentBlob"] = to_class(SendAttachmentBlob, self.send_attachment_blob) + result["SendAttachmentDirectory"] = to_class(SendAttachmentDirectory, self.send_attachment_directory) + result["SendAttachmentFile"] = to_class(SendAttachmentFile, self.send_attachment_file) + result["SendAttachmentFileLineRange"] = to_class(SendAttachmentFileLineRange, self.send_attachment_file_line_range) + result["SendAttachmentGithubReference"] = to_class(SendAttachmentGithubReference, self.send_attachment_github_reference) + result["SendAttachmentGithubReferenceType"] = to_enum(SendAttachmentGithubReferenceTypeEnum, self.send_attachment_github_reference_type) + result["SendAttachmentSelection"] = to_class(SendAttachmentSelection, self.send_attachment_selection) + result["SendAttachmentSelectionDetails"] = to_class(SendAttachmentSelectionDetails, self.send_attachment_selection_details) + result["SendAttachmentSelectionDetailsEnd"] = to_class(SendAttachmentSelectionDetailsEnd, self.send_attachment_selection_details_end) + result["SendAttachmentSelectionDetailsStart"] = to_class(SendAttachmentSelectionDetailsStart, self.send_attachment_selection_details_start) + result["SendMode"] = to_enum(SendMode, self.send_mode) + result["SendRequest"] = to_class(SendRequest, self.send_request) + result["SendResult"] = to_class(SendResult, self.send_result) result["ServerSkill"] = to_class(ServerSkill, self.server_skill) result["ServerSkillList"] = to_class(ServerSkillList, self.server_skill_list) result["SessionAuthStatus"] = to_class(SessionAuthStatus, self.session_auth_status) + result["SessionBulkDeleteResult"] = to_class(SessionBulkDeleteResult, self.session_bulk_delete_result) + result["SessionContext"] = to_class(SessionContext, self.session_context) + result["SessionContextHostType"] = to_enum(SessionContextHostType, self.session_context_host_type) + result["SessionEnrichMetadataResult"] = to_class(SessionEnrichMetadataResult, self.session_enrich_metadata_result) result["SessionFsAppendFileRequest"] = to_class(SessionFSAppendFileRequest, self.session_fs_append_file_request) result["SessionFsError"] = to_class(SessionFSError, self.session_fs_error) result["SessionFsErrorCode"] = to_enum(SessionFSErrorCode, self.session_fs_error_code) @@ -8201,21 +15326,68 @@ def to_dict(self) -> dict: result["SessionFsStatRequest"] = to_class(SessionFSStatRequest, self.session_fs_stat_request) result["SessionFsStatResult"] = to_class(SessionFSStatResult, self.session_fs_stat_result) result["SessionFsWriteFileRequest"] = to_class(SessionFSWriteFileRequest, self.session_fs_write_file_request) + result["SessionInstalledPlugin"] = to_class(SessionInstalledPlugin, self.session_installed_plugin) + result["SessionInstalledPluginSource"] = from_union([lambda x: to_class(SessionInstalledPluginSource, x), from_str], self.session_installed_plugin_source) + result["SessionInstalledPluginSourceGithub"] = to_class(SessionInstalledPluginSourceGithub, self.session_installed_plugin_source_github) + result["SessionInstalledPluginSourceLocal"] = to_class(SessionInstalledPluginSourceLocal, self.session_installed_plugin_source_local) + result["SessionInstalledPluginSourceUrl"] = to_class(SessionInstalledPluginSourceURL, self.session_installed_plugin_source_url) + result["SessionList"] = to_class(SessionList, self.session_list) + result["SessionLoadDeferredRepoHooksResult"] = to_class(SessionLoadDeferredRepoHooksResult, self.session_load_deferred_repo_hooks_result) result["SessionLogLevel"] = to_enum(SessionLogLevel, self.session_log_level) + result["SessionMetadata"] = to_class(SessionMetadata, self.session_metadata) + result["SessionMetadataSnapshot"] = to_class(SessionMetadataSnapshot, self.session_metadata_snapshot) result["SessionMode"] = to_enum(SessionMode, self.session_mode) + result["SessionPruneResult"] = to_class(SessionPruneResult, self.session_prune_result) + result["SessionsBulkDeleteRequest"] = to_class(SessionsBulkDeleteRequest, self.sessions_bulk_delete_request) + result["SessionsCheckInUseRequest"] = to_class(SessionsCheckInUseRequest, self.sessions_check_in_use_request) + result["SessionsCheckInUseResult"] = to_class(SessionsCheckInUseResult, self.sessions_check_in_use_result) + result["SessionsCloseRequest"] = to_class(SessionsCloseRequest, self.sessions_close_request) + result["SessionsCloseResult"] = to_class(SessionsCloseResult, self.sessions_close_result) + result["SessionsEnrichMetadataRequest"] = to_class(SessionsEnrichMetadataRequest, self.sessions_enrich_metadata_request) + result["SessionSetCredentialsParams"] = to_class(SessionSetCredentialsParams, self.session_set_credentials_params) + result["SessionSetCredentialsResult"] = to_class(SessionSetCredentialsResult, self.session_set_credentials_result) + result["SessionsFindByPrefixRequest"] = to_class(SessionsFindByPrefixRequest, self.sessions_find_by_prefix_request) + result["SessionsFindByPrefixResult"] = to_class(SessionsFindByPrefixResult, self.sessions_find_by_prefix_result) + result["SessionsFindByTaskIDRequest"] = to_class(SessionsFindByTaskIDRequest, self.sessions_find_by_task_id_request) + result["SessionsFindByTaskIDResult"] = to_class(SessionsFindByTaskIDResult, self.sessions_find_by_task_id_result) result["SessionsForkRequest"] = to_class(SessionsForkRequest, self.sessions_fork_request) result["SessionsForkResult"] = to_class(SessionsForkResult, self.sessions_fork_result) + result["SessionsGetEventFilePathRequest"] = to_class(SessionsGetEventFilePathRequest, self.sessions_get_event_file_path_request) + result["SessionsGetEventFilePathResult"] = to_class(SessionsGetEventFilePathResult, self.sessions_get_event_file_path_result) + result["SessionsGetLastForContextRequest"] = to_class(SessionsGetLastForContextRequest, self.sessions_get_last_for_context_request) + result["SessionsGetLastForContextResult"] = to_class(SessionsGetLastForContextResult, self.sessions_get_last_for_context_result) + result["SessionsGetPersistedRemoteSteerableRequest"] = to_class(SessionsGetPersistedRemoteSteerableRequest, self.sessions_get_persisted_remote_steerable_request) + result["SessionsGetPersistedRemoteSteerableResult"] = to_class(SessionsGetPersistedRemoteSteerableResult, self.sessions_get_persisted_remote_steerable_result) + result["SessionSizes"] = to_class(SessionSizes, self.session_sizes) + result["SessionsListRequest"] = to_class(SessionsListRequest, self.sessions_list_request) + result["SessionsLoadDeferredRepoHooksRequest"] = to_class(SessionsLoadDeferredRepoHooksRequest, self.sessions_load_deferred_repo_hooks_request) + result["SessionsPruneOldRequest"] = to_class(SessionsPruneOldRequest, self.sessions_prune_old_request) + result["SessionsReleaseLockRequest"] = to_class(SessionsReleaseLockRequest, self.sessions_release_lock_request) + result["SessionsReleaseLockResult"] = to_class(SessionsReleaseLockResult, self.sessions_release_lock_result) + result["SessionsReloadPluginHooksRequest"] = to_class(SessionsReloadPluginHooksRequest, self.sessions_reload_plugin_hooks_request) + result["SessionsReloadPluginHooksResult"] = to_class(SessionsReloadPluginHooksResult, self.sessions_reload_plugin_hooks_result) + result["SessionsSaveRequest"] = to_class(SessionsSaveRequest, self.sessions_save_request) + result["SessionsSaveResult"] = to_class(SessionsSaveResult, self.sessions_save_result) + result["SessionsSetAdditionalPluginsRequest"] = to_class(SessionsSetAdditionalPluginsRequest, self.sessions_set_additional_plugins_request) + result["SessionsSetAdditionalPluginsResult"] = to_class(SessionsSetAdditionalPluginsResult, self.sessions_set_additional_plugins_result) + result["SessionUpdateOptionsParams"] = to_class(SessionUpdateOptionsParams, self.session_update_options_params) + result["SessionUpdateOptionsResult"] = to_class(SessionUpdateOptionsResult, self.session_update_options_result) + result["SessionWorkingDirectoryContext"] = to_class(SessionWorkingDirectoryContext, self.session_working_directory_context) + result["SessionWorkingDirectoryContextHostType"] = to_enum(SessionContextHostType, self.session_working_directory_context_host_type) result["ShellExecRequest"] = to_class(ShellExecRequest, self.shell_exec_request) result["ShellExecResult"] = to_class(ShellExecResult, self.shell_exec_result) result["ShellKillRequest"] = to_class(ShellKillRequest, self.shell_kill_request) result["ShellKillResult"] = to_class(ShellKillResult, self.shell_kill_result) result["ShellKillSignal"] = to_enum(ShellKillSignal, self.shell_kill_signal) + result["ShutdownRequest"] = to_class(ShutdownRequest, self.shutdown_request) result["Skill"] = to_class(Skill, self.skill) result["SkillList"] = to_class(SkillList, self.skill_list) result["SkillsConfigSetDisabledSkillsRequest"] = to_class(SkillsConfigSetDisabledSkillsRequest, self.skills_config_set_disabled_skills_request) result["SkillsDisableRequest"] = to_class(SkillsDisableRequest, self.skills_disable_request) result["SkillsDiscoverRequest"] = to_class(SkillsDiscoverRequest, self.skills_discover_request) result["SkillsEnableRequest"] = to_class(SkillsEnableRequest, self.skills_enable_request) + result["SkillsGetInvokedResult"] = to_class(SkillsGetInvokedResult, self.skills_get_invoked_result) + result["SkillsInvokedSkill"] = to_class(SkillsInvokedSkill, self.skills_invoked_skill) result["SkillsLoadDiagnostics"] = to_class(SkillsLoadDiagnostics, self.skills_load_diagnostics) result["SlashCommandAgentPromptResult"] = to_class(SlashCommandAgentPromptResult, self.slash_command_agent_prompt_result) result["SlashCommandCompletedResult"] = to_class(SlashCommandCompletedResult, self.slash_command_completed_result) @@ -8226,15 +15398,22 @@ def to_dict(self) -> dict: result["SlashCommandKind"] = to_enum(SlashCommandKind, self.slash_command_kind) result["SlashCommandTextResult"] = to_class(SlashCommandTextResult, self.slash_command_text_result) result["TaskAgentInfo"] = to_class(TaskAgentInfo, self.task_agent_info) + result["TaskAgentProgress"] = to_class(TaskAgentProgress, self.task_agent_progress) result["TaskExecutionMode"] = to_enum(TaskExecutionMode, self.task_execution_mode) result["TaskInfo"] = to_class(TaskInfo, self.task_info) result["TaskList"] = to_class(TaskList, self.task_list) result["TasksCancelRequest"] = to_class(TasksCancelRequest, self.tasks_cancel_request) result["TasksCancelResult"] = to_class(TasksCancelResult, self.tasks_cancel_result) + result["TasksGetCurrentPromotableResult"] = to_class(TasksGetCurrentPromotableResult, self.tasks_get_current_promotable_result) + result["TasksGetProgressRequest"] = to_class(TasksGetProgressRequest, self.tasks_get_progress_request) + result["TasksGetProgressResult"] = to_class(TasksGetProgressResult, self.tasks_get_progress_result) result["TaskShellInfo"] = to_class(TaskShellInfo, self.task_shell_info) result["TaskShellInfoAttachmentMode"] = to_enum(TaskShellInfoAttachmentMode, self.task_shell_info_attachment_mode) + result["TaskShellProgress"] = from_none(self.task_shell_progress) + result["TasksPromoteCurrentToBackgroundResult"] = to_class(TasksPromoteCurrentToBackgroundResult, self.tasks_promote_current_to_background_result) result["TasksPromoteToBackgroundRequest"] = to_class(TasksPromoteToBackgroundRequest, self.tasks_promote_to_background_request) result["TasksPromoteToBackgroundResult"] = to_class(TasksPromoteToBackgroundResult, self.tasks_promote_to_background_result) + result["TasksRefreshResult"] = to_class(TasksRefreshResult, self.tasks_refresh_result) result["TasksRemoveRequest"] = to_class(TasksRemoveRequest, self.tasks_remove_request) result["TasksRemoveResult"] = to_class(TasksRemoveResult, self.tasks_remove_result) result["TasksSendMessageRequest"] = to_class(TasksSendMessageRequest, self.tasks_send_message_request) @@ -8242,9 +15421,14 @@ def to_dict(self) -> dict: result["TasksStartAgentRequest"] = to_class(TasksStartAgentRequest, self.tasks_start_agent_request) result["TasksStartAgentResult"] = to_class(TasksStartAgentResult, self.tasks_start_agent_result) result["TaskStatus"] = to_enum(TaskStatus, self.task_status) + result["TasksWaitForPendingResult"] = to_class(TasksWaitForPendingResult, self.tasks_wait_for_pending_result) + result["TelemetrySetFeatureOverridesRequest"] = to_class(TelemetrySetFeatureOverridesRequest, self.telemetry_set_feature_overrides_request) + result["TokenAuthInfo"] = to_class(TokenAuthInfo, self.token_auth_info) result["Tool"] = to_class(Tool, self.tool) result["ToolList"] = to_class(ToolList, self.tool_list) + result["ToolsInitializeAndValidateResult"] = to_class(ToolsInitializeAndValidateResult, self.tools_initialize_and_validate_result) result["ToolsListRequest"] = to_class(ToolsListRequest, self.tools_list_request) + result["UIAutoModeSwitchResponse"] = to_enum(UIAutoModeSwitchResponse, self.ui_auto_mode_switch_response) result["UIElicitationArrayAnyOfField"] = to_class(UIElicitationArrayAnyOfField, self.ui_elicitation_array_any_of_field) result["UIElicitationArrayAnyOfFieldItems"] = to_class(UIElicitationArrayAnyOfFieldItems, self.ui_elicitation_array_any_of_field_items) result["UIElicitationArrayAnyOfFieldItemsAnyOf"] = to_class(UIElicitationArrayAnyOfFieldItemsAnyOf, self.ui_elicitation_array_any_of_field_items_any_of) @@ -8266,7 +15450,19 @@ def to_dict(self) -> dict: result["UIElicitationStringEnumField"] = to_class(UIElicitationStringEnumField, self.ui_elicitation_string_enum_field) result["UIElicitationStringOneOfField"] = to_class(UIElicitationStringOneOfField, self.ui_elicitation_string_one_of_field) result["UIElicitationStringOneOfFieldOneOf"] = to_class(UIElicitationStringOneOfFieldOneOf, self.ui_elicitation_string_one_of_field_one_of) + result["UIExitPlanModeAction"] = to_enum(UIExitPlanModeAction, self.ui_exit_plan_mode_action) + result["UIExitPlanModeResponse"] = to_class(UIExitPlanModeResponse, self.ui_exit_plan_mode_response) + result["UIHandlePendingAutoModeSwitchRequest"] = to_class(UIHandlePendingAutoModeSwitchRequest, self.ui_handle_pending_auto_mode_switch_request) result["UIHandlePendingElicitationRequest"] = to_class(UIHandlePendingElicitationRequest, self.ui_handle_pending_elicitation_request) + result["UIHandlePendingExitPlanModeRequest"] = to_class(UIHandlePendingExitPlanModeRequest, self.ui_handle_pending_exit_plan_mode_request) + result["UIHandlePendingResult"] = to_class(UIHandlePendingResult, self.ui_handle_pending_result) + result["UIHandlePendingSamplingRequest"] = to_class(UIHandlePendingSamplingRequest, self.ui_handle_pending_sampling_request) + result["UIHandlePendingSamplingResponse"] = from_dict(lambda x: x, self.ui_handle_pending_sampling_response) + result["UIHandlePendingUserInputRequest"] = to_class(UIHandlePendingUserInputRequest, self.ui_handle_pending_user_input_request) + result["UIRegisterDirectAutoModeSwitchHandlerResult"] = to_class(UIRegisterDirectAutoModeSwitchHandlerResult, self.ui_register_direct_auto_mode_switch_handler_result) + result["UIUnregisterDirectAutoModeSwitchHandlerRequest"] = to_class(UIUnregisterDirectAutoModeSwitchHandlerRequest, self.ui_unregister_direct_auto_mode_switch_handler_request) + result["UIUnregisterDirectAutoModeSwitchHandlerResult"] = to_class(UIUnregisterDirectAutoModeSwitchHandlerResult, self.ui_unregister_direct_auto_mode_switch_handler_result) + result["UIUserInputResponse"] = to_class(UIUserInputResponse, self.ui_user_input_response) result["UsageGetMetricsResult"] = to_class(UsageGetMetricsResult, self.usage_get_metrics_result) result["UsageMetricsCodeChanges"] = to_class(UsageMetricsCodeChanges, self.usage_metrics_code_changes) result["UsageMetricsModelMetric"] = to_class(UsageMetricsModelMetric, self.usage_metrics_model_metric) @@ -8274,254 +15470,800 @@ def to_dict(self) -> dict: result["UsageMetricsModelMetricTokenDetail"] = to_class(UsageMetricsModelMetricTokenDetail, self.usage_metrics_model_metric_token_detail) result["UsageMetricsModelMetricUsage"] = to_class(UsageMetricsModelMetricUsage, self.usage_metrics_model_metric_usage) result["UsageMetricsTokenDetail"] = to_class(UsageMetricsTokenDetail, self.usage_metrics_token_detail) + result["UserAuthInfo"] = to_class(UserAuthInfo, self.user_auth_info) + result["UserToolSessionApprovalCommands"] = to_class(UserToolSessionApprovalCommands, self.user_tool_session_approval_commands) + result["UserToolSessionApprovalCustomTool"] = to_class(UserToolSessionApprovalCustomTool, self.user_tool_session_approval_custom_tool) + result["UserToolSessionApprovalExtensionManagement"] = to_class(UserToolSessionApprovalExtensionManagement, self.user_tool_session_approval_extension_management) + result["UserToolSessionApprovalExtensionPermissionAccess"] = to_class(UserToolSessionApprovalExtensionPermissionAccess, self.user_tool_session_approval_extension_permission_access) + result["UserToolSessionApprovalMcp"] = to_class(UserToolSessionApprovalMCP, self.user_tool_session_approval_mcp) + result["UserToolSessionApprovalMemory"] = to_class(UserToolSessionApprovalMemory, self.user_tool_session_approval_memory) + result["UserToolSessionApprovalRead"] = to_class(UserToolSessionApprovalRead, self.user_tool_session_approval_read) + result["UserToolSessionApprovalWrite"] = to_class(UserToolSessionApprovalWrite, self.user_tool_session_approval_write) + result["WorkspacesCheckpoints"] = to_class(WorkspacesCheckpoints, self.workspaces_checkpoints) result["WorkspacesCreateFileRequest"] = to_class(WorkspacesCreateFileRequest, self.workspaces_create_file_request) result["WorkspacesGetWorkspaceResult"] = to_class(WorkspacesGetWorkspaceResult, self.workspaces_get_workspace_result) + result["WorkspacesListCheckpointsResult"] = to_class(WorkspacesListCheckpointsResult, self.workspaces_list_checkpoints_result) result["WorkspacesListFilesResult"] = to_class(WorkspacesListFilesResult, self.workspaces_list_files_result) + result["WorkspacesReadCheckpointRequest"] = to_class(WorkspacesReadCheckpointRequest, self.workspaces_read_checkpoint_request) + result["WorkspacesReadCheckpointResult"] = to_class(WorkspacesReadCheckpointResult, self.workspaces_read_checkpoint_result) result["WorkspacesReadFileRequest"] = to_class(WorkspacesReadFileRequest, self.workspaces_read_file_request) result["WorkspacesReadFileResult"] = to_class(WorkspacesReadFileResult, self.workspaces_read_file_result) + result["WorkspacesSaveLargePasteRequest"] = to_class(WorkspacesSaveLargePasteRequest, self.workspaces_save_large_paste_request) + result["WorkspacesSaveLargePasteResult"] = to_class(WorkspacesSaveLargePasteResult, self.workspaces_save_large_paste_result) + result["SessionContextInfo"] = from_union([lambda x: to_class(SessionContextInfo, x), from_none], self.session_context_info) + result["TaskProgress"] = from_union([lambda x: to_class(TaskProgressClass, x), from_none], self.task_progress) + result["WorkspaceSummary"] = from_union([lambda x: to_class(WorkspaceSummary, x), from_none], self.workspace_summary) return result -def rpc_from_dict(s: Any) -> RPC: - return RPC.from_dict(s) +def rpc_from_dict(s: Any) -> RPC: + return RPC.from_dict(s) + +def rpc_to_dict(x: RPC) -> Any: + return to_class(RPC, x) + + +ExternalToolResult = ExternalToolTextResultForLlm +FilterMapping = dict +McpExecuteSamplingRequest = dict +McpExecuteSamplingResult = dict +OptionsUpdateEnvValueMode = MCPSetEnvValueModeDetails +SessionWorkingDirectoryContextHostType = SessionContextHostType +TaskInfoExecutionMode = TaskExecutionMode +TaskInfoStatus = TaskStatus +TaskInfoType = TaskAgentProgressType +TaskProgress = TaskProgressClass +TaskShellProgress = None + +def _timeout_kwargs(timeout: float | None) -> dict: + """Build keyword arguments for optional timeout forwarding.""" + if timeout is not None: + return {"timeout": timeout} + return {} + +def _patch_model_capabilities(data: dict) -> dict: + """Ensure model capabilities have required fields. + + TODO: Remove once the runtime schema correctly marks these fields as optional. + Some models (e.g. embedding models) may omit 'limits' or 'supports' in their + capabilities, or omit 'max_context_window_tokens' within limits. The generated + deserializer requires these fields, so we supply defaults here. + """ + for model in data.get("models", []): + caps = model.get("capabilities") + if caps is None: + model["capabilities"] = {"supports": {}, "limits": {"max_context_window_tokens": 0}} + continue + if "supports" not in caps: + caps["supports"] = {} + if "limits" not in caps: + caps["limits"] = {"max_context_window_tokens": 0} + elif "max_context_window_tokens" not in caps["limits"]: + caps["limits"]["max_context_window_tokens"] = 0 + return data + + +class ServerModelsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def list(self, params: ModelsListRequest | None = None, *, timeout: float | None = None) -> ModelList: + "Lists Copilot models available to the authenticated user.\n\nArgs:\n params: Optional GitHub token used to list models for a specific user instead of the global auth context.\n\nReturns:\n List of Copilot models available to the resolved user, including capabilities and billing metadata." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return ModelList.from_dict(_patch_model_capabilities(await self._client.request("models.list", params_dict, **_timeout_kwargs(timeout)))) + + +class ServerToolsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def list(self, params: ToolsListRequest | None = None, *, timeout: float | None = None) -> ToolList: + "Lists built-in tools available for a model.\n\nArgs:\n params: Optional model identifier whose tool overrides should be applied to the listing.\n\nReturns:\n Built-in tools available for the requested model, with their parameters and instructions." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return ToolList.from_dict(await self._client.request("tools.list", params_dict, **_timeout_kwargs(timeout))) + + +class ServerAccountApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def get_quota(self, params: AccountGetQuotaRequest | None = None, *, timeout: float | None = None) -> AccountGetQuotaResult: + "Gets Copilot quota usage for the authenticated user or supplied GitHub token.\n\nArgs:\n params: Optional GitHub token used to look up quota for a specific user instead of the global auth context.\n\nReturns:\n Quota usage snapshots for the resolved user, keyed by quota type." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return AccountGetQuotaResult.from_dict(await self._client.request("account.getQuota", params_dict, **_timeout_kwargs(timeout))) + + +class ServerMcpConfigApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def list(self, *, timeout: float | None = None) -> MCPConfigList: + "Lists MCP servers from user configuration.\n\nReturns:\n User-configured MCP servers, keyed by server name." + return MCPConfigList.from_dict(await self._client.request("mcp.config.list", {}, **_timeout_kwargs(timeout))) + + async def add(self, params: MCPConfigAddRequest, *, timeout: float | None = None) -> None: + "Adds an MCP server to user configuration.\n\nArgs:\n params: MCP server name and configuration to add to user configuration." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("mcp.config.add", params_dict, **_timeout_kwargs(timeout)) + + async def update(self, params: MCPConfigUpdateRequest, *, timeout: float | None = None) -> None: + "Updates an MCP server in user configuration.\n\nArgs:\n params: MCP server name and replacement configuration to write to user configuration." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("mcp.config.update", params_dict, **_timeout_kwargs(timeout)) + + async def remove(self, params: MCPConfigRemoveRequest, *, timeout: float | None = None) -> None: + "Removes an MCP server from user configuration.\n\nArgs:\n params: MCP server name to remove from user configuration." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("mcp.config.remove", params_dict, **_timeout_kwargs(timeout)) + + async def enable(self, params: MCPConfigEnableRequest, *, timeout: float | None = None) -> None: + "Enables MCP servers in user configuration for new sessions.\n\nArgs:\n params: MCP server names to enable for new sessions." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("mcp.config.enable", params_dict, **_timeout_kwargs(timeout)) + + async def disable(self, params: MCPConfigDisableRequest, *, timeout: float | None = None) -> None: + "Disables MCP servers in user configuration for new sessions.\n\nArgs:\n params: MCP server names to disable for new sessions." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("mcp.config.disable", params_dict, **_timeout_kwargs(timeout)) + + +class ServerMcpApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.config = ServerMcpConfigApi(client) + + async def discover(self, params: MCPDiscoverRequest | None = None, *, timeout: float | None = None) -> MCPDiscoverResult: + "Discovers MCP servers from user, workspace, plugin, and builtin sources.\n\nArgs:\n params: Optional working directory used as context for MCP server discovery.\n\nReturns:\n MCP servers discovered from user, workspace, plugin, and built-in sources." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return MCPDiscoverResult.from_dict(await self._client.request("mcp.discover", params_dict, **_timeout_kwargs(timeout))) + + +class ServerSkillsConfigApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def set_disabled_skills(self, params: SkillsConfigSetDisabledSkillsRequest, *, timeout: float | None = None) -> None: + "Replaces the global list of disabled skills.\n\nArgs:\n params: Skill names to mark as disabled in global configuration, replacing any previous list." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("skills.config.setDisabledSkills", params_dict, **_timeout_kwargs(timeout)) + + +class ServerSkillsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.config = ServerSkillsConfigApi(client) + + async def discover(self, params: SkillsDiscoverRequest | None = None, *, timeout: float | None = None) -> ServerSkillList: + "Discovers skills across global and project sources.\n\nArgs:\n params: Optional project paths and additional skill directories to include in discovery.\n\nReturns:\n Skills discovered across global and project sources." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return ServerSkillList.from_dict(await self._client.request("skills.discover", params_dict, **_timeout_kwargs(timeout))) + + +class ServerSessionFsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def set_provider(self, params: SessionFSSetProviderRequest, *, timeout: float | None = None) -> SessionFSSetProviderResult: + "Registers an SDK client as the session filesystem provider.\n\nArgs:\n params: Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider.\n\nReturns:\n Indicates whether the calling client was registered as the session filesystem provider." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionFSSetProviderResult.from_dict(await self._client.request("sessionFs.setProvider", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class ServerSessionsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def fork(self, params: SessionsForkRequest | None = None, *, timeout: float | None = None) -> SessionsForkResult: + "Creates a new session by forking persisted history from an existing session.\n\nArgs:\n params: Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session.\n\nReturns:\n Identifier and optional friendly name assigned to the newly forked session." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsForkResult.from_dict(await self._client.request("sessions.fork", params_dict, **_timeout_kwargs(timeout))) + + async def connect(self, params: ConnectRemoteSessionParams | None = None, *, timeout: float | None = None) -> RemoteSessionConnectionResult: + "Connects to an existing remote session and exposes it as an SDK session.\n\nArgs:\n params: Remote session connection parameters.\n\nReturns:\n Remote session connection result." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return RemoteSessionConnectionResult.from_dict(await self._client.request("sessions.connect", params_dict, **_timeout_kwargs(timeout))) + + async def list(self, params: SessionsListRequest | None = None, *, timeout: float | None = None) -> SessionList: + "Lists persisted sessions, optionally filtered by working-directory context.\n\nArgs:\n params: Optional metadata-load limit and context filter applied to the returned sessions.\n\nReturns:\n Persisted sessions matching the filter, ordered most-recently-modified first." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionList.from_dict(await self._client.request("sessions.list", params_dict, **_timeout_kwargs(timeout))) + + async def find_by_task_id(self, params: SessionsFindByTaskIDRequest, *, timeout: float | None = None) -> SessionsFindByTaskIDResult: + "Finds the local session bound to a GitHub task ID, if any.\n\nArgs:\n params: GitHub task ID to look up.\n\nReturns:\n ID of the local session bound to the given GitHub task, or omitted when none." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionsFindByTaskIDResult.from_dict(await self._client.request("sessions.findByTaskId", params_dict, **_timeout_kwargs(timeout))) + + async def find_by_prefix(self, params: SessionsFindByPrefixRequest, *, timeout: float | None = None) -> SessionsFindByPrefixResult: + "Resolves a UUID prefix to a unique session ID, if exactly one session matches.\n\nArgs:\n params: UUID prefix to resolve to a unique session ID.\n\nReturns:\n Session ID matching the prefix, omitted when no unique match exists." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionsFindByPrefixResult.from_dict(await self._client.request("sessions.findByPrefix", params_dict, **_timeout_kwargs(timeout))) + + async def get_last_for_context(self, params: SessionsGetLastForContextRequest | None = None, *, timeout: float | None = None) -> SessionsGetLastForContextResult: + "Returns the most-relevant prior session for a given working-directory context.\n\nArgs:\n params: Optional working-directory context used to score session relevance.\n\nReturns:\n Most-relevant session ID for the supplied context, or omitted when no sessions exist." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsGetLastForContextResult.from_dict(await self._client.request("sessions.getLastForContext", params_dict, **_timeout_kwargs(timeout))) + + async def get_event_file_path(self, params: SessionsGetEventFilePathRequest | None = None, *, timeout: float | None = None) -> SessionsGetEventFilePathResult: + "Computes the absolute path to a session's persisted events.jsonl file.\n\nArgs:\n params: Session ID whose event-log file path to compute.\n\nReturns:\n Absolute path to the session's events.jsonl file on disk." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsGetEventFilePathResult.from_dict(await self._client.request("sessions.getEventFilePath", params_dict, **_timeout_kwargs(timeout))) + + async def get_sizes(self, *, timeout: float | None = None) -> SessionSizes: + "Returns the on-disk byte size of each session's workspace directory.\n\nReturns:\n Map of sessionId -> on-disk size in bytes for each session's workspace directory." + return SessionSizes.from_dict(await self._client.request("sessions.getSizes", {}, **_timeout_kwargs(timeout))) + + async def check_in_use(self, params: SessionsCheckInUseRequest, *, timeout: float | None = None) -> SessionsCheckInUseResult: + "Returns the subset of the supplied session IDs that are currently held by another running process.\n\nArgs:\n params: Session IDs to test for live in-use locks.\n\nReturns:\n Session IDs from the input set that are currently in use by another process." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionsCheckInUseResult.from_dict(await self._client.request("sessions.checkInUse", params_dict, **_timeout_kwargs(timeout))) + + async def get_persisted_remote_steerable(self, params: SessionsGetPersistedRemoteSteerableRequest | None = None, *, timeout: float | None = None) -> SessionsGetPersistedRemoteSteerableResult: + "Returns a session's persisted remote-steerable flag, if any has been recorded.\n\nArgs:\n params: Session ID to look up the persisted remote-steerable flag for.\n\nReturns:\n The session's persisted remote-steerable flag, or omitted when no value has been persisted." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsGetPersistedRemoteSteerableResult.from_dict(await self._client.request("sessions.getPersistedRemoteSteerable", params_dict, **_timeout_kwargs(timeout))) + + async def close(self, params: SessionsCloseRequest | None = None, *, timeout: float | None = None) -> SessionsCloseResult: + "Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session.\n\nArgs:\n params: Session ID to close.\n\nReturns:\n Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsCloseResult.from_dict(await self._client.request("sessions.close", params_dict, **_timeout_kwargs(timeout))) + + async def bulk_delete(self, params: SessionsBulkDeleteRequest, *, timeout: float | None = None) -> SessionBulkDeleteResult: + "Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session.\n\nArgs:\n params: Session IDs to close, deactivate, and delete from disk.\n\nReturns:\n Map of sessionId -> bytes freed by removing the session's workspace directory." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionBulkDeleteResult.from_dict(await self._client.request("sessions.bulkDelete", params_dict, **_timeout_kwargs(timeout))) + + async def prune_old(self, params: SessionsPruneOldRequest, *, timeout: float | None = None) -> SessionPruneResult: + "Deletes sessions older than the given threshold, with optional dry-run and exclusion list.\n\nArgs:\n params: Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true).\n\nReturns:\n Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionPruneResult.from_dict(await self._client.request("sessions.pruneOld", params_dict, **_timeout_kwargs(timeout))) + + async def save(self, params: SessionsSaveRequest | None = None, *, timeout: float | None = None) -> SessionsSaveResult: + "Flushes a session's pending events to disk.\n\nArgs:\n params: Session ID whose pending events should be flushed to disk.\n\nReturns:\n Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed)." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsSaveResult.from_dict(await self._client.request("sessions.save", params_dict, **_timeout_kwargs(timeout))) + + async def release_lock(self, params: SessionsReleaseLockRequest | None = None, *, timeout: float | None = None) -> SessionsReleaseLockResult: + "Releases the in-use lock held by this process for a session.\n\nArgs:\n params: Session ID whose in-use lock should be released.\n\nReturns:\n Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsReleaseLockResult.from_dict(await self._client.request("sessions.releaseLock", params_dict, **_timeout_kwargs(timeout))) + + async def enrich_metadata(self, params: SessionsEnrichMetadataRequest, *, timeout: float | None = None) -> SessionEnrichMetadataResult: + "Backfills missing summary and context fields on the supplied session metadata records.\n\nArgs:\n params: Session metadata records to enrich with summary and context information.\n\nReturns:\n The same metadata records, with summary and context fields backfilled where available." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionEnrichMetadataResult.from_dict(await self._client.request("sessions.enrichMetadata", params_dict, **_timeout_kwargs(timeout))) + + async def reload_plugin_hooks(self, params: SessionsReloadPluginHooksRequest | None = None, *, timeout: float | None = None) -> SessionsReloadPluginHooksResult: + "Reloads user, plugin, and (optionally) repo hooks on the active session.\n\nArgs:\n params: Active session ID and an optional flag for deferring repo-level hooks until folder trust.\n\nReturns:\n Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionsReloadPluginHooksResult.from_dict(await self._client.request("sessions.reloadPluginHooks", params_dict, **_timeout_kwargs(timeout))) + + async def load_deferred_repo_hooks(self, params: SessionsLoadDeferredRepoHooksRequest | None = None, *, timeout: float | None = None) -> SessionLoadDeferredRepoHooksResult: + "Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts.\n\nArgs:\n params: Active session ID whose deferred repo-level hooks should be loaded.\n\nReturns:\n Queued repo-level startup prompts and the total hook command count after loading." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return SessionLoadDeferredRepoHooksResult.from_dict(await self._client.request("sessions.loadDeferredRepoHooks", params_dict, **_timeout_kwargs(timeout))) + + async def set_additional_plugins(self, params: SessionsSetAdditionalPluginsRequest, *, timeout: float | None = None) -> SessionsSetAdditionalPluginsResult: + "Replaces the manager-wide additional plugins registered with the session manager.\n\nArgs:\n params: Manager-wide additional plugins to register; replaces any previously-configured set.\n\nReturns:\n Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload." + if params is None: + raise TypeError("params is required") + + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SessionsSetAdditionalPluginsResult.from_dict(await self._client.request("sessions.setAdditionalPlugins", params_dict, **_timeout_kwargs(timeout))) + + +class ServerRpc: + """Typed server-scoped RPC methods.""" + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.models = ServerModelsApi(client) + self.tools = ServerToolsApi(client) + self.account = ServerAccountApi(client) + self.mcp = ServerMcpApi(client) + self.skills = ServerSkillsApi(client) + self.session_fs = ServerSessionFsApi(client) + self.sessions = ServerSessionsApi(client) + + async def ping(self, params: PingRequest | None = None, *, timeout: float | None = None) -> PingResult: + "Checks server responsiveness and returns protocol information.\n\nArgs:\n params: Optional message to echo back to the caller.\n\nReturns:\n Server liveness response, including the echoed message, current server timestamp, and protocol version." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return PingResult.from_dict(await self._client.request("ping", params_dict, **_timeout_kwargs(timeout))) -def rpc_to_dict(x: RPC) -> Any: - return to_class(RPC, x) +class _InternalServerRpc: + """Internal SDK server-scoped RPC methods. Not part of the public API.""" + def __init__(self, client: "JsonRpcClient"): + self._client = client -ExternalToolResult = ExternalToolTextResultForLlm -FilterMapping = dict -TaskInfoExecutionMode = TaskExecutionMode -TaskInfoStatus = TaskStatus + async def connect(self, params: ConnectRequest | None = None, *, timeout: float | None = None) -> ConnectResult: + "Performs the SDK server connection handshake and validates the optional connection token.\n\nArgs:\n params: Optional connection token presented by the SDK client during the handshake.\n\nReturns:\n Handshake result reporting the server's protocol version and package version on success.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + return ConnectResult.from_dict(await self._client.request("connect", params_dict, **_timeout_kwargs(timeout))) -def _timeout_kwargs(timeout: float | None) -> dict: - """Build keyword arguments for optional timeout forwarding.""" - if timeout is not None: - return {"timeout": timeout} - return {} -def _patch_model_capabilities(data: dict) -> dict: - """Ensure model capabilities have required fields. +class AuthApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active - TODO: Remove once the runtime schema correctly marks these fields as optional. - Some models (e.g. embedding models) may omit 'limits' or 'supports' in their - capabilities, or omit 'max_context_window_tokens' within limits. The generated - deserializer requires these fields, so we supply defaults here. - """ - for model in data.get("models", []): - caps = model.get("capabilities") - if caps is None: - model["capabilities"] = {"supports": {}, "limits": {"max_context_window_tokens": 0}} - continue - if "supports" not in caps: - caps["supports"] = {} - if "limits" not in caps: - caps["limits"] = {"max_context_window_tokens": 0} - elif "max_context_window_tokens" not in caps["limits"]: - caps["limits"]["max_context_window_tokens"] = 0 - return data + async def get_status(self, *, timeout: float | None = None) -> SessionAuthStatus: + "Gets authentication status and account metadata for the session.\n\nReturns:\n Authentication status and account metadata for the session." + if self._assert_active is not None: + self._assert_active() + return SessionAuthStatus.from_dict(await self._client.request("session.auth.getStatus", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) -class ServerModelsApi: - def __init__(self, client: "JsonRpcClient"): + async def set_credentials(self, params: SessionSetCredentialsParams | None = None, *, timeout: float | None = None) -> SessionSetCredentialsResult: + "Updates the session's auth credentials used for outbound model and API requests.\n\nArgs:\n params: New auth credentials to install on the session. Omit to leave credentials unchanged.\n\nReturns:\n Indicates whether the credential update succeeded." + if self._assert_active is not None: + self._assert_active() + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return SessionSetCredentialsResult.from_dict(await self._client.request("session.auth.setCredentials", params_dict, **_timeout_kwargs(timeout))) + + +class ModelApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def get_current(self, *, timeout: float | None = None) -> CurrentModel: + "Gets the currently selected model for the session.\n\nReturns:\n The currently selected model and reasoning effort for the session." + if self._assert_active is not None: + self._assert_active() + + return CurrentModel.from_dict(await self._client.request("session.model.getCurrent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def switch_to(self, params: ModelSwitchToRequest, *, timeout: float | None = None) -> ModelSwitchToResult: + "Switches the session to a model and optional reasoning configuration.\n\nArgs:\n params: Target model identifier and optional reasoning effort, summary, and capability overrides.\n\nReturns:\n The model identifier active on the session after the switch." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return ModelSwitchToResult.from_dict(await self._client.request("session.model.switchTo", params_dict, **_timeout_kwargs(timeout))) + + async def set_reasoning_effort(self, params: ModelSetReasoningEffortRequest, *, timeout: float | None = None) -> ModelSetReasoningEffortResult: + "Updates the session's reasoning effort without changing the selected model.\n\nArgs:\n params: Reasoning effort level to apply to the currently selected model.\n\nReturns:\n Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return ModelSetReasoningEffortResult.from_dict(await self._client.request("session.model.setReasoningEffort", params_dict, **_timeout_kwargs(timeout))) + + +class ModeApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def get(self, *, timeout: float | None = None) -> SessionMode: + "Gets the current agent interaction mode.\n\nReturns:\n The session mode the agent is operating in" + if self._assert_active is not None: + self._assert_active() + + return SessionMode(await self._client.request("session.mode.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def set(self, params: ModeSetRequest, *, timeout: float | None = None) -> None: + "Sets the current agent interaction mode.\n\nArgs:\n params: Agent interaction mode to apply to the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.mode.set", params_dict, **_timeout_kwargs(timeout)) + + +class NameApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def get(self, *, timeout: float | None = None) -> NameGetResult: + "Gets the session's friendly name.\n\nReturns:\n The session's friendly name, or null when not yet set." + if self._assert_active is not None: + self._assert_active() + + return NameGetResult.from_dict(await self._client.request("session.name.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def set(self, params: NameSetRequest, *, timeout: float | None = None) -> None: + "Sets the session's friendly name.\n\nArgs:\n params: New friendly name to apply to the session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.name.set", params_dict, **_timeout_kwargs(timeout)) + + async def set_auto(self, params: NameSetAutoRequest, *, timeout: float | None = None) -> NameSetAutoResult: + "Persists an auto-generated session summary as the session's name when no user-set name exists.\n\nArgs:\n params: Auto-generated session summary to apply as the session's name when no user-set name exists.\n\nReturns:\n Indicates whether the auto-generated summary was applied as the session's name." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return NameSetAutoResult.from_dict(await self._client.request("session.name.setAuto", params_dict, **_timeout_kwargs(timeout))) + + +class PlanApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def read(self, *, timeout: float | None = None) -> PlanReadResult: + "Reads the session plan file from the workspace.\n\nReturns:\n Existence, contents, and resolved path of the session plan file." + if self._assert_active is not None: + self._assert_active() + + return PlanReadResult.from_dict(await self._client.request("session.plan.read", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def update(self, params: PlanUpdateRequest, *, timeout: float | None = None) -> None: + "Writes new content to the session plan file.\n\nArgs:\n params: Replacement contents to write to the session plan file." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.plan.update", params_dict, **_timeout_kwargs(timeout)) + + async def delete(self, *, timeout: float | None = None) -> None: + "Deletes the session plan file from the workspace." + if self._assert_active is not None: + self._assert_active() + + await self._client.request("session.plan.delete", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + + +class WorkspacesApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def get_workspace(self, *, timeout: float | None = None) -> WorkspacesGetWorkspaceResult: + "Gets current workspace metadata for the session.\n\nReturns:\n Current workspace metadata for the session, including its absolute filesystem path when available." + if self._assert_active is not None: + self._assert_active() + + return WorkspacesGetWorkspaceResult.from_dict(await self._client.request("session.workspaces.getWorkspace", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def list_files(self, *, timeout: float | None = None) -> WorkspacesListFilesResult: + "Lists files stored in the session workspace files directory.\n\nReturns:\n Relative paths of files stored in the session workspace files directory." + if self._assert_active is not None: + self._assert_active() + + return WorkspacesListFilesResult.from_dict(await self._client.request("session.workspaces.listFiles", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def read_file(self, params: WorkspacesReadFileRequest, *, timeout: float | None = None) -> WorkspacesReadFileResult: + "Reads a file from the session workspace files directory.\n\nArgs:\n params: Relative path of the workspace file to read.\n\nReturns:\n Contents of the requested workspace file as a UTF-8 string." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return WorkspacesReadFileResult.from_dict(await self._client.request("session.workspaces.readFile", params_dict, **_timeout_kwargs(timeout))) + + async def create_file(self, params: WorkspacesCreateFileRequest, *, timeout: float | None = None) -> None: + "Creates or overwrites a file in the session workspace files directory.\n\nArgs:\n params: Relative path and UTF-8 content for the workspace file to create or overwrite." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.workspaces.createFile", params_dict, **_timeout_kwargs(timeout)) + + async def list_checkpoints(self, *, timeout: float | None = None) -> WorkspacesListCheckpointsResult: + "Lists workspace checkpoints in chronological order.\n\nReturns:\n Workspace checkpoints in chronological order; empty when the workspace is not enabled." + if self._assert_active is not None: + self._assert_active() + + return WorkspacesListCheckpointsResult.from_dict(await self._client.request("session.workspaces.listCheckpoints", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def read_checkpoint(self, params: WorkspacesReadCheckpointRequest, *, timeout: float | None = None) -> WorkspacesReadCheckpointResult: + "Reads the content of a workspace checkpoint by number.\n\nArgs:\n params: Checkpoint number to read.\n\nReturns:\n Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return WorkspacesReadCheckpointResult.from_dict(await self._client.request("session.workspaces.readCheckpoint", params_dict, **_timeout_kwargs(timeout))) + + async def save_large_paste(self, params: WorkspacesSaveLargePasteRequest, *, timeout: float | None = None) -> WorkspacesSaveLargePasteResult: + "Saves pasted content as a UTF-8 file in the session workspace.\n\nArgs:\n params: Pasted content to save as a UTF-8 file in the session workspace.\n\nReturns:\n Descriptor for the saved paste file, or null when the workspace is unavailable." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return WorkspacesSaveLargePasteResult.from_dict(await self._client.request("session.workspaces.saveLargePaste", params_dict, **_timeout_kwargs(timeout))) + + +class InstructionsApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client + self._session_id = session_id + self._assert_active = assert_active - async def list(self, params: ModelsListRequest | None = None, *, timeout: float | None = None) -> ModelList: - "Lists Copilot models available to the authenticated user.\n\nArgs:\n params: Optional GitHub token used to list models for a specific user instead of the global auth context.\n\nReturns:\n List of Copilot models available to the resolved user, including capabilities and billing metadata." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return ModelList.from_dict(_patch_model_capabilities(await self._client.request("models.list", params_dict, **_timeout_kwargs(timeout)))) + async def get_sources(self, *, timeout: float | None = None) -> InstructionsGetSourcesResult: + "Gets instruction sources loaded for the session.\n\nReturns:\n Instruction sources loaded for the session, in merge order." + if self._assert_active is not None: + self._assert_active() + return InstructionsGetSourcesResult.from_dict(await self._client.request("session.instructions.getSources", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) -class ServerToolsApi: - def __init__(self, client: "JsonRpcClient"): + +# Experimental: this API group is experimental and may change or be removed. +class FleetApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client + self._session_id = session_id + self._assert_active = assert_active - async def list(self, params: ToolsListRequest | None = None, *, timeout: float | None = None) -> ToolList: - "Lists built-in tools available for a model.\n\nArgs:\n params: Optional model identifier whose tool overrides should be applied to the listing.\n\nReturns:\n Built-in tools available for the requested model, with their parameters and instructions." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return ToolList.from_dict(await self._client.request("tools.list", params_dict, **_timeout_kwargs(timeout))) + async def start(self, params: FleetStartRequest | None = None, *, timeout: float | None = None) -> FleetStartResult: + "Starts fleet mode by submitting the fleet orchestration prompt to the session.\n\nArgs:\n params: Optional user prompt to combine with the fleet orchestration instructions.\n\nReturns:\n Indicates whether fleet mode was successfully activated." + if self._assert_active is not None: + self._assert_active() + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return FleetStartResult.from_dict(await self._client.request("session.fleet.start", params_dict, **_timeout_kwargs(timeout))) -class ServerAccountApi: - def __init__(self, client: "JsonRpcClient"): +# Experimental: this API group is experimental and may change or be removed. +class AgentApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client + self._session_id = session_id + self._assert_active = assert_active - async def get_quota(self, params: AccountGetQuotaRequest | None = None, *, timeout: float | None = None) -> AccountGetQuotaResult: - "Gets Copilot quota usage for the authenticated user or supplied GitHub token.\n\nArgs:\n params: Optional GitHub token used to look up quota for a specific user instead of the global auth context.\n\nReturns:\n Quota usage snapshots for the resolved user, keyed by quota type." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return AccountGetQuotaResult.from_dict(await self._client.request("account.getQuota", params_dict, **_timeout_kwargs(timeout))) + async def list(self, *, timeout: float | None = None) -> AgentList: + "Lists custom agents available to the session.\n\nReturns:\n Custom agents available to the session." + if self._assert_active is not None: + self._assert_active() + return AgentList.from_dict(await self._client.request("session.agent.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) -class ServerMcpConfigApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client + async def get_current(self, *, timeout: float | None = None) -> AgentGetCurrentResult: + "Gets the currently selected custom agent for the session.\n\nReturns:\n The currently selected custom agent, or null when using the default agent." + if self._assert_active is not None: + self._assert_active() - async def list(self, *, timeout: float | None = None) -> MCPConfigList: - "Lists MCP servers from user configuration.\n\nReturns:\n User-configured MCP servers, keyed by server name." - return MCPConfigList.from_dict(await self._client.request("mcp.config.list", {}, **_timeout_kwargs(timeout))) + return AgentGetCurrentResult.from_dict(await self._client.request("session.agent.getCurrent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def add(self, params: MCPConfigAddRequest, *, timeout: float | None = None) -> None: - "Adds an MCP server to user configuration.\n\nArgs:\n params: MCP server name and configuration to add to user configuration." + async def select(self, params: AgentSelectRequest, *, timeout: float | None = None) -> AgentSelectResult: + "Selects a custom agent for subsequent turns in the session.\n\nArgs:\n params: Name of the custom agent to select for subsequent turns.\n\nReturns:\n The newly selected custom agent." + if self._assert_active is not None: + self._assert_active() if params is None: raise TypeError("params is required") - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("mcp.config.add", params_dict, **_timeout_kwargs(timeout)) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return AgentSelectResult.from_dict(await self._client.request("session.agent.select", params_dict, **_timeout_kwargs(timeout))) - async def update(self, params: MCPConfigUpdateRequest, *, timeout: float | None = None) -> None: - "Updates an MCP server in user configuration.\n\nArgs:\n params: MCP server name and replacement configuration to write to user configuration." - if params is None: - raise TypeError("params is required") + async def deselect(self, *, timeout: float | None = None) -> None: + "Clears the selected custom agent and returns the session to the default agent." + if self._assert_active is not None: + self._assert_active() - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("mcp.config.update", params_dict, **_timeout_kwargs(timeout)) + await self._client.request("session.agent.deselect", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - async def remove(self, params: MCPConfigRemoveRequest, *, timeout: float | None = None) -> None: - "Removes an MCP server from user configuration.\n\nArgs:\n params: MCP server name to remove from user configuration." - if params is None: - raise TypeError("params is required") + async def reload(self, *, timeout: float | None = None) -> AgentReloadResult: + "Reloads custom agent definitions and returns the refreshed list.\n\nReturns:\n Custom agents available to the session after reloading definitions from disk." + if self._assert_active is not None: + self._assert_active() - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("mcp.config.remove", params_dict, **_timeout_kwargs(timeout)) + return AgentReloadResult.from_dict(await self._client.request("session.agent.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def enable(self, params: MCPConfigEnableRequest, *, timeout: float | None = None) -> None: - "Enables MCP servers in user configuration for new sessions.\n\nArgs:\n params: MCP server names to enable for new sessions." - if params is None: - raise TypeError("params is required") - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("mcp.config.enable", params_dict, **_timeout_kwargs(timeout)) +# Experimental: this API group is experimental and may change or be removed. +class TasksApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active - async def disable(self, params: MCPConfigDisableRequest, *, timeout: float | None = None) -> None: - "Disables MCP servers in user configuration for new sessions.\n\nArgs:\n params: MCP server names to disable for new sessions." + async def start_agent(self, params: TasksStartAgentRequest, *, timeout: float | None = None) -> TasksStartAgentResult: + "Starts a background agent task in the session.\n\nArgs:\n params: Agent type, prompt, name, and optional description and model override for the new task.\n\nReturns:\n Identifier assigned to the newly started background agent task." + if self._assert_active is not None: + self._assert_active() if params is None: raise TypeError("params is required") - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("mcp.config.disable", params_dict, **_timeout_kwargs(timeout)) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return TasksStartAgentResult.from_dict(await self._client.request("session.tasks.startAgent", params_dict, **_timeout_kwargs(timeout))) + async def list(self, *, timeout: float | None = None) -> TaskList: + "Lists background tasks tracked by the session.\n\nReturns:\n Background tasks currently tracked by the session." + if self._assert_active is not None: + self._assert_active() -class ServerMcpApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.config = ServerMcpConfigApi(client) + return TaskList.from_dict(await self._client.request("session.tasks.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def discover(self, params: MCPDiscoverRequest | None = None, *, timeout: float | None = None) -> MCPDiscoverResult: - "Discovers MCP servers from user, workspace, plugin, and builtin sources.\n\nArgs:\n params: Optional working directory used as context for MCP server discovery.\n\nReturns:\n MCP servers discovered from user, workspace, plugin, and built-in sources." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return MCPDiscoverResult.from_dict(await self._client.request("mcp.discover", params_dict, **_timeout_kwargs(timeout))) + async def refresh(self, *, timeout: float | None = None) -> TasksRefreshResult: + "Refreshes metadata for any detached background shells the runtime knows about.\n\nReturns:\n Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop." + if self._assert_active is not None: + self._assert_active() + return TasksRefreshResult.from_dict(await self._client.request("session.tasks.refresh", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) -class ServerSkillsConfigApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client + async def wait_for_pending(self, *, timeout: float | None = None) -> TasksWaitForPendingResult: + "Waits for all in-flight background tasks and any follow-up turns to settle.\n\nReturns:\n Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS)." + if self._assert_active is not None: + self._assert_active() - async def set_disabled_skills(self, params: SkillsConfigSetDisabledSkillsRequest, *, timeout: float | None = None) -> None: - "Replaces the global list of disabled skills.\n\nArgs:\n params: Skill names to mark as disabled in global configuration, replacing any previous list." + return TasksWaitForPendingResult.from_dict(await self._client.request("session.tasks.waitForPending", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def get_progress(self, params: TasksGetProgressRequest, *, timeout: float | None = None) -> TasksGetProgressResult: + "Returns progress information for a background task by ID.\n\nArgs:\n params: Identifier of the background task to fetch progress for.\n\nReturns:\n Progress information for the task, or null when no task with that ID is tracked." + if self._assert_active is not None: + self._assert_active() if params is None: raise TypeError("params is required") - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("skills.config.setDisabledSkills", params_dict, **_timeout_kwargs(timeout)) - - -class ServerSkillsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.config = ServerSkillsConfigApi(client) - - async def discover(self, params: SkillsDiscoverRequest | None = None, *, timeout: float | None = None) -> ServerSkillList: - "Discovers skills across global and project sources.\n\nArgs:\n params: Optional project paths and additional skill directories to include in discovery.\n\nReturns:\n Skills discovered across global and project sources." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return ServerSkillList.from_dict(await self._client.request("skills.discover", params_dict, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return TasksGetProgressResult.from_dict(await self._client.request("session.tasks.getProgress", params_dict, **_timeout_kwargs(timeout))) + async def get_current_promotable(self, *, timeout: float | None = None) -> TasksGetCurrentPromotableResult: + "Returns the first sync-waiting task that can currently be promoted to background mode.\n\nReturns:\n The first sync-waiting task that can currently be promoted to background mode." + if self._assert_active is not None: + self._assert_active() -class ServerSessionFsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client + return TasksGetCurrentPromotableResult.from_dict(await self._client.request("session.tasks.getCurrentPromotable", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def set_provider(self, params: SessionFSSetProviderRequest, *, timeout: float | None = None) -> SessionFSSetProviderResult: - "Registers an SDK client as the session filesystem provider.\n\nArgs:\n params: Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider.\n\nReturns:\n Indicates whether the calling client was registered as the session filesystem provider." + async def promote_to_background(self, params: TasksPromoteToBackgroundRequest, *, timeout: float | None = None) -> TasksPromoteToBackgroundResult: + "Promotes an eligible synchronously-waited task so it continues running in the background.\n\nArgs:\n params: Identifier of the task to promote to background mode.\n\nReturns:\n Indicates whether the task was successfully promoted to background mode." + if self._assert_active is not None: + self._assert_active() if params is None: raise TypeError("params is required") - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SessionFSSetProviderResult.from_dict(await self._client.request("sessionFs.setProvider", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class ServerSessionsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return TasksPromoteToBackgroundResult.from_dict(await self._client.request("session.tasks.promoteToBackground", params_dict, **_timeout_kwargs(timeout))) - async def fork(self, params: SessionsForkRequest | None = None, *, timeout: float | None = None) -> SessionsForkResult: - "Creates a new session by forking persisted history from an existing session.\n\nArgs:\n params: Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session.\n\nReturns:\n Identifier and optional friendly name assigned to the newly forked session." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return SessionsForkResult.from_dict(await self._client.request("sessions.fork", params_dict, **_timeout_kwargs(timeout))) + async def promote_current_to_background(self, *, timeout: float | None = None) -> TasksPromoteCurrentToBackgroundResult: + "Atomically promotes the first promotable sync-waiting task to background mode and returns it.\n\nReturns:\n The promoted task as it now exists in background mode, omitted if no promotable task was waiting." + if self._assert_active is not None: + self._assert_active() - async def connect(self, params: ConnectRemoteSessionParams | None = None, *, timeout: float | None = None) -> RemoteSessionConnectionResult: - "Connects to an existing remote session and exposes it as an SDK session.\n\nArgs:\n params: Remote session connection parameters.\n\nReturns:\n Remote session connection result." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return RemoteSessionConnectionResult.from_dict(await self._client.request("sessions.connect", params_dict, **_timeout_kwargs(timeout))) + return TasksPromoteCurrentToBackgroundResult.from_dict(await self._client.request("session.tasks.promoteCurrentToBackground", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + async def cancel(self, params: TasksCancelRequest, *, timeout: float | None = None) -> TasksCancelResult: + "Cancels a background task.\n\nArgs:\n params: Identifier of the background task to cancel.\n\nReturns:\n Indicates whether the background task was successfully cancelled." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") -class ServerRpc: - """Typed server-scoped RPC methods.""" - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.models = ServerModelsApi(client) - self.tools = ServerToolsApi(client) - self.account = ServerAccountApi(client) - self.mcp = ServerMcpApi(client) - self.skills = ServerSkillsApi(client) - self.session_fs = ServerSessionFsApi(client) - self.sessions = ServerSessionsApi(client) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return TasksCancelResult.from_dict(await self._client.request("session.tasks.cancel", params_dict, **_timeout_kwargs(timeout))) - async def ping(self, params: PingRequest | None = None, *, timeout: float | None = None) -> PingResult: - "Checks server responsiveness and returns protocol information.\n\nArgs:\n params: Optional message to echo back to the caller.\n\nReturns:\n Server liveness response, including the echoed message, current timestamp, and protocol version." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return PingResult.from_dict(await self._client.request("ping", params_dict, **_timeout_kwargs(timeout))) + async def remove(self, params: TasksRemoveRequest, *, timeout: float | None = None) -> TasksRemoveResult: + "Removes a completed or cancelled background task from tracking.\n\nArgs:\n params: Identifier of the completed or cancelled task to remove from tracking.\n\nReturns:\n Indicates whether the task was removed. False when the task does not exist or is still running/idle." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return TasksRemoveResult.from_dict(await self._client.request("session.tasks.remove", params_dict, **_timeout_kwargs(timeout))) -class _InternalServerRpc: - """Internal SDK server-scoped RPC methods. Not part of the public API.""" - def __init__(self, client: "JsonRpcClient"): - self._client = client + async def send_message(self, params: TasksSendMessageRequest, *, timeout: float | None = None) -> TasksSendMessageResult: + "Sends a message to a background agent task.\n\nArgs:\n params: Identifier of the target agent task, message content, and optional sender agent ID.\n\nReturns:\n Indicates whether the message was delivered, with an error message when delivery failed." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") - async def connect(self, params: ConnectRequest | None = None, *, timeout: float | None = None) -> ConnectResult: - "Performs the SDK server connection handshake and validates the optional connection token.\n\nArgs:\n params: Optional connection token presented by the SDK client during the handshake.\n\nReturns:\n Handshake result reporting the server's protocol version and package version on success.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} - return ConnectResult.from_dict(await self._client.request("connect", params_dict, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return TasksSendMessageResult.from_dict(await self._client.request("session.tasks.sendMessage", params_dict, **_timeout_kwargs(timeout))) -class AuthApi: +# Experimental: this API group is experimental and may change or be removed. +class SkillsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def get_status(self, *, timeout: float | None = None) -> SessionAuthStatus: - "Gets authentication status and account metadata for the session.\n\nReturns:\n Authentication status and account metadata for the session." + async def list(self, *, timeout: float | None = None) -> SkillList: + "Lists skills available to the session.\n\nReturns:\n Skills available to the session, with their enabled state." if self._assert_active is not None: self._assert_active() - return SessionAuthStatus.from_dict(await self._client.request("session.auth.getStatus", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return SkillList.from_dict(await self._client.request("session.skills.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + async def get_invoked(self, *, timeout: float | None = None) -> SkillsGetInvokedResult: + "Returns the skills that have been invoked during this session.\n\nReturns:\n Skills invoked during this session, ordered by invocation time (most recent last)." + if self._assert_active is not None: + self._assert_active() -class ModelApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active + return SkillsGetInvokedResult.from_dict(await self._client.request("session.skills.getInvoked", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def get_current(self, *, timeout: float | None = None) -> CurrentModel: - "Gets the currently selected model for the session.\n\nReturns:\n The currently selected model for the session." + async def enable(self, params: SkillsEnableRequest, *, timeout: float | None = None) -> None: + "Enables a skill for the session.\n\nArgs:\n params: Name of the skill to enable for the session." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - return CurrentModel.from_dict(await self._client.request("session.model.getCurrent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.skills.enable", params_dict, **_timeout_kwargs(timeout)) - async def switch_to(self, params: ModelSwitchToRequest, *, timeout: float | None = None) -> ModelSwitchToResult: - "Switches the session to a model and optional reasoning configuration.\n\nArgs:\n params: Target model identifier and optional reasoning effort, summary, and capability overrides.\n\nReturns:\n The model identifier active on the session after the switch." + async def disable(self, params: SkillsDisableRequest, *, timeout: float | None = None) -> None: + "Disables a skill for the session.\n\nArgs:\n params: Name of the skill to disable for the session." if self._assert_active is not None: self._assert_active() if params is None: @@ -8529,49 +16271,32 @@ async def switch_to(self, params: ModelSwitchToRequest, *, timeout: float | None params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return ModelSwitchToResult.from_dict(await self._client.request("session.model.switchTo", params_dict, **_timeout_kwargs(timeout))) - - -class ModeApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active + await self._client.request("session.skills.disable", params_dict, **_timeout_kwargs(timeout)) - async def get(self, *, timeout: float | None = None) -> SessionMode: - "Gets the current agent interaction mode.\n\nReturns:\n The session mode the agent is operating in" + async def reload(self, *, timeout: float | None = None) -> SkillsLoadDiagnostics: + "Reloads skill definitions for the session.\n\nReturns:\n Diagnostics from reloading skill definitions, with warnings and errors as separate lists." if self._assert_active is not None: self._assert_active() - return SessionMode(await self._client.request("session.mode.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return SkillsLoadDiagnostics.from_dict(await self._client.request("session.skills.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def set(self, params: ModeSetRequest, *, timeout: float | None = None) -> None: - "Sets the current agent interaction mode.\n\nArgs:\n params: Agent interaction mode to apply to the session." + async def ensure_loaded(self, *, timeout: float | None = None) -> None: + "Ensures the session's skill definitions have been loaded from disk." if self._assert_active is not None: self._assert_active() - if params is None: - raise TypeError("params is required") - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - await self._client.request("session.mode.set", params_dict, **_timeout_kwargs(timeout)) + await self._client.request("session.skills.ensureLoaded", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) -class NameApi: +# Experimental: this API group is experimental and may change or be removed. +class McpOauthApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def get(self, *, timeout: float | None = None) -> NameGetResult: - "Gets the session's friendly name.\n\nReturns:\n The session's friendly name, or null when not yet set." - if self._assert_active is not None: - self._assert_active() - - return NameGetResult.from_dict(await self._client.request("session.name.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def set(self, params: NameSetRequest, *, timeout: float | None = None) -> None: - "Sets the session's friendly name.\n\nArgs:\n params: New friendly name to apply to the session." + async def login(self, params: MCPOauthLoginRequest, *, timeout: float | None = None) -> MCPOauthLoginResult: + "Starts OAuth authentication for a remote MCP server.\n\nArgs:\n params: Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, and the callback success-page copy.\n\nReturns:\n OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server." if self._assert_active is not None: self._assert_active() if params is None: @@ -8579,24 +16304,26 @@ async def set(self, params: NameSetRequest, *, timeout: float | None = None) -> params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.name.set", params_dict, **_timeout_kwargs(timeout)) + return MCPOauthLoginResult.from_dict(await self._client.request("session.mcp.oauth.login", params_dict, **_timeout_kwargs(timeout))) -class PlanApi: +# Experimental: this API group is experimental and may change or be removed. +class McpApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active + self.oauth = McpOauthApi(client, session_id, assert_active) - async def read(self, *, timeout: float | None = None) -> PlanReadResult: - "Reads the session plan file from the workspace.\n\nReturns:\n Existence, contents, and resolved path of the session plan file." + async def list(self, *, timeout: float | None = None) -> MCPServerList: + "Lists MCP servers configured for the session and their connection status.\n\nReturns:\n MCP servers configured for the session, with their connection status." if self._assert_active is not None: self._assert_active() - return PlanReadResult.from_dict(await self._client.request("session.plan.read", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return MCPServerList.from_dict(await self._client.request("session.mcp.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def update(self, params: PlanUpdateRequest, *, timeout: float | None = None) -> None: - "Writes new content to the session plan file.\n\nArgs:\n params: Replacement contents to write to the session plan file." + async def enable(self, params: MCPEnableRequest, *, timeout: float | None = None) -> None: + "Enables an MCP server for the session.\n\nArgs:\n params: Name of the MCP server to enable for the session." if self._assert_active is not None: self._assert_active() if params is None: @@ -8604,38 +16331,39 @@ async def update(self, params: PlanUpdateRequest, *, timeout: float | None = Non params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.plan.update", params_dict, **_timeout_kwargs(timeout)) + await self._client.request("session.mcp.enable", params_dict, **_timeout_kwargs(timeout)) - async def delete(self, *, timeout: float | None = None) -> None: - "Deletes the session plan file from the workspace." + async def disable(self, params: MCPDisableRequest, *, timeout: float | None = None) -> None: + "Disables an MCP server for the session.\n\nArgs:\n params: Name of the MCP server to disable for the session." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - await self._client.request("session.plan.delete", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - - -class WorkspacesApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.mcp.disable", params_dict, **_timeout_kwargs(timeout)) - async def get_workspace(self, *, timeout: float | None = None) -> WorkspacesGetWorkspaceResult: - "Gets current workspace metadata for the session.\n\nReturns:\n Current workspace metadata for the session, or null when not available." + async def reload(self, *, timeout: float | None = None) -> None: + "Reloads MCP server connections for the session." if self._assert_active is not None: self._assert_active() - return WorkspacesGetWorkspaceResult.from_dict(await self._client.request("session.workspaces.getWorkspace", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + await self._client.request("session.mcp.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - async def list_files(self, *, timeout: float | None = None) -> WorkspacesListFilesResult: - "Lists files stored in the session workspace files directory.\n\nReturns:\n Relative paths of files stored in the session workspace files directory." + async def execute_sampling(self, params: MCPExecuteSamplingParams, *, timeout: float | None = None) -> MCPSamplingExecutionResult: + "Runs an MCP sampling inference on behalf of an MCP server.\n\nArgs:\n params: Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference.\n\nReturns:\n Outcome of an MCP sampling execution: success result, failure error, or cancellation." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - return WorkspacesListFilesResult.from_dict(await self._client.request("session.workspaces.listFiles", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return MCPSamplingExecutionResult.from_dict(await self._client.request("session.mcp.executeSampling", params_dict, **_timeout_kwargs(timeout))) - async def read_file(self, params: WorkspacesReadFileRequest, *, timeout: float | None = None) -> WorkspacesReadFileResult: - "Reads a file from the session workspace files directory.\n\nArgs:\n params: Relative path of the workspace file to read.\n\nReturns:\n Contents of the requested workspace file as a UTF-8 string." + async def cancel_sampling_execution(self, params: MCPCancelSamplingExecutionParams, *, timeout: float | None = None) -> MCPCancelSamplingExecutionResult: + "Cancels an in-flight MCP sampling execution by request ID.\n\nArgs:\n params: The requestId previously passed to executeSampling that should be cancelled.\n\nReturns:\n Indicates whether an in-flight sampling execution with the given requestId was found and cancelled." if self._assert_active is not None: self._assert_active() if params is None: @@ -8643,10 +16371,10 @@ async def read_file(self, params: WorkspacesReadFileRequest, *, timeout: float | params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return WorkspacesReadFileResult.from_dict(await self._client.request("session.workspaces.readFile", params_dict, **_timeout_kwargs(timeout))) + return MCPCancelSamplingExecutionResult.from_dict(await self._client.request("session.mcp.cancelSamplingExecution", params_dict, **_timeout_kwargs(timeout))) - async def create_file(self, params: WorkspacesCreateFileRequest, *, timeout: float | None = None) -> None: - "Creates or overwrites a file in the session workspace files directory.\n\nArgs:\n params: Relative path and UTF-8 content for the workspace file to create or overwrite." + async def set_env_value_mode(self, params: MCPSetEnvValueModeParams, *, timeout: float | None = None) -> MCPSetEnvValueModeResult: + "Sets how environment-variable values supplied to MCP servers are resolved (direct or indirect).\n\nArgs:\n params: Mode controlling how MCP server env values are resolved (`direct` or `indirect`).\n\nReturns:\n Env-value mode recorded on the session after the update." if self._assert_active is not None: self._assert_active() if params is None: @@ -8654,63 +16382,81 @@ async def create_file(self, params: WorkspacesCreateFileRequest, *, timeout: flo params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.workspaces.createFile", params_dict, **_timeout_kwargs(timeout)) + return MCPSetEnvValueModeResult.from_dict(await self._client.request("session.mcp.setEnvValueMode", params_dict, **_timeout_kwargs(timeout))) + + async def remove_git_hub(self, *, timeout: float | None = None) -> MCPRemoveGitHubResult: + "Removes the auto-managed `github` MCP server when present.\n\nReturns:\n Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove)." + if self._assert_active is not None: + self._assert_active() + return MCPRemoveGitHubResult.from_dict(await self._client.request("session.mcp.removeGitHub", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) -class InstructionsApi: + +# Experimental: this API group is experimental and may change or be removed. +class PluginsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def get_sources(self, *, timeout: float | None = None) -> InstructionsGetSourcesResult: - "Gets instruction sources loaded for the session.\n\nReturns:\n Instruction sources loaded for the session, in merge order." + async def list(self, *, timeout: float | None = None) -> PluginList: + "Lists plugins installed for the session.\n\nReturns:\n Plugins installed for the session, with their enabled state and version metadata." if self._assert_active is not None: self._assert_active() - return InstructionsGetSourcesResult.from_dict(await self._client.request("session.instructions.getSources", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return PluginList.from_dict(await self._client.request("session.plugins.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. -class FleetApi: +class OptionsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def start(self, params: FleetStartRequest | None = None, *, timeout: float | None = None) -> FleetStartResult: - "Starts fleet mode by submitting the fleet orchestration prompt to the session.\n\nArgs:\n params: Optional user prompt to combine with the fleet orchestration instructions.\n\nReturns:\n Indicates whether fleet mode was successfully activated." + async def update(self, params: SessionUpdateOptionsParams | None = None, *, timeout: float | None = None) -> SessionUpdateOptionsResult: + "Patches the genuinely-mutable subset of session options.\n\nArgs:\n params: Patch of mutable session options to apply to the running session.\n\nReturns:\n Indicates whether the session options patch was applied successfully." if self._assert_active is not None: self._assert_active() params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} params_dict["sessionId"] = self._session_id - return FleetStartResult.from_dict(await self._client.request("session.fleet.start", params_dict, **_timeout_kwargs(timeout))) + return SessionUpdateOptionsResult.from_dict(await self._client.request("session.options.update", params_dict, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. -class AgentApi: +class LspApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def list(self, *, timeout: float | None = None) -> AgentList: - "Lists custom agents available to the session.\n\nReturns:\n Custom agents available to the session." + async def initialize(self, params: LspInitializeRequest | None = None, *, timeout: float | None = None) -> None: + "Loads the merged LSP configuration set for the session's working directory.\n\nArgs:\n params: Parameters for (re)loading the merged LSP configuration set." if self._assert_active is not None: self._assert_active() - return AgentList.from_dict(await self._client.request("session.agent.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + await self._client.request("session.lsp.initialize", params_dict, **_timeout_kwargs(timeout)) - async def get_current(self, *, timeout: float | None = None) -> AgentGetCurrentResult: - "Gets the currently selected custom agent for the session.\n\nReturns:\n The currently selected custom agent, or null when using the default agent." + +# Experimental: this API group is experimental and may change or be removed. +class ExtensionsApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def list(self, *, timeout: float | None = None) -> ExtensionList: + "Lists extensions discovered for the session and their current status.\n\nReturns:\n Extensions discovered for the session, with their current status." if self._assert_active is not None: self._assert_active() - return AgentGetCurrentResult.from_dict(await self._client.request("session.agent.getCurrent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return ExtensionList.from_dict(await self._client.request("session.extensions.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def select(self, params: AgentSelectRequest, *, timeout: float | None = None) -> AgentSelectResult: - "Selects a custom agent for subsequent turns in the session.\n\nArgs:\n params: Name of the custom agent to select for subsequent turns.\n\nReturns:\n The newly selected custom agent." + async def enable(self, params: ExtensionsEnableRequest, *, timeout: float | None = None) -> None: + "Enables an extension for the session.\n\nArgs:\n params: Source-qualified extension identifier to enable for the session." if self._assert_active is not None: self._assert_active() if params is None: @@ -8718,32 +16464,35 @@ async def select(self, params: AgentSelectRequest, *, timeout: float | None = No params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return AgentSelectResult.from_dict(await self._client.request("session.agent.select", params_dict, **_timeout_kwargs(timeout))) + await self._client.request("session.extensions.enable", params_dict, **_timeout_kwargs(timeout)) - async def deselect(self, *, timeout: float | None = None) -> None: - "Clears the selected custom agent and returns the session to the default agent." + async def disable(self, params: ExtensionsDisableRequest, *, timeout: float | None = None) -> None: + "Disables an extension for the session.\n\nArgs:\n params: Source-qualified extension identifier to disable for the session." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - await self._client.request("session.agent.deselect", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.extensions.disable", params_dict, **_timeout_kwargs(timeout)) - async def reload(self, *, timeout: float | None = None) -> AgentReloadResult: - "Reloads custom agent definitions and returns the refreshed list.\n\nReturns:\n Custom agents available to the session after reloading definitions from disk." + async def reload(self, *, timeout: float | None = None) -> None: + "Reloads extension definitions and processes for the session." if self._assert_active is not None: self._assert_active() - return AgentReloadResult.from_dict(await self._client.request("session.agent.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + await self._client.request("session.extensions.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) -# Experimental: this API group is experimental and may change or be removed. -class TasksApi: +class ToolsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def start_agent(self, params: TasksStartAgentRequest, *, timeout: float | None = None) -> TasksStartAgentResult: - "Starts a background agent task in the session.\n\nArgs:\n params: Agent type, prompt, name, and optional description and model override for the new task.\n\nReturns:\n Identifier assigned to the newly started background agent task." + async def handle_pending_tool_call(self, params: HandlePendingToolCallRequest, *, timeout: float | None = None) -> HandlePendingToolCallResult: + "Provides the result for a pending external tool call.\n\nArgs:\n params: Pending external tool call request ID, with the tool result or an error describing why it failed.\n\nReturns:\n Indicates whether the external tool call result was handled successfully." if self._assert_active is not None: self._assert_active() if params is None: @@ -8751,17 +16500,33 @@ async def start_agent(self, params: TasksStartAgentRequest, *, timeout: float | params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return TasksStartAgentResult.from_dict(await self._client.request("session.tasks.startAgent", params_dict, **_timeout_kwargs(timeout))) + return HandlePendingToolCallResult.from_dict(await self._client.request("session.tools.handlePendingToolCall", params_dict, **_timeout_kwargs(timeout))) - async def list(self, *, timeout: float | None = None) -> TaskList: - "Lists background tasks tracked by the session.\n\nReturns:\n Background tasks currently tracked by the session." + async def initialize_and_validate(self, *, timeout: float | None = None) -> ToolsInitializeAndValidateResult: + "Resolves, builds, and validates the runtime tool list for the session.\n\nReturns:\n Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation." if self._assert_active is not None: self._assert_active() - return TaskList.from_dict(await self._client.request("session.tasks.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return ToolsInitializeAndValidateResult.from_dict(await self._client.request("session.tools.initializeAndValidate", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def promote_to_background(self, params: TasksPromoteToBackgroundRequest, *, timeout: float | None = None) -> TasksPromoteToBackgroundResult: - "Promotes an eligible synchronously-waited task so it continues running in the background.\n\nArgs:\n params: Identifier of the task to promote to background mode.\n\nReturns:\n Indicates whether the task was successfully promoted to background mode." + +class CommandsApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def list(self, params: CommandsListRequest | None = None, *, timeout: float | None = None) -> CommandList: + "Lists slash commands available in the session.\n\nArgs:\n params: Optional filters controlling which command sources to include in the listing.\n\nReturns:\n Slash commands available in the session, after applying any include/exclude filters." + if self._assert_active is not None: + self._assert_active() + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return CommandList.from_dict(await self._client.request("session.commands.list", params_dict, **_timeout_kwargs(timeout))) + + async def invoke(self, params: CommandsInvokeRequest, *, timeout: float | None = None) -> SlashCommandInvocationResult: + "Invokes a slash command in the session.\n\nArgs:\n params: Slash command name and optional raw input string to invoke.\n\nReturns:\n Result of invoking the slash command (text output, prompt to send to the agent, or completion)." if self._assert_active is not None: self._assert_active() if params is None: @@ -8769,10 +16534,10 @@ async def promote_to_background(self, params: TasksPromoteToBackgroundRequest, * params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return TasksPromoteToBackgroundResult.from_dict(await self._client.request("session.tasks.promoteToBackground", params_dict, **_timeout_kwargs(timeout))) + return SlashCommandInvocationResult.from_dict(await self._client.request("session.commands.invoke", params_dict, **_timeout_kwargs(timeout))) - async def cancel(self, params: TasksCancelRequest, *, timeout: float | None = None) -> TasksCancelResult: - "Cancels a background task.\n\nArgs:\n params: Identifier of the background task to cancel.\n\nReturns:\n Indicates whether the background task was successfully cancelled." + async def handle_pending_command(self, params: CommandsHandlePendingCommandRequest, *, timeout: float | None = None) -> CommandsHandlePendingCommandResult: + "Reports completion of a pending client-handled slash command.\n\nArgs:\n params: Pending command request ID and an optional error if the client handler failed.\n\nReturns:\n Indicates whether the pending client-handled command was completed successfully." if self._assert_active is not None: self._assert_active() if params is None: @@ -8780,10 +16545,10 @@ async def cancel(self, params: TasksCancelRequest, *, timeout: float | None = No params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return TasksCancelResult.from_dict(await self._client.request("session.tasks.cancel", params_dict, **_timeout_kwargs(timeout))) + return CommandsHandlePendingCommandResult.from_dict(await self._client.request("session.commands.handlePendingCommand", params_dict, **_timeout_kwargs(timeout))) - async def remove(self, params: TasksRemoveRequest, *, timeout: float | None = None) -> TasksRemoveResult: - "Removes a completed or cancelled background task from tracking.\n\nArgs:\n params: Identifier of the completed or cancelled task to remove from tracking.\n\nReturns:\n Indicates whether the task was removed. False when the task does not exist or is still running/idle." + async def execute(self, params: ExecuteCommandParams, *, timeout: float | None = None) -> ExecuteCommandResult: + "Executes a slash command synchronously and returns any error.\n\nArgs:\n params: Slash command name and argument string to execute synchronously.\n\nReturns:\n Error message produced while executing the command, if any." if self._assert_active is not None: self._assert_active() if params is None: @@ -8791,10 +16556,10 @@ async def remove(self, params: TasksRemoveRequest, *, timeout: float | None = No params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return TasksRemoveResult.from_dict(await self._client.request("session.tasks.remove", params_dict, **_timeout_kwargs(timeout))) + return ExecuteCommandResult.from_dict(await self._client.request("session.commands.execute", params_dict, **_timeout_kwargs(timeout))) - async def send_message(self, params: TasksSendMessageRequest, *, timeout: float | None = None) -> TasksSendMessageResult: - "Sends a message to a background agent task.\n\nArgs:\n params: Identifier of the target agent task, message content, and optional sender agent ID.\n\nReturns:\n Indicates whether the message was delivered, with an error message when delivery failed." + async def enqueue(self, params: EnqueueCommandParams, *, timeout: float | None = None) -> EnqueueCommandResult: + "Enqueues a slash command for FIFO processing on the local session.\n\nArgs:\n params: Slash-prefixed command string to enqueue for FIFO processing.\n\nReturns:\n Indicates whether the command was accepted into the local execution queue." if self._assert_active is not None: self._assert_active() if params is None: @@ -8802,25 +16567,29 @@ async def send_message(self, params: TasksSendMessageRequest, *, timeout: float params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return TasksSendMessageResult.from_dict(await self._client.request("session.tasks.sendMessage", params_dict, **_timeout_kwargs(timeout))) + return EnqueueCommandResult.from_dict(await self._client.request("session.commands.enqueue", params_dict, **_timeout_kwargs(timeout))) + + async def respond_to_queued_command(self, params: CommandsRespondToQueuedCommandRequest, *, timeout: float | None = None) -> CommandsRespondToQueuedCommandResult: + "Reports whether the host actually executed a queued command and whether to continue processing.\n\nArgs:\n params: Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands).\n\nReturns:\n Indicates whether the queued-command response was matched to a pending request." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return CommandsRespondToQueuedCommandResult.from_dict(await self._client.request("session.commands.respondToQueuedCommand", params_dict, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. -class SkillsApi: +class TelemetryApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def list(self, *, timeout: float | None = None) -> SkillList: - "Lists skills available to the session.\n\nReturns:\n Skills available to the session, with their enabled state." - if self._assert_active is not None: - self._assert_active() - - return SkillList.from_dict(await self._client.request("session.skills.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - async def enable(self, params: SkillsEnableRequest, *, timeout: float | None = None) -> None: - "Enables a skill for the session.\n\nArgs:\n params: Name of the skill to enable for the session." + async def set_feature_overrides(self, params: TelemetrySetFeatureOverridesRequest, *, timeout: float | None = None) -> None: + "Sets feature override key/value pairs to attach to subsequent telemetry events for the session.\n\nArgs:\n params: Feature override key/value pairs to attach to subsequent telemetry events from this session." if self._assert_active is not None: self._assert_active() if params is None: @@ -8828,10 +16597,17 @@ async def enable(self, params: SkillsEnableRequest, *, timeout: float | None = N params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.skills.enable", params_dict, **_timeout_kwargs(timeout)) + await self._client.request("session.telemetry.setFeatureOverrides", params_dict, **_timeout_kwargs(timeout)) - async def disable(self, params: SkillsDisableRequest, *, timeout: float | None = None) -> None: - "Disables a skill for the session.\n\nArgs:\n params: Name of the skill to disable for the session." + +class UiApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def elicitation(self, params: UIElicitationRequest, *, timeout: float | None = None) -> UIElicitationResponse: + "Requests structured input from a UI-capable client.\n\nArgs:\n params: Prompt message and JSON schema describing the form fields to elicit from the user.\n\nReturns:\n The elicitation response (accept with form values, decline, or cancel)" if self._assert_active is not None: self._assert_active() if params is None: @@ -8839,25 +16615,21 @@ async def disable(self, params: SkillsDisableRequest, *, timeout: float | None = params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.skills.disable", params_dict, **_timeout_kwargs(timeout)) + return UIElicitationResponse.from_dict(await self._client.request("session.ui.elicitation", params_dict, **_timeout_kwargs(timeout))) - async def reload(self, *, timeout: float | None = None) -> SkillsLoadDiagnostics: - "Reloads skill definitions for the session.\n\nReturns:\n Diagnostics from reloading skill definitions, with warnings and errors as separate lists." + async def handle_pending_elicitation(self, params: UIHandlePendingElicitationRequest, *, timeout: float | None = None) -> UIElicitationResult: + "Provides the user response for a pending elicitation request.\n\nArgs:\n params: Pending elicitation request ID and the user's response (accept/decline/cancel + form values).\n\nReturns:\n Indicates whether the elicitation response was accepted; false if it was already resolved by another client." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - return SkillsLoadDiagnostics.from_dict(await self._client.request("session.skills.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class McpOauthApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return UIElicitationResult.from_dict(await self._client.request("session.ui.handlePendingElicitation", params_dict, **_timeout_kwargs(timeout))) - async def login(self, params: MCPOauthLoginRequest, *, timeout: float | None = None) -> MCPOauthLoginResult: - "Starts OAuth authentication for a remote MCP server.\n\nArgs:\n params: Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, and the callback success-page copy.\n\nReturns:\n OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server." + async def handle_pending_user_input(self, params: UIHandlePendingUserInputRequest, *, timeout: float | None = None) -> UIHandlePendingResult: + "Resolves a pending `user_input.requested` event with the user's response.\n\nArgs:\n params: Request ID of a pending `user_input.requested` event and the user's response.\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." if self._assert_active is not None: self._assert_active() if params is None: @@ -8865,26 +16637,21 @@ async def login(self, params: MCPOauthLoginRequest, *, timeout: float | None = N params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return MCPOauthLoginResult.from_dict(await self._client.request("session.mcp.oauth.login", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class McpApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active - self.oauth = McpOauthApi(client, session_id, assert_active) + return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingUserInput", params_dict, **_timeout_kwargs(timeout))) - async def list(self, *, timeout: float | None = None) -> MCPServerList: - "Lists MCP servers configured for the session and their connection status.\n\nReturns:\n MCP servers configured for the session, with their connection status." + async def handle_pending_sampling(self, params: UIHandlePendingSamplingRequest, *, timeout: float | None = None) -> UIHandlePendingResult: + "Resolves a pending `sampling.requested` event with a sampling result, or rejects it.\n\nArgs:\n params: Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject).\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - return MCPServerList.from_dict(await self._client.request("session.mcp.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingSampling", params_dict, **_timeout_kwargs(timeout))) - async def enable(self, params: MCPEnableRequest, *, timeout: float | None = None) -> None: - "Enables an MCP server for the session.\n\nArgs:\n params: Name of the MCP server to enable for the session." + async def handle_pending_auto_mode_switch(self, params: UIHandlePendingAutoModeSwitchRequest, *, timeout: float | None = None) -> UIHandlePendingResult: + "Resolves a pending `auto_mode_switch.requested` event with the user's accept/decline decision.\n\nArgs:\n params: Request ID of a pending `auto_mode_switch.requested` event and the user's response.\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." if self._assert_active is not None: self._assert_active() if params is None: @@ -8892,10 +16659,10 @@ async def enable(self, params: MCPEnableRequest, *, timeout: float | None = None params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.mcp.enable", params_dict, **_timeout_kwargs(timeout)) + return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingAutoModeSwitch", params_dict, **_timeout_kwargs(timeout))) - async def disable(self, params: MCPDisableRequest, *, timeout: float | None = None) -> None: - "Disables an MCP server for the session.\n\nArgs:\n params: Name of the MCP server to disable for the session." + async def handle_pending_exit_plan_mode(self, params: UIHandlePendingExitPlanModeRequest, *, timeout: float | None = None) -> UIHandlePendingResult: + "Resolves a pending `exit_plan_mode.requested` event with the user's response.\n\nArgs:\n params: Request ID of a pending `exit_plan_mode.requested` event and the user's response.\n\nReturns:\n Indicates whether the pending UI request was resolved by this call." if self._assert_active is not None: self._assert_active() if params is None: @@ -8903,47 +16670,42 @@ async def disable(self, params: MCPDisableRequest, *, timeout: float | None = No params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.mcp.disable", params_dict, **_timeout_kwargs(timeout)) + return UIHandlePendingResult.from_dict(await self._client.request("session.ui.handlePendingExitPlanMode", params_dict, **_timeout_kwargs(timeout))) - async def reload(self, *, timeout: float | None = None) -> None: - "Reloads MCP server connections for the session." + async def register_direct_auto_mode_switch_handler(self, *, timeout: float | None = None) -> UIRegisterDirectAutoModeSwitchHandlerResult: + "Registers an in-process handler for auto-mode-switch requests so the server bridge skips dispatch.\n\nReturns:\n Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId)." if self._assert_active is not None: self._assert_active() - await self._client.request("session.mcp.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) - - -# Experimental: this API group is experimental and may change or be removed. -class PluginsApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active + return UIRegisterDirectAutoModeSwitchHandlerResult.from_dict(await self._client.request("session.ui.registerDirectAutoModeSwitchHandler", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def list(self, *, timeout: float | None = None) -> PluginList: - "Lists plugins installed for the session.\n\nReturns:\n Plugins installed for the session, with their enabled state and version metadata." + async def unregister_direct_auto_mode_switch_handler(self, params: UIUnregisterDirectAutoModeSwitchHandlerRequest, *, timeout: float | None = None) -> UIUnregisterDirectAutoModeSwitchHandlerResult: + "Unregisters a previously-registered in-process auto-mode-switch handler by its opaque handle.\n\nArgs:\n params: Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release.\n\nReturns:\n Indicates whether the handle was active and the registration count was decremented." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - return PluginList.from_dict(await self._client.request("session.plugins.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return UIUnregisterDirectAutoModeSwitchHandlerResult.from_dict(await self._client.request("session.ui.unregisterDirectAutoModeSwitchHandler", params_dict, **_timeout_kwargs(timeout))) -# Experimental: this API group is experimental and may change or be removed. -class ExtensionsApi: +class PermissionsPathsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def list(self, *, timeout: float | None = None) -> ExtensionList: - "Lists extensions discovered for the session and their current status.\n\nReturns:\n Extensions discovered for the session, with their current status." + async def list(self, *, timeout: float | None = None) -> PermissionPathsList: + "Returns the session's allowed directories and primary working directory.\n\nReturns:\n Snapshot of the session's allow-listed directories and primary working directory." if self._assert_active is not None: self._assert_active() - return ExtensionList.from_dict(await self._client.request("session.extensions.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + return PermissionPathsList.from_dict(await self._client.request("session.permissions.paths.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def enable(self, params: ExtensionsEnableRequest, *, timeout: float | None = None) -> None: - "Enables an extension for the session.\n\nArgs:\n params: Source-qualified extension identifier to enable for the session." + async def add(self, params: PermissionPathsAddParams, *, timeout: float | None = None) -> PermissionsPathsAddResult: + "Adds a directory to the session's allow-list.\n\nArgs:\n params: Directory path to add to the session's allowed directories.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -8951,10 +16713,10 @@ async def enable(self, params: ExtensionsEnableRequest, *, timeout: float | None params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.extensions.enable", params_dict, **_timeout_kwargs(timeout)) + return PermissionsPathsAddResult.from_dict(await self._client.request("session.permissions.paths.add", params_dict, **_timeout_kwargs(timeout))) - async def disable(self, params: ExtensionsDisableRequest, *, timeout: float | None = None) -> None: - "Disables an extension for the session.\n\nArgs:\n params: Source-qualified extension identifier to disable for the session." + async def update_primary(self, params: PermissionPathsUpdatePrimaryParams, *, timeout: float | None = None) -> PermissionsPathsUpdatePrimaryResult: + "Updates the session's primary working directory used by the permission policy.\n\nArgs:\n params: Directory path to set as the session's new primary working directory.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -8962,24 +16724,39 @@ async def disable(self, params: ExtensionsDisableRequest, *, timeout: float | No params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.extensions.disable", params_dict, **_timeout_kwargs(timeout)) + return PermissionsPathsUpdatePrimaryResult.from_dict(await self._client.request("session.permissions.paths.updatePrimary", params_dict, **_timeout_kwargs(timeout))) - async def reload(self, *, timeout: float | None = None) -> None: - "Reloads extension definitions and processes for the session." + async def is_path_within_allowed_directories(self, params: PermissionPathsAllowedCheckParams, *, timeout: float | None = None) -> PermissionPathsAllowedCheckResult: + "Reports whether a path falls within any of the session's allowed directories.\n\nArgs:\n params: Path to evaluate against the session's allowed directories.\n\nReturns:\n Indicates whether the supplied path is within the session's allowed directories." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - await self._client.request("session.extensions.reload", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return PermissionPathsAllowedCheckResult.from_dict(await self._client.request("session.permissions.paths.isPathWithinAllowedDirectories", params_dict, **_timeout_kwargs(timeout))) + + async def is_path_within_workspace(self, params: PermissionPathsWorkspaceCheckParams, *, timeout: float | None = None) -> PermissionPathsWorkspaceCheckResult: + "Reports whether a path falls within the session's workspace (primary) directory.\n\nArgs:\n params: Path to evaluate against the session's workspace (primary) directory.\n\nReturns:\n Indicates whether the supplied path is within the session's workspace directory." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return PermissionPathsWorkspaceCheckResult.from_dict(await self._client.request("session.permissions.paths.isPathWithinWorkspace", params_dict, **_timeout_kwargs(timeout))) -class ToolsApi: +class PermissionsUrlsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def handle_pending_tool_call(self, params: HandlePendingToolCallRequest, *, timeout: float | None = None) -> HandlePendingToolCallResult: - "Provides the result for a pending external tool call.\n\nArgs:\n params: Pending external tool call request ID, with the tool result or an error describing why it failed.\n\nReturns:\n Indicates whether the external tool call result was handled successfully." + async def set_unrestricted_mode(self, params: PermissionUrlsSetUnrestrictedModeParams, *, timeout: float | None = None) -> PermissionsUrlsSetUnrestrictedModeResult: + "Toggles the runtime's URL-permission policy between unrestricted and restricted modes.\n\nArgs:\n params: Whether the URL-permission policy should run in unrestricted mode.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -8987,26 +16764,28 @@ async def handle_pending_tool_call(self, params: HandlePendingToolCallRequest, * params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return HandlePendingToolCallResult.from_dict(await self._client.request("session.tools.handlePendingToolCall", params_dict, **_timeout_kwargs(timeout))) + return PermissionsUrlsSetUnrestrictedModeResult.from_dict(await self._client.request("session.permissions.urls.setUnrestrictedMode", params_dict, **_timeout_kwargs(timeout))) -class CommandsApi: +class PermissionsApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active + self.paths = PermissionsPathsApi(client, session_id, assert_active) + self.urls = PermissionsUrlsApi(client, session_id, assert_active) - async def list(self, params: CommandsListRequest | None = None, *, timeout: float | None = None) -> CommandList: - "Lists slash commands available in the session.\n\nArgs:\n params: Optional filters controlling which command sources to include in the listing.\n\nReturns:\n Slash commands available in the session, after applying any include/exclude filters." + async def configure(self, params: PermissionsConfigureParams | None = None, *, timeout: float | None = None) -> PermissionsConfigureResult: + "Replaces selected permission policy fields (rules, paths, URLs, exclusions, allow-all flags) on the session.\n\nArgs:\n params: Patch of permission policy fields to apply (omit a field to leave it unchanged).\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} params_dict["sessionId"] = self._session_id - return CommandList.from_dict(await self._client.request("session.commands.list", params_dict, **_timeout_kwargs(timeout))) + return PermissionsConfigureResult.from_dict(await self._client.request("session.permissions.configure", params_dict, **_timeout_kwargs(timeout))) - async def invoke(self, params: CommandsInvokeRequest, *, timeout: float | None = None) -> SlashCommandInvocationResult: - "Invokes a slash command in the session.\n\nArgs:\n params: Slash command name and optional raw input string to invoke.\n\nReturns:\n Result of invoking the slash command (text output, prompt to send to the agent, or completion)." + async def handle_pending_permission_request(self, params: PermissionDecisionRequest, *, timeout: float | None = None) -> PermissionRequestResult: + "Provides a decision for a pending tool permission request.\n\nArgs:\n params: Pending permission request ID and the decision to apply (approve/reject and scope).\n\nReturns:\n Indicates whether the permission decision was applied; false when the request was already resolved." if self._assert_active is not None: self._assert_active() if params is None: @@ -9014,10 +16793,17 @@ async def invoke(self, params: CommandsInvokeRequest, *, timeout: float | None = params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return SlashCommandInvocationResult.from_dict(await self._client.request("session.commands.invoke", params_dict, **_timeout_kwargs(timeout))) + return PermissionRequestResult.from_dict(await self._client.request("session.permissions.handlePendingPermissionRequest", params_dict, **_timeout_kwargs(timeout))) - async def handle_pending_command(self, params: CommandsHandlePendingCommandRequest, *, timeout: float | None = None) -> CommandsHandlePendingCommandResult: - "Reports completion of a pending client-handled slash command.\n\nArgs:\n params: Pending command request ID and an optional error if the client handler failed.\n\nReturns:\n Indicates whether the pending client-handled command was completed successfully." + async def pending_requests(self, *, timeout: float | None = None) -> PendingPermissionRequestList: + "Reconstructs the set of pending tool permission requests from the session's event history.\n\nReturns:\n List of pending permission requests reconstructed from event history." + if self._assert_active is not None: + self._assert_active() + + return PendingPermissionRequestList.from_dict(await self._client.request("session.permissions.pendingRequests", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def set_approve_all(self, params: PermissionsSetApproveAllRequest, *, timeout: float | None = None) -> PermissionsSetApproveAllResult: + "Enables or disables automatic approval of tool permission requests for the session.\n\nArgs:\n params: Allow-all toggle for tool permission requests, with an optional telemetry source.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -9025,10 +16811,10 @@ async def handle_pending_command(self, params: CommandsHandlePendingCommandReque params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return CommandsHandlePendingCommandResult.from_dict(await self._client.request("session.commands.handlePendingCommand", params_dict, **_timeout_kwargs(timeout))) + return PermissionsSetApproveAllResult.from_dict(await self._client.request("session.permissions.setApproveAll", params_dict, **_timeout_kwargs(timeout))) - async def respond_to_queued_command(self, params: CommandsRespondToQueuedCommandRequest, *, timeout: float | None = None) -> CommandsRespondToQueuedCommandResult: - "Responds to a queued command request from the session.\n\nArgs:\n params: Queued command request ID and the result indicating whether the client handled it.\n\nReturns:\n Indicates whether the queued-command response was accepted by the session." + async def modify_rules(self, params: PermissionsModifyRulesParams, *, timeout: float | None = None) -> PermissionsModifyRulesResult: + "Adds or removes session-scoped or location-scoped permission rules.\n\nArgs:\n params: Scope and add/remove instructions for modifying session- or location-scoped permission rules.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -9036,17 +16822,10 @@ async def respond_to_queued_command(self, params: CommandsRespondToQueuedCommand params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return CommandsRespondToQueuedCommandResult.from_dict(await self._client.request("session.commands.respondToQueuedCommand", params_dict, **_timeout_kwargs(timeout))) - + return PermissionsModifyRulesResult.from_dict(await self._client.request("session.permissions.modifyRules", params_dict, **_timeout_kwargs(timeout))) -class UiApi: - def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): - self._client = client - self._session_id = session_id - self._assert_active = assert_active - - async def elicitation(self, params: UIElicitationRequest, *, timeout: float | None = None) -> UIElicitationResponse: - "Requests structured input from a UI-capable client.\n\nArgs:\n params: Prompt message and JSON schema describing the form fields to elicit from the user.\n\nReturns:\n The elicitation response (accept with form values, decline, or cancel)" + async def set_required(self, params: PermissionsSetRequiredRequest, *, timeout: float | None = None) -> PermissionsSetRequiredResult: + "Sets whether the client wants permission prompts bridged into session events.\n\nArgs:\n params: Toggles whether permission prompts should be bridged into session events for this client.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -9054,10 +16833,17 @@ async def elicitation(self, params: UIElicitationRequest, *, timeout: float | No params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return UIElicitationResponse.from_dict(await self._client.request("session.ui.elicitation", params_dict, **_timeout_kwargs(timeout))) + return PermissionsSetRequiredResult.from_dict(await self._client.request("session.permissions.setRequired", params_dict, **_timeout_kwargs(timeout))) - async def handle_pending_elicitation(self, params: UIHandlePendingElicitationRequest, *, timeout: float | None = None) -> UIElicitationResult: - "Provides the user response for a pending elicitation request.\n\nArgs:\n params: Pending elicitation request ID and the user's response (accept/decline/cancel + form values).\n\nReturns:\n Indicates whether the elicitation response was accepted; false if it was already resolved by another client." + async def reset_session_approvals(self, *, timeout: float | None = None) -> PermissionsResetSessionApprovalsResult: + "Clears session-scoped tool permission approvals.\n\nReturns:\n Indicates whether the operation succeeded." + if self._assert_active is not None: + self._assert_active() + + return PermissionsResetSessionApprovalsResult.from_dict(await self._client.request("session.permissions.resetSessionApprovals", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def notify_prompt_shown(self, params: PermissionPromptShownNotification, *, timeout: float | None = None) -> PermissionsNotifyPromptShownResult: + "Notifies the runtime that a permission prompt UI has been shown to the user.\n\nArgs:\n params: Notification payload describing the permission prompt that the client just rendered.\n\nReturns:\n Indicates whether the operation succeeded." if self._assert_active is not None: self._assert_active() if params is None: @@ -9065,17 +16851,32 @@ async def handle_pending_elicitation(self, params: UIHandlePendingElicitationReq params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return UIElicitationResult.from_dict(await self._client.request("session.ui.handlePendingElicitation", params_dict, **_timeout_kwargs(timeout))) + return PermissionsNotifyPromptShownResult.from_dict(await self._client.request("session.permissions.notifyPromptShown", params_dict, **_timeout_kwargs(timeout))) -class PermissionsApi: +# Experimental: this API group is experimental and may change or be removed. +class MetadataApi: def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): self._client = client self._session_id = session_id self._assert_active = assert_active - async def handle_pending_permission_request(self, params: PermissionDecisionRequest, *, timeout: float | None = None) -> PermissionRequestResult: - "Provides a decision for a pending tool permission request.\n\nArgs:\n params: Pending permission request ID and the decision to apply (approve/reject and scope).\n\nReturns:\n Indicates whether the permission decision was applied; false when the request was already resolved." + async def snapshot(self, *, timeout: float | None = None) -> SessionMetadataSnapshot: + "Returns a snapshot of the session's identifying metadata, mode, agent, and remote info.\n\nReturns:\n Point-in-time snapshot of slow-changing session identifier and state fields" + if self._assert_active is not None: + self._assert_active() + + return SessionMetadataSnapshot.from_dict(await self._client.request("session.metadata.snapshot", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def is_processing(self, *, timeout: float | None = None) -> MetadataIsProcessingResult: + "Reports whether the local session is currently processing user/agent messages.\n\nReturns:\n Indicates whether the local session is currently processing a turn or background continuation." + if self._assert_active is not None: + self._assert_active() + + return MetadataIsProcessingResult.from_dict(await self._client.request("session.metadata.isProcessing", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def context_info(self, params: MetadataContextInfoRequest, *, timeout: float | None = None) -> MetadataContextInfoResult: + "Returns the token breakdown for the session's current context window for a given model.\n\nArgs:\n params: Model identifier and token limits used to compute the context-info breakdown.\n\nReturns:\n Token breakdown for the session's current context window, or null if uninitialized." if self._assert_active is not None: self._assert_active() if params is None: @@ -9083,10 +16884,10 @@ async def handle_pending_permission_request(self, params: PermissionDecisionRequ params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return PermissionRequestResult.from_dict(await self._client.request("session.permissions.handlePendingPermissionRequest", params_dict, **_timeout_kwargs(timeout))) + return MetadataContextInfoResult.from_dict(await self._client.request("session.metadata.contextInfo", params_dict, **_timeout_kwargs(timeout))) - async def set_approve_all(self, params: PermissionsSetApproveAllRequest, *, timeout: float | None = None) -> PermissionsSetApproveAllResult: - "Enables or disables automatic approval of tool permission requests for the session.\n\nArgs:\n params: Whether to auto-approve all tool permission requests for the rest of the session.\n\nReturns:\n Indicates whether the operation succeeded." + async def record_context_change(self, params: MetadataRecordContextChangeRequest, *, timeout: float | None = None) -> MetadataRecordContextChangeResult: + "Records a working-directory/git context change and emits a `session.context_changed` event.\n\nArgs:\n params: Updated working-directory/git context to record on the session.\n\nReturns:\n Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode)." if self._assert_active is not None: self._assert_active() if params is None: @@ -9094,14 +16895,29 @@ async def set_approve_all(self, params: PermissionsSetApproveAllRequest, *, time params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return PermissionsSetApproveAllResult.from_dict(await self._client.request("session.permissions.setApproveAll", params_dict, **_timeout_kwargs(timeout))) + return MetadataRecordContextChangeResult.from_dict(await self._client.request("session.metadata.recordContextChange", params_dict, **_timeout_kwargs(timeout))) - async def reset_session_approvals(self, *, timeout: float | None = None) -> PermissionsResetSessionApprovalsResult: - "Clears session-scoped tool permission approvals.\n\nReturns:\n Indicates whether the operation succeeded." + async def set_working_directory(self, params: MetadataSetWorkingDirectoryRequest, *, timeout: float | None = None) -> MetadataSetWorkingDirectoryResult: + "Updates the session's recorded working directory.\n\nArgs:\n params: Absolute path to set as the session's new working directory.\n\nReturns:\n Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for `process.chdir` and any related side-effects (file index, etc.); this method only updates the session's own recorded path." if self._assert_active is not None: self._assert_active() + if params is None: + raise TypeError("params is required") - return PermissionsResetSessionApprovalsResult.from_dict(await self._client.request("session.permissions.resetSessionApprovals", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return MetadataSetWorkingDirectoryResult.from_dict(await self._client.request("session.metadata.setWorkingDirectory", params_dict, **_timeout_kwargs(timeout))) + + async def recompute_context_tokens(self, params: MetadataRecomputeContextTokensRequest, *, timeout: float | None = None) -> MetadataRecomputeContextTokensResult: + "Re-tokenizes the session's existing messages against a model and returns aggregate token totals.\n\nArgs:\n params: Model identifier to use when re-tokenizing the session's existing messages.\n\nReturns:\n Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return MetadataRecomputeContextTokensResult.from_dict(await self._client.request("session.metadata.recomputeContextTokens", params_dict, **_timeout_kwargs(timeout))) class ShellApi: @@ -9141,7 +16957,7 @@ def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Call self._assert_active = assert_active async def compact(self, *, timeout: float | None = None) -> HistoryCompactResult: - "Compacts the session history to reduce context usage.\n\nReturns:\n Compaction outcome with the number of tokens and messages removed and the resulting context window breakdown." + "Compacts the session history to reduce context usage.\n\nReturns:\n Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown." if self._assert_active is not None: self._assert_active() @@ -9158,6 +16974,102 @@ async def truncate(self, params: HistoryTruncateRequest, *, timeout: float | Non params_dict["sessionId"] = self._session_id return HistoryTruncateResult.from_dict(await self._client.request("session.history.truncate", params_dict, **_timeout_kwargs(timeout))) + async def cancel_background_compaction(self, *, timeout: float | None = None) -> HistoryCancelBackgroundCompactionResult: + "Cancels any in-progress background compaction on a local session.\n\nReturns:\n Indicates whether an in-progress background compaction was cancelled." + if self._assert_active is not None: + self._assert_active() + + return HistoryCancelBackgroundCompactionResult.from_dict(await self._client.request("session.history.cancelBackgroundCompaction", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def abort_manual_compaction(self, *, timeout: float | None = None) -> HistoryAbortManualCompactionResult: + "Aborts any in-progress manual compaction on a local session.\n\nReturns:\n Indicates whether an in-progress manual compaction was aborted." + if self._assert_active is not None: + self._assert_active() + + return HistoryAbortManualCompactionResult.from_dict(await self._client.request("session.history.abortManualCompaction", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def summarize_for_handoff(self, *, timeout: float | None = None) -> HistorySummarizeForHandoffResult: + "Produces a markdown summary of the session's conversation context for hand-off scenarios.\n\nReturns:\n Markdown summary of the conversation context (empty when not available)." + if self._assert_active is not None: + self._assert_active() + + return HistorySummarizeForHandoffResult.from_dict(await self._client.request("session.history.summarizeForHandoff", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class QueueApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def pending_items(self, *, timeout: float | None = None) -> QueuePendingItemsResult: + "Returns the local session's pending user-facing queued items and steering messages.\n\nReturns:\n Snapshot of the session's pending queued items and immediate-steering messages." + if self._assert_active is not None: + self._assert_active() + + return QueuePendingItemsResult.from_dict(await self._client.request("session.queue.pendingItems", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def remove_most_recent(self, *, timeout: float | None = None) -> QueueRemoveMostRecentResult: + "Removes the most recently queued user-facing item (LIFO).\n\nReturns:\n Indicates whether a user-facing pending item was removed." + if self._assert_active is not None: + self._assert_active() + + return QueueRemoveMostRecentResult.from_dict(await self._client.request("session.queue.removeMostRecent", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def clear(self, *, timeout: float | None = None) -> None: + "Clears all pending queued items on the local session." + if self._assert_active is not None: + self._assert_active() + + await self._client.request("session.queue.clear", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + + +# Experimental: this API group is experimental and may change or be removed. +class EventLogApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def read(self, params: EventLogReadRequest | None = None, *, timeout: float | None = None) -> EventsReadResult: + "Reads a batch of session events from a cursor, optionally waiting for new events.\n\nArgs:\n params: Cursor, batch size, and optional long-poll/filter parameters for reading session events.\n\nReturns:\n Batch of session events returned by a read, with cursor and continuation metadata." + if self._assert_active is not None: + self._assert_active() + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return EventsReadResult.from_dict(await self._client.request("session.eventLog.read", params_dict, **_timeout_kwargs(timeout))) + + async def tail(self, *, timeout: float | None = None) -> EventLogTailResult: + "Returns a snapshot of the current tail cursor without consuming events.\n\nReturns:\n Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session)." + if self._assert_active is not None: + self._assert_active() + + return EventLogTailResult.from_dict(await self._client.request("session.eventLog.tail", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def register_interest(self, params: RegisterEventInterestParams, *, timeout: float | None = None) -> RegisterEventInterestResult: + "Registers consumer interest in an event type for runtime gating purposes.\n\nArgs:\n params: Event type to register consumer interest for, used by runtime gating logic.\n\nReturns:\n Opaque handle representing an event-type interest registration." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return RegisterEventInterestResult.from_dict(await self._client.request("session.eventLog.registerInterest", params_dict, **_timeout_kwargs(timeout))) + + async def release_interest(self, params: ReleaseEventInterestParams, *, timeout: float | None = None) -> EventLogReleaseInterestResult: + "Releases a consumer's previously-registered interest in an event type.\n\nArgs:\n params: Opaque handle previously returned by `registerInterest` to release.\n\nReturns:\n Indicates whether the operation succeeded." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return EventLogReleaseInterestResult.from_dict(await self._client.request("session.eventLog.releaseInterest", params_dict, **_timeout_kwargs(timeout))) + # Experimental: this API group is experimental and may change or be removed. class UsageApi: @@ -9197,6 +17109,43 @@ async def disable(self, *, timeout: float | None = None) -> None: await self._client.request("session.remote.disable", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + async def notify_steerable_changed(self, params: RemoteNotifySteerableChangedRequest, *, timeout: float | None = None) -> RemoteNotifySteerableChangedResult: + "Persists a remote-steerability change emitted by the host as a session event.\n\nArgs:\n params: New remote-steerability state to persist as a `session.remote_steerable_changed` event.\n\nReturns:\n Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return RemoteNotifySteerableChangedResult.from_dict(await self._client.request("session.remote.notifySteerableChanged", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class ScheduleApi: + def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Callable[[], None] | None = None): + self._client = client + self._session_id = session_id + self._assert_active = assert_active + + async def list(self, *, timeout: float | None = None) -> ScheduleList: + "Lists the session's currently active scheduled prompts.\n\nReturns:\n Snapshot of the currently active recurring prompts for this session." + if self._assert_active is not None: + self._assert_active() + + return ScheduleList.from_dict(await self._client.request("session.schedule.list", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def stop(self, params: ScheduleStopRequest, *, timeout: float | None = None) -> ScheduleStopResult: + "Removes a scheduled prompt by id.\n\nArgs:\n params: Identifier of the scheduled prompt to remove.\n\nReturns:\n Remove a scheduled prompt by id. The result entry is omitted if the id was unknown." + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return ScheduleStopResult.from_dict(await self._client.request("session.schedule.stop", params_dict, **_timeout_kwargs(timeout))) + class SessionRpc: """Typed session-scoped RPC methods.""" @@ -9217,15 +17166,22 @@ def __init__(self, client: "JsonRpcClient", session_id: str, assert_active: Call self.skills = SkillsApi(client, session_id, assert_active) self.mcp = McpApi(client, session_id, assert_active) self.plugins = PluginsApi(client, session_id, assert_active) + self.options = OptionsApi(client, session_id, assert_active) + self.lsp = LspApi(client, session_id, assert_active) self.extensions = ExtensionsApi(client, session_id, assert_active) self.tools = ToolsApi(client, session_id, assert_active) self.commands = CommandsApi(client, session_id, assert_active) + self.telemetry = TelemetryApi(client, session_id, assert_active) self.ui = UiApi(client, session_id, assert_active) self.permissions = PermissionsApi(client, session_id, assert_active) + self.metadata = MetadataApi(client, session_id, assert_active) self.shell = ShellApi(client, session_id, assert_active) self.history = HistoryApi(client, session_id, assert_active) + self.queue = QueueApi(client, session_id, assert_active) + self.event_log = EventLogApi(client, session_id, assert_active) self.usage = UsageApi(client, session_id, assert_active) self.remote = RemoteApi(client, session_id, assert_active) + self.schedule = ScheduleApi(client, session_id, assert_active) async def suspend(self, *, timeout: float | None = None) -> None: "Suspends the session while preserving persisted state for later resume." @@ -9234,8 +17190,37 @@ async def suspend(self, *, timeout: float | None = None) -> None: await self._client.request("session.suspend", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) + async def send(self, params: SendRequest, *, timeout: float | None = None) -> SendResult: + "Sends a user message to the session and returns its message ID.\n\nArgs:\n params: Parameters for sending a user message to the session\n\nReturns:\n Result of sending a user message" + if self._assert_active is not None: + self._assert_active() + if params is None: + raise TypeError("params is required") + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return SendResult.from_dict(await self._client.request("session.send", params_dict, **_timeout_kwargs(timeout))) + + async def abort(self, params: AbortRequest | None = None, *, timeout: float | None = None) -> AbortResult: + "Aborts the current agent turn.\n\nArgs:\n params: Parameters for aborting the current turn\n\nReturns:\n Result of aborting the current turn" + if self._assert_active is not None: + self._assert_active() + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return AbortResult.from_dict(await self._client.request("session.abort", params_dict, **_timeout_kwargs(timeout))) + + async def shutdown(self, params: ShutdownRequest | None = None, *, timeout: float | None = None) -> None: + "Shuts down the session and persists its final state. Awaits any deferred sessionEnd hooks before resolving so user-supplied hook scripts complete before the runtime tears down.\n\nArgs:\n params: Parameters for shutting down the session" + if self._assert_active is not None: + self._assert_active() + + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + await self._client.request("session.shutdown", params_dict, **_timeout_kwargs(timeout)) + async def log(self, params: LogRequest, *, timeout: float | None = None) -> LogResult: - "Emits a user-visible session log event.\n\nArgs:\n params: Message text, optional severity level, persistence flag, and optional follow-up URL.\n\nReturns:\n Identifier of the session event that was emitted for the log message." + "Emits a user-visible session log event.\n\nArgs:\n params: Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip.\n\nReturns:\n Identifier of the session event that was emitted for the log message." if self._assert_active is not None: self._assert_active() if params is None: diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 4f1b0bc03..f344650cd 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -325,7 +325,7 @@ class AssistantMessageData: encrypted_content: str | None = None interaction_id: str | None = None model: str | None = None - output_tokens: float | None = None + output_tokens: int | None = None # Deprecated: this field is deprecated. parent_tool_call_id: str | None = None phase: str | None = None @@ -345,7 +345,7 @@ def from_dict(obj: Any) -> "AssistantMessageData": encrypted_content = from_union([from_none, from_str], obj.get("encryptedContent")) interaction_id = from_union([from_none, from_str], obj.get("interactionId")) model = from_union([from_none, from_str], obj.get("model")) - output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) + output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) phase = from_union([from_none, from_str], obj.get("phase")) reasoning_opaque = from_union([from_none, from_str], obj.get("reasoningOpaque")) @@ -386,7 +386,7 @@ def to_dict(self) -> dict: if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) + result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) if self.parent_tool_call_id is not None: result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) if self.phase is not None: @@ -559,19 +559,19 @@ def to_dict(self) -> dict: @dataclass class AssistantStreamingDeltaData: "Streaming response progress with cumulative byte count" - total_response_size_bytes: float + total_response_size_bytes: int @staticmethod def from_dict(obj: Any) -> "AssistantStreamingDeltaData": assert isinstance(obj, dict) - total_response_size_bytes = from_float(obj.get("totalResponseSizeBytes")) + total_response_size_bytes = from_int(obj.get("totalResponseSizeBytes")) return AssistantStreamingDeltaData( total_response_size_bytes=total_response_size_bytes, ) def to_dict(self) -> dict: result: dict = {} - result["totalResponseSizeBytes"] = to_float(self.total_response_size_bytes) + result["totalResponseSizeBytes"] = to_int(self.total_response_size_bytes) return result @@ -622,13 +622,13 @@ def to_dict(self) -> dict: class AssistantUsageCopilotUsage: "Per-request cost and usage data from the CAPI copilot_usage response field" token_details: list[AssistantUsageCopilotUsageTokenDetail] - total_nano_aiu: float + total_nano_aiu: int @staticmethod def from_dict(obj: Any) -> "AssistantUsageCopilotUsage": assert isinstance(obj, dict) token_details = from_list(AssistantUsageCopilotUsageTokenDetail.from_dict, obj.get("tokenDetails")) - total_nano_aiu = from_float(obj.get("totalNanoAiu")) + total_nano_aiu = from_int(obj.get("totalNanoAiu")) return AssistantUsageCopilotUsage( token_details=token_details, total_nano_aiu=total_nano_aiu, @@ -637,24 +637,24 @@ def from_dict(obj: Any) -> "AssistantUsageCopilotUsage": def to_dict(self) -> dict: result: dict = {} result["tokenDetails"] = from_list(lambda x: to_class(AssistantUsageCopilotUsageTokenDetail, x), self.token_details) - result["totalNanoAiu"] = to_float(self.total_nano_aiu) + result["totalNanoAiu"] = to_int(self.total_nano_aiu) return result @dataclass class AssistantUsageCopilotUsageTokenDetail: "Token usage detail for a single billing category" - batch_size: float - cost_per_batch: float - token_count: float + batch_size: int + cost_per_batch: int + token_count: int token_type: str @staticmethod def from_dict(obj: Any) -> "AssistantUsageCopilotUsageTokenDetail": assert isinstance(obj, dict) - batch_size = from_float(obj.get("batchSize")) - cost_per_batch = from_float(obj.get("costPerBatch")) - token_count = from_float(obj.get("tokenCount")) + batch_size = from_int(obj.get("batchSize")) + cost_per_batch = from_int(obj.get("costPerBatch")) + token_count = from_int(obj.get("tokenCount")) token_type = from_str(obj.get("tokenType")) return AssistantUsageCopilotUsageTokenDetail( batch_size=batch_size, @@ -665,9 +665,9 @@ def from_dict(obj: Any) -> "AssistantUsageCopilotUsageTokenDetail": def to_dict(self) -> dict: result: dict = {} - result["batchSize"] = to_float(self.batch_size) - result["costPerBatch"] = to_float(self.cost_per_batch) - result["tokenCount"] = to_float(self.token_count) + result["batchSize"] = to_int(self.batch_size) + result["costPerBatch"] = to_int(self.cost_per_batch) + result["tokenCount"] = to_int(self.token_count) result["tokenType"] = from_str(self.token_type) return result @@ -678,21 +678,21 @@ class AssistantUsageData: model: str api_call_id: str | None = None api_endpoint: AssistantUsageApiEndpoint | None = None - cache_read_tokens: float | None = None - cache_write_tokens: float | None = None + cache_read_tokens: int | None = None + cache_write_tokens: int | None = None copilot_usage: AssistantUsageCopilotUsage | None = None cost: float | None = None duration: timedelta | None = None initiator: str | None = None - input_tokens: float | None = None + input_tokens: int | None = None inter_token_latency: timedelta | None = None - output_tokens: float | None = None + output_tokens: int | None = None # Deprecated: this field is deprecated. parent_tool_call_id: str | None = None provider_call_id: str | None = None quota_snapshots: dict[str, AssistantUsageQuotaSnapshot] | None = None reasoning_effort: str | None = None - reasoning_tokens: float | None = None + reasoning_tokens: int | None = None ttft: timedelta | None = None @staticmethod @@ -701,20 +701,20 @@ def from_dict(obj: Any) -> "AssistantUsageData": model = from_str(obj.get("model")) api_call_id = from_union([from_none, from_str], obj.get("apiCallId")) api_endpoint = from_union([from_none, lambda x: parse_enum(AssistantUsageApiEndpoint, x)], obj.get("apiEndpoint")) - cache_read_tokens = from_union([from_none, from_float], obj.get("cacheReadTokens")) - cache_write_tokens = from_union([from_none, from_float], obj.get("cacheWriteTokens")) + cache_read_tokens = from_union([from_none, from_int], obj.get("cacheReadTokens")) + cache_write_tokens = from_union([from_none, from_int], obj.get("cacheWriteTokens")) copilot_usage = from_union([from_none, AssistantUsageCopilotUsage.from_dict], obj.get("copilotUsage")) cost = from_union([from_none, from_float], obj.get("cost")) duration = from_union([from_none, from_timedelta], obj.get("duration")) initiator = from_union([from_none, from_str], obj.get("initiator")) - input_tokens = from_union([from_none, from_float], obj.get("inputTokens")) + input_tokens = from_union([from_none, from_int], obj.get("inputTokens")) inter_token_latency = from_union([from_none, from_timedelta], obj.get("interTokenLatencyMs")) - output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) + output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) parent_tool_call_id = from_union([from_none, from_str], obj.get("parentToolCallId")) provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) quota_snapshots = from_union([from_none, lambda x: from_dict(AssistantUsageQuotaSnapshot.from_dict, x)], obj.get("quotaSnapshots")) reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) - reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) + reasoning_tokens = from_union([from_none, from_int], obj.get("reasoningTokens")) ttft = from_union([from_none, from_timedelta], obj.get("ttftMs")) return AssistantUsageData( model=model, @@ -745,23 +745,23 @@ def to_dict(self) -> dict: if self.api_endpoint is not None: result["apiEndpoint"] = from_union([from_none, lambda x: to_enum(AssistantUsageApiEndpoint, x)], self.api_endpoint) if self.cache_read_tokens is not None: - result["cacheReadTokens"] = from_union([from_none, to_float], self.cache_read_tokens) + result["cacheReadTokens"] = from_union([from_none, to_int], self.cache_read_tokens) if self.cache_write_tokens is not None: - result["cacheWriteTokens"] = from_union([from_none, to_float], self.cache_write_tokens) + result["cacheWriteTokens"] = from_union([from_none, to_int], self.cache_write_tokens) if self.copilot_usage is not None: result["copilotUsage"] = from_union([from_none, lambda x: to_class(AssistantUsageCopilotUsage, x)], self.copilot_usage) if self.cost is not None: result["cost"] = from_union([from_none, to_float], self.cost) if self.duration is not None: - result["duration"] = from_union([from_none, to_timedelta], self.duration) + result["duration"] = from_union([from_none, to_timedelta_int], self.duration) if self.initiator is not None: result["initiator"] = from_union([from_none, from_str], self.initiator) if self.input_tokens is not None: - result["inputTokens"] = from_union([from_none, to_float], self.input_tokens) + result["inputTokens"] = from_union([from_none, to_int], self.input_tokens) if self.inter_token_latency is not None: result["interTokenLatencyMs"] = from_union([from_none, to_timedelta], self.inter_token_latency) if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) + result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) if self.parent_tool_call_id is not None: result["parentToolCallId"] = from_union([from_none, from_str], self.parent_tool_call_id) if self.provider_call_id is not None: @@ -771,34 +771,34 @@ def to_dict(self) -> dict: if self.reasoning_effort is not None: result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) + result["reasoningTokens"] = from_union([from_none, to_int], self.reasoning_tokens) if self.ttft is not None: - result["ttftMs"] = from_union([from_none, to_timedelta], self.ttft) + result["ttftMs"] = from_union([from_none, to_timedelta_int], self.ttft) return result @dataclass class AssistantUsageQuotaSnapshot: "Schema for the `AssistantUsageQuotaSnapshot` type." - entitlement_requests: float + entitlement_requests: int is_unlimited_entitlement: bool overage: float overage_allowed_with_exhausted_quota: bool remaining_percentage: float usage_allowed_with_exhausted_quota: bool - used_requests: float + used_requests: int reset_date: datetime | None = None @staticmethod def from_dict(obj: Any) -> "AssistantUsageQuotaSnapshot": assert isinstance(obj, dict) - entitlement_requests = from_float(obj.get("entitlementRequests")) + entitlement_requests = from_int(obj.get("entitlementRequests")) is_unlimited_entitlement = from_bool(obj.get("isUnlimitedEntitlement")) overage = from_float(obj.get("overage")) overage_allowed_with_exhausted_quota = from_bool(obj.get("overageAllowedWithExhaustedQuota")) remaining_percentage = from_float(obj.get("remainingPercentage")) usage_allowed_with_exhausted_quota = from_bool(obj.get("usageAllowedWithExhaustedQuota")) - used_requests = from_float(obj.get("usedRequests")) + used_requests = from_int(obj.get("usedRequests")) reset_date = from_union([from_none, from_datetime], obj.get("resetDate")) return AssistantUsageQuotaSnapshot( entitlement_requests=entitlement_requests, @@ -813,13 +813,13 @@ def from_dict(obj: Any) -> "AssistantUsageQuotaSnapshot": def to_dict(self) -> dict: result: dict = {} - result["entitlementRequests"] = to_float(self.entitlement_requests) + result["entitlementRequests"] = to_int(self.entitlement_requests) result["isUnlimitedEntitlement"] = from_bool(self.is_unlimited_entitlement) result["overage"] = to_float(self.overage) result["overageAllowedWithExhaustedQuota"] = from_bool(self.overage_allowed_with_exhausted_quota) result["remainingPercentage"] = to_float(self.remaining_percentage) result["usageAllowedWithExhaustedQuota"] = from_bool(self.usage_allowed_with_exhausted_quota) - result["usedRequests"] = to_float(self.used_requests) + result["usedRequests"] = to_int(self.used_requests) if self.reset_date is not None: result["resetDate"] = from_union([from_none, to_datetime], self.reset_date) return result @@ -853,14 +853,14 @@ class AutoModeSwitchRequestedData: "Auto mode switch request notification requiring user approval" request_id: str error_code: str | None = None - retry_after_seconds: float | None = None + retry_after_seconds: int | None = None @staticmethod def from_dict(obj: Any) -> "AutoModeSwitchRequestedData": assert isinstance(obj, dict) request_id = from_str(obj.get("requestId")) error_code = from_union([from_none, from_str], obj.get("errorCode")) - retry_after_seconds = from_union([from_none, from_float], obj.get("retryAfterSeconds")) + retry_after_seconds = from_union([from_none, from_int], obj.get("retryAfterSeconds")) return AutoModeSwitchRequestedData( request_id=request_id, error_code=error_code, @@ -873,7 +873,7 @@ def to_dict(self) -> dict: if self.error_code is not None: result["errorCode"] = from_union([from_none, from_str], self.error_code) if self.retry_after_seconds is not None: - result["retryAfterSeconds"] = from_union([from_none, to_float], self.retry_after_seconds) + result["retryAfterSeconds"] = from_union([from_none, to_int], self.retry_after_seconds) return result @@ -1036,24 +1036,24 @@ def to_dict(self) -> dict: @dataclass class CompactionCompleteCompactionTokensUsed: "Token usage breakdown for the compaction LLM call (aligned with assistant.usage format)" - cache_read_tokens: float | None = None - cache_write_tokens: float | None = None + cache_read_tokens: int | None = None + cache_write_tokens: int | None = None copilot_usage: CompactionCompleteCompactionTokensUsedCopilotUsage | None = None duration: timedelta | None = None - input_tokens: float | None = None + input_tokens: int | None = None model: str | None = None - output_tokens: float | None = None + output_tokens: int | None = None @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": assert isinstance(obj, dict) - cache_read_tokens = from_union([from_none, from_float], obj.get("cacheReadTokens")) - cache_write_tokens = from_union([from_none, from_float], obj.get("cacheWriteTokens")) + cache_read_tokens = from_union([from_none, from_int], obj.get("cacheReadTokens")) + cache_write_tokens = from_union([from_none, from_int], obj.get("cacheWriteTokens")) copilot_usage = from_union([from_none, CompactionCompleteCompactionTokensUsedCopilotUsage.from_dict], obj.get("copilotUsage")) duration = from_union([from_none, from_timedelta], obj.get("duration")) - input_tokens = from_union([from_none, from_float], obj.get("inputTokens")) + input_tokens = from_union([from_none, from_int], obj.get("inputTokens")) model = from_union([from_none, from_str], obj.get("model")) - output_tokens = from_union([from_none, from_float], obj.get("outputTokens")) + output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) return CompactionCompleteCompactionTokensUsed( cache_read_tokens=cache_read_tokens, cache_write_tokens=cache_write_tokens, @@ -1067,19 +1067,19 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": def to_dict(self) -> dict: result: dict = {} if self.cache_read_tokens is not None: - result["cacheReadTokens"] = from_union([from_none, to_float], self.cache_read_tokens) + result["cacheReadTokens"] = from_union([from_none, to_int], self.cache_read_tokens) if self.cache_write_tokens is not None: - result["cacheWriteTokens"] = from_union([from_none, to_float], self.cache_write_tokens) + result["cacheWriteTokens"] = from_union([from_none, to_int], self.cache_write_tokens) if self.copilot_usage is not None: result["copilotUsage"] = from_union([from_none, lambda x: to_class(CompactionCompleteCompactionTokensUsedCopilotUsage, x)], self.copilot_usage) if self.duration is not None: - result["duration"] = from_union([from_none, to_timedelta], self.duration) + result["duration"] = from_union([from_none, to_timedelta_int], self.duration) if self.input_tokens is not None: - result["inputTokens"] = from_union([from_none, to_float], self.input_tokens) + result["inputTokens"] = from_union([from_none, to_int], self.input_tokens) if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.output_tokens is not None: - result["outputTokens"] = from_union([from_none, to_float], self.output_tokens) + result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) return result @@ -1087,13 +1087,13 @@ def to_dict(self) -> dict: class CompactionCompleteCompactionTokensUsedCopilotUsage: "Per-request cost and usage data from the CAPI copilot_usage response field" token_details: list[CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail] - total_nano_aiu: float + total_nano_aiu: int @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsage": assert isinstance(obj, dict) token_details = from_list(CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail.from_dict, obj.get("tokenDetails")) - total_nano_aiu = from_float(obj.get("totalNanoAiu")) + total_nano_aiu = from_int(obj.get("totalNanoAiu")) return CompactionCompleteCompactionTokensUsedCopilotUsage( token_details=token_details, total_nano_aiu=total_nano_aiu, @@ -1102,24 +1102,24 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsage": def to_dict(self) -> dict: result: dict = {} result["tokenDetails"] = from_list(lambda x: to_class(CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail, x), self.token_details) - result["totalNanoAiu"] = to_float(self.total_nano_aiu) + result["totalNanoAiu"] = to_int(self.total_nano_aiu) return result @dataclass class CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail: "Token usage detail for a single billing category" - batch_size: float - cost_per_batch: float - token_count: float + batch_size: int + cost_per_batch: int + token_count: int token_type: str @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail": assert isinstance(obj, dict) - batch_size = from_float(obj.get("batchSize")) - cost_per_batch = from_float(obj.get("costPerBatch")) - token_count = from_float(obj.get("tokenCount")) + batch_size = from_int(obj.get("batchSize")) + cost_per_batch = from_int(obj.get("costPerBatch")) + token_count = from_int(obj.get("tokenCount")) token_type = from_str(obj.get("tokenType")) return CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail( batch_size=batch_size, @@ -1130,9 +1130,9 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsedCopilotUsageTo def to_dict(self) -> dict: result: dict = {} - result["batchSize"] = to_float(self.batch_size) - result["costPerBatch"] = to_float(self.cost_per_batch) - result["tokenCount"] = to_float(self.token_count) + result["batchSize"] = to_int(self.batch_size) + result["costPerBatch"] = to_int(self.cost_per_batch) + result["tokenCount"] = to_int(self.token_count) result["tokenType"] = from_str(self.token_type) return result @@ -1786,7 +1786,7 @@ def to_dict(self) -> dict: if self.api_call_id is not None: result["apiCallId"] = from_union([from_none, from_str], self.api_call_id) if self.duration is not None: - result["durationMs"] = from_union([from_none, to_timedelta], self.duration) + result["durationMs"] = from_union([from_none, to_timedelta_int], self.duration) if self.error_message is not None: result["errorMessage"] = from_union([from_none, from_str], self.error_message) if self.initiator is not None: @@ -2402,39 +2402,39 @@ def to_dict(self) -> dict: class SessionCompactionCompleteData: "Conversation compaction results including success status, metrics, and optional error details" success: bool - checkpoint_number: float | None = None + checkpoint_number: int | None = None checkpoint_path: str | None = None compaction_tokens_used: CompactionCompleteCompactionTokensUsed | None = None - conversation_tokens: float | None = None + conversation_tokens: int | None = None error: str | None = None - messages_removed: float | None = None - post_compaction_tokens: float | None = None - pre_compaction_messages_length: float | None = None - pre_compaction_tokens: float | None = None + messages_removed: int | None = None + post_compaction_tokens: int | None = None + pre_compaction_messages_length: int | None = None + pre_compaction_tokens: int | None = None request_id: str | None = None summary_content: str | None = None - system_tokens: float | None = None - tokens_removed: float | None = None - tool_definitions_tokens: float | None = None + system_tokens: int | None = None + tokens_removed: int | None = None + tool_definitions_tokens: int | None = None @staticmethod def from_dict(obj: Any) -> "SessionCompactionCompleteData": assert isinstance(obj, dict) success = from_bool(obj.get("success")) - checkpoint_number = from_union([from_none, from_float], obj.get("checkpointNumber")) + checkpoint_number = from_union([from_none, from_int], obj.get("checkpointNumber")) checkpoint_path = from_union([from_none, from_str], obj.get("checkpointPath")) compaction_tokens_used = from_union([from_none, CompactionCompleteCompactionTokensUsed.from_dict], obj.get("compactionTokensUsed")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) error = from_union([from_none, from_str], obj.get("error")) - messages_removed = from_union([from_none, from_float], obj.get("messagesRemoved")) - post_compaction_tokens = from_union([from_none, from_float], obj.get("postCompactionTokens")) - pre_compaction_messages_length = from_union([from_none, from_float], obj.get("preCompactionMessagesLength")) - pre_compaction_tokens = from_union([from_none, from_float], obj.get("preCompactionTokens")) + messages_removed = from_union([from_none, from_int], obj.get("messagesRemoved")) + post_compaction_tokens = from_union([from_none, from_int], obj.get("postCompactionTokens")) + pre_compaction_messages_length = from_union([from_none, from_int], obj.get("preCompactionMessagesLength")) + pre_compaction_tokens = from_union([from_none, from_int], obj.get("preCompactionTokens")) request_id = from_union([from_none, from_str], obj.get("requestId")) summary_content = from_union([from_none, from_str], obj.get("summaryContent")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - tokens_removed = from_union([from_none, from_float], obj.get("tokensRemoved")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) + tokens_removed = from_union([from_none, from_int], obj.get("tokensRemoved")) + tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) return SessionCompactionCompleteData( success=success, checkpoint_number=checkpoint_number, @@ -2457,49 +2457,49 @@ def to_dict(self) -> dict: result: dict = {} result["success"] = from_bool(self.success) if self.checkpoint_number is not None: - result["checkpointNumber"] = from_union([from_none, to_float], self.checkpoint_number) + result["checkpointNumber"] = from_union([from_none, to_int], self.checkpoint_number) if self.checkpoint_path is not None: result["checkpointPath"] = from_union([from_none, from_str], self.checkpoint_path) if self.compaction_tokens_used is not None: result["compactionTokensUsed"] = from_union([from_none, lambda x: to_class(CompactionCompleteCompactionTokensUsed, x)], self.compaction_tokens_used) if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) if self.error is not None: result["error"] = from_union([from_none, from_str], self.error) if self.messages_removed is not None: - result["messagesRemoved"] = from_union([from_none, to_float], self.messages_removed) + result["messagesRemoved"] = from_union([from_none, to_int], self.messages_removed) if self.post_compaction_tokens is not None: - result["postCompactionTokens"] = from_union([from_none, to_float], self.post_compaction_tokens) + result["postCompactionTokens"] = from_union([from_none, to_int], self.post_compaction_tokens) if self.pre_compaction_messages_length is not None: - result["preCompactionMessagesLength"] = from_union([from_none, to_float], self.pre_compaction_messages_length) + result["preCompactionMessagesLength"] = from_union([from_none, to_int], self.pre_compaction_messages_length) if self.pre_compaction_tokens is not None: - result["preCompactionTokens"] = from_union([from_none, to_float], self.pre_compaction_tokens) + result["preCompactionTokens"] = from_union([from_none, to_int], self.pre_compaction_tokens) if self.request_id is not None: result["requestId"] = from_union([from_none, from_str], self.request_id) if self.summary_content is not None: result["summaryContent"] = from_union([from_none, from_str], self.summary_content) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) if self.tokens_removed is not None: - result["tokensRemoved"] = from_union([from_none, to_float], self.tokens_removed) + result["tokensRemoved"] = from_union([from_none, to_int], self.tokens_removed) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) return result @dataclass class SessionCompactionStartData: "Context window breakdown at the start of LLM-powered conversation compaction" - conversation_tokens: float | None = None - system_tokens: float | None = None - tool_definitions_tokens: float | None = None + conversation_tokens: int | None = None + system_tokens: int | None = None + tool_definitions_tokens: int | None = None @staticmethod def from_dict(obj: Any) -> "SessionCompactionStartData": assert isinstance(obj, dict) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) + system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) return SessionCompactionStartData( conversation_tokens=conversation_tokens, system_tokens=system_tokens, @@ -2509,11 +2509,11 @@ def from_dict(obj: Any) -> "SessionCompactionStartData": def to_dict(self) -> dict: result: dict = {} if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) return result @@ -2963,7 +2963,7 @@ def to_dict(self) -> dict: @dataclass class SessionResumeData: "Session resume metadata including current context and event count" - event_count: float + event_count: int resume_time: datetime already_in_use: bool | None = None context: WorkingDirectoryContext | None = None @@ -2977,7 +2977,7 @@ class SessionResumeData: @staticmethod def from_dict(obj: Any) -> "SessionResumeData": assert isinstance(obj, dict) - event_count = from_float(obj.get("eventCount")) + event_count = from_int(obj.get("eventCount")) resume_time = from_datetime(obj.get("resumeTime")) already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) @@ -3002,7 +3002,7 @@ def from_dict(obj: Any) -> "SessionResumeData": def to_dict(self) -> dict: result: dict = {} - result["eventCount"] = to_float(self.event_count) + result["eventCount"] = to_int(self.event_count) result["resumeTime"] = to_datetime(self.resume_time) if self.already_in_use is not None: result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) @@ -3084,36 +3084,36 @@ class SessionShutdownData: "Session termination metrics including usage statistics, code changes, and shutdown reason" code_changes: ShutdownCodeChanges model_metrics: dict[str, ShutdownModelMetric] - session_start_time: float + session_start_time: int shutdown_type: ShutdownType total_api_duration: timedelta - total_premium_requests: float - conversation_tokens: float | None = None + total_premium_requests: int + conversation_tokens: int | None = None current_model: str | None = None - current_tokens: float | None = None + current_tokens: int | None = None error_reason: str | None = None - system_tokens: float | None = None + system_tokens: int | None = None token_details: dict[str, ShutdownTokenDetail] | None = None - tool_definitions_tokens: float | None = None - total_nano_aiu: float | None = None + tool_definitions_tokens: int | None = None + total_nano_aiu: int | None = None @staticmethod def from_dict(obj: Any) -> "SessionShutdownData": assert isinstance(obj, dict) code_changes = ShutdownCodeChanges.from_dict(obj.get("codeChanges")) model_metrics = from_dict(ShutdownModelMetric.from_dict, obj.get("modelMetrics")) - session_start_time = from_float(obj.get("sessionStartTime")) + session_start_time = from_int(obj.get("sessionStartTime")) shutdown_type = parse_enum(ShutdownType, obj.get("shutdownType")) total_api_duration = from_timedelta(obj.get("totalApiDurationMs")) - total_premium_requests = from_float(obj.get("totalPremiumRequests")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + total_premium_requests = from_int(obj.get("totalPremiumRequests")) + conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) current_model = from_union([from_none, from_str], obj.get("currentModel")) - current_tokens = from_union([from_none, from_float], obj.get("currentTokens")) + current_tokens = from_union([from_none, from_int], obj.get("currentTokens")) error_reason = from_union([from_none, from_str], obj.get("errorReason")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) + system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) token_details = from_union([from_none, lambda x: from_dict(ShutdownTokenDetail.from_dict, x)], obj.get("tokenDetails")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) - total_nano_aiu = from_union([from_none, from_float], obj.get("totalNanoAiu")) + tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) + total_nano_aiu = from_union([from_none, from_int], obj.get("totalNanoAiu")) return SessionShutdownData( code_changes=code_changes, model_metrics=model_metrics, @@ -3135,26 +3135,26 @@ def to_dict(self) -> dict: result: dict = {} result["codeChanges"] = to_class(ShutdownCodeChanges, self.code_changes) result["modelMetrics"] = from_dict(lambda x: to_class(ShutdownModelMetric, x), self.model_metrics) - result["sessionStartTime"] = to_float(self.session_start_time) + result["sessionStartTime"] = to_int(self.session_start_time) result["shutdownType"] = to_enum(ShutdownType, self.shutdown_type) - result["totalApiDurationMs"] = to_timedelta(self.total_api_duration) - result["totalPremiumRequests"] = to_float(self.total_premium_requests) + result["totalApiDurationMs"] = to_timedelta_int(self.total_api_duration) + result["totalPremiumRequests"] = to_int(self.total_premium_requests) if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) if self.current_model is not None: result["currentModel"] = from_union([from_none, from_str], self.current_model) if self.current_tokens is not None: - result["currentTokens"] = from_union([from_none, to_float], self.current_tokens) + result["currentTokens"] = from_union([from_none, to_int], self.current_tokens) if self.error_reason is not None: result["errorReason"] = from_union([from_none, from_str], self.error_reason) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) if self.token_details is not None: result["tokenDetails"] = from_union([from_none, lambda x: from_dict(lambda x: to_class(ShutdownTokenDetail, x), x)], self.token_details) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_none, to_float], self.total_nano_aiu) + result["totalNanoAiu"] = from_union([from_none, to_int], self.total_nano_aiu) return result @@ -3180,13 +3180,13 @@ def to_dict(self) -> dict: @dataclass class SessionSnapshotRewindData: "Session rewind details including target event and count of removed events" - events_removed: float + events_removed: int up_to_event_id: str @staticmethod def from_dict(obj: Any) -> "SessionSnapshotRewindData": assert isinstance(obj, dict) - events_removed = from_float(obj.get("eventsRemoved")) + events_removed = from_int(obj.get("eventsRemoved")) up_to_event_id = from_str(obj.get("upToEventId")) return SessionSnapshotRewindData( events_removed=events_removed, @@ -3195,7 +3195,7 @@ def from_dict(obj: Any) -> "SessionSnapshotRewindData": def to_dict(self) -> dict: result: dict = {} - result["eventsRemoved"] = to_float(self.events_removed) + result["eventsRemoved"] = to_int(self.events_removed) result["upToEventId"] = from_str(self.up_to_event_id) return result @@ -3207,7 +3207,7 @@ class SessionStartData: producer: str session_id: str start_time: datetime - version: float + version: int already_in_use: bool | None = None context: WorkingDirectoryContext | None = None detached_from_spawning_parent_session_id: str | None = None @@ -3223,7 +3223,7 @@ def from_dict(obj: Any) -> "SessionStartData": producer = from_str(obj.get("producer")) session_id = from_str(obj.get("sessionId")) start_time = from_datetime(obj.get("startTime")) - version = from_float(obj.get("version")) + version = from_int(obj.get("version")) already_in_use = from_union([from_none, from_bool], obj.get("alreadyInUse")) context = from_union([from_none, WorkingDirectoryContext.from_dict], obj.get("context")) detached_from_spawning_parent_session_id = from_union([from_none, from_str], obj.get("detachedFromSpawningParentSessionId")) @@ -3252,7 +3252,7 @@ def to_dict(self) -> dict: result["producer"] = from_str(self.producer) result["sessionId"] = from_str(self.session_id) result["startTime"] = to_datetime(self.start_time) - result["version"] = to_float(self.version) + result["version"] = to_int(self.version) if self.already_in_use is not None: result["alreadyInUse"] = from_union([from_none, from_bool], self.already_in_use) if self.context is not None: @@ -3336,26 +3336,26 @@ def to_dict(self) -> dict: @dataclass class SessionTruncationData: "Conversation truncation statistics including token counts and removed content metrics" - messages_removed_during_truncation: float + messages_removed_during_truncation: int performed_by: str - post_truncation_messages_length: float - post_truncation_tokens_in_messages: float - pre_truncation_messages_length: float - pre_truncation_tokens_in_messages: float - token_limit: float - tokens_removed_during_truncation: float + post_truncation_messages_length: int + post_truncation_tokens_in_messages: int + pre_truncation_messages_length: int + pre_truncation_tokens_in_messages: int + token_limit: int + tokens_removed_during_truncation: int @staticmethod def from_dict(obj: Any) -> "SessionTruncationData": assert isinstance(obj, dict) - messages_removed_during_truncation = from_float(obj.get("messagesRemovedDuringTruncation")) + messages_removed_during_truncation = from_int(obj.get("messagesRemovedDuringTruncation")) performed_by = from_str(obj.get("performedBy")) - post_truncation_messages_length = from_float(obj.get("postTruncationMessagesLength")) - post_truncation_tokens_in_messages = from_float(obj.get("postTruncationTokensInMessages")) - pre_truncation_messages_length = from_float(obj.get("preTruncationMessagesLength")) - pre_truncation_tokens_in_messages = from_float(obj.get("preTruncationTokensInMessages")) - token_limit = from_float(obj.get("tokenLimit")) - tokens_removed_during_truncation = from_float(obj.get("tokensRemovedDuringTruncation")) + post_truncation_messages_length = from_int(obj.get("postTruncationMessagesLength")) + post_truncation_tokens_in_messages = from_int(obj.get("postTruncationTokensInMessages")) + pre_truncation_messages_length = from_int(obj.get("preTruncationMessagesLength")) + pre_truncation_tokens_in_messages = from_int(obj.get("preTruncationTokensInMessages")) + token_limit = from_int(obj.get("tokenLimit")) + tokens_removed_during_truncation = from_int(obj.get("tokensRemovedDuringTruncation")) return SessionTruncationData( messages_removed_during_truncation=messages_removed_during_truncation, performed_by=performed_by, @@ -3369,38 +3369,38 @@ def from_dict(obj: Any) -> "SessionTruncationData": def to_dict(self) -> dict: result: dict = {} - result["messagesRemovedDuringTruncation"] = to_float(self.messages_removed_during_truncation) + result["messagesRemovedDuringTruncation"] = to_int(self.messages_removed_during_truncation) result["performedBy"] = from_str(self.performed_by) - result["postTruncationMessagesLength"] = to_float(self.post_truncation_messages_length) - result["postTruncationTokensInMessages"] = to_float(self.post_truncation_tokens_in_messages) - result["preTruncationMessagesLength"] = to_float(self.pre_truncation_messages_length) - result["preTruncationTokensInMessages"] = to_float(self.pre_truncation_tokens_in_messages) - result["tokenLimit"] = to_float(self.token_limit) - result["tokensRemovedDuringTruncation"] = to_float(self.tokens_removed_during_truncation) + result["postTruncationMessagesLength"] = to_int(self.post_truncation_messages_length) + result["postTruncationTokensInMessages"] = to_int(self.post_truncation_tokens_in_messages) + result["preTruncationMessagesLength"] = to_int(self.pre_truncation_messages_length) + result["preTruncationTokensInMessages"] = to_int(self.pre_truncation_tokens_in_messages) + result["tokenLimit"] = to_int(self.token_limit) + result["tokensRemovedDuringTruncation"] = to_int(self.tokens_removed_during_truncation) return result @dataclass class SessionUsageInfoData: "Current context window usage statistics including token and message counts" - current_tokens: float - messages_length: float - token_limit: float - conversation_tokens: float | None = None + current_tokens: int + messages_length: int + token_limit: int + conversation_tokens: int | None = None is_initial: bool | None = None - system_tokens: float | None = None - tool_definitions_tokens: float | None = None + system_tokens: int | None = None + tool_definitions_tokens: int | None = None @staticmethod def from_dict(obj: Any) -> "SessionUsageInfoData": assert isinstance(obj, dict) - current_tokens = from_float(obj.get("currentTokens")) - messages_length = from_float(obj.get("messagesLength")) - token_limit = from_float(obj.get("tokenLimit")) - conversation_tokens = from_union([from_none, from_float], obj.get("conversationTokens")) + current_tokens = from_int(obj.get("currentTokens")) + messages_length = from_int(obj.get("messagesLength")) + token_limit = from_int(obj.get("tokenLimit")) + conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) is_initial = from_union([from_none, from_bool], obj.get("isInitial")) - system_tokens = from_union([from_none, from_float], obj.get("systemTokens")) - tool_definitions_tokens = from_union([from_none, from_float], obj.get("toolDefinitionsTokens")) + system_tokens = from_union([from_none, from_int], obj.get("systemTokens")) + tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) return SessionUsageInfoData( current_tokens=current_tokens, messages_length=messages_length, @@ -3413,17 +3413,17 @@ def from_dict(obj: Any) -> "SessionUsageInfoData": def to_dict(self) -> dict: result: dict = {} - result["currentTokens"] = to_float(self.current_tokens) - result["messagesLength"] = to_float(self.messages_length) - result["tokenLimit"] = to_float(self.token_limit) + result["currentTokens"] = to_int(self.current_tokens) + result["messagesLength"] = to_int(self.messages_length) + result["tokenLimit"] = to_int(self.token_limit) if self.conversation_tokens is not None: - result["conversationTokens"] = from_union([from_none, to_float], self.conversation_tokens) + result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) if self.is_initial is not None: result["isInitial"] = from_union([from_none, from_bool], self.is_initial) if self.system_tokens is not None: - result["systemTokens"] = from_union([from_none, to_float], self.system_tokens) + result["systemTokens"] = from_union([from_none, to_int], self.system_tokens) if self.tool_definitions_tokens is not None: - result["toolDefinitionsTokens"] = from_union([from_none, to_float], self.tool_definitions_tokens) + result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) return result @@ -3482,15 +3482,15 @@ def to_dict(self) -> dict: class ShutdownCodeChanges: "Aggregate code change metrics for the session" files_modified: list[str] - lines_added: float - lines_removed: float + lines_added: int + lines_removed: int @staticmethod def from_dict(obj: Any) -> "ShutdownCodeChanges": assert isinstance(obj, dict) files_modified = from_list(from_str, obj.get("filesModified")) - lines_added = from_float(obj.get("linesAdded")) - lines_removed = from_float(obj.get("linesRemoved")) + lines_added = from_int(obj.get("linesAdded")) + lines_removed = from_int(obj.get("linesRemoved")) return ShutdownCodeChanges( files_modified=files_modified, lines_added=lines_added, @@ -3500,8 +3500,8 @@ def from_dict(obj: Any) -> "ShutdownCodeChanges": def to_dict(self) -> dict: result: dict = {} result["filesModified"] = from_list(from_str, self.files_modified) - result["linesAdded"] = to_float(self.lines_added) - result["linesRemoved"] = to_float(self.lines_removed) + result["linesAdded"] = to_int(self.lines_added) + result["linesRemoved"] = to_int(self.lines_removed) return result @@ -3511,7 +3511,7 @@ class ShutdownModelMetric: requests: ShutdownModelMetricRequests usage: ShutdownModelMetricUsage token_details: dict[str, ShutdownModelMetricTokenDetail] | None = None - total_nano_aiu: float | None = None + total_nano_aiu: int | None = None @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetric": @@ -3519,7 +3519,7 @@ def from_dict(obj: Any) -> "ShutdownModelMetric": requests = ShutdownModelMetricRequests.from_dict(obj.get("requests")) usage = ShutdownModelMetricUsage.from_dict(obj.get("usage")) token_details = from_union([from_none, lambda x: from_dict(ShutdownModelMetricTokenDetail.from_dict, x)], obj.get("tokenDetails")) - total_nano_aiu = from_union([from_none, from_float], obj.get("totalNanoAiu")) + total_nano_aiu = from_union([from_none, from_int], obj.get("totalNanoAiu")) return ShutdownModelMetric( requests=requests, usage=usage, @@ -3534,7 +3534,7 @@ def to_dict(self) -> dict: if self.token_details is not None: result["tokenDetails"] = from_union([from_none, lambda x: from_dict(lambda x: to_class(ShutdownModelMetricTokenDetail, x), x)], self.token_details) if self.total_nano_aiu is not None: - result["totalNanoAiu"] = from_union([from_none, to_float], self.total_nano_aiu) + result["totalNanoAiu"] = from_union([from_none, to_int], self.total_nano_aiu) return result @@ -3542,13 +3542,13 @@ def to_dict(self) -> dict: class ShutdownModelMetricRequests: "Request count and cost metrics" cost: float - count: float + count: int @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricRequests": assert isinstance(obj, dict) cost = from_float(obj.get("cost")) - count = from_float(obj.get("count")) + count = from_int(obj.get("count")) return ShutdownModelMetricRequests( cost=cost, count=count, @@ -3557,46 +3557,46 @@ def from_dict(obj: Any) -> "ShutdownModelMetricRequests": def to_dict(self) -> dict: result: dict = {} result["cost"] = to_float(self.cost) - result["count"] = to_float(self.count) + result["count"] = to_int(self.count) return result @dataclass class ShutdownModelMetricTokenDetail: "Schema for the `ShutdownModelMetricTokenDetail` type." - token_count: float + token_count: int @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricTokenDetail": assert isinstance(obj, dict) - token_count = from_float(obj.get("tokenCount")) + token_count = from_int(obj.get("tokenCount")) return ShutdownModelMetricTokenDetail( token_count=token_count, ) def to_dict(self) -> dict: result: dict = {} - result["tokenCount"] = to_float(self.token_count) + result["tokenCount"] = to_int(self.token_count) return result @dataclass class ShutdownModelMetricUsage: "Token usage breakdown" - cache_read_tokens: float - cache_write_tokens: float - input_tokens: float - output_tokens: float - reasoning_tokens: float | None = None + cache_read_tokens: int + cache_write_tokens: int + input_tokens: int + output_tokens: int + reasoning_tokens: int | None = None @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricUsage": assert isinstance(obj, dict) - cache_read_tokens = from_float(obj.get("cacheReadTokens")) - cache_write_tokens = from_float(obj.get("cacheWriteTokens")) - input_tokens = from_float(obj.get("inputTokens")) - output_tokens = from_float(obj.get("outputTokens")) - reasoning_tokens = from_union([from_none, from_float], obj.get("reasoningTokens")) + cache_read_tokens = from_int(obj.get("cacheReadTokens")) + cache_write_tokens = from_int(obj.get("cacheWriteTokens")) + input_tokens = from_int(obj.get("inputTokens")) + output_tokens = from_int(obj.get("outputTokens")) + reasoning_tokens = from_union([from_none, from_int], obj.get("reasoningTokens")) return ShutdownModelMetricUsage( cache_read_tokens=cache_read_tokens, cache_write_tokens=cache_write_tokens, @@ -3607,31 +3607,31 @@ def from_dict(obj: Any) -> "ShutdownModelMetricUsage": def to_dict(self) -> dict: result: dict = {} - result["cacheReadTokens"] = to_float(self.cache_read_tokens) - result["cacheWriteTokens"] = to_float(self.cache_write_tokens) - result["inputTokens"] = to_float(self.input_tokens) - result["outputTokens"] = to_float(self.output_tokens) + result["cacheReadTokens"] = to_int(self.cache_read_tokens) + result["cacheWriteTokens"] = to_int(self.cache_write_tokens) + result["inputTokens"] = to_int(self.input_tokens) + result["outputTokens"] = to_int(self.output_tokens) if self.reasoning_tokens is not None: - result["reasoningTokens"] = from_union([from_none, to_float], self.reasoning_tokens) + result["reasoningTokens"] = from_union([from_none, to_int], self.reasoning_tokens) return result @dataclass class ShutdownTokenDetail: "Schema for the `ShutdownTokenDetail` type." - token_count: float + token_count: int @staticmethod def from_dict(obj: Any) -> "ShutdownTokenDetail": assert isinstance(obj, dict) - token_count = from_float(obj.get("tokenCount")) + token_count = from_int(obj.get("tokenCount")) return ShutdownTokenDetail( token_count=token_count, ) def to_dict(self) -> dict: result: dict = {} - result["tokenCount"] = to_float(self.token_count) + result["tokenCount"] = to_int(self.token_count) return result @@ -3730,8 +3730,8 @@ class SubagentCompletedData: tool_call_id: str duration: timedelta | None = None model: str | None = None - total_tokens: float | None = None - total_tool_calls: float | None = None + total_tokens: int | None = None + total_tool_calls: int | None = None @staticmethod def from_dict(obj: Any) -> "SubagentCompletedData": @@ -3741,8 +3741,8 @@ def from_dict(obj: Any) -> "SubagentCompletedData": tool_call_id = from_str(obj.get("toolCallId")) duration = from_union([from_none, from_timedelta], obj.get("durationMs")) model = from_union([from_none, from_str], obj.get("model")) - total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) - total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) + total_tokens = from_union([from_none, from_int], obj.get("totalTokens")) + total_tool_calls = from_union([from_none, from_int], obj.get("totalToolCalls")) return SubagentCompletedData( agent_display_name=agent_display_name, agent_name=agent_name, @@ -3759,13 +3759,13 @@ def to_dict(self) -> dict: result["agentName"] = from_str(self.agent_name) result["toolCallId"] = from_str(self.tool_call_id) if self.duration is not None: - result["durationMs"] = from_union([from_none, to_timedelta], self.duration) + result["durationMs"] = from_union([from_none, to_timedelta_int], self.duration) if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.total_tokens is not None: - result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) + result["totalTokens"] = from_union([from_none, to_int], self.total_tokens) if self.total_tool_calls is not None: - result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) + result["totalToolCalls"] = from_union([from_none, to_int], self.total_tool_calls) return result @@ -3790,8 +3790,8 @@ class SubagentFailedData: tool_call_id: str duration: timedelta | None = None model: str | None = None - total_tokens: float | None = None - total_tool_calls: float | None = None + total_tokens: int | None = None + total_tool_calls: int | None = None @staticmethod def from_dict(obj: Any) -> "SubagentFailedData": @@ -3802,8 +3802,8 @@ def from_dict(obj: Any) -> "SubagentFailedData": tool_call_id = from_str(obj.get("toolCallId")) duration = from_union([from_none, from_timedelta], obj.get("durationMs")) model = from_union([from_none, from_str], obj.get("model")) - total_tokens = from_union([from_none, from_float], obj.get("totalTokens")) - total_tool_calls = from_union([from_none, from_float], obj.get("totalToolCalls")) + total_tokens = from_union([from_none, from_int], obj.get("totalTokens")) + total_tool_calls = from_union([from_none, from_int], obj.get("totalToolCalls")) return SubagentFailedData( agent_display_name=agent_display_name, agent_name=agent_name, @@ -3822,13 +3822,13 @@ def to_dict(self) -> dict: result["error"] = from_str(self.error) result["toolCallId"] = from_str(self.tool_call_id) if self.duration is not None: - result["durationMs"] = from_union([from_none, to_timedelta], self.duration) + result["durationMs"] = from_union([from_none, to_timedelta_int], self.duration) if self.model is not None: result["model"] = from_union([from_none, from_str], self.model) if self.total_tokens is not None: - result["totalTokens"] = from_union([from_none, to_float], self.total_tokens) + result["totalTokens"] = from_union([from_none, to_int], self.total_tokens) if self.total_tool_calls is not None: - result["totalToolCalls"] = from_union([from_none, to_float], self.total_tool_calls) + result["totalToolCalls"] = from_union([from_none, to_int], self.total_tool_calls) return result @@ -3961,7 +3961,7 @@ class SystemNotification: agent_type: str | None = None description: str | None = None entry_id: str | None = None - exit_code: float | None = None + exit_code: int | None = None prompt: str | None = None sender_name: str | None = None sender_type: str | None = None @@ -3980,7 +3980,7 @@ def from_dict(obj: Any) -> "SystemNotification": agent_type = from_union([from_none, from_str], obj.get("agentType")) description = from_union([from_none, from_str], obj.get("description")) entry_id = from_union([from_none, from_str], obj.get("entryId")) - exit_code = from_union([from_none, from_float], obj.get("exitCode")) + exit_code = from_union([from_none, from_int], obj.get("exitCode")) prompt = from_union([from_none, from_str], obj.get("prompt")) sender_name = from_union([from_none, from_str], obj.get("senderName")) sender_type = from_union([from_none, from_str], obj.get("senderType")) @@ -4020,7 +4020,7 @@ def to_dict(self) -> dict: if self.entry_id is not None: result["entryId"] = from_union([from_none, from_str], self.entry_id) if self.exit_code is not None: - result["exitCode"] = from_union([from_none, to_float], self.exit_code) + result["exitCode"] = from_union([from_none, to_int], self.exit_code) if self.prompt is not None: result["prompt"] = from_union([from_none, from_str], self.prompt) if self.sender_name is not None: @@ -4072,12 +4072,12 @@ class ToolExecutionCompleteContent: cwd: str | None = None data: str | None = None description: str | None = None - exit_code: float | None = None + exit_code: int | None = None icons: list[ToolExecutionCompleteContentResourceLinkIcon] | None = None mime_type: str | None = None name: str | None = None resource: ToolExecutionCompleteContentResourceDetails | None = None - size: float | None = None + size: int | None = None text: str | None = None title: str | None = None uri: str | None = None @@ -4089,12 +4089,12 @@ def from_dict(obj: Any) -> "ToolExecutionCompleteContent": cwd = from_union([from_none, from_str], obj.get("cwd")) data = from_union([from_none, from_str], obj.get("data")) description = from_union([from_none, from_str], obj.get("description")) - exit_code = from_union([from_none, from_float], obj.get("exitCode")) + exit_code = from_union([from_none, from_int], obj.get("exitCode")) icons = from_union([from_none, lambda x: from_list(ToolExecutionCompleteContentResourceLinkIcon.from_dict, x)], obj.get("icons")) mime_type = from_union([from_none, from_str], obj.get("mimeType")) name = from_union([from_none, from_str], obj.get("name")) resource = from_union([from_none, lambda x: from_union([EmbeddedTextResourceContents.from_dict, EmbeddedBlobResourceContents.from_dict], x)], obj.get("resource")) - size = from_union([from_none, from_float], obj.get("size")) + size = from_union([from_none, from_int], obj.get("size")) text = from_union([from_none, from_str], obj.get("text")) title = from_union([from_none, from_str], obj.get("title")) uri = from_union([from_none, from_str], obj.get("uri")) @@ -4124,7 +4124,7 @@ def to_dict(self) -> dict: if self.description is not None: result["description"] = from_union([from_none, from_str], self.description) if self.exit_code is not None: - result["exitCode"] = from_union([from_none, to_float], self.exit_code) + result["exitCode"] = from_union([from_none, to_int], self.exit_code) if self.icons is not None: result["icons"] = from_union([from_none, lambda x: from_list(lambda x: to_class(ToolExecutionCompleteContentResourceLinkIcon, x), x)], self.icons) if self.mime_type is not None: @@ -4134,7 +4134,7 @@ def to_dict(self) -> dict: if self.resource is not None: result["resource"] = from_union([from_none, lambda x: from_union([lambda x: to_class(EmbeddedTextResourceContents, x), lambda x: to_class(EmbeddedBlobResourceContents, x)], x)], self.resource) if self.size is not None: - result["size"] = from_union([from_none, to_float], self.size) + result["size"] = from_union([from_none, to_int], self.size) if self.text is not None: result["text"] = from_union([from_none, from_str], self.text) if self.title is not None: @@ -4494,7 +4494,7 @@ class UserMessageAttachment: file_path: str | None = None line_range: UserMessageAttachmentFileLineRange | None = None mime_type: str | None = None - number: float | None = None + number: int | None = None path: str | None = None reference_type: UserMessageAttachmentGithubReferenceType | None = None selection: UserMessageAttachmentSelectionDetails | None = None @@ -4512,7 +4512,7 @@ def from_dict(obj: Any) -> "UserMessageAttachment": file_path = from_union([from_none, from_str], obj.get("filePath")) line_range = from_union([from_none, UserMessageAttachmentFileLineRange.from_dict], obj.get("lineRange")) mime_type = from_union([from_none, from_str], obj.get("mimeType")) - number = from_union([from_none, from_float], obj.get("number")) + number = from_union([from_none, from_int], obj.get("number")) path = from_union([from_none, from_str], obj.get("path")) reference_type = from_union([from_none, lambda x: parse_enum(UserMessageAttachmentGithubReferenceType, x)], obj.get("referenceType")) selection = from_union([from_none, UserMessageAttachmentSelectionDetails.from_dict], obj.get("selection")) @@ -4551,7 +4551,7 @@ def to_dict(self) -> dict: if self.mime_type is not None: result["mimeType"] = from_union([from_none, from_str], self.mime_type) if self.number is not None: - result["number"] = from_union([from_none, to_float], self.number) + result["number"] = from_union([from_none, to_int], self.number) if self.path is not None: result["path"] = from_union([from_none, from_str], self.path) if self.reference_type is not None: @@ -4572,14 +4572,14 @@ def to_dict(self) -> dict: @dataclass class UserMessageAttachmentFileLineRange: "Optional line range to scope the attachment to a specific section of the file" - end: float - start: float + end: int + start: int @staticmethod def from_dict(obj: Any) -> "UserMessageAttachmentFileLineRange": assert isinstance(obj, dict) - end = from_float(obj.get("end")) - start = from_float(obj.get("start")) + end = from_int(obj.get("end")) + start = from_int(obj.get("start")) return UserMessageAttachmentFileLineRange( end=end, start=start, @@ -4587,8 +4587,8 @@ def from_dict(obj: Any) -> "UserMessageAttachmentFileLineRange": def to_dict(self) -> dict: result: dict = {} - result["end"] = to_float(self.end) - result["start"] = to_float(self.start) + result["end"] = to_int(self.end) + result["start"] = to_int(self.start) return result @@ -4618,14 +4618,14 @@ def to_dict(self) -> dict: @dataclass class UserMessageAttachmentSelectionDetailsEnd: "End position of the selection" - character: float - line: float + character: int + line: int @staticmethod def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsEnd": assert isinstance(obj, dict) - character = from_float(obj.get("character")) - line = from_float(obj.get("line")) + character = from_int(obj.get("character")) + line = from_int(obj.get("line")) return UserMessageAttachmentSelectionDetailsEnd( character=character, line=line, @@ -4633,22 +4633,22 @@ def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsEnd": def to_dict(self) -> dict: result: dict = {} - result["character"] = to_float(self.character) - result["line"] = to_float(self.line) + result["character"] = to_int(self.character) + result["line"] = to_int(self.line) return result @dataclass class UserMessageAttachmentSelectionDetailsStart: "Start position of the selection" - character: float - line: float + character: int + line: int @staticmethod def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsStart": assert isinstance(obj, dict) - character = from_float(obj.get("character")) - line = from_float(obj.get("line")) + character = from_int(obj.get("character")) + line = from_int(obj.get("line")) return UserMessageAttachmentSelectionDetailsStart( character=character, line=line, @@ -4656,8 +4656,8 @@ def from_dict(obj: Any) -> "UserMessageAttachmentSelectionDetailsStart": def to_dict(self) -> dict: result: dict = {} - result["character"] = to_float(self.character) - result["line"] = to_float(self.line) + result["character"] = to_int(self.character) + result["line"] = to_int(self.line) return result From 7d6e12016c08688d5d0cb6c120ca441f0fd0269b Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 10:33:59 -0400 Subject: [PATCH 6/6] Fix Python same-client resume tests Mark Python test sessions inactive before same-client resume so the duplicate active-session guard is preserved without destroying the server-side session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- python/e2e/test_client_e2e.py | 3 ++- python/e2e/test_commands_e2e.py | 2 ++ python/e2e/test_mcp_and_agents_e2e.py | 4 +++- python/e2e/test_permissions_e2e.py | 4 +++- python/e2e/test_session_config_e2e.py | 7 ++++++- python/e2e/test_session_e2e.py | 11 +++++++++-- python/e2e/testharness/__init__.py | 3 ++- python/e2e/testharness/helper.py | 5 +++++ python/test_commands_and_elicitation.py | 2 ++ 9 files changed, 34 insertions(+), 7 deletions(-) diff --git a/python/e2e/test_client_e2e.py b/python/e2e/test_client_e2e.py index fc7315a58..b7e14ba98 100644 --- a/python/e2e/test_client_e2e.py +++ b/python/e2e/test_client_e2e.py @@ -13,7 +13,7 @@ ) from copilot.session import PermissionHandler -from .testharness import CLI_PATH +from .testharness import CLI_PATH, mark_inactive_for_resume class TestClient: @@ -270,6 +270,7 @@ async def test_should_resume_session_without_permission_handler(self): try: await client.start() session = await client.create_session() + mark_inactive_for_resume(session) resumed = await client.resume_session(session.session_id) assert resumed.session_id == session.session_id diff --git a/python/e2e/test_commands_e2e.py b/python/e2e/test_commands_e2e.py index a1c44b7b3..1a7784f35 100644 --- a/python/e2e/test_commands_e2e.py +++ b/python/e2e/test_commands_e2e.py @@ -20,6 +20,7 @@ from copilot.session import CommandDefinition, PermissionHandler from .testharness.context import SNAPSHOTS_DIR, get_cli_path_for_tests +from .testharness.helper import mark_inactive_for_resume from .testharness.proxy import CapiProxy pytestmark = pytest.mark.asyncio(loop_scope="module") @@ -258,6 +259,7 @@ async def test_session_with_commands_resumes_successfully(self, ctx): ) session_id = session1.session_id + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, diff --git a/python/e2e/test_mcp_and_agents_e2e.py b/python/e2e/test_mcp_and_agents_e2e.py index 5d1275ad6..df27c2ecf 100644 --- a/python/e2e/test_mcp_and_agents_e2e.py +++ b/python/e2e/test_mcp_and_agents_e2e.py @@ -8,7 +8,7 @@ from copilot.session import CustomAgentConfig, MCPServerConfig, PermissionHandler -from .testharness import E2ETestContext, get_final_assistant_message +from .testharness import E2ETestContext, get_final_assistant_message, mark_inactive_for_resume TEST_MCP_SERVER = str( (Path(__file__).parents[2] / "test" / "harness" / "test-mcp-server.mjs").resolve() @@ -64,6 +64,7 @@ async def test_should_accept_mcp_server_configuration_on_session_resume( } } + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, @@ -157,6 +158,7 @@ async def test_should_accept_custom_agent_configuration_on_session_resume( } ] + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, diff --git a/python/e2e/test_permissions_e2e.py b/python/e2e/test_permissions_e2e.py index 46cf2f3d4..5a62342ce 100644 --- a/python/e2e/test_permissions_e2e.py +++ b/python/e2e/test_permissions_e2e.py @@ -13,7 +13,7 @@ ) from copilot.session import PermissionHandler, PermissionRequestResult -from .testharness import E2ETestContext +from .testharness import E2ETestContext, mark_inactive_for_resume from .testharness.helper import read_file, write_file pytestmark = pytest.mark.asyncio(loop_scope="module") @@ -140,6 +140,7 @@ async def test_should_deny_tool_operations_when_handler_explicitly_denies_after_ def deny_all(request, invocation): return PermissionRequestResult() + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session(session_id, on_permission_request=deny_all) denied_events = [] @@ -218,6 +219,7 @@ def on_permission_request( permission_requests.append(request) return PermissionRequestResult(kind="approve-once") + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=on_permission_request ) diff --git a/python/e2e/test_session_config_e2e.py b/python/e2e/test_session_config_e2e.py index 1fd2cd0a2..b69893bc5 100644 --- a/python/e2e/test_session_config_e2e.py +++ b/python/e2e/test_session_config_e2e.py @@ -9,7 +9,7 @@ from copilot import ModelCapabilitiesOverride, ModelSupportsOverride from copilot.session import PermissionHandler -from .testharness import E2ETestContext +from .testharness import E2ETestContext, mark_inactive_for_resume pytestmark = pytest.mark.asyncio(loop_scope="module") @@ -217,6 +217,7 @@ async def test_should_forward_custom_provider_headers_on_resume(self, ctx: E2ETe ) session_id = session1.session_id + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, @@ -314,6 +315,7 @@ async def test_should_apply_workingdirectory_on_session_resume(self, ctx: E2ETes ) session_id = session1.session_id + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, @@ -335,6 +337,7 @@ async def test_should_apply_systemmessage_on_session_resume(self, ctx: E2ETestCo session_id = session1.session_id resume_instruction = "End the response with RESUME_SYSTEM_MESSAGE_SENTINEL." + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, @@ -394,6 +397,7 @@ async def test_should_apply_instruction_directories_on_resume(self, ctx: E2ETest working_directory=project_dir, ) + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session1.session_id, on_permission_request=PermissionHandler.approve_all, @@ -416,6 +420,7 @@ async def test_should_apply_availabletools_on_session_resume(self, ctx: E2ETestC ) session_id = session1.session_id + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, diff --git a/python/e2e/test_session_e2e.py b/python/e2e/test_session_e2e.py index 062ce8d58..92c8e0aef 100644 --- a/python/e2e/test_session_e2e.py +++ b/python/e2e/test_session_e2e.py @@ -11,7 +11,12 @@ from copilot.session import PermissionHandler from copilot.tools import Tool, ToolResult -from .testharness import E2ETestContext, get_final_assistant_message, get_next_event_of_type +from .testharness import ( + E2ETestContext, + get_final_assistant_message, + get_next_event_of_type, + mark_inactive_for_resume, +) pytestmark = pytest.mark.asyncio(loop_scope="module") @@ -31,7 +36,7 @@ async def test_should_create_and_disconnect_sessions(self, ctx: E2ETestContext): await session.disconnect() - with pytest.raises(Exception, match="Session not found"): + with pytest.raises(Exception, match="Session has been disconnected"): await session.get_messages() async def test_should_have_stateful_conversation(self, ctx: E2ETestContext): @@ -216,6 +221,7 @@ async def test_should_resume_a_session_using_the_same_client(self, ctx: E2ETestC assert "2" in answer.data.content # Resume using the same client + mark_inactive_for_resume(session1) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all ) @@ -457,6 +463,7 @@ async def test_should_resume_session_with_custom_provider(self, ctx: E2ETestCont session_id = session.session_id # Resume the session with a provider + mark_inactive_for_resume(session) session2 = await ctx.client.resume_session( session_id, on_permission_request=PermissionHandler.approve_all, diff --git a/python/e2e/testharness/__init__.py b/python/e2e/testharness/__init__.py index 28558d687..8d74f6873 100644 --- a/python/e2e/testharness/__init__.py +++ b/python/e2e/testharness/__init__.py @@ -1,7 +1,7 @@ """Test harness for E2E tests.""" from .context import CLI_PATH, DEFAULT_GITHUB_TOKEN, E2ETestContext -from .helper import get_final_assistant_message, get_next_event_of_type +from .helper import get_final_assistant_message, get_next_event_of_type, mark_inactive_for_resume from .proxy import CapiProxy __all__ = [ @@ -11,4 +11,5 @@ "CapiProxy", "get_final_assistant_message", "get_next_event_of_type", + "mark_inactive_for_resume", ] diff --git a/python/e2e/testharness/helper.py b/python/e2e/testharness/helper.py index c603a8ec5..b9ca78aca 100644 --- a/python/e2e/testharness/helper.py +++ b/python/e2e/testharness/helper.py @@ -139,6 +139,11 @@ def read_file(work_dir: str, filename: str) -> str: return f.read() +def mark_inactive_for_resume(session: CopilotSession) -> None: + """Clear local active-session tracking without destroying the server session.""" + session._mark_disconnected() + + async def get_next_event_of_type(session: CopilotSession, event_type: str, timeout: float = 30.0): """ Wait for and return the next event of a specific type from a session. diff --git a/python/test_commands_and_elicitation.py b/python/test_commands_and_elicitation.py index 470e2f8f3..2897a0e3e 100644 --- a/python/test_commands_and_elicitation.py +++ b/python/test_commands_and_elicitation.py @@ -107,6 +107,7 @@ async def mock_request(method, params): client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all, @@ -525,6 +526,7 @@ async def mock_request(method, params): client._client.request = mock_request + session._mark_disconnected() await client.resume_session( session.session_id, on_permission_request=PermissionHandler.approve_all,