diff --git a/go/client.go b/go/client.go index 6960fe9a2..8b6a70aed 100644 --- a/go/client.go +++ b/go/client.go @@ -63,7 +63,7 @@ func validateSessionFsConfig(config *SessionFsConfig) error { if config.SessionStatePath == "" { return errors.New("SessionFs.SessionStatePath is required") } - if config.Conventions != rpc.SessionFSSetProviderConventionsPosix && config.Conventions != rpc.SessionFSSetProviderConventionsWindows { + if config.Conventions != rpc.SessionFsSetProviderConventionsPosix && config.Conventions != rpc.SessionFsSetProviderConventionsWindows { return errors.New("SessionFs.Conventions must be either 'posix' or 'windows'") } return nil @@ -372,7 +372,7 @@ func (c *Client) Start(ctx context.Context) error { // If a session filesystem provider was configured, register it. if c.options.SessionFs != nil { - _, err := c.RPC.SessionFs.SetProvider(ctx, &rpc.SessionFSSetProviderRequest{ + _, err := c.RPC.SessionFs.SetProvider(ctx, &rpc.SessionFsSetProviderRequest{ InitialCwd: c.options.SessionFs.InitialCwd, SessionStatePath: c.options.SessionFs.SessionStatePath, Conventions: c.options.SessionFs.Conventions, diff --git a/go/client_test.go b/go/client_test.go index f9f47fc30..34e7b803d 100644 --- a/go/client_test.go +++ b/go/client_test.go @@ -241,7 +241,7 @@ func TestClient_SessionFsConfig(t *testing.T) { NewClient(&ClientOptions{ SessionFs: &SessionFsConfig{ SessionStatePath: "/session-state", - Conventions: rpc.SessionFSSetProviderConventionsPosix, + Conventions: rpc.SessionFsSetProviderConventionsPosix, }, }) }) @@ -261,7 +261,7 @@ func TestClient_SessionFsConfig(t *testing.T) { NewClient(&ClientOptions{ SessionFs: &SessionFsConfig{ InitialCwd: "/", - Conventions: rpc.SessionFSSetProviderConventionsPosix, + Conventions: rpc.SessionFsSetProviderConventionsPosix, }, }) }) diff --git a/go/generated_session_events.go b/go/generated_session_events.go index a507fa8ac..7dc1f3a32 100644 --- a/go/generated_session_events.go +++ b/go/generated_session_events.go @@ -5,6 +5,7 @@ package copilot import ( "encoding/json" + "errors" "time" ) @@ -27,6 +28,8 @@ func (r RawSessionEventData) MarshalJSON() ([]byte, error) { return r.Raw, nil } type SessionEvent struct { // Sub-agent instance identifier. Absent for events from the root/main agent and session-level events. AgentID *string `json:"agentId,omitempty"` + // Typed event payload. Use a type switch to access per-event fields. + Data SessionEventData `json:"-"` // When true, the event is transient and not persisted to the session event log on disk Ephemeral *bool `json:"ephemeral,omitempty"` // Unique event identifier (UUID v4), generated when the event is emitted @@ -37,8 +40,6 @@ type SessionEvent struct { Timestamp time.Time `json:"timestamp"` // The event type discriminator. Type SessionEventType `json:"type"` - // Typed event payload. Use a type switch to access per-event fields. - Data SessionEventData `json:"-"` } // UnmarshalSessionEvent parses JSON bytes into a SessionEvent. @@ -56,12 +57,12 @@ func (r *SessionEvent) Marshal() ([]byte, error) { func (e *SessionEvent) UnmarshalJSON(data []byte) error { type rawEvent struct { AgentID *string `json:"agentId,omitempty"` + Data json.RawMessage `json:"data"` Ephemeral *bool `json:"ephemeral,omitempty"` ID string `json:"id"` ParentID *string `json:"parentId"` Timestamp time.Time `json:"timestamp"` Type SessionEventType `json:"type"` - Data json.RawMessage `json:"data"` } var raw rawEvent if err := json.Unmarshal(data, &raw); err != nil { @@ -75,482 +76,482 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error { e.Type = raw.Type switch raw.Type { - case SessionEventTypeSessionStart: - var d SessionStartData + case SessionEventTypeAbort: + var d AbortData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionResume: - var d SessionResumeData + case SessionEventTypeAssistantIntent: + var d AssistantIntentData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionRemoteSteerableChanged: - var d SessionRemoteSteerableChangedData + case SessionEventTypeAssistantMessage: + var d AssistantMessageData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionError: - var d SessionErrorData + case SessionEventTypeAssistantMessageDelta: + var d AssistantMessageDeltaData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionIdle: - var d SessionIdleData + case SessionEventTypeAssistantMessageStart: + var d AssistantMessageStartData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionTitleChanged: - var d SessionTitleChangedData + case SessionEventTypeAssistantReasoning: + var d AssistantReasoningData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionScheduleCreated: - var d SessionScheduleCreatedData + case SessionEventTypeAssistantReasoningDelta: + var d AssistantReasoningDeltaData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionScheduleCancelled: - var d SessionScheduleCancelledData + case SessionEventTypeAssistantStreamingDelta: + var d AssistantStreamingDeltaData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionInfo: - var d SessionInfoData + case SessionEventTypeAssistantTurnEnd: + var d AssistantTurnEndData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionWarning: - var d SessionWarningData + case SessionEventTypeAssistantTurnStart: + var d AssistantTurnStartData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionModelChange: - var d SessionModelChangeData + case SessionEventTypeAssistantUsage: + var d AssistantUsageData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionModeChanged: - var d SessionModeChangedData + case SessionEventTypeAutoModeSwitchCompleted: + var d AutoModeSwitchCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionPlanChanged: - var d SessionPlanChangedData + case SessionEventTypeAutoModeSwitchRequested: + var d AutoModeSwitchRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionWorkspaceFileChanged: - var d SessionWorkspaceFileChangedData + case SessionEventTypeCapabilitiesChanged: + var d CapabilitiesChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionHandoff: - var d SessionHandoffData + case SessionEventTypeCommandCompleted: + var d CommandCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionTruncation: - var d SessionTruncationData + case SessionEventTypeCommandExecute: + var d CommandExecuteData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionSnapshotRewind: - var d SessionSnapshotRewindData + case SessionEventTypeCommandQueued: + var d CommandQueuedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionShutdown: - var d SessionShutdownData + case SessionEventTypeCommandsChanged: + var d CommandsChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionContextChanged: - var d SessionContextChangedData + case SessionEventTypeElicitationCompleted: + var d ElicitationCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionUsageInfo: - var d SessionUsageInfoData + case SessionEventTypeElicitationRequested: + var d ElicitationRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionCompactionStart: - var d SessionCompactionStartData + case SessionEventTypeExitPlanModeCompleted: + var d ExitPlanModeCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionCompactionComplete: - var d SessionCompactionCompleteData + case SessionEventTypeExitPlanModeRequested: + var d ExitPlanModeRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionTaskComplete: - var d SessionTaskCompleteData + case SessionEventTypeExternalToolCompleted: + var d ExternalToolCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeUserMessage: - var d UserMessageData + case SessionEventTypeExternalToolRequested: + var d ExternalToolRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypePendingMessagesModified: - var d PendingMessagesModifiedData + case SessionEventTypeHookEnd: + var d HookEndData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantTurnStart: - var d AssistantTurnStartData + case SessionEventTypeHookStart: + var d HookStartData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantIntent: - var d AssistantIntentData + case SessionEventTypeMcpOauthCompleted: + var d McpOauthCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantReasoning: - var d AssistantReasoningData + case SessionEventTypeMcpOauthRequired: + var d McpOauthRequiredData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantReasoningDelta: - var d AssistantReasoningDeltaData + case SessionEventTypeModelCallFailure: + var d ModelCallFailureData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantStreamingDelta: - var d AssistantStreamingDeltaData + case SessionEventTypePendingMessagesModified: + var d PendingMessagesModifiedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantMessage: - var d AssistantMessageData + case SessionEventTypePermissionCompleted: + var d PermissionCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantMessageStart: - var d AssistantMessageStartData + case SessionEventTypePermissionRequested: + var d PermissionRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantMessageDelta: - var d AssistantMessageDeltaData + case SessionEventTypeSamplingCompleted: + var d SamplingCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantTurnEnd: - var d AssistantTurnEndData + case SessionEventTypeSamplingRequested: + var d SamplingRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAssistantUsage: - var d AssistantUsageData + case SessionEventTypeSessionBackgroundTasksChanged: + var d SessionBackgroundTasksChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeModelCallFailure: - var d ModelCallFailureData + case SessionEventTypeSessionCompactionComplete: + var d SessionCompactionCompleteData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAbort: - var d AbortData + case SessionEventTypeSessionCompactionStart: + var d SessionCompactionStartData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeToolUserRequested: - var d ToolUserRequestedData + case SessionEventTypeSessionContextChanged: + var d SessionContextChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeToolExecutionStart: - var d ToolExecutionStartData + case SessionEventTypeSessionCustomAgentsUpdated: + var d SessionCustomAgentsUpdatedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeToolExecutionPartialResult: - var d ToolExecutionPartialResultData + case SessionEventTypeSessionError: + var d SessionErrorData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeToolExecutionProgress: - var d ToolExecutionProgressData + case SessionEventTypeSessionExtensionsLoaded: + var d SessionExtensionsLoadedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeToolExecutionComplete: - var d ToolExecutionCompleteData + case SessionEventTypeSessionHandoff: + var d SessionHandoffData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSkillInvoked: - var d SkillInvokedData + case SessionEventTypeSessionIdle: + var d SessionIdleData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSubagentStarted: - var d SubagentStartedData + case SessionEventTypeSessionInfo: + var d SessionInfoData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSubagentCompleted: - var d SubagentCompletedData + case SessionEventTypeSessionMcpServersLoaded: + var d SessionMcpServersLoadedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSubagentFailed: - var d SubagentFailedData + case SessionEventTypeSessionMcpServerStatusChanged: + var d SessionMcpServerStatusChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSubagentSelected: - var d SubagentSelectedData + case SessionEventTypeSessionModeChanged: + var d SessionModeChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSubagentDeselected: - var d SubagentDeselectedData + case SessionEventTypeSessionModelChange: + var d SessionModelChangeData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeHookStart: - var d HookStartData + case SessionEventTypeSessionPlanChanged: + var d SessionPlanChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeHookEnd: - var d HookEndData + case SessionEventTypeSessionRemoteSteerableChanged: + var d SessionRemoteSteerableChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSystemMessage: - var d SystemMessageData + case SessionEventTypeSessionResume: + var d SessionResumeData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSystemNotification: - var d SystemNotificationData + case SessionEventTypeSessionScheduleCancelled: + var d SessionScheduleCancelledData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypePermissionRequested: - var d PermissionRequestedData + case SessionEventTypeSessionScheduleCreated: + var d SessionScheduleCreatedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypePermissionCompleted: - var d PermissionCompletedData + case SessionEventTypeSessionShutdown: + var d SessionShutdownData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeUserInputRequested: - var d UserInputRequestedData + case SessionEventTypeSessionSkillsLoaded: + var d SessionSkillsLoadedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeUserInputCompleted: - var d UserInputCompletedData + case SessionEventTypeSessionSnapshotRewind: + var d SessionSnapshotRewindData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeElicitationRequested: - var d ElicitationRequestedData + case SessionEventTypeSessionStart: + var d SessionStartData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeElicitationCompleted: - var d ElicitationCompletedData + case SessionEventTypeSessionTaskComplete: + var d SessionTaskCompleteData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSamplingRequested: - var d SamplingRequestedData + case SessionEventTypeSessionTitleChanged: + var d SessionTitleChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSamplingCompleted: - var d SamplingCompletedData + case SessionEventTypeSessionToolsUpdated: + var d SessionToolsUpdatedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeMcpOauthRequired: - var d McpOauthRequiredData + case SessionEventTypeSessionTruncation: + var d SessionTruncationData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeMcpOauthCompleted: - var d McpOauthCompletedData + case SessionEventTypeSessionUsageInfo: + var d SessionUsageInfoData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeExternalToolRequested: - var d ExternalToolRequestedData + case SessionEventTypeSessionWarning: + var d SessionWarningData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeExternalToolCompleted: - var d ExternalToolCompletedData + case SessionEventTypeSessionWorkspaceFileChanged: + var d SessionWorkspaceFileChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeCommandQueued: - var d CommandQueuedData + case SessionEventTypeSkillInvoked: + var d SkillInvokedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeCommandExecute: - var d CommandExecuteData + case SessionEventTypeSubagentCompleted: + var d SubagentCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeCommandCompleted: - var d CommandCompletedData + case SessionEventTypeSubagentDeselected: + var d SubagentDeselectedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAutoModeSwitchRequested: - var d AutoModeSwitchRequestedData + case SessionEventTypeSubagentFailed: + var d SubagentFailedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeAutoModeSwitchCompleted: - var d AutoModeSwitchCompletedData + case SessionEventTypeSubagentSelected: + var d SubagentSelectedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeCommandsChanged: - var d CommandsChangedData + case SessionEventTypeSubagentStarted: + var d SubagentStartedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeCapabilitiesChanged: - var d CapabilitiesChangedData + case SessionEventTypeSystemMessage: + var d SystemMessageData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeExitPlanModeRequested: - var d ExitPlanModeRequestedData + case SessionEventTypeSystemNotification: + var d SystemNotificationData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeExitPlanModeCompleted: - var d ExitPlanModeCompletedData + case SessionEventTypeToolExecutionComplete: + var d ToolExecutionCompleteData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionToolsUpdated: - var d SessionToolsUpdatedData + case SessionEventTypeToolExecutionPartialResult: + var d ToolExecutionPartialResultData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionBackgroundTasksChanged: - var d SessionBackgroundTasksChangedData + case SessionEventTypeToolExecutionProgress: + var d ToolExecutionProgressData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionSkillsLoaded: - var d SessionSkillsLoadedData + case SessionEventTypeToolExecutionStart: + var d ToolExecutionStartData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionCustomAgentsUpdated: - var d SessionCustomAgentsUpdatedData + case SessionEventTypeToolUserRequested: + var d ToolUserRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionMcpServersLoaded: - var d SessionMcpServersLoadedData + case SessionEventTypeUserInputCompleted: + var d UserInputCompletedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionMcpServerStatusChanged: - var d SessionMcpServerStatusChangedData + case SessionEventTypeUserInputRequested: + var d UserInputRequestedData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } e.Data = &d - case SessionEventTypeSessionExtensionsLoaded: - var d SessionExtensionsLoadedData + case SessionEventTypeUserMessage: + var d UserMessageData if err := json.Unmarshal(raw.Data, &d); err != nil { return err } @@ -564,21 +565,21 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error { func (e SessionEvent) MarshalJSON() ([]byte, error) { type rawEvent struct { AgentID *string `json:"agentId,omitempty"` + Data any `json:"data"` Ephemeral *bool `json:"ephemeral,omitempty"` ID string `json:"id"` ParentID *string `json:"parentId"` Timestamp time.Time `json:"timestamp"` Type SessionEventType `json:"type"` - Data any `json:"data"` } return json.Marshal(rawEvent{ AgentID: e.AgentID, + Data: e.Data, Ephemeral: e.Ephemeral, ID: e.ID, ParentID: e.ParentID, Timestamp: e.Timestamp, Type: e.Type, - Data: e.Data, }) } @@ -586,86 +587,86 @@ func (e SessionEvent) MarshalJSON() ([]byte, error) { type SessionEventType string const ( - SessionEventTypeSessionStart SessionEventType = "session.start" - SessionEventTypeSessionResume SessionEventType = "session.resume" - SessionEventTypeSessionRemoteSteerableChanged SessionEventType = "session.remote_steerable_changed" - SessionEventTypeSessionError SessionEventType = "session.error" - SessionEventTypeSessionIdle SessionEventType = "session.idle" - SessionEventTypeSessionTitleChanged SessionEventType = "session.title_changed" - SessionEventTypeSessionScheduleCreated SessionEventType = "session.schedule_created" - SessionEventTypeSessionScheduleCancelled SessionEventType = "session.schedule_cancelled" - SessionEventTypeSessionInfo SessionEventType = "session.info" - SessionEventTypeSessionWarning SessionEventType = "session.warning" - SessionEventTypeSessionModelChange SessionEventType = "session.model_change" - SessionEventTypeSessionModeChanged SessionEventType = "session.mode_changed" - SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed" - SessionEventTypeSessionWorkspaceFileChanged SessionEventType = "session.workspace_file_changed" - SessionEventTypeSessionHandoff SessionEventType = "session.handoff" - SessionEventTypeSessionTruncation SessionEventType = "session.truncation" - SessionEventTypeSessionSnapshotRewind SessionEventType = "session.snapshot_rewind" - SessionEventTypeSessionShutdown SessionEventType = "session.shutdown" - SessionEventTypeSessionContextChanged SessionEventType = "session.context_changed" - SessionEventTypeSessionUsageInfo SessionEventType = "session.usage_info" - SessionEventTypeSessionCompactionStart SessionEventType = "session.compaction_start" - SessionEventTypeSessionCompactionComplete SessionEventType = "session.compaction_complete" - SessionEventTypeSessionTaskComplete SessionEventType = "session.task_complete" - SessionEventTypeUserMessage SessionEventType = "user.message" - SessionEventTypePendingMessagesModified SessionEventType = "pending_messages.modified" - SessionEventTypeAssistantTurnStart SessionEventType = "assistant.turn_start" + SessionEventTypeAbort SessionEventType = "abort" SessionEventTypeAssistantIntent SessionEventType = "assistant.intent" + SessionEventTypeAssistantMessage SessionEventType = "assistant.message" + SessionEventTypeAssistantMessageDelta SessionEventType = "assistant.message_delta" + SessionEventTypeAssistantMessageStart SessionEventType = "assistant.message_start" SessionEventTypeAssistantReasoning SessionEventType = "assistant.reasoning" SessionEventTypeAssistantReasoningDelta SessionEventType = "assistant.reasoning_delta" SessionEventTypeAssistantStreamingDelta SessionEventType = "assistant.streaming_delta" - SessionEventTypeAssistantMessage SessionEventType = "assistant.message" - SessionEventTypeAssistantMessageStart SessionEventType = "assistant.message_start" - SessionEventTypeAssistantMessageDelta SessionEventType = "assistant.message_delta" SessionEventTypeAssistantTurnEnd SessionEventType = "assistant.turn_end" + SessionEventTypeAssistantTurnStart SessionEventType = "assistant.turn_start" SessionEventTypeAssistantUsage SessionEventType = "assistant.usage" + SessionEventTypeAutoModeSwitchCompleted SessionEventType = "auto_mode_switch.completed" + SessionEventTypeAutoModeSwitchRequested SessionEventType = "auto_mode_switch.requested" + SessionEventTypeCapabilitiesChanged SessionEventType = "capabilities.changed" + SessionEventTypeCommandCompleted SessionEventType = "command.completed" + SessionEventTypeCommandExecute SessionEventType = "command.execute" + SessionEventTypeCommandQueued SessionEventType = "command.queued" + SessionEventTypeCommandsChanged SessionEventType = "commands.changed" + SessionEventTypeElicitationCompleted SessionEventType = "elicitation.completed" + SessionEventTypeElicitationRequested SessionEventType = "elicitation.requested" + SessionEventTypeExitPlanModeCompleted SessionEventType = "exit_plan_mode.completed" + SessionEventTypeExitPlanModeRequested SessionEventType = "exit_plan_mode.requested" + SessionEventTypeExternalToolCompleted SessionEventType = "external_tool.completed" + SessionEventTypeExternalToolRequested SessionEventType = "external_tool.requested" + SessionEventTypeHookEnd SessionEventType = "hook.end" + SessionEventTypeHookStart SessionEventType = "hook.start" + SessionEventTypeMcpOauthCompleted SessionEventType = "mcp.oauth_completed" + SessionEventTypeMcpOauthRequired SessionEventType = "mcp.oauth_required" SessionEventTypeModelCallFailure SessionEventType = "model.call_failure" - SessionEventTypeAbort SessionEventType = "abort" - SessionEventTypeToolUserRequested SessionEventType = "tool.user_requested" - SessionEventTypeToolExecutionStart SessionEventType = "tool.execution_start" - SessionEventTypeToolExecutionPartialResult SessionEventType = "tool.execution_partial_result" - SessionEventTypeToolExecutionProgress SessionEventType = "tool.execution_progress" - SessionEventTypeToolExecutionComplete SessionEventType = "tool.execution_complete" + SessionEventTypePendingMessagesModified SessionEventType = "pending_messages.modified" + SessionEventTypePermissionCompleted SessionEventType = "permission.completed" + SessionEventTypePermissionRequested SessionEventType = "permission.requested" + SessionEventTypeSamplingCompleted SessionEventType = "sampling.completed" + SessionEventTypeSamplingRequested SessionEventType = "sampling.requested" + SessionEventTypeSessionBackgroundTasksChanged SessionEventType = "session.background_tasks_changed" + SessionEventTypeSessionCompactionComplete SessionEventType = "session.compaction_complete" + SessionEventTypeSessionCompactionStart SessionEventType = "session.compaction_start" + SessionEventTypeSessionContextChanged SessionEventType = "session.context_changed" + SessionEventTypeSessionCustomAgentsUpdated SessionEventType = "session.custom_agents_updated" + SessionEventTypeSessionError SessionEventType = "session.error" + SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded" + SessionEventTypeSessionHandoff SessionEventType = "session.handoff" + SessionEventTypeSessionIdle SessionEventType = "session.idle" + SessionEventTypeSessionInfo SessionEventType = "session.info" + SessionEventTypeSessionMcpServersLoaded SessionEventType = "session.mcp_servers_loaded" + SessionEventTypeSessionMcpServerStatusChanged SessionEventType = "session.mcp_server_status_changed" + SessionEventTypeSessionModeChanged SessionEventType = "session.mode_changed" + SessionEventTypeSessionModelChange SessionEventType = "session.model_change" + SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed" + SessionEventTypeSessionRemoteSteerableChanged SessionEventType = "session.remote_steerable_changed" + SessionEventTypeSessionResume SessionEventType = "session.resume" + SessionEventTypeSessionScheduleCancelled SessionEventType = "session.schedule_cancelled" + SessionEventTypeSessionScheduleCreated SessionEventType = "session.schedule_created" + SessionEventTypeSessionShutdown SessionEventType = "session.shutdown" + SessionEventTypeSessionSkillsLoaded SessionEventType = "session.skills_loaded" + SessionEventTypeSessionSnapshotRewind SessionEventType = "session.snapshot_rewind" + SessionEventTypeSessionStart SessionEventType = "session.start" + SessionEventTypeSessionTaskComplete SessionEventType = "session.task_complete" + SessionEventTypeSessionTitleChanged SessionEventType = "session.title_changed" + SessionEventTypeSessionToolsUpdated SessionEventType = "session.tools_updated" + SessionEventTypeSessionTruncation SessionEventType = "session.truncation" + SessionEventTypeSessionUsageInfo SessionEventType = "session.usage_info" + SessionEventTypeSessionWarning SessionEventType = "session.warning" + SessionEventTypeSessionWorkspaceFileChanged SessionEventType = "session.workspace_file_changed" SessionEventTypeSkillInvoked SessionEventType = "skill.invoked" - SessionEventTypeSubagentStarted SessionEventType = "subagent.started" SessionEventTypeSubagentCompleted SessionEventType = "subagent.completed" + SessionEventTypeSubagentDeselected SessionEventType = "subagent.deselected" SessionEventTypeSubagentFailed SessionEventType = "subagent.failed" SessionEventTypeSubagentSelected SessionEventType = "subagent.selected" - SessionEventTypeSubagentDeselected SessionEventType = "subagent.deselected" - SessionEventTypeHookStart SessionEventType = "hook.start" - SessionEventTypeHookEnd SessionEventType = "hook.end" + SessionEventTypeSubagentStarted SessionEventType = "subagent.started" SessionEventTypeSystemMessage SessionEventType = "system.message" SessionEventTypeSystemNotification SessionEventType = "system.notification" - SessionEventTypePermissionRequested SessionEventType = "permission.requested" - SessionEventTypePermissionCompleted SessionEventType = "permission.completed" - SessionEventTypeUserInputRequested SessionEventType = "user_input.requested" + SessionEventTypeToolExecutionComplete SessionEventType = "tool.execution_complete" + SessionEventTypeToolExecutionPartialResult SessionEventType = "tool.execution_partial_result" + SessionEventTypeToolExecutionProgress SessionEventType = "tool.execution_progress" + SessionEventTypeToolExecutionStart SessionEventType = "tool.execution_start" + SessionEventTypeToolUserRequested SessionEventType = "tool.user_requested" SessionEventTypeUserInputCompleted SessionEventType = "user_input.completed" - SessionEventTypeElicitationRequested SessionEventType = "elicitation.requested" - SessionEventTypeElicitationCompleted SessionEventType = "elicitation.completed" - SessionEventTypeSamplingRequested SessionEventType = "sampling.requested" - SessionEventTypeSamplingCompleted SessionEventType = "sampling.completed" - SessionEventTypeMcpOauthRequired SessionEventType = "mcp.oauth_required" - SessionEventTypeMcpOauthCompleted SessionEventType = "mcp.oauth_completed" - SessionEventTypeExternalToolRequested SessionEventType = "external_tool.requested" - SessionEventTypeExternalToolCompleted SessionEventType = "external_tool.completed" - SessionEventTypeCommandQueued SessionEventType = "command.queued" - SessionEventTypeCommandExecute SessionEventType = "command.execute" - SessionEventTypeCommandCompleted SessionEventType = "command.completed" - SessionEventTypeAutoModeSwitchRequested SessionEventType = "auto_mode_switch.requested" - SessionEventTypeAutoModeSwitchCompleted SessionEventType = "auto_mode_switch.completed" - SessionEventTypeCommandsChanged SessionEventType = "commands.changed" - SessionEventTypeCapabilitiesChanged SessionEventType = "capabilities.changed" - SessionEventTypeExitPlanModeRequested SessionEventType = "exit_plan_mode.requested" - SessionEventTypeExitPlanModeCompleted SessionEventType = "exit_plan_mode.completed" - SessionEventTypeSessionToolsUpdated SessionEventType = "session.tools_updated" - SessionEventTypeSessionBackgroundTasksChanged SessionEventType = "session.background_tasks_changed" - SessionEventTypeSessionSkillsLoaded SessionEventType = "session.skills_loaded" - SessionEventTypeSessionCustomAgentsUpdated SessionEventType = "session.custom_agents_updated" - SessionEventTypeSessionMcpServersLoaded SessionEventType = "session.mcp_servers_loaded" - SessionEventTypeSessionMcpServerStatusChanged SessionEventType = "session.mcp_server_status_changed" - SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded" + SessionEventTypeUserInputRequested SessionEventType = "user_input.requested" + SessionEventTypeUserMessage SessionEventType = "user.message" ) // Agent intent description for current activity or plan @@ -856,7 +857,7 @@ type ElicitationCompletedData struct { // The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) Action *ElicitationCompletedAction `json:"action,omitempty"` // The submitted form data when action is 'accept'; keys match the requested schema fields - Content map[string]any `json:"content,omitempty"` + Content map[string]*ElicitationCompletedContent `json:"content,omitempty"` // Request ID of the resolved elicitation request; clients should dismiss any UI for this request RequestID string `json:"requestId"` } @@ -1796,36 +1797,6 @@ type SessionWorkspaceFileChangedData struct { func (*SessionWorkspaceFileChangedData) sessionEventData() {} -// A content block within a tool result, which may be text, terminal output, image, audio, or a resource -type ToolExecutionCompleteContent struct { - // Type discriminator - Type ToolExecutionCompleteContentType `json:"type"` - // Working directory where the command was executed - Cwd *string `json:"cwd,omitempty"` - // Base64-encoded image data - Data *string `json:"data,omitempty"` - // Human-readable description of the resource - Description *string `json:"description,omitempty"` - // Process exit code, if the command has completed - ExitCode *float64 `json:"exitCode,omitempty"` - // Icons associated with this resource - Icons []ToolExecutionCompleteContentResourceLinkIcon `json:"icons,omitempty"` - // MIME type of the image (e.g., image/png, image/jpeg) - MIMEType *string `json:"mimeType,omitempty"` - // Resource name identifier - Name *string `json:"name,omitempty"` - // The embedded resource contents, either text or base64-encoded binary - Resource any `json:"resource,omitempty"` - // Size of the resource in bytes - Size *float64 `json:"size,omitempty"` - // The text content - Text *string `json:"text,omitempty"` - // Human-readable display title for the resource - Title *string `json:"title,omitempty"` - // URI identifying the resource - URI *string `json:"uri,omitempty"` -} - // A tool invocation request from the assistant type AssistantMessageToolRequest struct { // Arguments to pass to the tool, format depends on the tool @@ -1846,52 +1817,234 @@ type AssistantMessageToolRequest struct { Type *AssistantMessageToolRequestType `json:"type,omitempty"` } -// A user message attachment — a file, directory, code selection, blob, or GitHub reference -type UserMessageAttachment struct { - // Type discriminator - Type UserMessageAttachmentType `json:"type"` - // Base64-encoded content - Data *string `json:"data,omitempty"` - // User-facing display name for the attachment - DisplayName *string `json:"displayName,omitempty"` - // Absolute path to the file containing the selection - FilePath *string `json:"filePath,omitempty"` - // Optional line range to scope the attachment to a specific section of the file - LineRange *UserMessageAttachmentFileLineRange `json:"lineRange,omitempty"` - // MIME type of the inline data - MIMEType *string `json:"mimeType,omitempty"` - // Issue, pull request, or discussion number - Number *float64 `json:"number,omitempty"` - // Absolute file path - Path *string `json:"path,omitempty"` - // Type of GitHub reference - ReferenceType *UserMessageAttachmentGithubReferenceType `json:"referenceType,omitempty"` - // Position range of the selection within the file - Selection *UserMessageAttachmentSelectionDetails `json:"selection,omitempty"` - // Current state of the referenced item (e.g., open, closed, merged) - State *string `json:"state,omitempty"` - // The selected text content - Text *string `json:"text,omitempty"` - // Title of the referenced item - Title *string `json:"title,omitempty"` - // URL to the referenced item on GitHub - URL *string `json:"url,omitempty"` +// Per-request cost and usage data from the CAPI copilot_usage response field +type AssistantUsageCopilotUsage struct { + // Itemized token usage breakdown + TokenDetails []AssistantUsageCopilotUsageTokenDetail `json:"tokenDetails"` + // Total cost in nano-AI units for this request + TotalNanoAiu float64 `json:"totalNanoAiu"` } -// Aggregate code change metrics for the session -type ShutdownCodeChanges struct { - // List of file paths that were modified during the session - FilesModified []string `json:"filesModified"` - // Total number of lines added during the session - LinesAdded float64 `json:"linesAdded"` - // Total number of lines removed during the session - LinesRemoved float64 `json:"linesRemoved"` +// Token usage detail for a single billing category +type AssistantUsageCopilotUsageTokenDetail struct { + // Number of tokens in this billing batch + BatchSize float64 `json:"batchSize"` + // Cost per batch of tokens + CostPerBatch float64 `json:"costPerBatch"` + // Total token count for this entry + TokenCount float64 `json:"tokenCount"` + // Token category (e.g., "input", "output") + TokenType string `json:"tokenType"` +} + +type AssistantUsageQuotaSnapshot struct { + // Total requests allowed by the entitlement + EntitlementRequests float64 `json:"entitlementRequests"` + // Whether the user has an unlimited usage entitlement + IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` + // Number of requests over the entitlement limit + Overage float64 `json:"overage"` + // Whether overage is allowed when quota is exhausted + OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` + // Percentage of quota remaining (0.0 to 1.0) + RemainingPercentage float64 `json:"remainingPercentage"` + // Date when the quota resets + ResetDate *time.Time `json:"resetDate,omitempty"` + // Whether usage is still permitted after quota exhaustion + UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` + // Number of requests already consumed + UsedRequests float64 `json:"usedRequests"` +} + +// UI capability changes +type CapabilitiesChangedUI struct { + // Whether elicitation is now supported + Elicitation *bool `json:"elicitation,omitempty"` +} + +type CommandsChangedCommand struct { + Description *string `json:"description,omitempty"` + Name string `json:"name"` +} + +// Token usage breakdown for the compaction LLM call (aligned with assistant.usage format) +type CompactionCompleteCompactionTokensUsed struct { + // Cached input tokens reused in the compaction LLM call + CacheReadTokens *float64 `json:"cacheReadTokens,omitempty"` + // Tokens written to prompt cache in the compaction LLM call + CacheWriteTokens *float64 `json:"cacheWriteTokens,omitempty"` + // Per-request cost and usage data from the CAPI copilot_usage response field + CopilotUsage *CompactionCompleteCompactionTokensUsedCopilotUsage `json:"copilotUsage,omitempty"` + // Duration of the compaction LLM call in milliseconds + Duration *float64 `json:"duration,omitempty"` + // Input tokens consumed by the compaction LLM call + InputTokens *float64 `json:"inputTokens,omitempty"` + // Model identifier used for the compaction LLM call + Model *string `json:"model,omitempty"` + // Output tokens produced by the compaction LLM call + OutputTokens *float64 `json:"outputTokens,omitempty"` +} + +// Per-request cost and usage data from the CAPI copilot_usage response field +type CompactionCompleteCompactionTokensUsedCopilotUsage struct { + // Itemized token usage breakdown + TokenDetails []CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail `json:"tokenDetails"` + // Total cost in nano-AI units for this request + TotalNanoAiu float64 `json:"totalNanoAiu"` +} + +// Token usage detail for a single billing category +type CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail struct { + // Number of tokens in this billing batch + BatchSize float64 `json:"batchSize"` + // Cost per batch of tokens + CostPerBatch float64 `json:"costPerBatch"` + // Total token count for this entry + TokenCount float64 `json:"tokenCount"` + // Token category (e.g., "input", "output") + TokenType string `json:"tokenType"` +} + +type CustomAgentsUpdatedAgent struct { + // Description of what the agent does + Description string `json:"description"` + // Human-readable display name + DisplayName string `json:"displayName"` + // Unique identifier for the agent + ID string `json:"id"` + // Model override for this agent, if set + Model *string `json:"model,omitempty"` + // Internal name of the agent + Name string `json:"name"` + // Source location: user, project, inherited, remote, or plugin + Source string `json:"source"` + // List of tool names available to this agent, or null when all tools are available + Tools []string `json:"tools"` + // Whether the agent can be selected by the user + UserInvocable bool `json:"userInvocable"` +} + +type ElicitationCompletedContent struct { + Bool *bool + Double *float64 + String *string + StringArray []string +} + +func (r ElicitationCompletedContent) MarshalJSON() ([]byte, error) { + if r.Bool != nil { + return json.Marshal(r.Bool) + } + if r.Double != nil { + return json.Marshal(r.Double) + } + if r.String != nil { + return json.Marshal(r.String) + } + if r.StringArray != nil { + return json.Marshal(r.StringArray) + } + return []byte("null"), nil +} + +func (r *ElicitationCompletedContent) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + *r = ElicitationCompletedContent{} + return nil + } + { + var value bool + if err := json.Unmarshal(data, &value); err == nil { + *r = ElicitationCompletedContent{Bool: &value} + return nil + } + } + { + var value float64 + if err := json.Unmarshal(data, &value); err == nil { + *r = ElicitationCompletedContent{Double: &value} + return nil + } + } + { + var value string + if err := json.Unmarshal(data, &value); err == nil { + *r = ElicitationCompletedContent{String: &value} + return nil + } + } + { + var value []string + if err := json.Unmarshal(data, &value); err == nil { + *r = ElicitationCompletedContent{StringArray: value} + return nil + } + } + return errors.New("data did not match any union variant for ElicitationCompletedContent") +} + +// JSON Schema describing the form fields to present to the user (form mode only) +type ElicitationRequestedSchema struct { + // Form field definitions, keyed by field name + Properties map[string]any `json:"properties"` + // List of required field names + Required []string `json:"required,omitempty"` + // Schema type indicator (always 'object') + Type ElicitationRequestedSchemaType `json:"type"` +} + +type ExtensionsLoadedExtension struct { + // Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') + ID string `json:"id"` + // Extension name (directory name) + Name string `json:"name"` + // Discovery source + Source ExtensionsLoadedExtensionSource `json:"source"` + // Current status: running, disabled, failed, or starting + Status ExtensionsLoadedExtensionStatus `json:"status"` +} + +// Repository context for the handed-off session +type HandoffRepository struct { + // Git branch name, if applicable + Branch *string `json:"branch,omitempty"` + // Repository name + Name string `json:"name"` + // Repository owner (user or organization) + Owner string `json:"owner"` +} + +// Error details when the hook failed +type HookEndError struct { + // Human-readable error message + Message string `json:"message"` + // Error stack trace, when available + Stack *string `json:"stack,omitempty"` +} + +// Static OAuth client configuration, if the server specifies one +type McpOauthRequiredStaticClientConfig struct { + // OAuth client ID for the server + ClientID string `json:"clientId"` + // Optional non-default OAuth grant type. When set to 'client_credentials', the OAuth flow runs headlessly using the client_id + keychain-stored secret (no browser, no callback server). + GrantType *McpOauthRequiredStaticClientConfigGrantType `json:"grantType,omitempty"` + // Whether this is a public OAuth client + PublicClient *bool `json:"publicClient,omitempty"` +} + +type McpServersLoadedServer struct { + // Error message if the server failed to connect + Error *string `json:"error,omitempty"` + // Server name (config key) + Name string `json:"name"` + // Configuration source: user, workspace, plugin, or builtin + Source *string `json:"source,omitempty"` + // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured + Status McpServersLoadedServerStatus `json:"status"` } // Derived user-facing permission prompt details for UI consumers type PermissionPromptRequest struct { - // Kind discriminator - Kind PermissionPromptRequestKind `json:"kind"` // Underlying permission kind that needs path approval AccessKind *PermissionPromptRequestPathAccessKind `json:"accessKind,omitempty"` // Whether this is a store or vote memory operation @@ -1922,6 +2075,8 @@ type PermissionPromptRequest struct { HookMessage *string `json:"hookMessage,omitempty"` // Human-readable description of what the command intends to do Intention *string `json:"intention,omitempty"` + // Kind discriminator + Kind PermissionPromptRequestKind `json:"kind"` // Complete new file contents for newly created files NewFileContents *string `json:"newFileContents,omitempty"` // The extension management operation (scaffold, reload) @@ -1954,8 +2109,6 @@ type PermissionPromptRequest struct { // Details of the permission being requested type PermissionRequest struct { - // Kind discriminator - Kind PermissionRequestKind `json:"kind"` // Whether this is a store or vote memory operation Action *PermissionRequestMemoryAction `json:"action,omitempty"` // Arguments to pass to the MCP tool @@ -1986,6 +2139,8 @@ type PermissionRequest struct { HookMessage *string `json:"hookMessage,omitempty"` // Human-readable description of what the command intends to do Intention *string `json:"intention,omitempty"` + // Kind discriminator + Kind PermissionRequestKind `json:"kind"` // Complete new file contents for newly created files NewFileContents *string `json:"newFileContents,omitempty"` // The extension management operation (scaffold, reload) @@ -2020,132 +2175,127 @@ type PermissionRequest struct { Warning *string `json:"warning,omitempty"` } -// End position of the selection -type UserMessageAttachmentSelectionDetailsEnd struct { - // End character offset within the line (0-based) - Character float64 `json:"character"` - // End line number (0-based) - Line float64 `json:"line"` +type PermissionRequestShellCommand struct { + // Command identifier (e.g., executable name) + Identifier string `json:"identifier"` + // Whether this command is read-only (no side effects) + ReadOnly bool `json:"readOnly"` } -// Error details when the hook failed -type HookEndError struct { - // Human-readable error message - Message string `json:"message"` - // Error stack trace, when available - Stack *string `json:"stack,omitempty"` +type PermissionRequestShellPossibleURL struct { + // URL that may be accessed by the command + URL string `json:"url"` } -// Error details when the tool execution failed -type ToolExecutionCompleteError struct { - // Machine-readable error code - Code *string `json:"code,omitempty"` - // Human-readable error message - Message string `json:"message"` +// The result of the permission request +type PermissionResult struct { + // The approval to add as a session-scoped rule + Approval *UserToolSessionApproval `json:"approval,omitempty"` + // Optional feedback from the user explaining the denial + Feedback *string `json:"feedback,omitempty"` + // Whether to force-reject the current agent turn + ForceReject *bool `json:"forceReject,omitempty"` + // Whether to interrupt the current agent turn + Interrupt *bool `json:"interrupt,omitempty"` + // Kind discriminator + Kind PermissionResultKind `json:"kind"` + // The location key (git root or cwd) to persist the approval to + LocationKey *string `json:"locationKey,omitempty"` + // Human-readable explanation of why the path was excluded + Message *string `json:"message,omitempty"` + // File path that triggered the exclusion + Path *string `json:"path,omitempty"` + // Optional explanation of why the request was cancelled + Reason *string `json:"reason,omitempty"` + // Rules that denied the request + Rules []PermissionRule `json:"rules,omitempty"` } -// Icon image for a resource -type ToolExecutionCompleteContentResourceLinkIcon struct { - // MIME type of the icon image - MIMEType *string `json:"mimeType,omitempty"` - // Available icon sizes (e.g., ['16x16', '32x32']) - Sizes []string `json:"sizes,omitempty"` - // URL or path to the icon image - Src string `json:"src"` - // Theme variant this icon is intended for - Theme *ToolExecutionCompleteContentResourceLinkIconTheme `json:"theme,omitempty"` +type PermissionRule struct { + // Optional rule argument matched against the request + Argument *string `json:"argument"` + // The rule kind, such as Shell or GitHubMCP + Kind string `json:"kind"` } -// JSON Schema describing the form fields to present to the user (form mode only) -type ElicitationRequestedSchema struct { - // Form field definitions, keyed by field name - Properties map[string]any `json:"properties"` - // List of required field names - Required []string `json:"required,omitempty"` - // Schema type indicator (always 'object') - Type string `json:"type"` +// Aggregate code change metrics for the session +type ShutdownCodeChanges struct { + // List of file paths that were modified during the session + FilesModified []string `json:"filesModified"` + // Total number of lines added during the session + LinesAdded float64 `json:"linesAdded"` + // Total number of lines removed during the session + LinesRemoved float64 `json:"linesRemoved"` } -// Metadata about the prompt template and its construction -type SystemMessageMetadata struct { - // Version identifier of the prompt template used - PromptVersion *string `json:"promptVersion,omitempty"` - // Template variables used when constructing the prompt - Variables map[string]any `json:"variables,omitempty"` +type ShutdownModelMetric struct { + // Request count and cost metrics + Requests ShutdownModelMetricRequests `json:"requests"` + // Token count details per type + TokenDetails map[string]ShutdownModelMetricTokenDetail `json:"tokenDetails,omitempty"` + // Accumulated nano-AI units cost for this model + TotalNanoAiu *float64 `json:"totalNanoAiu,omitempty"` + // Token usage breakdown + Usage ShutdownModelMetricUsage `json:"usage"` } -// Optional line range to scope the attachment to a specific section of the file -type UserMessageAttachmentFileLineRange struct { - // End line number (1-based, inclusive) - End float64 `json:"end"` - // Start line number (1-based) - Start float64 `json:"start"` +// Request count and cost metrics +type ShutdownModelMetricRequests struct { + // Cumulative cost multiplier for requests to this model + Cost float64 `json:"cost"` + // Total number of API requests made to this model + Count float64 `json:"count"` } -// Per-request cost and usage data from the CAPI copilot_usage response field -type AssistantUsageCopilotUsage struct { - // Itemized token usage breakdown - TokenDetails []AssistantUsageCopilotUsageTokenDetail `json:"tokenDetails"` - // Total cost in nano-AI units for this request - TotalNanoAiu float64 `json:"totalNanoAiu"` +type ShutdownModelMetricTokenDetail struct { + // Accumulated token count for this token type + TokenCount float64 `json:"tokenCount"` } -// Per-request cost and usage data from the CAPI copilot_usage response field -type CompactionCompleteCompactionTokensUsedCopilotUsage struct { - // Itemized token usage breakdown - TokenDetails []CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail `json:"tokenDetails"` - // Total cost in nano-AI units for this request - TotalNanoAiu float64 `json:"totalNanoAiu"` +// Token usage breakdown +type ShutdownModelMetricUsage struct { + // Total tokens read from prompt cache across all requests + CacheReadTokens float64 `json:"cacheReadTokens"` + // Total tokens written to prompt cache across all requests + CacheWriteTokens float64 `json:"cacheWriteTokens"` + // Total input tokens consumed across all requests to this model + InputTokens float64 `json:"inputTokens"` + // Total output tokens produced across all requests to this model + OutputTokens float64 `json:"outputTokens"` + // Total reasoning tokens produced across all requests to this model + ReasoningTokens *float64 `json:"reasoningTokens,omitempty"` } -// Position range of the selection within the file -type UserMessageAttachmentSelectionDetails struct { - // End position of the selection - End UserMessageAttachmentSelectionDetailsEnd `json:"end"` - // Start position of the selection - Start UserMessageAttachmentSelectionDetailsStart `json:"start"` +type ShutdownTokenDetail struct { + // Accumulated token count for this token type + TokenCount float64 `json:"tokenCount"` } -// Repository context for the handed-off session -type HandoffRepository struct { - // Git branch name, if applicable - Branch *string `json:"branch,omitempty"` - // Repository name +type SkillsLoadedSkill struct { + // Description of what the skill does + Description string `json:"description"` + // Whether the skill is currently enabled + Enabled bool `json:"enabled"` + // Unique identifier for the skill Name string `json:"name"` - // Repository owner (user or organization) - Owner string `json:"owner"` -} - -// Request count and cost metrics -type ShutdownModelMetricRequests struct { - // Cumulative cost multiplier for requests to this model - Cost float64 `json:"cost"` - // Total number of API requests made to this model - Count float64 `json:"count"` -} - -// Start position of the selection -type UserMessageAttachmentSelectionDetailsStart struct { - // Start character offset within the line (0-based) - Character float64 `json:"character"` - // Start line number (0-based) - Line float64 `json:"line"` + // Absolute path to the skill file, if available + Path *string `json:"path,omitempty"` + // Source location type of the skill (e.g., project, personal, plugin) + Source string `json:"source"` + // Whether the skill can be invoked by the user as a slash command + UserInvocable bool `json:"userInvocable"` } -// Static OAuth client configuration, if the server specifies one -type McpOauthRequiredStaticClientConfig struct { - // OAuth client ID for the server - ClientID string `json:"clientId"` - // Optional non-default OAuth grant type. When set to 'client_credentials', the OAuth flow runs headlessly using the client_id + keychain-stored secret (no browser, no callback server). - GrantType *string `json:"grantType,omitempty"` - // Whether this is a public OAuth client - PublicClient *bool `json:"publicClient,omitempty"` +// Metadata about the prompt template and its construction +type SystemMessageMetadata struct { + // Version identifier of the prompt template used + PromptVersion *string `json:"promptVersion,omitempty"` + // Template variables used when constructing the prompt + Variables map[string]any `json:"variables,omitempty"` } // Structured metadata identifying what triggered this notification type SystemNotification struct { - // Type discriminator - Type SystemNotificationType `json:"type"` // Unique identifier of the background agent AgentID *string `json:"agentId,omitempty"` // Type of the agent (e.g., explore, task, general-purpose) @@ -2174,114 +2324,156 @@ type SystemNotification struct { TriggerFile *string `json:"triggerFile,omitempty"` // Tool command that triggered discovery (currently always 'view') TriggerTool *string `json:"triggerTool,omitempty"` + // Type discriminator + Type SystemNotificationType `json:"type"` } -// The approval to add as a session-scoped rule -type UserToolSessionApproval struct { - // Kind discriminator - Kind UserToolSessionApprovalKind `json:"kind"` - // Command identifiers approved by the user - CommandIdentifiers []string `json:"commandIdentifiers,omitempty"` - // MCP server name - ServerName *string `json:"serverName,omitempty"` - // Optional MCP tool name, or null for all tools on the server - ToolName *string `json:"toolName,omitempty"` +// A content block within a tool result, which may be text, terminal output, image, audio, or a resource +type ToolExecutionCompleteContent struct { + // Working directory where the command was executed + Cwd *string `json:"cwd,omitempty"` + // Base64-encoded image data + Data *string `json:"data,omitempty"` + // Human-readable description of the resource + Description *string `json:"description,omitempty"` + // Process exit code, if the command has completed + ExitCode *float64 `json:"exitCode,omitempty"` + // Icons associated with this resource + Icons []ToolExecutionCompleteContentResourceLinkIcon `json:"icons,omitempty"` + // MIME type of the image (e.g., image/png, image/jpeg) + MIMEType *string `json:"mimeType,omitempty"` + // Resource name identifier + Name *string `json:"name,omitempty"` + // The embedded resource contents, either text or base64-encoded binary + Resource *ToolExecutionCompleteContentResourceDetails `json:"resource,omitempty"` + // Size of the resource in bytes + Size *float64 `json:"size,omitempty"` + // The text content + Text *string `json:"text,omitempty"` + // Human-readable display title for the resource + Title *string `json:"title,omitempty"` + // Type discriminator + Type ToolExecutionCompleteContentType `json:"type"` + // URI identifying the resource + URI *string `json:"uri,omitempty"` } -// The result of the permission request -type PermissionResult struct { - // Kind discriminator - Kind PermissionResultKind `json:"kind"` - // The approval to add as a session-scoped rule - Approval *UserToolSessionApproval `json:"approval,omitempty"` - // Optional feedback from the user explaining the denial - Feedback *string `json:"feedback,omitempty"` - // Whether to force-reject the current agent turn - ForceReject *bool `json:"forceReject,omitempty"` - // Whether to interrupt the current agent turn - Interrupt *bool `json:"interrupt,omitempty"` - // The location key (git root or cwd) to persist the approval to - LocationKey *string `json:"locationKey,omitempty"` - // Human-readable explanation of why the path was excluded - Message *string `json:"message,omitempty"` - // File path that triggered the exclusion - Path *string `json:"path,omitempty"` - // Optional explanation of why the request was cancelled - Reason *string `json:"reason,omitempty"` - // Rules that denied the request - Rules []PermissionRule `json:"rules,omitempty"` +// The embedded resource contents, either text or base64-encoded binary +type ToolExecutionCompleteContentResourceDetails struct { + // Base64-encoded binary content of the resource + Blob *string `json:"blob,omitempty"` + // MIME type of the text content + MIMEType *string `json:"mimeType,omitempty"` + // Text content of the resource + Text *string `json:"text,omitempty"` + // URI identifying the resource + URI string `json:"uri"` } -// Token usage breakdown -type ShutdownModelMetricUsage struct { - // Total tokens read from prompt cache across all requests - CacheReadTokens float64 `json:"cacheReadTokens"` - // Total tokens written to prompt cache across all requests - CacheWriteTokens float64 `json:"cacheWriteTokens"` - // Total input tokens consumed across all requests to this model - InputTokens float64 `json:"inputTokens"` - // Total output tokens produced across all requests to this model - OutputTokens float64 `json:"outputTokens"` - // Total reasoning tokens produced across all requests to this model - ReasoningTokens *float64 `json:"reasoningTokens,omitempty"` +// Icon image for a resource +type ToolExecutionCompleteContentResourceLinkIcon struct { + // MIME type of the icon image + MIMEType *string `json:"mimeType,omitempty"` + // Available icon sizes (e.g., ['16x16', '32x32']) + Sizes []string `json:"sizes,omitempty"` + // URL or path to the icon image + Src string `json:"src"` + // Theme variant this icon is intended for + Theme *ToolExecutionCompleteContentResourceLinkIconTheme `json:"theme,omitempty"` } -// Token usage breakdown for the compaction LLM call (aligned with assistant.usage format) -type CompactionCompleteCompactionTokensUsed struct { - // Cached input tokens reused in the compaction LLM call - CacheReadTokens *float64 `json:"cacheReadTokens,omitempty"` - // Tokens written to prompt cache in the compaction LLM call - CacheWriteTokens *float64 `json:"cacheWriteTokens,omitempty"` - // Per-request cost and usage data from the CAPI copilot_usage response field - CopilotUsage *CompactionCompleteCompactionTokensUsedCopilotUsage `json:"copilotUsage,omitempty"` - // Duration of the compaction LLM call in milliseconds - Duration *float64 `json:"duration,omitempty"` - // Input tokens consumed by the compaction LLM call - InputTokens *float64 `json:"inputTokens,omitempty"` - // Model identifier used for the compaction LLM call - Model *string `json:"model,omitempty"` - // Output tokens produced by the compaction LLM call - OutputTokens *float64 `json:"outputTokens,omitempty"` +// Error details when the tool execution failed +type ToolExecutionCompleteError struct { + // Machine-readable error code + Code *string `json:"code,omitempty"` + // Human-readable error message + Message string `json:"message"` +} + +// Tool execution result on success +type ToolExecutionCompleteResult struct { + // Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency + Content string `json:"content"` + // Structured content blocks (text, images, audio, resources) returned by the tool in their native format + Contents []ToolExecutionCompleteContent `json:"contents,omitempty"` + // Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. + DetailedContent *string `json:"detailedContent,omitempty"` +} + +// A user message attachment — a file, directory, code selection, blob, or GitHub reference +type UserMessageAttachment struct { + // Base64-encoded content + Data *string `json:"data,omitempty"` + // User-facing display name for the attachment + DisplayName *string `json:"displayName,omitempty"` + // Absolute path to the file containing the selection + FilePath *string `json:"filePath,omitempty"` + // Optional line range to scope the attachment to a specific section of the file + LineRange *UserMessageAttachmentFileLineRange `json:"lineRange,omitempty"` + // MIME type of the inline data + MIMEType *string `json:"mimeType,omitempty"` + // Issue, pull request, or discussion number + Number *float64 `json:"number,omitempty"` + // Absolute file path + Path *string `json:"path,omitempty"` + // Type of GitHub reference + ReferenceType *UserMessageAttachmentGithubReferenceType `json:"referenceType,omitempty"` + // Position range of the selection within the file + Selection *UserMessageAttachmentSelectionDetails `json:"selection,omitempty"` + // Current state of the referenced item (e.g., open, closed, merged) + State *string `json:"state,omitempty"` + // The selected text content + Text *string `json:"text,omitempty"` + // Title of the referenced item + Title *string `json:"title,omitempty"` + // Type discriminator + Type UserMessageAttachmentType `json:"type"` + // URL to the referenced item on GitHub + URL *string `json:"url,omitempty"` +} + +// Optional line range to scope the attachment to a specific section of the file +type UserMessageAttachmentFileLineRange struct { + // End line number (1-based, inclusive) + End float64 `json:"end"` + // Start line number (1-based) + Start float64 `json:"start"` } -// Token usage detail for a single billing category -type AssistantUsageCopilotUsageTokenDetail struct { - // Number of tokens in this billing batch - BatchSize float64 `json:"batchSize"` - // Cost per batch of tokens - CostPerBatch float64 `json:"costPerBatch"` - // Total token count for this entry - TokenCount float64 `json:"tokenCount"` - // Token category (e.g., "input", "output") - TokenType string `json:"tokenType"` +// Position range of the selection within the file +type UserMessageAttachmentSelectionDetails struct { + // End position of the selection + End UserMessageAttachmentSelectionDetailsEnd `json:"end"` + // Start position of the selection + Start UserMessageAttachmentSelectionDetailsStart `json:"start"` } -// Token usage detail for a single billing category -type CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail struct { - // Number of tokens in this billing batch - BatchSize float64 `json:"batchSize"` - // Cost per batch of tokens - CostPerBatch float64 `json:"costPerBatch"` - // Total token count for this entry - TokenCount float64 `json:"tokenCount"` - // Token category (e.g., "input", "output") - TokenType string `json:"tokenType"` +// End position of the selection +type UserMessageAttachmentSelectionDetailsEnd struct { + // End character offset within the line (0-based) + Character float64 `json:"character"` + // End line number (0-based) + Line float64 `json:"line"` } -// Tool execution result on success -type ToolExecutionCompleteResult struct { - // Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency - Content string `json:"content"` - // Structured content blocks (text, images, audio, resources) returned by the tool in their native format - Contents []ToolExecutionCompleteContent `json:"contents,omitempty"` - // Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent. - DetailedContent *string `json:"detailedContent,omitempty"` +// Start position of the selection +type UserMessageAttachmentSelectionDetailsStart struct { + // Start character offset within the line (0-based) + Character float64 `json:"character"` + // Start line number (0-based) + Line float64 `json:"line"` } -// UI capability changes -type CapabilitiesChangedUI struct { - // Whether elicitation is now supported - Elicitation *bool `json:"elicitation,omitempty"` +// The approval to add as a session-scoped rule +type UserToolSessionApproval struct { + // Command identifiers approved by the user + CommandIdentifiers []string `json:"commandIdentifiers,omitempty"` + // Kind discriminator + Kind UserToolSessionApprovalKind `json:"kind"` + // MCP server name + ServerName *string `json:"serverName,omitempty"` + // Optional MCP tool name, or null for all tools on the server + ToolName *string `json:"toolName,omitempty"` } // Working directory and git context at session start @@ -2304,179 +2496,111 @@ type WorkingDirectoryContext struct { RepositoryHost *string `json:"repositoryHost,omitempty"` } -type AssistantUsageQuotaSnapshot struct { - // Total requests allowed by the entitlement - EntitlementRequests float64 `json:"entitlementRequests"` - // Whether the user has an unlimited usage entitlement - IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` - // Number of requests over the entitlement limit - Overage float64 `json:"overage"` - // Whether overage is allowed when quota is exhausted - OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` - // Percentage of quota remaining (0.0 to 1.0) - RemainingPercentage float64 `json:"remainingPercentage"` - // Date when the quota resets - ResetDate *time.Time `json:"resetDate,omitempty"` - // Whether usage is still permitted after quota exhaustion - UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` - // Number of requests already consumed - UsedRequests float64 `json:"usedRequests"` -} - -type CommandsChangedCommand struct { - Description *string `json:"description,omitempty"` - Name string `json:"name"` -} - -type CustomAgentsUpdatedAgent struct { - // Description of what the agent does - Description string `json:"description"` - // Human-readable display name - DisplayName string `json:"displayName"` - // Unique identifier for the agent - ID string `json:"id"` - // Model override for this agent, if set - Model *string `json:"model,omitempty"` - // Internal name of the agent - Name string `json:"name"` - // Source location: user, project, inherited, remote, or plugin - Source string `json:"source"` - // List of tool names available to this agent, or null when all tools are available - Tools []string `json:"tools"` - // Whether the agent can be selected by the user - UserInvocable bool `json:"userInvocable"` -} +// Finite reason code describing why the current turn was aborted +type AbortReason string -type ExtensionsLoadedExtension struct { - // Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper') - ID string `json:"id"` - // Extension name (directory name) - Name string `json:"name"` - // Discovery source - Source ExtensionsLoadedExtensionSource `json:"source"` - // Current status: running, disabled, failed, or starting - Status ExtensionsLoadedExtensionStatus `json:"status"` -} +const ( + AbortReasonRemoteCommand AbortReason = "remote_command" + AbortReasonUserAbort AbortReason = "user_abort" + AbortReasonUserInitiated AbortReason = "user_initiated" +) -type McpServersLoadedServer struct { - // Error message if the server failed to connect - Error *string `json:"error,omitempty"` - // Server name (config key) - Name string `json:"name"` - // Configuration source: user, workspace, plugin, or builtin - Source *string `json:"source,omitempty"` - // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - Status McpServersLoadedServerStatus `json:"status"` -} +// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. +type AssistantMessageToolRequestType string -type PermissionRequestShellCommand struct { - // Command identifier (e.g., executable name) - Identifier string `json:"identifier"` - // Whether this command is read-only (no side effects) - ReadOnly bool `json:"readOnly"` -} +const ( + AssistantMessageToolRequestTypeCustom AssistantMessageToolRequestType = "custom" + AssistantMessageToolRequestTypeFunction AssistantMessageToolRequestType = "function" +) -type PermissionRequestShellPossibleURL struct { - // URL that may be accessed by the command - URL string `json:"url"` -} +// The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) +type ElicitationCompletedAction string -type PermissionRule struct { - // Optional rule argument matched against the request - Argument *string `json:"argument"` - // The rule kind, such as Shell or GitHubMCP - Kind string `json:"kind"` -} +const ( + ElicitationCompletedActionAccept ElicitationCompletedAction = "accept" + ElicitationCompletedActionCancel ElicitationCompletedAction = "cancel" + ElicitationCompletedActionDecline ElicitationCompletedAction = "decline" +) -type ShutdownModelMetric struct { - // Request count and cost metrics - Requests ShutdownModelMetricRequests `json:"requests"` - // Token count details per type - TokenDetails map[string]ShutdownModelMetricTokenDetail `json:"tokenDetails,omitempty"` - // Accumulated nano-AI units cost for this model - TotalNanoAiu *float64 `json:"totalNanoAiu,omitempty"` - // Token usage breakdown - Usage ShutdownModelMetricUsage `json:"usage"` -} +// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. +type ElicitationRequestedMode string -type ShutdownModelMetricTokenDetail struct { - // Accumulated token count for this token type - TokenCount float64 `json:"tokenCount"` -} +const ( + ElicitationRequestedModeForm ElicitationRequestedMode = "form" + ElicitationRequestedModeURL ElicitationRequestedMode = "url" +) -type ShutdownTokenDetail struct { - // Accumulated token count for this token type - TokenCount float64 `json:"tokenCount"` -} +// Schema type indicator (always 'object') +type ElicitationRequestedSchemaType string -type SkillsLoadedSkill struct { - // Description of what the skill does - Description string `json:"description"` - // Whether the skill is currently enabled - Enabled bool `json:"enabled"` - // Unique identifier for the skill - Name string `json:"name"` - // Absolute path to the skill file, if available - Path *string `json:"path,omitempty"` - // Source location type of the skill (e.g., project, personal, plugin) - Source string `json:"source"` - // Whether the skill can be invoked by the user as a slash command - UserInvocable bool `json:"userInvocable"` -} +const ( + ElicitationRequestedSchemaTypeObject ElicitationRequestedSchemaType = "object" +) -// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured -type McpServersLoadedServerStatus string +// Discovery source +type ExtensionsLoadedExtensionSource string const ( - McpServersLoadedServerStatusConnected McpServersLoadedServerStatus = "connected" - McpServersLoadedServerStatusFailed McpServersLoadedServerStatus = "failed" - McpServersLoadedServerStatusNeedsAuth McpServersLoadedServerStatus = "needs-auth" - McpServersLoadedServerStatusPending McpServersLoadedServerStatus = "pending" - McpServersLoadedServerStatusDisabled McpServersLoadedServerStatus = "disabled" - McpServersLoadedServerStatusNotConfigured McpServersLoadedServerStatus = "not_configured" + ExtensionsLoadedExtensionSourceProject ExtensionsLoadedExtensionSource = "project" + ExtensionsLoadedExtensionSourceUser ExtensionsLoadedExtensionSource = "user" ) // Current status: running, disabled, failed, or starting type ExtensionsLoadedExtensionStatus string const ( - ExtensionsLoadedExtensionStatusRunning ExtensionsLoadedExtensionStatus = "running" ExtensionsLoadedExtensionStatusDisabled ExtensionsLoadedExtensionStatus = "disabled" ExtensionsLoadedExtensionStatusFailed ExtensionsLoadedExtensionStatus = "failed" + ExtensionsLoadedExtensionStatusRunning ExtensionsLoadedExtensionStatus = "running" ExtensionsLoadedExtensionStatusStarting ExtensionsLoadedExtensionStatus = "starting" ) -// Discovery source -type ExtensionsLoadedExtensionSource string +// Origin type of the session being handed off +type HandoffSourceType string const ( - ExtensionsLoadedExtensionSourceProject ExtensionsLoadedExtensionSource = "project" - ExtensionsLoadedExtensionSourceUser ExtensionsLoadedExtensionSource = "user" + HandoffSourceTypeLocal HandoffSourceType = "local" + HandoffSourceTypeRemote HandoffSourceType = "remote" ) -// Elicitation mode; "form" for structured input, "url" for browser-based. Defaults to "form" when absent. -type ElicitationRequestedMode string +// Optional non-default OAuth grant type. When set to 'client_credentials', the OAuth flow runs headlessly using the client_id + keychain-stored secret (no browser, no callback server). +type McpOauthRequiredStaticClientConfigGrantType string const ( - ElicitationRequestedModeForm ElicitationRequestedMode = "form" - ElicitationRequestedModeURL ElicitationRequestedMode = "url" + McpOauthRequiredStaticClientConfigGrantTypeClientCredentials McpOauthRequiredStaticClientConfigGrantType = "client_credentials" ) -// Finite reason code describing why the current turn was aborted -type AbortReason string +// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured +type McpServersLoadedServerStatus string const ( - AbortReasonUserInitiated AbortReason = "user_initiated" - AbortReasonRemoteCommand AbortReason = "remote_command" - AbortReasonUserAbort AbortReason = "user_abort" + McpServersLoadedServerStatusConnected McpServersLoadedServerStatus = "connected" + McpServersLoadedServerStatusDisabled McpServersLoadedServerStatus = "disabled" + McpServersLoadedServerStatusFailed McpServersLoadedServerStatus = "failed" + McpServersLoadedServerStatusNeedsAuth McpServersLoadedServerStatus = "needs-auth" + McpServersLoadedServerStatusNotConfigured McpServersLoadedServerStatus = "not_configured" + McpServersLoadedServerStatusPending McpServersLoadedServerStatus = "pending" ) -// Hosting platform type of the repository (github or ado) -type WorkingDirectoryContextHostType string +// New connection status: connected, failed, needs-auth, pending, disabled, or not_configured +type McpServerStatusChangedStatus string const ( - WorkingDirectoryContextHostTypeGithub WorkingDirectoryContextHostType = "github" - WorkingDirectoryContextHostTypeAdo WorkingDirectoryContextHostType = "ado" + McpServerStatusChangedStatusConnected McpServerStatusChangedStatus = "connected" + McpServerStatusChangedStatusDisabled McpServerStatusChangedStatus = "disabled" + McpServerStatusChangedStatusFailed McpServerStatusChangedStatus = "failed" + McpServerStatusChangedStatusNeedsAuth McpServerStatusChangedStatus = "needs-auth" + McpServerStatusChangedStatusNotConfigured McpServerStatusChangedStatus = "not_configured" + McpServerStatusChangedStatusPending McpServerStatusChangedStatus = "pending" +) + +// Where the failed model call originated +type ModelCallFailureSource string + +const ( + ModelCallFailureSourceMcpSampling ModelCallFailureSource = "mcp_sampling" + ModelCallFailureSourceSubagent ModelCallFailureSource = "subagent" + ModelCallFailureSourceTopLevel ModelCallFailureSource = "top_level" ) // Kind discriminator for PermissionPromptRequest. @@ -2484,97 +2608,88 @@ type PermissionPromptRequestKind string const ( PermissionPromptRequestKindCommands PermissionPromptRequestKind = "commands" - PermissionPromptRequestKindWrite PermissionPromptRequestKind = "write" - PermissionPromptRequestKindRead PermissionPromptRequestKind = "read" - PermissionPromptRequestKindMcp PermissionPromptRequestKind = "mcp" - PermissionPromptRequestKindURL PermissionPromptRequestKind = "url" - PermissionPromptRequestKindMemory PermissionPromptRequestKind = "memory" PermissionPromptRequestKindCustomTool PermissionPromptRequestKind = "custom-tool" - PermissionPromptRequestKindPath PermissionPromptRequestKind = "path" - PermissionPromptRequestKindHook PermissionPromptRequestKind = "hook" PermissionPromptRequestKindExtensionManagement PermissionPromptRequestKind = "extension-management" PermissionPromptRequestKindExtensionPermissionAccess PermissionPromptRequestKind = "extension-permission-access" + PermissionPromptRequestKindHook PermissionPromptRequestKind = "hook" + PermissionPromptRequestKindMcp PermissionPromptRequestKind = "mcp" + PermissionPromptRequestKindMemory PermissionPromptRequestKind = "memory" + PermissionPromptRequestKindPath PermissionPromptRequestKind = "path" + PermissionPromptRequestKindRead PermissionPromptRequestKind = "read" + PermissionPromptRequestKindURL PermissionPromptRequestKind = "url" + PermissionPromptRequestKindWrite PermissionPromptRequestKind = "write" ) -// Kind discriminator for PermissionRequest. -type PermissionRequestKind string +// Whether this is a store or vote memory operation +type PermissionPromptRequestMemoryAction string const ( - PermissionRequestKindShell PermissionRequestKind = "shell" - PermissionRequestKindWrite PermissionRequestKind = "write" - PermissionRequestKindRead PermissionRequestKind = "read" - PermissionRequestKindMcp PermissionRequestKind = "mcp" - PermissionRequestKindURL PermissionRequestKind = "url" - PermissionRequestKindMemory PermissionRequestKind = "memory" - PermissionRequestKindCustomTool PermissionRequestKind = "custom-tool" - PermissionRequestKindHook PermissionRequestKind = "hook" - PermissionRequestKindExtensionManagement PermissionRequestKind = "extension-management" - PermissionRequestKindExtensionPermissionAccess PermissionRequestKind = "extension-permission-access" + PermissionPromptRequestMemoryActionStore PermissionPromptRequestMemoryAction = "store" + PermissionPromptRequestMemoryActionVote PermissionPromptRequestMemoryAction = "vote" ) -// Kind discriminator for PermissionResult. -type PermissionResultKind string +// Vote direction (vote only) +type PermissionPromptRequestMemoryDirection string const ( - PermissionResultKindApproved PermissionResultKind = "approved" - PermissionResultKindApprovedForSession PermissionResultKind = "approved-for-session" - PermissionResultKindApprovedForLocation PermissionResultKind = "approved-for-location" - PermissionResultKindCancelled PermissionResultKind = "cancelled" - PermissionResultKindDeniedByRules PermissionResultKind = "denied-by-rules" - PermissionResultKindDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionResultKind = "denied-no-approval-rule-and-could-not-request-from-user" - PermissionResultKindDeniedInteractivelyByUser PermissionResultKind = "denied-interactively-by-user" - PermissionResultKindDeniedByContentExclusionPolicy PermissionResultKind = "denied-by-content-exclusion-policy" - PermissionResultKindDeniedByPermissionRequestHook PermissionResultKind = "denied-by-permission-request-hook" + PermissionPromptRequestMemoryDirectionDownvote PermissionPromptRequestMemoryDirection = "downvote" + PermissionPromptRequestMemoryDirectionUpvote PermissionPromptRequestMemoryDirection = "upvote" ) -// Kind discriminator for UserToolSessionApproval. -type UserToolSessionApprovalKind string +// Underlying permission kind that needs path approval +type PermissionPromptRequestPathAccessKind string const ( - UserToolSessionApprovalKindCommands UserToolSessionApprovalKind = "commands" - UserToolSessionApprovalKindRead UserToolSessionApprovalKind = "read" - UserToolSessionApprovalKindWrite UserToolSessionApprovalKind = "write" - UserToolSessionApprovalKindMcp UserToolSessionApprovalKind = "mcp" - UserToolSessionApprovalKindMemory UserToolSessionApprovalKind = "memory" - UserToolSessionApprovalKindCustomTool UserToolSessionApprovalKind = "custom-tool" + PermissionPromptRequestPathAccessKindRead PermissionPromptRequestPathAccessKind = "read" + PermissionPromptRequestPathAccessKindShell PermissionPromptRequestPathAccessKind = "shell" + PermissionPromptRequestPathAccessKindWrite PermissionPromptRequestPathAccessKind = "write" ) -// Message role: "system" for system prompts, "developer" for developer-injected instructions -type SystemMessageRole string +// Kind discriminator for PermissionRequest. +type PermissionRequestKind string const ( - SystemMessageRoleSystem SystemMessageRole = "system" - SystemMessageRoleDeveloper SystemMessageRole = "developer" + PermissionRequestKindCustomTool PermissionRequestKind = "custom-tool" + PermissionRequestKindExtensionManagement PermissionRequestKind = "extension-management" + PermissionRequestKindExtensionPermissionAccess PermissionRequestKind = "extension-permission-access" + PermissionRequestKindHook PermissionRequestKind = "hook" + PermissionRequestKindMcp PermissionRequestKind = "mcp" + PermissionRequestKindMemory PermissionRequestKind = "memory" + PermissionRequestKindRead PermissionRequestKind = "read" + PermissionRequestKindShell PermissionRequestKind = "shell" + PermissionRequestKindURL PermissionRequestKind = "url" + PermissionRequestKindWrite PermissionRequestKind = "write" ) -// New connection status: connected, failed, needs-auth, pending, disabled, or not_configured -type McpServerStatusChangedStatus string +// Whether this is a store or vote memory operation +type PermissionRequestMemoryAction string const ( - McpServerStatusChangedStatusConnected McpServerStatusChangedStatus = "connected" - McpServerStatusChangedStatusFailed McpServerStatusChangedStatus = "failed" - McpServerStatusChangedStatusNeedsAuth McpServerStatusChangedStatus = "needs-auth" - McpServerStatusChangedStatusPending McpServerStatusChangedStatus = "pending" - McpServerStatusChangedStatusDisabled McpServerStatusChangedStatus = "disabled" - McpServerStatusChangedStatusNotConfigured McpServerStatusChangedStatus = "not_configured" + PermissionRequestMemoryActionStore PermissionRequestMemoryAction = "store" + PermissionRequestMemoryActionVote PermissionRequestMemoryAction = "vote" ) -// Origin type of the session being handed off -type HandoffSourceType string +// Vote direction (vote only) +type PermissionRequestMemoryDirection string const ( - HandoffSourceTypeRemote HandoffSourceType = "remote" - HandoffSourceTypeLocal HandoffSourceType = "local" + PermissionRequestMemoryDirectionDownvote PermissionRequestMemoryDirection = "downvote" + PermissionRequestMemoryDirectionUpvote PermissionRequestMemoryDirection = "upvote" ) -// The agent mode that was active when this message was sent -type UserMessageAgentMode string +// Kind discriminator for PermissionResult. +type PermissionResultKind string const ( - UserMessageAgentModeInteractive UserMessageAgentMode = "interactive" - UserMessageAgentModePlan UserMessageAgentMode = "plan" - UserMessageAgentModeAutopilot UserMessageAgentMode = "autopilot" - UserMessageAgentModeShell UserMessageAgentMode = "shell" + PermissionResultKindApproved PermissionResultKind = "approved" + PermissionResultKindApprovedForLocation PermissionResultKind = "approved-for-location" + PermissionResultKindApprovedForSession PermissionResultKind = "approved-for-session" + PermissionResultKindCancelled PermissionResultKind = "cancelled" + PermissionResultKindDeniedByContentExclusionPolicy PermissionResultKind = "denied-by-content-exclusion-policy" + PermissionResultKindDeniedByPermissionRequestHook PermissionResultKind = "denied-by-permission-request-hook" + PermissionResultKindDeniedByRules PermissionResultKind = "denied-by-rules" + PermissionResultKindDeniedInteractivelyByUser PermissionResultKind = "denied-interactively-by-user" + PermissionResultKindDeniedNoApprovalRuleAndCouldNotRequestFromUser PermissionResultKind = "denied-no-approval-rule-and-could-not-request-from-user" ) // The type of operation performed on the plan file @@ -2582,33 +2697,32 @@ type PlanChangedOperation string const ( PlanChangedOperationCreate PlanChangedOperation = "create" - PlanChangedOperationUpdate PlanChangedOperation = "update" PlanChangedOperationDelete PlanChangedOperation = "delete" + PlanChangedOperationUpdate PlanChangedOperation = "update" ) -// The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed) -type ElicitationCompletedAction string +// Whether the session ended normally ("routine") or due to a crash/fatal error ("error") +type ShutdownType string const ( - ElicitationCompletedActionAccept ElicitationCompletedAction = "accept" - ElicitationCompletedActionDecline ElicitationCompletedAction = "decline" - ElicitationCompletedActionCancel ElicitationCompletedAction = "cancel" + ShutdownTypeError ShutdownType = "error" + ShutdownTypeRoutine ShutdownType = "routine" ) -// Theme variant this icon is intended for -type ToolExecutionCompleteContentResourceLinkIconTheme string +// Message role: "system" for system prompts, "developer" for developer-injected instructions +type SystemMessageRole string const ( - ToolExecutionCompleteContentResourceLinkIconThemeLight ToolExecutionCompleteContentResourceLinkIconTheme = "light" - ToolExecutionCompleteContentResourceLinkIconThemeDark ToolExecutionCompleteContentResourceLinkIconTheme = "dark" + SystemMessageRoleDeveloper SystemMessageRole = "developer" + SystemMessageRoleSystem SystemMessageRole = "system" ) -// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. -type AssistantMessageToolRequestType string +// Whether the agent completed successfully or failed +type SystemNotificationAgentCompletedStatus string const ( - AssistantMessageToolRequestTypeFunction AssistantMessageToolRequestType = "function" - AssistantMessageToolRequestTypeCustom AssistantMessageToolRequestType = "custom" + SystemNotificationAgentCompletedStatusCompleted SystemNotificationAgentCompletedStatus = "completed" + SystemNotificationAgentCompletedStatusFailed SystemNotificationAgentCompletedStatus = "failed" ) // Type discriminator for SystemNotification. @@ -2617,84 +2731,80 @@ type SystemNotificationType string const ( SystemNotificationTypeAgentCompleted SystemNotificationType = "agent_completed" SystemNotificationTypeAgentIdle SystemNotificationType = "agent_idle" + SystemNotificationTypeInstructionDiscovered SystemNotificationType = "instruction_discovered" SystemNotificationTypeNewInboxMessage SystemNotificationType = "new_inbox_message" SystemNotificationTypeShellCompleted SystemNotificationType = "shell_completed" SystemNotificationTypeShellDetachedCompleted SystemNotificationType = "shell_detached_completed" - SystemNotificationTypeInstructionDiscovered SystemNotificationType = "instruction_discovered" +) + +// Theme variant this icon is intended for +type ToolExecutionCompleteContentResourceLinkIconTheme string + +const ( + ToolExecutionCompleteContentResourceLinkIconThemeDark ToolExecutionCompleteContentResourceLinkIconTheme = "dark" + ToolExecutionCompleteContentResourceLinkIconThemeLight ToolExecutionCompleteContentResourceLinkIconTheme = "light" ) // Type discriminator for ToolExecutionCompleteContent. type ToolExecutionCompleteContentType string const ( - ToolExecutionCompleteContentTypeText ToolExecutionCompleteContentType = "text" - ToolExecutionCompleteContentTypeTerminal ToolExecutionCompleteContentType = "terminal" - ToolExecutionCompleteContentTypeImage ToolExecutionCompleteContentType = "image" ToolExecutionCompleteContentTypeAudio ToolExecutionCompleteContentType = "audio" - ToolExecutionCompleteContentTypeResourceLink ToolExecutionCompleteContentType = "resource_link" + ToolExecutionCompleteContentTypeImage ToolExecutionCompleteContentType = "image" ToolExecutionCompleteContentTypeResource ToolExecutionCompleteContentType = "resource" + ToolExecutionCompleteContentTypeResourceLink ToolExecutionCompleteContentType = "resource_link" + ToolExecutionCompleteContentTypeTerminal ToolExecutionCompleteContentType = "terminal" + ToolExecutionCompleteContentTypeText ToolExecutionCompleteContentType = "text" ) -// Type discriminator for UserMessageAttachment. -type UserMessageAttachmentType string +// The agent mode that was active when this message was sent +type UserMessageAgentMode string const ( - UserMessageAttachmentTypeFile UserMessageAttachmentType = "file" - UserMessageAttachmentTypeDirectory UserMessageAttachmentType = "directory" - UserMessageAttachmentTypeSelection UserMessageAttachmentType = "selection" - UserMessageAttachmentTypeGithubReference UserMessageAttachmentType = "github_reference" - UserMessageAttachmentTypeBlob UserMessageAttachmentType = "blob" + UserMessageAgentModeAutopilot UserMessageAgentMode = "autopilot" + UserMessageAgentModeInteractive UserMessageAgentMode = "interactive" + UserMessageAgentModePlan UserMessageAgentMode = "plan" + UserMessageAgentModeShell UserMessageAgentMode = "shell" ) // Type of GitHub reference type UserMessageAttachmentGithubReferenceType string const ( + UserMessageAttachmentGithubReferenceTypeDiscussion UserMessageAttachmentGithubReferenceType = "discussion" UserMessageAttachmentGithubReferenceTypeIssue UserMessageAttachmentGithubReferenceType = "issue" UserMessageAttachmentGithubReferenceTypePr UserMessageAttachmentGithubReferenceType = "pr" - UserMessageAttachmentGithubReferenceTypeDiscussion UserMessageAttachmentGithubReferenceType = "discussion" -) - -// Underlying permission kind that needs path approval -type PermissionPromptRequestPathAccessKind string - -const ( - PermissionPromptRequestPathAccessKindRead PermissionPromptRequestPathAccessKind = "read" - PermissionPromptRequestPathAccessKindShell PermissionPromptRequestPathAccessKind = "shell" - PermissionPromptRequestPathAccessKindWrite PermissionPromptRequestPathAccessKind = "write" -) - -// Vote direction (vote only) -type PermissionPromptRequestMemoryDirection string - -const ( - PermissionPromptRequestMemoryDirectionUpvote PermissionPromptRequestMemoryDirection = "upvote" - PermissionPromptRequestMemoryDirectionDownvote PermissionPromptRequestMemoryDirection = "downvote" ) -// Vote direction (vote only) -type PermissionRequestMemoryDirection string +// Type discriminator for UserMessageAttachment. +type UserMessageAttachmentType string const ( - PermissionRequestMemoryDirectionUpvote PermissionRequestMemoryDirection = "upvote" - PermissionRequestMemoryDirectionDownvote PermissionRequestMemoryDirection = "downvote" + UserMessageAttachmentTypeBlob UserMessageAttachmentType = "blob" + UserMessageAttachmentTypeDirectory UserMessageAttachmentType = "directory" + UserMessageAttachmentTypeFile UserMessageAttachmentType = "file" + UserMessageAttachmentTypeGithubReference UserMessageAttachmentType = "github_reference" + UserMessageAttachmentTypeSelection UserMessageAttachmentType = "selection" ) -// Where the failed model call originated -type ModelCallFailureSource string +// Kind discriminator for UserToolSessionApproval. +type UserToolSessionApprovalKind string const ( - ModelCallFailureSourceTopLevel ModelCallFailureSource = "top_level" - ModelCallFailureSourceSubagent ModelCallFailureSource = "subagent" - ModelCallFailureSourceMcpSampling ModelCallFailureSource = "mcp_sampling" + UserToolSessionApprovalKindCommands UserToolSessionApprovalKind = "commands" + UserToolSessionApprovalKindCustomTool UserToolSessionApprovalKind = "custom-tool" + UserToolSessionApprovalKindMcp UserToolSessionApprovalKind = "mcp" + UserToolSessionApprovalKindMemory UserToolSessionApprovalKind = "memory" + UserToolSessionApprovalKindRead UserToolSessionApprovalKind = "read" + UserToolSessionApprovalKindWrite UserToolSessionApprovalKind = "write" ) -// Whether the agent completed successfully or failed -type SystemNotificationAgentCompletedStatus string +// Hosting platform type of the repository (github or ado) +type WorkingDirectoryContextHostType string const ( - SystemNotificationAgentCompletedStatusCompleted SystemNotificationAgentCompletedStatus = "completed" - SystemNotificationAgentCompletedStatusFailed SystemNotificationAgentCompletedStatus = "failed" + WorkingDirectoryContextHostTypeAdo WorkingDirectoryContextHostType = "ado" + WorkingDirectoryContextHostTypeGithub WorkingDirectoryContextHostType = "github" ) // Whether the file was newly created or updated @@ -2705,43 +2815,19 @@ const ( WorkspaceFileChangedOperationUpdate WorkspaceFileChangedOperation = "update" ) -// Whether the session ended normally ("routine") or due to a crash/fatal error ("error") -type ShutdownType string - -const ( - ShutdownTypeRoutine ShutdownType = "routine" - ShutdownTypeError ShutdownType = "error" -) - -// Whether this is a store or vote memory operation -type PermissionPromptRequestMemoryAction string - -const ( - PermissionPromptRequestMemoryActionStore PermissionPromptRequestMemoryAction = "store" - PermissionPromptRequestMemoryActionVote PermissionPromptRequestMemoryAction = "vote" -) - -// Whether this is a store or vote memory operation -type PermissionRequestMemoryAction string - -const ( - PermissionRequestMemoryActionStore PermissionRequestMemoryAction = "store" - PermissionRequestMemoryActionVote PermissionRequestMemoryAction = "vote" -) - // Type aliases for convenience. type ( - PermissionRequestCommand = PermissionRequestShellCommand - PossibleURL = PermissionRequestShellPossibleURL Attachment = UserMessageAttachment AttachmentType = UserMessageAttachmentType + PermissionRequestCommand = PermissionRequestShellCommand + PossibleURL = PermissionRequestShellPossibleURL ) // Constant aliases for convenience. const ( - AttachmentTypeFile = UserMessageAttachmentTypeFile + AttachmentTypeBlob = UserMessageAttachmentTypeBlob AttachmentTypeDirectory = UserMessageAttachmentTypeDirectory - AttachmentTypeSelection = UserMessageAttachmentTypeSelection + AttachmentTypeFile = UserMessageAttachmentTypeFile AttachmentTypeGithubReference = UserMessageAttachmentTypeGithubReference - AttachmentTypeBlob = UserMessageAttachmentTypeBlob + AttachmentTypeSelection = UserMessageAttachmentTypeSelection ) diff --git a/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go b/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go index cff80e4ff..9a8ef8ebd 100644 --- a/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go +++ b/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go @@ -193,11 +193,11 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) { } assertRpcError(t, "Mcp.Enable", func() error { - _, e := session.RPC.Mcp.Enable(t.Context(), &rpc.MCPEnableRequest{ServerName: "missing-server"}) + _, e := session.RPC.Mcp.Enable(t.Context(), &rpc.McpEnableRequest{ServerName: "missing-server"}) return e }, "no mcp host initialized") assertRpcError(t, "Mcp.Disable", func() error { - _, e := session.RPC.Mcp.Disable(t.Context(), &rpc.MCPDisableRequest{ServerName: "missing-server"}) + _, e := session.RPC.Mcp.Disable(t.Context(), &rpc.McpDisableRequest{ServerName: "missing-server"}) return e }, "no mcp host initialized") assertRpcError(t, "Mcp.Reload", func() error { diff --git a/go/internal/e2e/rpc_mcp_config_e2e_test.go b/go/internal/e2e/rpc_mcp_config_e2e_test.go index 187ee3802..34134c68a 100644 --- a/go/internal/e2e/rpc_mcp_config_e2e_test.go +++ b/go/internal/e2e/rpc_mcp_config_e2e_test.go @@ -22,11 +22,11 @@ func TestRpcMcpConfigE2E(t *testing.T) { serverName := fmt.Sprintf("sdk-test-%s", randomHex(t)) nodeCmd := "node" - baseConfig := rpc.MCPServerConfig{ + baseConfig := rpc.McpServerConfig{ Command: &nodeCmd, Args: []string{"-v"}, } - updatedConfig := rpc.MCPServerConfig{ + updatedConfig := rpc.McpServerConfig{ Command: &nodeCmd, Args: []string{"--version"}, } @@ -41,10 +41,10 @@ func TestRpcMcpConfigE2E(t *testing.T) { // Best-effort cleanup if a subtest assertion fails mid-flight. t.Cleanup(func() { - _, _ = client.RPC.Mcp.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName}) + _, _ = client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName}) }) - if _, err := client.RPC.Mcp.Config().Add(t.Context(), &rpc.MCPConfigAddRequest{ + if _, err := client.RPC.Mcp.Config().Add(t.Context(), &rpc.McpConfigAddRequest{ Name: serverName, Config: baseConfig, }); err != nil { @@ -59,7 +59,7 @@ func TestRpcMcpConfigE2E(t *testing.T) { t.Fatalf("Expected %q to be present after Add", serverName) } - if _, err := client.RPC.Mcp.Config().Update(t.Context(), &rpc.MCPConfigUpdateRequest{ + if _, err := client.RPC.Mcp.Config().Update(t.Context(), &rpc.McpConfigUpdateRequest{ Name: serverName, Config: updatedConfig, }); err != nil { @@ -81,14 +81,14 @@ func TestRpcMcpConfigE2E(t *testing.T) { t.Errorf("Expected args[0]='--version', got %v", updated.Args) } - if _, err := client.RPC.Mcp.Config().Disable(t.Context(), &rpc.MCPConfigDisableRequest{Names: []string{serverName}}); err != nil { + if _, err := client.RPC.Mcp.Config().Disable(t.Context(), &rpc.McpConfigDisableRequest{Names: []string{serverName}}); err != nil { t.Fatalf("Mcp.Config.Disable failed: %v", err) } - if _, err := client.RPC.Mcp.Config().Enable(t.Context(), &rpc.MCPConfigEnableRequest{Names: []string{serverName}}); err != nil { + if _, err := client.RPC.Mcp.Config().Enable(t.Context(), &rpc.McpConfigEnableRequest{Names: []string{serverName}}); err != nil { t.Fatalf("Mcp.Config.Enable failed: %v", err) } - if _, err := client.RPC.Mcp.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName}); err != nil { + if _, err := client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName}); err != nil { t.Fatalf("Mcp.Config.Remove failed: %v", err) } @@ -111,19 +111,19 @@ func TestRpcMcpConfigE2E(t *testing.T) { serverName := fmt.Sprintf("sdk-http-oauth-%s", randomHex(t)) - httpType := rpc.MCPServerConfigTypeHTTP + httpType := rpc.McpServerConfigTypeHTTP urlBase := "https://example.com/mcp" urlUpdated := "https://example.com/updated-mcp" clientID := "client-id" clientIDUpdated := "updated-client-id" - grantClientCreds := rpc.MCPServerConfigHTTPOauthGrantTypeClientCredentials - grantAuthCode := rpc.MCPServerConfigHTTPOauthGrantTypeAuthorizationCode + grantClientCreds := rpc.McpServerConfigHTTPOauthGrantTypeClientCredentials + grantAuthCode := rpc.McpServerConfigHTTPOauthGrantTypeAuthorizationCode var publicFalse = false var publicTrue = true var timeoutBase int64 = 3000 var timeoutUpdated int64 = 4000 - baseConfig := rpc.MCPServerConfig{ + baseConfig := rpc.McpServerConfig{ Type: &httpType, URL: &urlBase, Headers: map[string]string{"Authorization": "Bearer token"}, @@ -133,7 +133,7 @@ func TestRpcMcpConfigE2E(t *testing.T) { Tools: []string{"*"}, Timeout: &timeoutBase, } - updatedConfig := rpc.MCPServerConfig{ + updatedConfig := rpc.McpServerConfig{ Type: &httpType, URL: &urlUpdated, OauthClientID: &clientIDUpdated, @@ -144,10 +144,10 @@ func TestRpcMcpConfigE2E(t *testing.T) { } t.Cleanup(func() { - _, _ = client.RPC.Mcp.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName}) + _, _ = client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName}) }) - if _, err := client.RPC.Mcp.Config().Add(t.Context(), &rpc.MCPConfigAddRequest{ + if _, err := client.RPC.Mcp.Config().Add(t.Context(), &rpc.McpConfigAddRequest{ Name: serverName, Config: baseConfig, }); err != nil { @@ -181,7 +181,7 @@ func TestRpcMcpConfigE2E(t *testing.T) { t.Errorf("Expected oauthGrantType='client_credentials', got %v", added.OauthGrantType) } - if _, err := client.RPC.Mcp.Config().Update(t.Context(), &rpc.MCPConfigUpdateRequest{ + if _, err := client.RPC.Mcp.Config().Update(t.Context(), &rpc.McpConfigUpdateRequest{ Name: serverName, Config: updatedConfig, }); err != nil { @@ -214,7 +214,7 @@ func TestRpcMcpConfigE2E(t *testing.T) { t.Errorf("Expected timeout=4000, got %v", updated.Timeout) } - if _, err := client.RPC.Mcp.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName}); err != nil { + if _, err := client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName}); err != nil { t.Fatalf("Mcp.Config.Remove failed: %v", err) } diff --git a/go/internal/e2e/rpc_server_e2e_test.go b/go/internal/e2e/rpc_server_e2e_test.go index 1a22627ac..35a71e24e 100644 --- a/go/internal/e2e/rpc_server_e2e_test.go +++ b/go/internal/e2e/rpc_server_e2e_test.go @@ -160,7 +160,7 @@ func TestRpcServerE2E(t *testing.T) { skillsDir := createMcpSkillsRpcDirectory(t, ctx.WorkDir, "server-rpc-skills", skillName, "Skill discovered by server-scoped RPC tests.") workingDir := ctx.WorkDir - mcp, err := client.RPC.Mcp.Discover(t.Context(), &rpc.MCPDiscoverRequest{WorkingDirectory: &workingDir}) + mcp, err := client.RPC.Mcp.Discover(t.Context(), &rpc.McpDiscoverRequest{WorkingDirectory: &workingDir}) if err != nil { t.Fatalf("Mcp.Discover failed: %v", err) } diff --git a/go/internal/e2e/rpc_session_state_e2e_test.go b/go/internal/e2e/rpc_session_state_e2e_test.go index 885deb805..e9cf1110f 100644 --- a/go/internal/e2e/rpc_session_state_e2e_test.go +++ b/go/internal/e2e/rpc_session_state_e2e_test.go @@ -500,7 +500,7 @@ func TestRpcSessionStateE2E(t *testing.T) { t.Errorf("session.history.truncate should be implemented; error suggests it isn't: %v", err) } - _, err = session.RPC.Mcp.Oauth().Login(t.Context(), &rpc.MCPOauthLoginRequest{ServerName: "missing-server"}) + _, err = session.RPC.Mcp.Oauth().Login(t.Context(), &rpc.McpOauthLoginRequest{ServerName: "missing-server"}) if err == nil { t.Fatal("Expected Mcp.Oauth.Login with unknown server to fail") } diff --git a/go/internal/e2e/session_fs_e2e_test.go b/go/internal/e2e/session_fs_e2e_test.go index ffa1db98f..d56dc14a3 100644 --- a/go/internal/e2e/session_fs_e2e_test.go +++ b/go/internal/e2e/session_fs_e2e_test.go @@ -22,7 +22,7 @@ func TestSessionFsE2E(t *testing.T) { sessionFsConfig := &copilot.SessionFsConfig{ InitialCwd: "/", SessionStatePath: sessionStatePath, - Conventions: rpc.SessionFSSetProviderConventionsPosix, + Conventions: rpc.SessionFsSetProviderConventionsPosix, } createSessionFsHandler := func(session *copilot.Session) copilot.SessionFsProvider { return &testSessionFsHandler{ @@ -163,11 +163,11 @@ func TestSessionFsE2E(t *testing.T) { t.Cleanup(func() { client2.ForceStop() }) if err := client2.Start(t.Context()); err == nil { - t.Fatal("Expected Start to fail when sessionFs provider is set after sessions already exist") + t.Fatal("Expected Start to fail when SessionFs provider is set after sessions already exist") } }) - t.Run("should map large output handling into sessionFs", func(t *testing.T) { + t.Run("should map large output handling into SessionFs", func(t *testing.T) { ctx.ConfigureForTest(t) suppliedFileContent := strings.Repeat("x", 100_000) @@ -213,7 +213,7 @@ func TestSessionFsE2E(t *testing.T) { } }) - t.Run("should succeed with compaction while using sessionFs", func(t *testing.T) { + t.Run("should succeed with compaction while using SessionFs", func(t *testing.T) { ctx.ConfigureForTest(t) session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ @@ -252,7 +252,7 @@ func TestSessionFsE2E(t *testing.T) { t.Fatalf("Timed out waiting for checkpoint rewrite: %v", err) } }) - t.Run("should write workspace metadata via sessionFs", func(t *testing.T) { + t.Run("should write workspace metadata via SessionFs", func(t *testing.T) { ctx.ConfigureForTest(t) session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ @@ -277,17 +277,10 @@ func TestSessionFsE2E(t *testing.T) { t.Fatalf("Expected response to contain 56, got %q", content) } - // WorkspaceManager should have created workspace.yaml via sessionFs + // WorkspaceManager should have created workspace.yaml via SessionFs workspaceYamlPath := p(session.SessionID, sessionStatePath+"/workspace.yaml") - if err := waitForFile(workspaceYamlPath, 5*time.Second); err != nil { - t.Fatalf("Timed out waiting for workspace.yaml: %v", err) - } - yaml, err := os.ReadFile(workspaceYamlPath) - if err != nil { - t.Fatalf("Failed to read workspace.yaml: %v", err) - } - if !strings.Contains(string(yaml), "id:") { - t.Fatalf("Expected workspace.yaml to contain 'id:', got %q", string(yaml)) + if err := waitForFileContent(workspaceYamlPath, "id:", 5*time.Second); err != nil { + t.Fatalf("Timed out waiting for workspace.yaml content: %v", err) } // Checkpoint index should also exist @@ -301,7 +294,7 @@ func TestSessionFsE2E(t *testing.T) { } }) - t.Run("should persist plan.md via sessionFs", func(t *testing.T) { + t.Run("should persist plan.md via SessionFs", func(t *testing.T) { ctx.ConfigureForTest(t) session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ @@ -439,18 +432,18 @@ func (h *testSessionFsHandler) Readdir(path string) ([]string, error) { return names, nil } -func (h *testSessionFsHandler) ReaddirWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error) { +func (h *testSessionFsHandler) ReaddirWithTypes(path string) ([]rpc.SessionFsReaddirWithTypesEntry, error) { entries, err := os.ReadDir(providerPath(h.root, h.sessionID, path)) if err != nil { return nil, err } - result := make([]rpc.SessionFSReaddirWithTypesEntry, 0, len(entries)) + result := make([]rpc.SessionFsReaddirWithTypesEntry, 0, len(entries)) for _, entry := range entries { - entryType := rpc.SessionFSReaddirWithTypesEntryTypeFile + entryType := rpc.SessionFsReaddirWithTypesEntryTypeFile if entry.IsDir() { - entryType = rpc.SessionFSReaddirWithTypesEntryTypeDirectory + entryType = rpc.SessionFsReaddirWithTypesEntryTypeDirectory } - result = append(result, rpc.SessionFSReaddirWithTypesEntry{ + result = append(result, rpc.SessionFsReaddirWithTypesEntry{ Name: entry.Name(), Type: entryType, }) @@ -596,7 +589,7 @@ func TestSessionFsHandlerOperationsE2E(t *testing.T) { } var found bool for _, entry := range typedEntries { - if entry.Name == "file.txt" && entry.Type == rpc.SessionFSReaddirWithTypesEntryTypeFile { + if entry.Name == "file.txt" && entry.Type == rpc.SessionFsReaddirWithTypesEntryTypeFile { found = true break } diff --git a/go/rpc/generated_rpc.go b/go/rpc/generated_rpc.go index dce096c3d..87f323814 100644 --- a/go/rpc/generated_rpc.go +++ b/go/rpc/generated_rpc.go @@ -12,263 +12,6 @@ import ( "time" ) -type RPCTypes struct { - AccountGetQuotaRequest AccountGetQuotaRequest `json:"AccountGetQuotaRequest"` - AccountGetQuotaResult AccountGetQuotaResult `json:"AccountGetQuotaResult"` - AccountQuotaSnapshot AccountQuotaSnapshot `json:"AccountQuotaSnapshot"` - AgentDeselectResult AgentDeselectResult `json:"AgentDeselectResult"` - AgentGetCurrentResult AgentGetCurrentResult `json:"AgentGetCurrentResult"` - AgentInfo AgentInfo `json:"AgentInfo"` - AgentList AgentList `json:"AgentList"` - AgentReloadResult AgentReloadResult `json:"AgentReloadResult"` - AgentSelectRequest AgentSelectRequest `json:"AgentSelectRequest"` - AgentSelectResult AgentSelectResult `json:"AgentSelectResult"` - AuthInfoType AuthInfoType `json:"AuthInfoType"` - CommandsHandlePendingCommandRequest CommandsHandlePendingCommandRequest `json:"CommandsHandlePendingCommandRequest"` - CommandsHandlePendingCommandResult CommandsHandlePendingCommandResult `json:"CommandsHandlePendingCommandResult"` - ConnectRequest ConnectRequest `json:"ConnectRequest"` - ConnectResult ConnectResult `json:"ConnectResult"` - CurrentModel CurrentModel `json:"CurrentModel"` - DiscoveredMCPServer DiscoveredMCPServer `json:"DiscoveredMcpServer"` - DiscoveredMCPServerSource MCPServerSource `json:"DiscoveredMcpServerSource"` - DiscoveredMCPServerType DiscoveredMCPServerType `json:"DiscoveredMcpServerType"` - EmbeddedBlobResourceContents EmbeddedBlobResourceContents `json:"EmbeddedBlobResourceContents"` - EmbeddedTextResourceContents EmbeddedTextResourceContents `json:"EmbeddedTextResourceContents"` - Extension Extension `json:"Extension"` - ExtensionList ExtensionList `json:"ExtensionList"` - ExtensionsDisableRequest ExtensionsDisableRequest `json:"ExtensionsDisableRequest"` - ExtensionsDisableResult ExtensionsDisableResult `json:"ExtensionsDisableResult"` - ExtensionsEnableRequest ExtensionsEnableRequest `json:"ExtensionsEnableRequest"` - ExtensionsEnableResult ExtensionsEnableResult `json:"ExtensionsEnableResult"` - ExtensionSource ExtensionSource `json:"ExtensionSource"` - ExtensionsReloadResult ExtensionsReloadResult `json:"ExtensionsReloadResult"` - ExtensionStatus ExtensionStatus `json:"ExtensionStatus"` - ExternalToolResult *ExternalToolResult `json:"ExternalToolResult"` - ExternalToolTextResultForLlm ExternalToolTextResultForLlm `json:"ExternalToolTextResultForLlm"` - ExternalToolTextResultForLlmContent ExternalToolTextResultForLlmContent `json:"ExternalToolTextResultForLlmContent"` - ExternalToolTextResultForLlmContentAudio ExternalToolTextResultForLlmContentAudio `json:"ExternalToolTextResultForLlmContentAudio"` - ExternalToolTextResultForLlmContentImage ExternalToolTextResultForLlmContentImage `json:"ExternalToolTextResultForLlmContentImage"` - ExternalToolTextResultForLlmContentResource ExternalToolTextResultForLlmContentResource `json:"ExternalToolTextResultForLlmContentResource"` - ExternalToolTextResultForLlmContentResourceDetails ExternalToolTextResultForLlmContentResourceDetails `json:"ExternalToolTextResultForLlmContentResourceDetails"` - ExternalToolTextResultForLlmContentResourceLink ExternalToolTextResultForLlmContentResourceLink `json:"ExternalToolTextResultForLlmContentResourceLink"` - ExternalToolTextResultForLlmContentResourceLinkIcon ExternalToolTextResultForLlmContentResourceLinkIcon `json:"ExternalToolTextResultForLlmContentResourceLinkIcon"` - ExternalToolTextResultForLlmContentResourceLinkIconTheme ExternalToolTextResultForLlmContentResourceLinkIconTheme `json:"ExternalToolTextResultForLlmContentResourceLinkIconTheme"` - ExternalToolTextResultForLlmContentTerminal ExternalToolTextResultForLlmContentTerminal `json:"ExternalToolTextResultForLlmContentTerminal"` - ExternalToolTextResultForLlmContentText ExternalToolTextResultForLlmContentText `json:"ExternalToolTextResultForLlmContentText"` - FilterMapping *FilterMapping `json:"FilterMapping"` - FilterMappingString FilterMappingString `json:"FilterMappingString"` - FilterMappingValue FilterMappingString `json:"FilterMappingValue"` - FleetStartRequest FleetStartRequest `json:"FleetStartRequest"` - FleetStartResult FleetStartResult `json:"FleetStartResult"` - HandlePendingToolCallRequest HandlePendingToolCallRequest `json:"HandlePendingToolCallRequest"` - HandlePendingToolCallResult HandlePendingToolCallResult `json:"HandlePendingToolCallResult"` - HistoryCompactContextWindow HistoryCompactContextWindow `json:"HistoryCompactContextWindow"` - HistoryCompactResult HistoryCompactResult `json:"HistoryCompactResult"` - HistoryTruncateRequest HistoryTruncateRequest `json:"HistoryTruncateRequest"` - HistoryTruncateResult HistoryTruncateResult `json:"HistoryTruncateResult"` - InstructionsGetSourcesResult InstructionsGetSourcesResult `json:"InstructionsGetSourcesResult"` - InstructionsSources InstructionsSources `json:"InstructionsSources"` - InstructionsSourcesLocation InstructionsSourcesLocation `json:"InstructionsSourcesLocation"` - InstructionsSourcesType InstructionsSourcesType `json:"InstructionsSourcesType"` - LogRequest LogRequest `json:"LogRequest"` - LogResult LogResult `json:"LogResult"` - MCPConfigAddRequest MCPConfigAddRequest `json:"McpConfigAddRequest"` - MCPConfigAddResult MCPConfigAddResult `json:"McpConfigAddResult"` - MCPConfigDisableRequest MCPConfigDisableRequest `json:"McpConfigDisableRequest"` - MCPConfigDisableResult MCPConfigDisableResult `json:"McpConfigDisableResult"` - MCPConfigEnableRequest MCPConfigEnableRequest `json:"McpConfigEnableRequest"` - MCPConfigEnableResult MCPConfigEnableResult `json:"McpConfigEnableResult"` - MCPConfigList MCPConfigList `json:"McpConfigList"` - MCPConfigRemoveRequest MCPConfigRemoveRequest `json:"McpConfigRemoveRequest"` - MCPConfigRemoveResult MCPConfigRemoveResult `json:"McpConfigRemoveResult"` - MCPConfigUpdateRequest MCPConfigUpdateRequest `json:"McpConfigUpdateRequest"` - MCPConfigUpdateResult MCPConfigUpdateResult `json:"McpConfigUpdateResult"` - MCPDisableRequest MCPDisableRequest `json:"McpDisableRequest"` - MCPDisableResult MCPDisableResult `json:"McpDisableResult"` - MCPDiscoverRequest MCPDiscoverRequest `json:"McpDiscoverRequest"` - MCPDiscoverResult MCPDiscoverResult `json:"McpDiscoverResult"` - MCPEnableRequest MCPEnableRequest `json:"McpEnableRequest"` - MCPEnableResult MCPEnableResult `json:"McpEnableResult"` - MCPOauthLoginRequest MCPOauthLoginRequest `json:"McpOauthLoginRequest"` - MCPOauthLoginResult MCPOauthLoginResult `json:"McpOauthLoginResult"` - MCPReloadResult MCPReloadResult `json:"McpReloadResult"` - MCPServer MCPServer `json:"McpServer"` - MCPServerConfig MCPServerConfig `json:"McpServerConfig"` - MCPServerConfigHTTP MCPServerConfigHTTP `json:"McpServerConfigHttp"` - MCPServerConfigHTTPOauthGrantType MCPServerConfigHTTPOauthGrantType `json:"McpServerConfigHttpOauthGrantType"` - MCPServerConfigHTTPType MCPServerConfigHTTPType `json:"McpServerConfigHttpType"` - MCPServerConfigLocal MCPServerConfigLocal `json:"McpServerConfigLocal"` - MCPServerConfigLocalType MCPServerConfigLocalType `json:"McpServerConfigLocalType"` - MCPServerList MCPServerList `json:"McpServerList"` - MCPServerSource MCPServerSource `json:"McpServerSource"` - MCPServerStatus MCPServerStatus `json:"McpServerStatus"` - Model ModelElement `json:"Model"` - ModelBilling ModelBilling `json:"ModelBilling"` - ModelCapabilities ModelCapabilities `json:"ModelCapabilities"` - ModelCapabilitiesLimits ModelCapabilitiesLimits `json:"ModelCapabilitiesLimits"` - ModelCapabilitiesLimitsVision ModelCapabilitiesLimitsVision `json:"ModelCapabilitiesLimitsVision"` - ModelCapabilitiesOverride ModelCapabilitiesOverride `json:"ModelCapabilitiesOverride"` - ModelCapabilitiesOverrideLimits ModelCapabilitiesOverrideLimits `json:"ModelCapabilitiesOverrideLimits"` - ModelCapabilitiesOverrideLimitsVision ModelCapabilitiesOverrideLimitsVision `json:"ModelCapabilitiesOverrideLimitsVision"` - ModelCapabilitiesOverrideSupports ModelCapabilitiesOverrideSupports `json:"ModelCapabilitiesOverrideSupports"` - ModelCapabilitiesSupports ModelCapabilitiesSupports `json:"ModelCapabilitiesSupports"` - ModelList ModelList `json:"ModelList"` - ModelPolicy ModelPolicy `json:"ModelPolicy"` - ModelsListRequest ModelsListRequest `json:"ModelsListRequest"` - ModelSwitchToRequest ModelSwitchToRequest `json:"ModelSwitchToRequest"` - ModelSwitchToResult ModelSwitchToResult `json:"ModelSwitchToResult"` - ModeSetRequest ModeSetRequest `json:"ModeSetRequest"` - ModeSetResult ModeSetResult `json:"ModeSetResult"` - NameGetResult NameGetResult `json:"NameGetResult"` - NameSetRequest NameSetRequest `json:"NameSetRequest"` - NameSetResult NameSetResult `json:"NameSetResult"` - PermissionDecision PermissionDecision `json:"PermissionDecision"` - PermissionDecisionApproveForLocation PermissionDecisionApproveForLocation `json:"PermissionDecisionApproveForLocation"` - PermissionDecisionApproveForLocationApproval PermissionDecisionApproveForLocationApproval `json:"PermissionDecisionApproveForLocationApproval"` - PermissionDecisionApproveForLocationApprovalCommands PermissionDecisionApproveForLocationApprovalCommands `json:"PermissionDecisionApproveForLocationApprovalCommands"` - PermissionDecisionApproveForLocationApprovalCustomTool PermissionDecisionApproveForLocationApprovalCustomTool `json:"PermissionDecisionApproveForLocationApprovalCustomTool"` - PermissionDecisionApproveForLocationApprovalExtensionManagement PermissionDecisionApproveForLocationApprovalExtensionManagement `json:"PermissionDecisionApproveForLocationApprovalExtensionManagement"` - PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess `json:"PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess"` - PermissionDecisionApproveForLocationApprovalMCP PermissionDecisionApproveForLocationApprovalMCP `json:"PermissionDecisionApproveForLocationApprovalMcp"` - PermissionDecisionApproveForLocationApprovalMCPSampling PermissionDecisionApproveForLocationApprovalMCPSampling `json:"PermissionDecisionApproveForLocationApprovalMcpSampling"` - PermissionDecisionApproveForLocationApprovalMemory PermissionDecisionApproveForLocationApprovalMemory `json:"PermissionDecisionApproveForLocationApprovalMemory"` - PermissionDecisionApproveForLocationApprovalRead PermissionDecisionApproveForLocationApprovalRead `json:"PermissionDecisionApproveForLocationApprovalRead"` - PermissionDecisionApproveForLocationApprovalWrite PermissionDecisionApproveForLocationApprovalWrite `json:"PermissionDecisionApproveForLocationApprovalWrite"` - PermissionDecisionApproveForSession PermissionDecisionApproveForSession `json:"PermissionDecisionApproveForSession"` - PermissionDecisionApproveForSessionApproval PermissionDecisionApproveForSessionApproval `json:"PermissionDecisionApproveForSessionApproval"` - PermissionDecisionApproveForSessionApprovalCommands PermissionDecisionApproveForSessionApprovalCommands `json:"PermissionDecisionApproveForSessionApprovalCommands"` - PermissionDecisionApproveForSessionApprovalCustomTool PermissionDecisionApproveForSessionApprovalCustomTool `json:"PermissionDecisionApproveForSessionApprovalCustomTool"` - PermissionDecisionApproveForSessionApprovalExtensionManagement PermissionDecisionApproveForSessionApprovalExtensionManagement `json:"PermissionDecisionApproveForSessionApprovalExtensionManagement"` - PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess `json:"PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess"` - PermissionDecisionApproveForSessionApprovalMCP PermissionDecisionApproveForSessionApprovalMCP `json:"PermissionDecisionApproveForSessionApprovalMcp"` - PermissionDecisionApproveForSessionApprovalMCPSampling PermissionDecisionApproveForSessionApprovalMCPSampling `json:"PermissionDecisionApproveForSessionApprovalMcpSampling"` - PermissionDecisionApproveForSessionApprovalMemory PermissionDecisionApproveForSessionApprovalMemory `json:"PermissionDecisionApproveForSessionApprovalMemory"` - PermissionDecisionApproveForSessionApprovalRead PermissionDecisionApproveForSessionApprovalRead `json:"PermissionDecisionApproveForSessionApprovalRead"` - PermissionDecisionApproveForSessionApprovalWrite PermissionDecisionApproveForSessionApprovalWrite `json:"PermissionDecisionApproveForSessionApprovalWrite"` - PermissionDecisionApproveOnce PermissionDecisionApproveOnce `json:"PermissionDecisionApproveOnce"` - PermissionDecisionApprovePermanently PermissionDecisionApprovePermanently `json:"PermissionDecisionApprovePermanently"` - PermissionDecisionReject PermissionDecisionReject `json:"PermissionDecisionReject"` - PermissionDecisionRequest PermissionDecisionRequest `json:"PermissionDecisionRequest"` - PermissionDecisionUserNotAvailable PermissionDecisionUserNotAvailable `json:"PermissionDecisionUserNotAvailable"` - PermissionRequestResult PermissionRequestResult `json:"PermissionRequestResult"` - PermissionsResetSessionApprovalsRequest PermissionsResetSessionApprovalsRequest `json:"PermissionsResetSessionApprovalsRequest"` - PermissionsResetSessionApprovalsResult PermissionsResetSessionApprovalsResult `json:"PermissionsResetSessionApprovalsResult"` - PermissionsSetApproveAllRequest PermissionsSetApproveAllRequest `json:"PermissionsSetApproveAllRequest"` - PermissionsSetApproveAllResult PermissionsSetApproveAllResult `json:"PermissionsSetApproveAllResult"` - PingRequest PingRequest `json:"PingRequest"` - PingResult PingResult `json:"PingResult"` - PlanDeleteResult PlanDeleteResult `json:"PlanDeleteResult"` - PlanReadResult PlanReadResult `json:"PlanReadResult"` - PlanUpdateRequest PlanUpdateRequest `json:"PlanUpdateRequest"` - PlanUpdateResult PlanUpdateResult `json:"PlanUpdateResult"` - Plugin PluginElement `json:"Plugin"` - PluginList PluginList `json:"PluginList"` - RemoteDisableResult RemoteDisableResult `json:"RemoteDisableResult"` - RemoteEnableResult RemoteEnableResult `json:"RemoteEnableResult"` - ServerSkill ServerSkill `json:"ServerSkill"` - ServerSkillList ServerSkillList `json:"ServerSkillList"` - SessionAuthStatus SessionAuthStatus `json:"SessionAuthStatus"` - SessionFSAppendFileRequest SessionFSAppendFileRequest `json:"SessionFsAppendFileRequest"` - SessionFSError SessionFSError `json:"SessionFsError"` - SessionFSErrorCode SessionFSErrorCode `json:"SessionFsErrorCode"` - SessionFSExistsRequest SessionFSExistsRequest `json:"SessionFsExistsRequest"` - SessionFSExistsResult SessionFSExistsResult `json:"SessionFsExistsResult"` - SessionFSMkdirRequest SessionFSMkdirRequest `json:"SessionFsMkdirRequest"` - SessionFSReaddirRequest SessionFSReaddirRequest `json:"SessionFsReaddirRequest"` - SessionFSReaddirResult SessionFSReaddirResult `json:"SessionFsReaddirResult"` - SessionFSReaddirWithTypesEntry SessionFSReaddirWithTypesEntry `json:"SessionFsReaddirWithTypesEntry"` - SessionFSReaddirWithTypesEntryType SessionFSReaddirWithTypesEntryType `json:"SessionFsReaddirWithTypesEntryType"` - SessionFSReaddirWithTypesRequest SessionFSReaddirWithTypesRequest `json:"SessionFsReaddirWithTypesRequest"` - SessionFSReaddirWithTypesResult SessionFSReaddirWithTypesResult `json:"SessionFsReaddirWithTypesResult"` - SessionFSReadFileRequest SessionFSReadFileRequest `json:"SessionFsReadFileRequest"` - SessionFSReadFileResult SessionFSReadFileResult `json:"SessionFsReadFileResult"` - SessionFSRenameRequest SessionFSRenameRequest `json:"SessionFsRenameRequest"` - SessionFSRmRequest SessionFSRmRequest `json:"SessionFsRmRequest"` - SessionFSSetProviderConventions SessionFSSetProviderConventions `json:"SessionFsSetProviderConventions"` - SessionFSSetProviderRequest SessionFSSetProviderRequest `json:"SessionFsSetProviderRequest"` - SessionFSSetProviderResult SessionFSSetProviderResult `json:"SessionFsSetProviderResult"` - SessionFSStatRequest SessionFSStatRequest `json:"SessionFsStatRequest"` - SessionFSStatResult SessionFSStatResult `json:"SessionFsStatResult"` - SessionFSWriteFileRequest SessionFSWriteFileRequest `json:"SessionFsWriteFileRequest"` - SessionLogLevel SessionLogLevel `json:"SessionLogLevel"` - SessionMode SessionMode `json:"SessionMode"` - SessionsForkRequest SessionsForkRequest `json:"SessionsForkRequest"` - SessionsForkResult SessionsForkResult `json:"SessionsForkResult"` - ShellExecRequest ShellExecRequest `json:"ShellExecRequest"` - ShellExecResult ShellExecResult `json:"ShellExecResult"` - ShellKillRequest ShellKillRequest `json:"ShellKillRequest"` - ShellKillResult ShellKillResult `json:"ShellKillResult"` - ShellKillSignal ShellKillSignal `json:"ShellKillSignal"` - Skill Skill `json:"Skill"` - SkillList SkillList `json:"SkillList"` - SkillsConfigSetDisabledSkillsRequest SkillsConfigSetDisabledSkillsRequest `json:"SkillsConfigSetDisabledSkillsRequest"` - SkillsConfigSetDisabledSkillsResult SkillsConfigSetDisabledSkillsResult `json:"SkillsConfigSetDisabledSkillsResult"` - SkillsDisableRequest SkillsDisableRequest `json:"SkillsDisableRequest"` - SkillsDisableResult SkillsDisableResult `json:"SkillsDisableResult"` - SkillsDiscoverRequest SkillsDiscoverRequest `json:"SkillsDiscoverRequest"` - SkillsEnableRequest SkillsEnableRequest `json:"SkillsEnableRequest"` - SkillsEnableResult SkillsEnableResult `json:"SkillsEnableResult"` - SkillsReloadResult SkillsReloadResult `json:"SkillsReloadResult"` - SuspendResult SuspendResult `json:"SuspendResult"` - TaskAgentInfo TaskAgentInfo `json:"TaskAgentInfo"` - TaskAgentInfoExecutionMode TaskInfoExecutionMode `json:"TaskAgentInfoExecutionMode"` - TaskAgentInfoStatus TaskInfoStatus `json:"TaskAgentInfoStatus"` - TaskInfo TaskInfo `json:"TaskInfo"` - TaskList TaskList `json:"TaskList"` - TasksCancelRequest TasksCancelRequest `json:"TasksCancelRequest"` - TasksCancelResult TasksCancelResult `json:"TasksCancelResult"` - TaskShellInfo TaskShellInfo `json:"TaskShellInfo"` - TaskShellInfoAttachmentMode TaskShellInfoAttachmentMode `json:"TaskShellInfoAttachmentMode"` - TaskShellInfoExecutionMode TaskInfoExecutionMode `json:"TaskShellInfoExecutionMode"` - TaskShellInfoStatus TaskInfoStatus `json:"TaskShellInfoStatus"` - TasksPromoteToBackgroundRequest TasksPromoteToBackgroundRequest `json:"TasksPromoteToBackgroundRequest"` - TasksPromoteToBackgroundResult TasksPromoteToBackgroundResult `json:"TasksPromoteToBackgroundResult"` - TasksRemoveRequest TasksRemoveRequest `json:"TasksRemoveRequest"` - TasksRemoveResult TasksRemoveResult `json:"TasksRemoveResult"` - TasksSendMessageRequest TasksSendMessageRequest `json:"TasksSendMessageRequest"` - TasksSendMessageResult TasksSendMessageResult `json:"TasksSendMessageResult"` - TasksStartAgentRequest TasksStartAgentRequest `json:"TasksStartAgentRequest"` - TasksStartAgentResult TasksStartAgentResult `json:"TasksStartAgentResult"` - Tool Tool `json:"Tool"` - ToolList ToolList `json:"ToolList"` - ToolsListRequest ToolsListRequest `json:"ToolsListRequest"` - UIElicitationArrayAnyOfField UIElicitationArrayAnyOfField `json:"UIElicitationArrayAnyOfField"` - UIElicitationArrayAnyOfFieldItems UIElicitationArrayAnyOfFieldItems `json:"UIElicitationArrayAnyOfFieldItems"` - UIElicitationArrayAnyOfFieldItemsAnyOf UIElicitationArrayAnyOfFieldItemsAnyOf `json:"UIElicitationArrayAnyOfFieldItemsAnyOf"` - UIElicitationArrayEnumField UIElicitationArrayEnumField `json:"UIElicitationArrayEnumField"` - UIElicitationArrayEnumFieldItems UIElicitationArrayEnumFieldItems `json:"UIElicitationArrayEnumFieldItems"` - UIElicitationFieldValue *UIElicitationFieldValue `json:"UIElicitationFieldValue"` - UIElicitationRequest UIElicitationRequest `json:"UIElicitationRequest"` - UIElicitationResponse UIElicitationResponse `json:"UIElicitationResponse"` - UIElicitationResponseAction UIElicitationResponseAction `json:"UIElicitationResponseAction"` - UIElicitationResponseContent map[string]*UIElicitationFieldValue `json:"UIElicitationResponseContent"` - UIElicitationResult UIElicitationResult `json:"UIElicitationResult"` - UIElicitationSchema UIElicitationSchema `json:"UIElicitationSchema"` - UIElicitationSchemaProperty UIElicitationSchemaProperty `json:"UIElicitationSchemaProperty"` - UIElicitationSchemaPropertyBoolean UIElicitationSchemaPropertyBoolean `json:"UIElicitationSchemaPropertyBoolean"` - UIElicitationSchemaPropertyNumber UIElicitationSchemaPropertyNumber `json:"UIElicitationSchemaPropertyNumber"` - UIElicitationSchemaPropertyNumberType UIElicitationSchemaPropertyNumberTypeEnum `json:"UIElicitationSchemaPropertyNumberType"` - UIElicitationSchemaPropertyString UIElicitationSchemaPropertyString `json:"UIElicitationSchemaPropertyString"` - UIElicitationSchemaPropertyStringFormat UIElicitationSchemaPropertyStringFormat `json:"UIElicitationSchemaPropertyStringFormat"` - UIElicitationStringEnumField UIElicitationStringEnumField `json:"UIElicitationStringEnumField"` - UIElicitationStringOneOfField UIElicitationStringOneOfField `json:"UIElicitationStringOneOfField"` - UIElicitationStringOneOfFieldOneOf UIElicitationStringOneOfFieldOneOf `json:"UIElicitationStringOneOfFieldOneOf"` - UIHandlePendingElicitationRequest UIHandlePendingElicitationRequest `json:"UIHandlePendingElicitationRequest"` - UsageGetMetricsResult UsageGetMetricsResult `json:"UsageGetMetricsResult"` - UsageMetricsCodeChanges UsageMetricsCodeChanges `json:"UsageMetricsCodeChanges"` - UsageMetricsModelMetric UsageMetricsModelMetric `json:"UsageMetricsModelMetric"` - UsageMetricsModelMetricRequests UsageMetricsModelMetricRequests `json:"UsageMetricsModelMetricRequests"` - UsageMetricsModelMetricTokenDetail UsageMetricsModelMetricTokenDetail `json:"UsageMetricsModelMetricTokenDetail"` - UsageMetricsModelMetricUsage UsageMetricsModelMetricUsage `json:"UsageMetricsModelMetricUsage"` - UsageMetricsTokenDetail UsageMetricsTokenDetail `json:"UsageMetricsTokenDetail"` - WorkspacesCreateFileRequest WorkspacesCreateFileRequest `json:"WorkspacesCreateFileRequest"` - WorkspacesCreateFileResult WorkspacesCreateFileResult `json:"WorkspacesCreateFileResult"` - WorkspacesGetWorkspaceResult WorkspacesGetWorkspaceResult `json:"WorkspacesGetWorkspaceResult"` - WorkspacesListFilesResult WorkspacesListFilesResult `json:"WorkspacesListFilesResult"` - WorkspacesReadFileRequest WorkspacesReadFileRequest `json:"WorkspacesReadFileRequest"` - WorkspacesReadFileResult WorkspacesReadFileResult `json:"WorkspacesReadFileResult"` -} - type AccountGetQuotaRequest struct { // GitHub token for per-user quota lookup. When provided, resolves this token to determine // the user's quota instead of using the global auth. @@ -299,17 +42,18 @@ type AccountQuotaSnapshot struct { UsedRequests int64 `json:"usedRequests"` } -// Experimental: AgentDeselectResult is part of an experimental API and may change or be removed. +// Experimental: AgentDeselectResult is part of an experimental API and may change or be +// removed. type AgentDeselectResult struct { } -// Experimental: AgentGetCurrentResult is part of an experimental API and may change or be removed. +// Experimental: AgentGetCurrentResult is part of an experimental API and may change or be +// removed. type AgentGetCurrentResult struct { // Currently selected custom agent, or null if using the default agent Agent *AgentInfo `json:"agent,omitempty"` } -// The newly selected custom agent type AgentInfo struct { // Description of the agent's purpose Description string `json:"description"` @@ -328,19 +72,22 @@ type AgentList struct { Agents []AgentInfo `json:"agents"` } -// Experimental: AgentReloadResult is part of an experimental API and may change or be removed. +// Experimental: AgentReloadResult is part of an experimental API and may change or be +// removed. type AgentReloadResult struct { // Reloaded custom agents Agents []AgentInfo `json:"agents"` } -// Experimental: AgentSelectRequest is part of an experimental API and may change or be removed. +// Experimental: AgentSelectRequest is part of an experimental API and may change or be +// removed. type AgentSelectRequest struct { // Name of the custom agent to select Name string `json:"name"` } -// Experimental: AgentSelectResult is part of an experimental API and may change or be removed. +// Experimental: AgentSelectResult is part of an experimental API and may change or be +// removed. type AgentSelectResult struct { // The newly selected custom agent Agent AgentInfo `json:"agent"` @@ -379,15 +126,15 @@ type CurrentModel struct { ModelID *string `json:"modelId,omitempty"` } -type DiscoveredMCPServer struct { +type DiscoveredMcpServer struct { // Whether the server is enabled (not in the disabled list) Enabled bool `json:"enabled"` // Server name (config key) Name string `json:"name"` // Configuration source - Source MCPServerSource `json:"source"` + Source DiscoveredMcpServerSource `json:"source"` // Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio) - Type *DiscoveredMCPServerType `json:"type,omitempty"` + Type *DiscoveredMcpServerType `json:"type,omitempty"` } type EmbeddedBlobResourceContents struct { @@ -414,7 +161,7 @@ type Extension struct { // Extension name (directory name) Name string `json:"name"` // Process ID if the extension is running - PID *int64 `json:"pid,omitempty"` + Pid *int64 `json:"pid,omitempty"` // Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) Source ExtensionSource `json:"source"` // Current status: running, disabled, failed, or starting @@ -427,30 +174,73 @@ type ExtensionList struct { Extensions []Extension `json:"extensions"` } -// Experimental: ExtensionsDisableRequest is part of an experimental API and may change or be removed. +// Experimental: ExtensionsDisableRequest is part of an experimental API and may change or +// be removed. type ExtensionsDisableRequest struct { // Source-qualified extension ID to disable ID string `json:"id"` } -// Experimental: ExtensionsDisableResult is part of an experimental API and may change or be removed. +// Experimental: ExtensionsDisableResult is part of an experimental API and may change or be +// removed. type ExtensionsDisableResult struct { } -// Experimental: ExtensionsEnableRequest is part of an experimental API and may change or be removed. +// Experimental: ExtensionsEnableRequest is part of an experimental API and may change or be +// removed. type ExtensionsEnableRequest struct { // Source-qualified extension ID to enable ID string `json:"id"` } -// Experimental: ExtensionsEnableResult is part of an experimental API and may change or be removed. +// Experimental: ExtensionsEnableResult is part of an experimental API and may change or be +// removed. type ExtensionsEnableResult struct { } -// Experimental: ExtensionsReloadResult is part of an experimental API and may change or be removed. +// Experimental: ExtensionsReloadResult is part of an experimental API and may change or be +// removed. type ExtensionsReloadResult struct { } +// Tool call result (string or expanded result object) +type ExternalToolResult struct { + ExternalToolTextResultForLlm *ExternalToolTextResultForLlm + String *string +} + +func (r ExternalToolResult) MarshalJSON() ([]byte, error) { + if r.ExternalToolTextResultForLlm != nil { + return json.Marshal(r.ExternalToolTextResultForLlm) + } + if r.String != nil { + return json.Marshal(r.String) + } + return []byte("null"), nil +} + +func (r *ExternalToolResult) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + *r = ExternalToolResult{} + return nil + } + { + var value ExternalToolTextResultForLlm + if err := json.Unmarshal(data, &value); err == nil { + *r = ExternalToolResult{ExternalToolTextResultForLlm: &value} + return nil + } + } + { + var value string + if err := json.Unmarshal(data, &value); err == nil { + *r = ExternalToolResult{String: &value} + return nil + } + } + return errors.New("data did not match any union variant for ExternalToolResult") +} + // Expanded external tool result payload type ExternalToolTextResultForLlm struct { // Structured content blocks from the tool @@ -470,79 +260,33 @@ type ExternalToolTextResultForLlm struct { // 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 ExternalToolTextResultForLlmContent struct { - // The text content - // - // Terminal/shell output text - Text *string `json:"text,omitempty"` - // Content block type discriminator - Type ExternalToolTextResultForLlmContentType `json:"type"` // Working directory where the command was executed Cwd *string `json:"cwd,omitempty"` - // Process exit code, if the command has completed - ExitCode *float64 `json:"exitCode,omitempty"` // Base64-encoded image data - // - // Base64-encoded audio data Data *string `json:"data,omitempty"` - // 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 - MIMEType *string `json:"mimeType,omitempty"` // Human-readable description of the resource Description *string `json:"description,omitempty"` + // Process exit code, if the command has completed + ExitCode *float64 `json:"exitCode,omitempty"` // Icons associated with this resource Icons []ExternalToolTextResultForLlmContentResourceLinkIcon `json:"icons,omitempty"` + // MIME type of the image (e.g., image/png, image/jpeg) + MIMEType *string `json:"mimeType,omitempty"` // Resource name identifier Name *string `json:"name,omitempty"` + // The embedded resource contents, either text or base64-encoded binary + Resource *ExternalToolTextResultForLlmContentResourceDetails `json:"resource,omitempty"` // Size of the resource in bytes Size *float64 `json:"size,omitempty"` + // The text content + Text *string `json:"text,omitempty"` // Human-readable display title for the resource Title *string `json:"title,omitempty"` + // Type discriminator + Type ExternalToolTextResultForLlmContentType `json:"type"` // URI identifying the resource URI *string `json:"uri,omitempty"` - // The embedded resource contents, either text or base64-encoded binary - Resource *ExternalToolTextResultForLlmContentResourceDetails `json:"resource,omitempty"` -} - -// Icon image for a resource -type ExternalToolTextResultForLlmContentResourceLinkIcon struct { - // MIME type of the icon image - MIMEType *string `json:"mimeType,omitempty"` - // Available icon sizes (e.g., ['16x16', '32x32']) - Sizes []string `json:"sizes,omitempty"` - // URL or path to the icon image - Src string `json:"src"` - // Theme variant this icon is intended for - Theme *ExternalToolTextResultForLlmContentResourceLinkIconTheme `json:"theme,omitempty"` -} - -// The embedded resource contents, either text or base64-encoded binary -type ExternalToolTextResultForLlmContentResourceDetails struct { - // MIME type of the text content - // - // MIME type of the blob content - MIMEType *string `json:"mimeType,omitempty"` - // Text content of the resource - Text *string `json:"text,omitempty"` - // URI identifying the resource - URI string `json:"uri"` - // Base64-encoded binary content of the resource - Blob *string `json:"blob,omitempty"` } // Audio content block with base64-encoded data @@ -573,6 +317,18 @@ type ExternalToolTextResultForLlmContentResource struct { Type ExternalToolTextResultForLlmContentResourceType `json:"type"` } +// The embedded resource contents, either text or base64-encoded binary +type ExternalToolTextResultForLlmContentResourceDetails struct { + // Base64-encoded binary content of the resource + Blob *string `json:"blob,omitempty"` + // MIME type of the text content + MIMEType *string `json:"mimeType,omitempty"` + // Text content of the resource + Text *string `json:"text,omitempty"` + // URI identifying the resource + URI string `json:"uri"` +} + // Resource link content block referencing an external resource type ExternalToolTextResultForLlmContentResourceLink struct { // Human-readable description of the resource @@ -593,6 +349,18 @@ type ExternalToolTextResultForLlmContentResourceLink struct { URI string `json:"uri"` } +// Icon image for a resource +type ExternalToolTextResultForLlmContentResourceLinkIcon struct { + // MIME type of the icon image + MIMEType *string `json:"mimeType,omitempty"` + // Available icon sizes (e.g., ['16x16', '32x32']) + Sizes []string `json:"sizes,omitempty"` + // URL or path to the icon image + Src string `json:"src"` + // Theme variant this icon is intended for + Theme *ExternalToolTextResultForLlmContentResourceLinkIconTheme `json:"theme,omitempty"` +} + // Terminal/shell output content block with optional exit code and working directory type ExternalToolTextResultForLlmContentTerminal struct { // Working directory where the command was executed @@ -613,13 +381,52 @@ type ExternalToolTextResultForLlmContentText struct { Type ExternalToolTextResultForLlmContentTextType `json:"type"` } -// Experimental: FleetStartRequest is part of an experimental API and may change or be removed. +type FilterMapping struct { + Enum *FilterMappingString + EnumMap map[string]FilterMappingValue +} + +func (r FilterMapping) MarshalJSON() ([]byte, error) { + if r.Enum != nil { + return json.Marshal(r.Enum) + } + if r.EnumMap != nil { + return json.Marshal(r.EnumMap) + } + return []byte("null"), nil +} + +func (r *FilterMapping) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + *r = FilterMapping{} + return nil + } + { + var value FilterMappingString + if err := json.Unmarshal(data, &value); err == nil { + *r = FilterMapping{Enum: &value} + return nil + } + } + { + var value map[string]FilterMappingValue + if err := json.Unmarshal(data, &value); err == nil { + *r = FilterMapping{EnumMap: value} + return nil + } + } + return errors.New("data did not match any union variant for FilterMapping") +} + +// Experimental: FleetStartRequest is part of an experimental API and may change or be +// removed. type FleetStartRequest struct { // Optional user prompt to combine with fleet instructions Prompt *string `json:"prompt,omitempty"` } -// Experimental: FleetStartResult is part of an experimental API and may change or be removed. +// Experimental: FleetStartResult is part of an experimental API and may change or be +// removed. type FleetStartResult struct { // Whether fleet mode was successfully activated Started bool `json:"started"` @@ -655,7 +462,8 @@ type HistoryCompactContextWindow struct { ToolDefinitionsTokens *int64 `json:"toolDefinitionsTokens,omitempty"` } -// Experimental: HistoryCompactResult is part of an experimental API and may change or be removed. +// Experimental: HistoryCompactResult is part of an experimental API and may change or be +// removed. type HistoryCompactResult struct { // Post-compaction context window usage breakdown ContextWindow *HistoryCompactContextWindow `json:"contextWindow,omitempty"` @@ -667,13 +475,15 @@ type HistoryCompactResult struct { TokensRemoved int64 `json:"tokensRemoved"` } -// Experimental: HistoryTruncateRequest is part of an experimental API and may change or be removed. +// Experimental: HistoryTruncateRequest is part of an experimental API and may change or be +// removed. type HistoryTruncateRequest struct { // Event ID to truncate to. This event and all events after it are removed from the session. EventID string `json:"eventId"` } -// Experimental: HistoryTruncateResult is part of an experimental API and may change or be removed. +// Experimental: HistoryTruncateResult is part of an experimental API and may change or be +// removed. type HistoryTruncateResult struct { // Number of events that were removed EventsRemoved int64 `json:"eventsRemoved"` @@ -720,106 +530,94 @@ type LogResult struct { EventID string `json:"eventId"` } -type MCPConfigAddRequest struct { +type McpConfigAddRequest struct { // MCP server configuration (local/stdio or remote/http) - Config MCPServerConfig `json:"config"` + Config McpServerConfig `json:"config"` // Unique name for the MCP server Name string `json:"name"` } -// MCP server configuration (local/stdio or remote/http) -type MCPServerConfig struct { - Args []string `json:"args,omitempty"` - Command *string `json:"command,omitempty"` - Cwd *string `json:"cwd,omitempty"` - Env map[string]string `json:"env,omitempty"` - FilterMapping *FilterMapping `json:"filterMapping,omitempty"` - IsDefaultServer *bool `json:"isDefaultServer,omitempty"` - // Timeout in milliseconds for tool calls to this server. - Timeout *int64 `json:"timeout,omitempty"` - // Tools to include. Defaults to all tools if not specified. - Tools []string `json:"tools,omitempty"` - // Remote transport type. Defaults to "http" when omitted. - Type *MCPServerConfigType `json:"type,omitempty"` - Headers map[string]string `json:"headers,omitempty"` - OauthClientID *string `json:"oauthClientId,omitempty"` - OauthGrantType *MCPServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"` - OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` - URL *string `json:"url,omitempty"` -} - -type MCPConfigAddResult struct { +type McpConfigAddResult struct { } -type MCPConfigDisableRequest struct { +type McpConfigDisableRequest struct { // Names of MCP servers to disable. Each server is added to the persisted disabled list so // new sessions skip it. Already-disabled names are ignored. Active sessions keep their // current connections until they end. Names []string `json:"names"` } -type MCPConfigDisableResult struct { +type McpConfigDisableResult struct { } -type MCPConfigEnableRequest struct { +type McpConfigEnableRequest struct { // Names of MCP servers to enable. Each server is removed from the persisted disabled list // so new sessions spawn it. Unknown or already-enabled names are ignored. Names []string `json:"names"` } -type MCPConfigEnableResult struct { +type McpConfigEnableResult struct { } -type MCPConfigList struct { +type McpConfigList struct { // All MCP servers from user config, keyed by name - Servers map[string]MCPServerConfig `json:"servers"` + Servers map[string]McpServerConfig `json:"servers"` } -type MCPConfigRemoveRequest struct { +type McpConfigRemoveRequest struct { // Name of the MCP server to remove Name string `json:"name"` } -type MCPConfigRemoveResult struct { +type McpConfigRemoveResult struct { } -type MCPConfigUpdateRequest struct { +type McpConfigUpdateRequest struct { // MCP server configuration (local/stdio or remote/http) - Config MCPServerConfig `json:"config"` + Config McpServerConfig `json:"config"` // Name of the MCP server to update Name string `json:"name"` } -type MCPConfigUpdateResult struct { +type McpConfigUpdateResult struct { } -type MCPDisableRequest struct { +// Experimental: McpDisableRequest is part of an experimental API and may change or be +// removed. +type McpDisableRequest struct { // Name of the MCP server to disable ServerName string `json:"serverName"` } -type MCPDisableResult struct { +// Experimental: McpDisableResult is part of an experimental API and may change or be +// removed. +type McpDisableResult struct { } -type MCPDiscoverRequest struct { +type McpDiscoverRequest struct { // Working directory used as context for discovery (e.g., plugin resolution) WorkingDirectory *string `json:"workingDirectory,omitempty"` } -type MCPDiscoverResult struct { +type McpDiscoverResult struct { // MCP servers discovered from all sources - Servers []DiscoveredMCPServer `json:"servers"` + Servers []DiscoveredMcpServer `json:"servers"` } -type MCPEnableRequest struct { +// Experimental: McpEnableRequest is part of an experimental API and may change or be +// removed. +type McpEnableRequest struct { // Name of the MCP server to enable ServerName string `json:"serverName"` } -type MCPEnableResult struct { +// Experimental: McpEnableResult is part of an experimental API and may change or be removed. +type McpEnableResult struct { } -type MCPOauthLoginRequest struct { +// Experimental: McpOauthLoginRequest is part of an experimental API and may change or be +// removed. +type McpOauthLoginRequest struct { // Optional override for the body text shown on the OAuth loopback callback success page. // When omitted, the runtime applies a neutral fallback; callers driving interactive auth // should pass surface-specific copy telling the user where to return. @@ -838,7 +636,9 @@ type MCPOauthLoginRequest struct { ServerName string `json:"serverName"` } -type MCPOauthLoginResult struct { +// Experimental: McpOauthLoginResult is part of an experimental API and may change or be +// removed. +type McpOauthLoginResult struct { // URL the caller should open in a browser to complete OAuth. Omitted when cached tokens // were still valid and no browser interaction was needed — the server is already // reconnected in that case. When present, the runtime starts the callback listener before @@ -847,37 +647,59 @@ type MCPOauthLoginResult struct { AuthorizationURL *string `json:"authorizationUrl,omitempty"` } -type MCPReloadResult struct { +// Experimental: McpReloadResult is part of an experimental API and may change or be removed. +type McpReloadResult struct { } -type MCPServer struct { +type McpServer struct { // Error message if the server failed to connect Error *string `json:"error,omitempty"` // Server name (config key) Name string `json:"name"` // Configuration source: user, workspace, plugin, or builtin - Source *MCPServerSource `json:"source,omitempty"` + Source *McpServerSource `json:"source,omitempty"` // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured - Status MCPServerStatus `json:"status"` + Status McpServerStatus `json:"status"` +} + +// MCP server configuration (local/stdio or remote/http) +type McpServerConfig struct { + Args []string `json:"args,omitempty"` + Command *string `json:"command,omitempty"` + Cwd *string `json:"cwd,omitempty"` + Env map[string]string `json:"env,omitempty"` + FilterMapping *FilterMapping `json:"filterMapping,omitempty"` + Headers map[string]string `json:"headers,omitempty"` + IsDefaultServer *bool `json:"isDefaultServer,omitempty"` + OauthClientID *string `json:"oauthClientId,omitempty"` + OauthGrantType *McpServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"` + OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` + // Timeout in milliseconds for tool calls to this server. + Timeout *int64 `json:"timeout,omitempty"` + // Tools to include. Defaults to all tools if not specified. + Tools []string `json:"tools,omitempty"` + // Remote transport type. Defaults to "http" when omitted. + Type *McpServerConfigType `json:"type,omitempty"` + URL *string `json:"url,omitempty"` } -type MCPServerConfigHTTP struct { +type McpServerConfigHTTP struct { FilterMapping *FilterMapping `json:"filterMapping,omitempty"` Headers map[string]string `json:"headers,omitempty"` IsDefaultServer *bool `json:"isDefaultServer,omitempty"` OauthClientID *string `json:"oauthClientId,omitempty"` - OauthGrantType *MCPServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"` + OauthGrantType *McpServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"` OauthPublicClient *bool `json:"oauthPublicClient,omitempty"` // Timeout in milliseconds for tool calls to this server. Timeout *int64 `json:"timeout,omitempty"` // Tools to include. Defaults to all tools if not specified. Tools []string `json:"tools,omitempty"` // Remote transport type. Defaults to "http" when omitted. - Type *MCPServerConfigHTTPType `json:"type,omitempty"` + Type *McpServerConfigHTTPType `json:"type,omitempty"` URL string `json:"url"` } -type MCPServerConfigLocal struct { +type McpServerConfigLocal struct { Args []string `json:"args"` Command string `json:"command"` Cwd *string `json:"cwd,omitempty"` @@ -888,23 +710,16 @@ type MCPServerConfigLocal struct { Timeout *int64 `json:"timeout,omitempty"` // Tools to include. Defaults to all tools if not specified. Tools []string `json:"tools,omitempty"` - Type *MCPServerConfigLocalType `json:"type,omitempty"` + Type *McpServerConfigLocalType `json:"type,omitempty"` } -type MCPServerList struct { +// Experimental: McpServerList is part of an experimental API and may change or be removed. +type McpServerList struct { // Configured MCP servers - Servers []MCPServer `json:"servers"` -} - -type ModeSetRequest struct { - // The agent mode. Valid values: "interactive", "plan", "autopilot". - Mode SessionMode `json:"mode"` -} - -type ModeSetResult struct { + Servers []McpServer `json:"servers"` } -type ModelElement struct { +type Model struct { // Billing information Billing *ModelBilling `json:"billing,omitempty"` // Model capabilities and limits @@ -949,30 +764,14 @@ type ModelCapabilitiesLimits struct { // Vision-specific limits type ModelCapabilitiesLimitsVision struct { - // Maximum image size in bytes - MaxPromptImageSize int64 `json:"max_prompt_image_size"` // Maximum number of images per prompt MaxPromptImages int64 `json:"max_prompt_images"` + // Maximum image size in bytes + MaxPromptImageSize int64 `json:"max_prompt_image_size"` // MIME types the model accepts SupportedMediaTypes []string `json:"supported_media_types"` } -// Feature flags indicating what the model supports -type ModelCapabilitiesSupports struct { - // Whether this model supports reasoning effort configuration - ReasoningEffort *bool `json:"reasoningEffort,omitempty"` - // Whether this model supports vision/image input - Vision *bool `json:"vision,omitempty"` -} - -// Policy state (if applicable) -type ModelPolicy struct { - // Current policy state for this model - State string `json:"state"` - // Usage terms or conditions for this model - Terms *string `json:"terms,omitempty"` -} - // Override individual model capabilities resolved by the runtime type ModelCapabilitiesOverride struct { // Token limits for prompts, outputs, and context window @@ -991,10 +790,10 @@ type ModelCapabilitiesOverrideLimits struct { } type ModelCapabilitiesOverrideLimitsVision struct { - // Maximum image size in bytes - MaxPromptImageSize *int64 `json:"max_prompt_image_size,omitempty"` // Maximum number of images per prompt MaxPromptImages *int64 `json:"max_prompt_images,omitempty"` + // Maximum image size in bytes + MaxPromptImageSize *int64 `json:"max_prompt_image_size,omitempty"` // MIME types the model accepts SupportedMediaTypes []string `json:"supported_media_types,omitempty"` } @@ -1005,9 +804,31 @@ type ModelCapabilitiesOverrideSupports struct { Vision *bool `json:"vision,omitempty"` } +// Feature flags indicating what the model supports +type ModelCapabilitiesSupports struct { + // Whether this model supports reasoning effort configuration + ReasoningEffort *bool `json:"reasoningEffort,omitempty"` + // Whether this model supports vision/image input + Vision *bool `json:"vision,omitempty"` +} + type ModelList struct { // List of available models with full metadata - Models []ModelElement `json:"models"` + Models []Model `json:"models"` +} + +// Policy state (if applicable) +type ModelPolicy struct { + // Current policy state for this model + State string `json:"state"` + // Usage terms or conditions for this model + Terms *string `json:"terms,omitempty"` +} + +type ModelsListRequest struct { + // GitHub token for per-user model listing. When provided, resolves this token to determine + // the user's Copilot plan and available models instead of using the global auth. + GitHubToken *string `json:"gitHubToken,omitempty"` } type ModelSwitchToRequest struct { @@ -1024,10 +845,12 @@ type ModelSwitchToResult struct { ModelID *string `json:"modelId,omitempty"` } -type ModelsListRequest struct { - // GitHub token for per-user model listing. When provided, resolves this token to determine - // the user's Copilot plan and available models instead of using the global auth. - GitHubToken *string `json:"gitHubToken,omitempty"` +type ModeSetRequest struct { + // The agent mode. Valid values: "interactive", "plan", "autopilot". + Mode SessionMode `json:"mode"` +} + +type ModeSetResult struct { } type NameGetResult struct { @@ -1044,30 +867,16 @@ type NameSetResult struct { } type PermissionDecision struct { - // 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 - // - // Approved and persisted across sessions - // - // Denied by the user during an interactive prompt - // - // Denied because user confirmation was unavailable - Kind PermissionDecisionKind `json:"kind"` // The approval to add as a session-scoped rule - // - // The approval to persist for this location - Approval *PermissionDecisionApproveForLocationApproval `json:"approval,omitempty"` + Approval *PermissionDecisionApproveForSessionApproval `json:"approval,omitempty"` // The URL domain to approve for this session - // - // The URL domain to approve permanently Domain *string `json:"domain,omitempty"` - // The location key (git root or cwd) to persist the approval to - LocationKey *string `json:"locationKey,omitempty"` // Optional feedback from the user explaining the denial Feedback *string `json:"feedback,omitempty"` + // Kind discriminator + Kind PermissionDecisionKind `json:"kind"` + // The location key (git root or cwd) to persist the approval to + LocationKey *string `json:"locationKey,omitempty"` } type PermissionDecisionApproveForLocation struct { @@ -1081,12 +890,13 @@ type PermissionDecisionApproveForLocation struct { // The approval to persist for this location type PermissionDecisionApproveForLocationApproval struct { - CommandIdentifiers []string `json:"commandIdentifiers,omitempty"` - Kind ApprovalKind `json:"kind"` - ServerName *string `json:"serverName,omitempty"` - ToolName *string `json:"toolName,omitempty"` - Operation *string `json:"operation,omitempty"` - ExtensionName *string `json:"extensionName,omitempty"` + CommandIdentifiers []string `json:"commandIdentifiers,omitempty"` + ExtensionName *string `json:"extensionName,omitempty"` + // Kind discriminator + Kind PermissionDecisionApproveForLocationApprovalKind `json:"kind"` + Operation *string `json:"operation,omitempty"` + ServerName *string `json:"serverName,omitempty"` + ToolName *string `json:"toolName,omitempty"` } type PermissionDecisionApproveForLocationApprovalCommands struct { @@ -1109,14 +919,14 @@ type PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess struc Kind PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind `json:"kind"` } -type PermissionDecisionApproveForLocationApprovalMCP struct { - Kind PermissionDecisionApproveForLocationApprovalMCPKind `json:"kind"` +type PermissionDecisionApproveForLocationApprovalMcp struct { + Kind PermissionDecisionApproveForLocationApprovalMcpKind `json:"kind"` ServerName string `json:"serverName"` ToolName *string `json:"toolName"` } -type PermissionDecisionApproveForLocationApprovalMCPSampling struct { - Kind PermissionDecisionApproveForLocationApprovalMCPSamplingKind `json:"kind"` +type PermissionDecisionApproveForLocationApprovalMcpSampling struct { + Kind PermissionDecisionApproveForLocationApprovalMcpSamplingKind `json:"kind"` ServerName string `json:"serverName"` } @@ -1143,55 +953,56 @@ type PermissionDecisionApproveForSession struct { // The approval to add as a session-scoped rule type PermissionDecisionApproveForSessionApproval struct { - CommandIdentifiers []string `json:"commandIdentifiers,omitempty"` - Kind ApprovalKind `json:"kind"` - ServerName *string `json:"serverName,omitempty"` - ToolName *string `json:"toolName,omitempty"` - Operation *string `json:"operation,omitempty"` - ExtensionName *string `json:"extensionName,omitempty"` + CommandIdentifiers []string `json:"commandIdentifiers,omitempty"` + ExtensionName *string `json:"extensionName,omitempty"` + // Kind discriminator + Kind PermissionDecisionApproveForSessionApprovalKind `json:"kind"` + Operation *string `json:"operation,omitempty"` + ServerName *string `json:"serverName,omitempty"` + ToolName *string `json:"toolName,omitempty"` } type PermissionDecisionApproveForSessionApprovalCommands struct { - CommandIdentifiers []string `json:"commandIdentifiers"` - Kind PermissionDecisionApproveForLocationApprovalCommandsKind `json:"kind"` + CommandIdentifiers []string `json:"commandIdentifiers"` + Kind PermissionDecisionApproveForSessionApprovalCommandsKind `json:"kind"` } type PermissionDecisionApproveForSessionApprovalCustomTool struct { - Kind PermissionDecisionApproveForLocationApprovalCustomToolKind `json:"kind"` - ToolName string `json:"toolName"` + Kind PermissionDecisionApproveForSessionApprovalCustomToolKind `json:"kind"` + ToolName string `json:"toolName"` } type PermissionDecisionApproveForSessionApprovalExtensionManagement struct { - Kind PermissionDecisionApproveForLocationApprovalExtensionManagementKind `json:"kind"` - Operation *string `json:"operation,omitempty"` + Kind PermissionDecisionApproveForSessionApprovalExtensionManagementKind `json:"kind"` + Operation *string `json:"operation,omitempty"` } type PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess struct { - ExtensionName string `json:"extensionName"` - Kind PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind `json:"kind"` + ExtensionName string `json:"extensionName"` + Kind PermissionDecisionApproveForSessionApprovalExtensionPermissionAccessKind `json:"kind"` } -type PermissionDecisionApproveForSessionApprovalMCP struct { - Kind PermissionDecisionApproveForLocationApprovalMCPKind `json:"kind"` - ServerName string `json:"serverName"` - ToolName *string `json:"toolName"` +type PermissionDecisionApproveForSessionApprovalMcp struct { + Kind PermissionDecisionApproveForSessionApprovalMcpKind `json:"kind"` + ServerName string `json:"serverName"` + ToolName *string `json:"toolName"` } -type PermissionDecisionApproveForSessionApprovalMCPSampling struct { - Kind PermissionDecisionApproveForLocationApprovalMCPSamplingKind `json:"kind"` - ServerName string `json:"serverName"` +type PermissionDecisionApproveForSessionApprovalMcpSampling struct { + Kind PermissionDecisionApproveForSessionApprovalMcpSamplingKind `json:"kind"` + ServerName string `json:"serverName"` } type PermissionDecisionApproveForSessionApprovalMemory struct { - Kind PermissionDecisionApproveForLocationApprovalMemoryKind `json:"kind"` + Kind PermissionDecisionApproveForSessionApprovalMemoryKind `json:"kind"` } type PermissionDecisionApproveForSessionApprovalRead struct { - Kind PermissionDecisionApproveForLocationApprovalReadKind `json:"kind"` + Kind PermissionDecisionApproveForSessionApprovalReadKind `json:"kind"` } type PermissionDecisionApproveForSessionApprovalWrite struct { - Kind PermissionDecisionApproveForLocationApprovalWriteKind `json:"kind"` + Kind PermissionDecisionApproveForSessionApprovalWriteKind `json:"kind"` } type PermissionDecisionApproveOnce struct { @@ -1281,7 +1092,7 @@ type PlanUpdateRequest struct { type PlanUpdateResult struct { } -type PluginElement struct { +type Plugin struct { // Whether the plugin is currently enabled Enabled bool `json:"enabled"` // Marketplace the plugin came from @@ -1295,14 +1106,16 @@ type PluginElement struct { // Experimental: PluginList is part of an experimental API and may change or be removed. type PluginList struct { // Installed plugins - Plugins []PluginElement `json:"plugins"` + Plugins []Plugin `json:"plugins"` } -// Experimental: RemoteDisableResult is part of an experimental API and may change or be removed. +// Experimental: RemoteDisableResult is part of an experimental API and may change or be +// removed. type RemoteDisableResult struct { } -// Experimental: RemoteEnableResult is part of an experimental API and may change or be removed. +// Experimental: RemoteEnableResult is part of an experimental API and may change or be +// removed. type RemoteEnableResult struct { // Whether remote steering is enabled RemoteSteerable bool `json:"remoteSteerable"` @@ -1347,7 +1160,7 @@ type SessionAuthStatus struct { StatusMessage *string `json:"statusMessage,omitempty"` } -type SessionFSAppendFileRequest struct { +type SessionFsAppendFileRequest struct { // Content to append Content string `json:"content"` // Optional POSIX-style mode for newly created files @@ -1359,26 +1172,26 @@ type SessionFSAppendFileRequest struct { } // Describes a filesystem error. -type SessionFSError struct { +type SessionFsError struct { // Error classification - Code SessionFSErrorCode `json:"code"` + Code SessionFsErrorCode `json:"code"` // Free-form detail about the error, for logging/diagnostics Message *string `json:"message,omitempty"` } -type SessionFSExistsRequest struct { +type SessionFsExistsRequest struct { // Path using SessionFs conventions Path string `json:"path"` // Target session identifier SessionID string `json:"sessionId"` } -type SessionFSExistsResult struct { +type SessionFsExistsResult struct { // Whether the path exists Exists bool `json:"exists"` } -type SessionFSMkdirRequest struct { +type SessionFsMkdirRequest struct { // Optional POSIX-style mode for newly created directories Mode *int64 `json:"mode,omitempty"` // Path using SessionFs conventions @@ -1389,56 +1202,56 @@ type SessionFSMkdirRequest struct { SessionID string `json:"sessionId"` } -type SessionFSReadFileRequest struct { +type SessionFsReaddirRequest struct { // Path using SessionFs conventions Path string `json:"path"` // Target session identifier SessionID string `json:"sessionId"` } -type SessionFSReadFileResult struct { - // File content as UTF-8 string - Content string `json:"content"` +type SessionFsReaddirResult struct { + // Entry names in the directory + Entries []string `json:"entries"` // Describes a filesystem error. - Error *SessionFSError `json:"error,omitempty"` + Error *SessionFsError `json:"error,omitempty"` +} + +type SessionFsReaddirWithTypesEntry struct { + // Entry name + Name string `json:"name"` + // Entry type + Type SessionFsReaddirWithTypesEntryType `json:"type"` } -type SessionFSReaddirRequest struct { +type SessionFsReaddirWithTypesRequest struct { // Path using SessionFs conventions Path string `json:"path"` // Target session identifier SessionID string `json:"sessionId"` } -type SessionFSReaddirResult struct { - // Entry names in the directory - Entries []string `json:"entries"` +type SessionFsReaddirWithTypesResult struct { + // Directory entries with type information + Entries []SessionFsReaddirWithTypesEntry `json:"entries"` // Describes a filesystem error. - Error *SessionFSError `json:"error,omitempty"` -} - -type SessionFSReaddirWithTypesEntry struct { - // Entry name - Name string `json:"name"` - // Entry type - Type SessionFSReaddirWithTypesEntryType `json:"type"` + Error *SessionFsError `json:"error,omitempty"` } -type SessionFSReaddirWithTypesRequest struct { +type SessionFsReadFileRequest struct { // Path using SessionFs conventions Path string `json:"path"` // Target session identifier SessionID string `json:"sessionId"` } -type SessionFSReaddirWithTypesResult struct { - // Directory entries with type information - Entries []SessionFSReaddirWithTypesEntry `json:"entries"` +type SessionFsReadFileResult struct { + // File content as UTF-8 string + Content string `json:"content"` // Describes a filesystem error. - Error *SessionFSError `json:"error,omitempty"` + Error *SessionFsError `json:"error,omitempty"` } -type SessionFSRenameRequest struct { +type SessionFsRenameRequest struct { // Destination path using SessionFs conventions Dest string `json:"dest"` // Target session identifier @@ -1447,7 +1260,7 @@ type SessionFSRenameRequest struct { Src string `json:"src"` } -type SessionFSRmRequest struct { +type SessionFsRmRequest struct { // Ignore errors if the path does not exist Force *bool `json:"force,omitempty"` // Path using SessionFs conventions @@ -1458,32 +1271,32 @@ type SessionFSRmRequest struct { SessionID string `json:"sessionId"` } -type SessionFSSetProviderRequest struct { +type SessionFsSetProviderRequest struct { // Path conventions used by this filesystem - Conventions SessionFSSetProviderConventions `json:"conventions"` + Conventions SessionFsSetProviderConventions `json:"conventions"` // Initial working directory for sessions InitialCwd string `json:"initialCwd"` // Path within each session's SessionFs where the runtime stores files for that session SessionStatePath string `json:"sessionStatePath"` } -type SessionFSSetProviderResult struct { +type SessionFsSetProviderResult struct { // Whether the provider was set successfully Success bool `json:"success"` } -type SessionFSStatRequest struct { +type SessionFsStatRequest struct { // Path using SessionFs conventions Path string `json:"path"` // Target session identifier SessionID string `json:"sessionId"` } -type SessionFSStatResult struct { +type SessionFsStatResult struct { // ISO 8601 timestamp of creation Birthtime time.Time `json:"birthtime"` // Describes a filesystem error. - Error *SessionFSError `json:"error,omitempty"` + Error *SessionFsError `json:"error,omitempty"` // Whether the path is a directory IsDirectory bool `json:"isDirectory"` // Whether the path is a file @@ -1494,7 +1307,7 @@ type SessionFSStatResult struct { Size int64 `json:"size"` } -type SessionFSWriteFileRequest struct { +type SessionFsWriteFileRequest struct { // Content to write Content string `json:"content"` // Optional POSIX-style mode for newly created files @@ -1505,7 +1318,8 @@ type SessionFSWriteFileRequest struct { SessionID string `json:"sessionId"` } -// Experimental: SessionsForkRequest is part of an experimental API and may change or be removed. +// Experimental: SessionsForkRequest is part of an experimental API and may change or be +// removed. type SessionsForkRequest struct { // Source session ID to fork from SessionID string `json:"sessionId"` @@ -1514,7 +1328,8 @@ type SessionsForkRequest struct { ToEventID *string `json:"toEventId,omitempty"` } -// Experimental: SessionsForkResult is part of an experimental API and may change or be removed. +// Experimental: SessionsForkResult is part of an experimental API and may change or be +// removed. type SessionsForkResult struct { // The new forked session's ID SessionID string `json:"sessionId"` @@ -1575,13 +1390,15 @@ type SkillsConfigSetDisabledSkillsRequest struct { type SkillsConfigSetDisabledSkillsResult struct { } -// Experimental: SkillsDisableRequest is part of an experimental API and may change or be removed. +// Experimental: SkillsDisableRequest is part of an experimental API and may change or be +// removed. type SkillsDisableRequest struct { // Name of the skill to disable Name string `json:"name"` } -// Experimental: SkillsDisableResult is part of an experimental API and may change or be removed. +// Experimental: SkillsDisableResult is part of an experimental API and may change or be +// removed. type SkillsDisableResult struct { } @@ -1592,17 +1409,20 @@ type SkillsDiscoverRequest struct { SkillDirectories []string `json:"skillDirectories,omitempty"` } -// Experimental: SkillsEnableRequest is part of an experimental API and may change or be removed. +// Experimental: SkillsEnableRequest is part of an experimental API and may change or be +// removed. type SkillsEnableRequest struct { // Name of the skill to enable Name string `json:"name"` } -// Experimental: SkillsEnableResult is part of an experimental API and may change or be removed. +// Experimental: SkillsEnableResult is part of an experimental API and may change or be +// removed. type SkillsEnableResult struct { } -// Experimental: SkillsReloadResult is part of an experimental API and may change or be removed. +// Experimental: SkillsReloadResult is part of an experimental API and may change or be +// removed. type SkillsReloadResult struct { } @@ -1613,7 +1433,7 @@ type TaskAgentInfo struct { // ISO 8601 timestamp when the current active period began ActiveStartedAt *time.Time `json:"activeStartedAt,omitempty"` // Accumulated active execution time in milliseconds - ActiveTimeMS *int64 `json:"activeTimeMs,omitempty"` + ActiveTimeMs *int64 `json:"activeTimeMs,omitempty"` // Type of agent running this task AgentType string `json:"agentType"` // Whether the task is currently in the original sync wait and can be moved to background @@ -1627,7 +1447,7 @@ type TaskAgentInfo struct { // Error message when the task failed Error *string `json:"error,omitempty"` // How the agent is currently being managed by the runtime - ExecutionMode *TaskInfoExecutionMode `json:"executionMode,omitempty"` + ExecutionMode *TaskAgentInfoExecutionMode `json:"executionMode,omitempty"` // Unique task identifier ID string `json:"id"` // ISO 8601 timestamp when the agent entered idle state @@ -1643,7 +1463,7 @@ type TaskAgentInfo struct { // ISO 8601 timestamp when the task was started StartedAt time.Time `json:"startedAt"` // Current lifecycle status of the task - Status TaskInfoStatus `json:"status"` + Status TaskAgentInfoStatus `json:"status"` // Tool call ID associated with this agent task ToolCallID string `json:"toolCallId"` // Task kind @@ -1654,33 +1474,38 @@ type TaskInfo struct { // ISO 8601 timestamp when the current active period began ActiveStartedAt *time.Time `json:"activeStartedAt,omitempty"` // Accumulated active execution time in milliseconds - ActiveTimeMS *int64 `json:"activeTimeMs,omitempty"` + ActiveTimeMs *int64 `json:"activeTimeMs,omitempty"` // Type of agent running this task AgentType *string `json:"agentType,omitempty"` + // Whether the shell runs inside a managed PTY session or as an independent background + // process + AttachmentMode *TaskShellInfoAttachmentMode `json:"attachmentMode,omitempty"` // 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 CanPromoteToBackground *bool `json:"canPromoteToBackground,omitempty"` - // ISO 8601 timestamp when the task finished + // Command being executed + Command *string `json:"command,omitempty"` + // ISO 8601 timestamp when the task finished CompletedAt *time.Time `json:"completedAt,omitempty"` // Short description of the task Description string `json:"description"` // Error message when the task failed Error *string `json:"error,omitempty"` // How the agent is currently being managed by the runtime - // - // Whether the shell command is currently sync-waited or background-managed - ExecutionMode *TaskInfoExecutionMode `json:"executionMode,omitempty"` + ExecutionMode *TaskAgentInfoExecutionMode `json:"executionMode,omitempty"` // Unique task identifier ID string `json:"id"` // ISO 8601 timestamp when the agent entered idle state IdleSince *time.Time `json:"idleSince,omitempty"` // Most recent response text from the agent LatestResponse *string `json:"latestResponse,omitempty"` + // Path to the detached shell log, when available + LogPath *string `json:"logPath,omitempty"` // Model used for the task when specified Model *string `json:"model,omitempty"` + // Process ID when available + Pid *int64 `json:"pid,omitempty"` // Prompt passed to the agent Prompt *string `json:"prompt,omitempty"` // Result text from the task when available @@ -1688,20 +1513,11 @@ type TaskInfo struct { // ISO 8601 timestamp when the task was started StartedAt time.Time `json:"startedAt"` // Current lifecycle status of the task - Status TaskInfoStatus `json:"status"` + Status TaskAgentInfoStatus `json:"status"` // Tool call ID associated with this agent task ToolCallID *string `json:"toolCallId,omitempty"` - // Task kind + // Type discriminator Type TaskInfoType `json:"type"` - // Whether the shell runs inside a managed PTY session or as an independent background - // process - AttachmentMode *TaskShellInfoAttachmentMode `json:"attachmentMode,omitempty"` - // Command being executed - Command *string `json:"command,omitempty"` - // Path to the detached shell log, when available - LogPath *string `json:"logPath,omitempty"` - // Process ID when available - PID *int64 `json:"pid,omitempty"` } // Experimental: TaskList is part of an experimental API and may change or be removed. @@ -1710,6 +1526,20 @@ type TaskList struct { Tasks []TaskInfo `json:"tasks"` } +// Experimental: TasksCancelRequest is part of an experimental API and may change or be +// removed. +type TasksCancelRequest struct { + // Task identifier + ID string `json:"id"` +} + +// Experimental: TasksCancelResult is part of an experimental API and may change or be +// removed. +type TasksCancelResult struct { + // Whether the task was successfully cancelled + Cancelled bool `json:"cancelled"` +} + type TaskShellInfo struct { // Whether the shell runs inside a managed PTY session or as an independent background // process @@ -1723,59 +1553,52 @@ type TaskShellInfo struct { // Short description of the task Description string `json:"description"` // Whether the shell command is currently sync-waited or background-managed - ExecutionMode *TaskInfoExecutionMode `json:"executionMode,omitempty"` + ExecutionMode *TaskShellInfoExecutionMode `json:"executionMode,omitempty"` // Unique task identifier ID string `json:"id"` // Path to the detached shell log, when available LogPath *string `json:"logPath,omitempty"` // Process ID when available - PID *int64 `json:"pid,omitempty"` + Pid *int64 `json:"pid,omitempty"` // ISO 8601 timestamp when the task was started StartedAt time.Time `json:"startedAt"` // Current lifecycle status of the task - Status TaskInfoStatus `json:"status"` + Status TaskShellInfoStatus `json:"status"` // Task kind Type TaskShellInfoType `json:"type"` } -// Experimental: TasksCancelRequest is part of an experimental API and may change or be removed. -type TasksCancelRequest struct { - // Task identifier - ID string `json:"id"` -} - -// Experimental: TasksCancelResult is part of an experimental API and may change or be removed. -type TasksCancelResult struct { - // Whether the task was successfully cancelled - Cancelled bool `json:"cancelled"` -} - -// Experimental: TasksPromoteToBackgroundRequest is part of an experimental API and may change or be removed. +// Experimental: TasksPromoteToBackgroundRequest is part of an experimental API and may +// change or be removed. type TasksPromoteToBackgroundRequest struct { // Task identifier ID string `json:"id"` } -// Experimental: TasksPromoteToBackgroundResult is part of an experimental API and may change or be removed. +// Experimental: TasksPromoteToBackgroundResult is part of an experimental API and may +// change or be removed. type TasksPromoteToBackgroundResult struct { // Whether the task was successfully promoted to background mode Promoted bool `json:"promoted"` } -// Experimental: TasksRemoveRequest is part of an experimental API and may change or be removed. +// Experimental: TasksRemoveRequest is part of an experimental API and may change or be +// removed. type TasksRemoveRequest struct { // Task identifier ID string `json:"id"` } -// Experimental: TasksRemoveResult is part of an experimental API and may change or be removed. +// Experimental: TasksRemoveResult is part of an experimental API and may change or be +// removed. type TasksRemoveResult struct { // Whether the task was removed. Returns false if the task does not exist or is still // running/idle (cancel it first). Removed bool `json:"removed"` } -// Experimental: TasksSendMessageRequest is part of an experimental API and may change or be removed. +// Experimental: TasksSendMessageRequest is part of an experimental API and may change or be +// removed. type TasksSendMessageRequest struct { // Agent ID of the sender, if sent on behalf of another agent FromAgentID *string `json:"fromAgentId,omitempty"` @@ -1785,7 +1608,8 @@ type TasksSendMessageRequest struct { Message string `json:"message"` } -// Experimental: TasksSendMessageResult is part of an experimental API and may change or be removed. +// Experimental: TasksSendMessageResult is part of an experimental API and may change or be +// removed. type TasksSendMessageResult struct { // Error message if delivery failed Error *string `json:"error,omitempty"` @@ -1793,7 +1617,8 @@ type TasksSendMessageResult struct { Sent bool `json:"sent"` } -// Experimental: TasksStartAgentRequest is part of an experimental API and may change or be removed. +// Experimental: TasksStartAgentRequest is part of an experimental API and may change or be +// removed. type TasksStartAgentRequest struct { // Type of agent to start (e.g., 'explore', 'task', 'general-purpose') AgentType string `json:"agentType"` @@ -1807,7 +1632,8 @@ type TasksStartAgentRequest struct { Prompt string `json:"prompt"` } -// Experimental: TasksStartAgentResult is part of an experimental API and may change or be removed. +// Experimental: TasksStartAgentResult is part of an experimental API and may change or be +// removed. type TasksStartAgentResult struct { // Generated agent ID for the background task AgentID string `json:"agentId"` @@ -1864,7 +1690,7 @@ type UIElicitationArrayEnumField struct { MaxItems *float64 `json:"maxItems,omitempty"` MinItems *float64 `json:"minItems,omitempty"` Title *string `json:"title,omitempty"` - Type UIElicitationArrayAnyOfFieldType `json:"type"` + Type UIElicitationArrayEnumFieldType `json:"type"` } type UIElicitationArrayEnumFieldItems struct { @@ -1872,6 +1698,65 @@ type UIElicitationArrayEnumFieldItems struct { Type UIElicitationArrayEnumFieldItemsType `json:"type"` } +type UIElicitationFieldValue struct { + Bool *bool + Double *float64 + String *string + StringArray []string +} + +func (r UIElicitationFieldValue) MarshalJSON() ([]byte, error) { + if r.Bool != nil { + return json.Marshal(r.Bool) + } + if r.Double != nil { + return json.Marshal(r.Double) + } + if r.String != nil { + return json.Marshal(r.String) + } + if r.StringArray != nil { + return json.Marshal(r.StringArray) + } + return []byte("null"), nil +} + +func (r *UIElicitationFieldValue) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + *r = UIElicitationFieldValue{} + return nil + } + { + var value bool + if err := json.Unmarshal(data, &value); err == nil { + *r = UIElicitationFieldValue{Bool: &value} + return nil + } + } + { + var value float64 + if err := json.Unmarshal(data, &value); err == nil { + *r = UIElicitationFieldValue{Double: &value} + return nil + } + } + { + var value string + if err := json.Unmarshal(data, &value); err == nil { + *r = UIElicitationFieldValue{String: &value} + return nil + } + } + { + var value []string + if err := json.Unmarshal(data, &value); err == nil { + *r = UIElicitationFieldValue{StringArray: value} + return nil + } + } + return errors.New("data did not match any union variant for UIElicitationFieldValue") +} + type UIElicitationRequest struct { // Message describing what information is needed from the user Message string `json:"message"` @@ -1879,6 +1764,23 @@ type UIElicitationRequest struct { RequestedSchema UIElicitationSchema `json:"requestedSchema"` } +// The elicitation response (accept with form values, decline, or cancel) +type UIElicitationResponse struct { + // The user's response: accept (submitted), decline (rejected), or cancel (dismissed) + Action UIElicitationResponseAction `json:"action"` + // The form values submitted by the user (present when action is 'accept') + Content map[string]*UIElicitationFieldValue `json:"content,omitempty"` +} + +// The form values submitted by the user (present when action is 'accept') +type UIElicitationResponseContent map[string]*UIElicitationFieldValue + +type UIElicitationResult struct { + // Whether the response was accepted. False if the request was already resolved by another + // client. + Success bool `json:"success"` +} + // JSON Schema describing the form fields to present to the user type UIElicitationSchema struct { // Form field definitions, keyed by field name @@ -1894,42 +1796,17 @@ type UIElicitationSchemaProperty struct { Description *string `json:"description,omitempty"` Enum []string `json:"enum,omitempty"` EnumNames []string `json:"enumNames,omitempty"` - Title *string `json:"title,omitempty"` - Type UIElicitationSchemaPropertyType `json:"type"` - OneOf []UIElicitationStringOneOfFieldOneOf `json:"oneOf,omitempty"` - Items *UIElicitationArrayFieldItems `json:"items,omitempty"` - MaxItems *float64 `json:"maxItems,omitempty"` - MinItems *float64 `json:"minItems,omitempty"` Format *UIElicitationSchemaPropertyStringFormat `json:"format,omitempty"` - MaxLength *float64 `json:"maxLength,omitempty"` - MinLength *float64 `json:"minLength,omitempty"` + Items *UIElicitationSchemaPropertyItems `json:"items,omitempty"` Maximum *float64 `json:"maximum,omitempty"` + MaxItems *float64 `json:"maxItems,omitempty"` + MaxLength *float64 `json:"maxLength,omitempty"` Minimum *float64 `json:"minimum,omitempty"` -} - -type UIElicitationArrayFieldItems struct { - Enum []string `json:"enum,omitempty"` - Type *UIElicitationArrayEnumFieldItemsType `json:"type,omitempty"` - AnyOf []UIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf,omitempty"` -} - -type UIElicitationStringOneOfFieldOneOf struct { - Const string `json:"const"` - Title string `json:"title"` -} - -// The elicitation response (accept with form values, decline, or cancel) -type UIElicitationResponse struct { - // The user's response: accept (submitted), decline (rejected), or cancel (dismissed) - Action UIElicitationResponseAction `json:"action"` - // The form values submitted by the user (present when action is 'accept') - Content map[string]*UIElicitationFieldValue `json:"content,omitempty"` -} - -type UIElicitationResult struct { - // Whether the response was accepted. False if the request was already resolved by another - // client. - Success bool `json:"success"` + MinItems *float64 `json:"minItems,omitempty"` + MinLength *float64 `json:"minLength,omitempty"` + OneOf []UIElicitationStringOneOfFieldOneOf `json:"oneOf,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationSchemaPropertyType `json:"type"` } type UIElicitationSchemaPropertyBoolean struct { @@ -1939,13 +1816,19 @@ type UIElicitationSchemaPropertyBoolean struct { Type UIElicitationSchemaPropertyBooleanType `json:"type"` } +type UIElicitationSchemaPropertyItems struct { + AnyOf []UIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf,omitempty"` + Enum []string `json:"enum,omitempty"` + Type *UIElicitationSchemaPropertyItemsType `json:"type,omitempty"` +} + type UIElicitationSchemaPropertyNumber struct { - Default *float64 `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Maximum *float64 `json:"maximum,omitempty"` - Minimum *float64 `json:"minimum,omitempty"` - Title *string `json:"title,omitempty"` - Type UIElicitationSchemaPropertyNumberTypeEnum `json:"type"` + Default *float64 `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationSchemaPropertyNumberType `json:"type"` } type UIElicitationSchemaPropertyString struct { @@ -1955,16 +1838,16 @@ type UIElicitationSchemaPropertyString struct { MaxLength *float64 `json:"maxLength,omitempty"` MinLength *float64 `json:"minLength,omitempty"` Title *string `json:"title,omitempty"` - Type UIElicitationArrayEnumFieldItemsType `json:"type"` + Type UIElicitationSchemaPropertyStringType `json:"type"` } type UIElicitationStringEnumField struct { - Default *string `json:"default,omitempty"` - Description *string `json:"description,omitempty"` - Enum []string `json:"enum"` - EnumNames []string `json:"enumNames,omitempty"` - Title *string `json:"title,omitempty"` - Type UIElicitationArrayEnumFieldItemsType `json:"type"` + Default *string `json:"default,omitempty"` + Description *string `json:"description,omitempty"` + Enum []string `json:"enum"` + EnumNames []string `json:"enumNames,omitempty"` + Title *string `json:"title,omitempty"` + Type UIElicitationStringEnumFieldType `json:"type"` } type UIElicitationStringOneOfField struct { @@ -1972,7 +1855,12 @@ type UIElicitationStringOneOfField struct { Description *string `json:"description,omitempty"` OneOf []UIElicitationStringOneOfFieldOneOf `json:"oneOf"` Title *string `json:"title,omitempty"` - Type UIElicitationArrayEnumFieldItemsType `json:"type"` + Type UIElicitationStringOneOfFieldType `json:"type"` +} + +type UIElicitationStringOneOfFieldOneOf struct { + Const string `json:"const"` + Title string `json:"title"` } type UIHandlePendingElicitationRequest struct { @@ -1982,7 +1870,8 @@ type UIHandlePendingElicitationRequest struct { Result UIElicitationResponse `json:"result"` } -// Experimental: UsageGetMetricsResult is part of an experimental API and may change or be removed. +// Experimental: UsageGetMetricsResult is part of an experimental API and may change or be +// removed. type UsageGetMetricsResult struct { // Aggregated code change metrics CodeChanges UsageMetricsCodeChanges `json:"codeChanges"` @@ -1999,7 +1888,7 @@ type UsageGetMetricsResult struct { // Session-wide per-token-type accumulated token counts TokenDetails map[string]UsageMetricsTokenDetail `json:"tokenDetails,omitempty"` // Total time spent in model API calls (milliseconds) - TotalAPIDurationMS float64 `json:"totalApiDurationMs"` + TotalAPIDurationMs float64 `json:"totalApiDurationMs"` // Session-wide accumulated nano-AI units cost TotalNanoAiu *int64 `json:"totalNanoAiu,omitempty"` // Total user-initiated premium request cost across all models (may be fractional due to @@ -2074,27 +1963,27 @@ type WorkspacesCreateFileResult struct { type WorkspacesGetWorkspaceResult struct { // Current workspace metadata, or null if not available - Workspace *WorkspaceClass `json:"workspace"` -} - -type WorkspaceClass struct { - Branch *string `json:"branch,omitempty"` - ChronicleSyncDismissed *bool `json:"chronicle_sync_dismissed,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - Cwd *string `json:"cwd,omitempty"` - GitRoot *string `json:"git_root,omitempty"` - HostType *HostType `json:"host_type,omitempty"` - ID string `json:"id"` - McLastEventID *string `json:"mc_last_event_id,omitempty"` - McSessionID *string `json:"mc_session_id,omitempty"` - McTaskID *string `json:"mc_task_id,omitempty"` - Name *string `json:"name,omitempty"` - RemoteSteerable *bool `json:"remote_steerable,omitempty"` - Repository *string `json:"repository,omitempty"` - Summary *string `json:"summary,omitempty"` - SummaryCount *int64 `json:"summary_count,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - UserNamed *bool `json:"user_named,omitempty"` + Workspace *WorkspacesGetWorkspaceResultWorkspace `json:"workspace"` +} + +type WorkspacesGetWorkspaceResultWorkspace struct { + Branch *string `json:"branch,omitempty"` + ChronicleSyncDismissed *bool `json:"chronicle_sync_dismissed,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + Cwd *string `json:"cwd,omitempty"` + GitRoot *string `json:"git_root,omitempty"` + HostType *WorkspacesGetWorkspaceResultWorkspaceHostType `json:"host_type,omitempty"` + ID string `json:"id"` + McLastEventID *string `json:"mc_last_event_id,omitempty"` + McSessionID *string `json:"mc_session_id,omitempty"` + McTaskID *string `json:"mc_task_id,omitempty"` + Name *string `json:"name,omitempty"` + RemoteSteerable *bool `json:"remote_steerable,omitempty"` + Repository *string `json:"repository,omitempty"` + Summary *string `json:"summary,omitempty"` + SummaryCount *int64 `json:"summary_count,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + UserNamed *bool `json:"user_named,omitempty"` } type WorkspacesListFilesResult struct { @@ -2117,42 +2006,40 @@ type AuthInfoType string const ( AuthInfoTypeAPIKey AuthInfoType = "api-key" - AuthInfoTypeUser AuthInfoType = "user" AuthInfoTypeCopilotAPIToken AuthInfoType = "copilot-api-token" AuthInfoTypeEnv AuthInfoType = "env" AuthInfoTypeGhCli AuthInfoType = "gh-cli" AuthInfoTypeHmac AuthInfoType = "hmac" AuthInfoTypeToken AuthInfoType = "token" + AuthInfoTypeUser AuthInfoType = "user" ) // Configuration source -// -// Configuration source: user, workspace, plugin, or builtin -type MCPServerSource string +type DiscoveredMcpServerSource string const ( - MCPServerSourceBuiltin MCPServerSource = "builtin" - MCPServerSourceUser MCPServerSource = "user" - MCPServerSourcePlugin MCPServerSource = "plugin" - MCPServerSourceWorkspace MCPServerSource = "workspace" + DiscoveredMcpServerSourceBuiltin DiscoveredMcpServerSource = "builtin" + DiscoveredMcpServerSourcePlugin DiscoveredMcpServerSource = "plugin" + DiscoveredMcpServerSourceUser DiscoveredMcpServerSource = "user" + DiscoveredMcpServerSourceWorkspace DiscoveredMcpServerSource = "workspace" ) // Server transport type: stdio, http, sse, or memory (local configs are normalized to stdio) -type DiscoveredMCPServerType string +type DiscoveredMcpServerType string const ( - DiscoveredMCPServerTypeHTTP DiscoveredMCPServerType = "http" - DiscoveredMCPServerTypeMemory DiscoveredMCPServerType = "memory" - DiscoveredMCPServerTypeSSE DiscoveredMCPServerType = "sse" - DiscoveredMCPServerTypeStdio DiscoveredMCPServerType = "stdio" + DiscoveredMcpServerTypeHTTP DiscoveredMcpServerType = "http" + DiscoveredMcpServerTypeMemory DiscoveredMcpServerType = "memory" + DiscoveredMcpServerTypeSse DiscoveredMcpServerType = "sse" + DiscoveredMcpServerTypeStdio DiscoveredMcpServerType = "stdio" ) // Discovery source: project (.github/extensions/) or user (~/.copilot/extensions/) type ExtensionSource string const ( - ExtensionSourceUser ExtensionSource = "user" ExtensionSourceProject ExtensionSource = "project" + ExtensionSourceUser ExtensionSource = "user" ) // Current status: running, disabled, failed, or starting @@ -2165,61 +2052,68 @@ const ( ExtensionStatusStarting ExtensionStatus = "starting" ) -// Theme variant this icon is intended for -type ExternalToolTextResultForLlmContentResourceLinkIconTheme string - -const ( - ExternalToolTextResultForLlmContentResourceLinkIconThemeDark ExternalToolTextResultForLlmContentResourceLinkIconTheme = "dark" - ExternalToolTextResultForLlmContentResourceLinkIconThemeLight ExternalToolTextResultForLlmContentResourceLinkIconTheme = "light" -) - -type ExternalToolTextResultForLlmContentType string - -const ( - ExternalToolTextResultForLlmContentTypeAudio ExternalToolTextResultForLlmContentType = "audio" - ExternalToolTextResultForLlmContentTypeImage ExternalToolTextResultForLlmContentType = "image" - ExternalToolTextResultForLlmContentTypeResource ExternalToolTextResultForLlmContentType = "resource" - ExternalToolTextResultForLlmContentTypeResourceLink ExternalToolTextResultForLlmContentType = "resource_link" - ExternalToolTextResultForLlmContentTypeTerminal ExternalToolTextResultForLlmContentType = "terminal" - ExternalToolTextResultForLlmContentTypeText ExternalToolTextResultForLlmContentType = "text" -) - +// Content block type discriminator type ExternalToolTextResultForLlmContentAudioType string const ( ExternalToolTextResultForLlmContentAudioTypeAudio ExternalToolTextResultForLlmContentAudioType = "audio" ) +// Content block type discriminator type ExternalToolTextResultForLlmContentImageType string const ( ExternalToolTextResultForLlmContentImageTypeImage ExternalToolTextResultForLlmContentImageType = "image" ) -type ExternalToolTextResultForLlmContentResourceType string +// Theme variant this icon is intended for +type ExternalToolTextResultForLlmContentResourceLinkIconTheme string const ( - ExternalToolTextResultForLlmContentResourceTypeResource ExternalToolTextResultForLlmContentResourceType = "resource" + ExternalToolTextResultForLlmContentResourceLinkIconThemeDark ExternalToolTextResultForLlmContentResourceLinkIconTheme = "dark" + ExternalToolTextResultForLlmContentResourceLinkIconThemeLight ExternalToolTextResultForLlmContentResourceLinkIconTheme = "light" ) +// Content block type discriminator type ExternalToolTextResultForLlmContentResourceLinkType string const ( ExternalToolTextResultForLlmContentResourceLinkTypeResourceLink ExternalToolTextResultForLlmContentResourceLinkType = "resource_link" ) +// Content block type discriminator +type ExternalToolTextResultForLlmContentResourceType string + +const ( + ExternalToolTextResultForLlmContentResourceTypeResource ExternalToolTextResultForLlmContentResourceType = "resource" +) + +// Content block type discriminator type ExternalToolTextResultForLlmContentTerminalType string const ( ExternalToolTextResultForLlmContentTerminalTypeTerminal ExternalToolTextResultForLlmContentTerminalType = "terminal" ) +// Content block type discriminator type ExternalToolTextResultForLlmContentTextType string const ( ExternalToolTextResultForLlmContentTextTypeText ExternalToolTextResultForLlmContentTextType = "text" ) +// Type discriminator for ExternalToolTextResultForLlmContent. +type ExternalToolTextResultForLlmContentType string + +const ( + ExternalToolTextResultForLlmContentTypeAudio ExternalToolTextResultForLlmContentType = "audio" + ExternalToolTextResultForLlmContentTypeImage ExternalToolTextResultForLlmContentType = "image" + ExternalToolTextResultForLlmContentTypeResource ExternalToolTextResultForLlmContentType = "resource" + ExternalToolTextResultForLlmContentTypeResourceLink ExternalToolTextResultForLlmContentType = "resource_link" + ExternalToolTextResultForLlmContentTypeTerminal ExternalToolTextResultForLlmContentType = "terminal" + ExternalToolTextResultForLlmContentTypeText ExternalToolTextResultForLlmContentType = "text" +) + type FilterMappingString string const ( @@ -2228,12 +2122,20 @@ const ( FilterMappingStringNone FilterMappingString = "none" ) +type FilterMappingValue string + +const ( + FilterMappingValueHiddenCharacters FilterMappingValue = "hidden_characters" + FilterMappingValueMarkdown FilterMappingValue = "markdown" + FilterMappingValueNone FilterMappingValue = "none" +) + // Where this source lives — used for UI grouping type InstructionsSourcesLocation string const ( - InstructionsSourcesLocationUser InstructionsSourcesLocation = "user" InstructionsSourcesLocationRepository InstructionsSourcesLocation = "repository" + InstructionsSourcesLocationUser InstructionsSourcesLocation = "user" InstructionsSourcesLocationWorkingDirectory InstructionsSourcesLocation = "working-directory" ) @@ -2249,98 +2151,57 @@ const ( InstructionsSourcesTypeVscode InstructionsSourcesType = "vscode" ) -// Log severity level. Determines how the message is displayed in the timeline. Defaults to -// "info". -type SessionLogLevel string - -const ( - SessionLogLevelError SessionLogLevel = "error" - SessionLogLevelInfo SessionLogLevel = "info" - SessionLogLevelWarning SessionLogLevel = "warning" -) - -type MCPServerConfigHTTPOauthGrantType string - -const ( - MCPServerConfigHTTPOauthGrantTypeAuthorizationCode MCPServerConfigHTTPOauthGrantType = "authorization_code" - MCPServerConfigHTTPOauthGrantTypeClientCredentials MCPServerConfigHTTPOauthGrantType = "client_credentials" -) - -// Remote transport type. Defaults to "http" when omitted. -type MCPServerConfigType string - -const ( - MCPServerConfigTypeHTTP MCPServerConfigType = "http" - MCPServerConfigTypeLocal MCPServerConfigType = "local" - MCPServerConfigTypeSSE MCPServerConfigType = "sse" - MCPServerConfigTypeStdio MCPServerConfigType = "stdio" -) - -// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured -type MCPServerStatus string +type McpServerConfigHTTPOauthGrantType string const ( - MCPServerStatusConnected MCPServerStatus = "connected" - MCPServerStatusDisabled MCPServerStatus = "disabled" - MCPServerStatusFailed MCPServerStatus = "failed" - MCPServerStatusNeedsAuth MCPServerStatus = "needs-auth" - MCPServerStatusNotConfigured MCPServerStatus = "not_configured" - MCPServerStatusPending MCPServerStatus = "pending" + McpServerConfigHTTPOauthGrantTypeAuthorizationCode McpServerConfigHTTPOauthGrantType = "authorization_code" + McpServerConfigHTTPOauthGrantTypeClientCredentials McpServerConfigHTTPOauthGrantType = "client_credentials" ) // Remote transport type. Defaults to "http" when omitted. -type MCPServerConfigHTTPType string +type McpServerConfigHTTPType string const ( - MCPServerConfigHTTPTypeHTTP MCPServerConfigHTTPType = "http" - MCPServerConfigHTTPTypeSSE MCPServerConfigHTTPType = "sse" + McpServerConfigHTTPTypeHTTP McpServerConfigHTTPType = "http" + McpServerConfigHTTPTypeSse McpServerConfigHTTPType = "sse" ) -type MCPServerConfigLocalType string +type McpServerConfigLocalType string const ( - MCPServerConfigLocalTypeLocal MCPServerConfigLocalType = "local" - MCPServerConfigLocalTypeStdio MCPServerConfigLocalType = "stdio" -) - -// The agent mode. Valid values: "interactive", "plan", "autopilot". -type SessionMode string - -const ( - SessionModeAutopilot SessionMode = "autopilot" - SessionModeInteractive SessionMode = "interactive" - SessionModePlan SessionMode = "plan" + McpServerConfigLocalTypeLocal McpServerConfigLocalType = "local" + McpServerConfigLocalTypeStdio McpServerConfigLocalType = "stdio" ) -type ApprovalKind string +type McpServerConfigType string const ( - ApprovalKindCommands ApprovalKind = "commands" - ApprovalKindCustomTool ApprovalKind = "custom-tool" - ApprovalKindExtensionManagement ApprovalKind = "extension-management" - ApprovalKindExtensionPermissionAccess ApprovalKind = "extension-permission-access" - ApprovalKindMcp ApprovalKind = "mcp" - ApprovalKindMcpSampling ApprovalKind = "mcp-sampling" - ApprovalKindMemory ApprovalKind = "memory" - ApprovalKindRead ApprovalKind = "read" - ApprovalKindWrite ApprovalKind = "write" + McpServerConfigTypeHTTP McpServerConfigType = "http" + McpServerConfigTypeLocal McpServerConfigType = "local" + McpServerConfigTypeSse McpServerConfigType = "sse" + McpServerConfigTypeStdio McpServerConfigType = "stdio" ) -type PermissionDecisionKind string +// Configuration source: user, workspace, plugin, or builtin +type McpServerSource string const ( - PermissionDecisionKindApproveForLocation PermissionDecisionKind = "approve-for-location" - PermissionDecisionKindApproveForSession PermissionDecisionKind = "approve-for-session" - PermissionDecisionKindApproveOnce PermissionDecisionKind = "approve-once" - PermissionDecisionKindApprovePermanently PermissionDecisionKind = "approve-permanently" - PermissionDecisionKindReject PermissionDecisionKind = "reject" - PermissionDecisionKindUserNotAvailable PermissionDecisionKind = "user-not-available" + McpServerSourceBuiltin McpServerSource = "builtin" + McpServerSourcePlugin McpServerSource = "plugin" + McpServerSourceUser McpServerSource = "user" + McpServerSourceWorkspace McpServerSource = "workspace" ) -type PermissionDecisionApproveForLocationKind string +// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured +type McpServerStatus string const ( - PermissionDecisionApproveForLocationKindApproveForLocation PermissionDecisionApproveForLocationKind = "approve-for-location" + McpServerStatusConnected McpServerStatus = "connected" + McpServerStatusDisabled McpServerStatus = "disabled" + McpServerStatusFailed McpServerStatus = "failed" + McpServerStatusNeedsAuth McpServerStatus = "needs-auth" + McpServerStatusNotConfigured McpServerStatus = "not_configured" + McpServerStatusPending McpServerStatus = "pending" ) type PermissionDecisionApproveForLocationApprovalCommandsKind string @@ -2367,16 +2228,31 @@ const ( PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKindExtensionPermissionAccess PermissionDecisionApproveForLocationApprovalExtensionPermissionAccessKind = "extension-permission-access" ) -type PermissionDecisionApproveForLocationApprovalMCPKind string +// Kind discriminator for PermissionDecisionApproveForLocationApproval. +type PermissionDecisionApproveForLocationApprovalKind string + +const ( + PermissionDecisionApproveForLocationApprovalKindCommands PermissionDecisionApproveForLocationApprovalKind = "commands" + PermissionDecisionApproveForLocationApprovalKindCustomTool PermissionDecisionApproveForLocationApprovalKind = "custom-tool" + PermissionDecisionApproveForLocationApprovalKindExtensionManagement PermissionDecisionApproveForLocationApprovalKind = "extension-management" + PermissionDecisionApproveForLocationApprovalKindExtensionPermissionAccess PermissionDecisionApproveForLocationApprovalKind = "extension-permission-access" + PermissionDecisionApproveForLocationApprovalKindMcp PermissionDecisionApproveForLocationApprovalKind = "mcp" + PermissionDecisionApproveForLocationApprovalKindMcpSampling PermissionDecisionApproveForLocationApprovalKind = "mcp-sampling" + PermissionDecisionApproveForLocationApprovalKindMemory PermissionDecisionApproveForLocationApprovalKind = "memory" + PermissionDecisionApproveForLocationApprovalKindRead PermissionDecisionApproveForLocationApprovalKind = "read" + PermissionDecisionApproveForLocationApprovalKindWrite PermissionDecisionApproveForLocationApprovalKind = "write" +) + +type PermissionDecisionApproveForLocationApprovalMcpKind string const ( - PermissionDecisionApproveForLocationApprovalMCPKindMcp PermissionDecisionApproveForLocationApprovalMCPKind = "mcp" + PermissionDecisionApproveForLocationApprovalMcpKindMcp PermissionDecisionApproveForLocationApprovalMcpKind = "mcp" ) -type PermissionDecisionApproveForLocationApprovalMCPSamplingKind string +type PermissionDecisionApproveForLocationApprovalMcpSamplingKind string const ( - PermissionDecisionApproveForLocationApprovalMCPSamplingKindMcpSampling PermissionDecisionApproveForLocationApprovalMCPSamplingKind = "mcp-sampling" + PermissionDecisionApproveForLocationApprovalMcpSamplingKindMcpSampling PermissionDecisionApproveForLocationApprovalMcpSamplingKind = "mcp-sampling" ) type PermissionDecisionApproveForLocationApprovalMemoryKind string @@ -2397,105 +2273,208 @@ const ( PermissionDecisionApproveForLocationApprovalWriteKindWrite PermissionDecisionApproveForLocationApprovalWriteKind = "write" ) -type PermissionDecisionApproveForSessionKind string +// Approved and persisted for this project location +type PermissionDecisionApproveForLocationKind string const ( - PermissionDecisionApproveForSessionKindApproveForSession PermissionDecisionApproveForSessionKind = "approve-for-session" + PermissionDecisionApproveForLocationKindApproveForLocation PermissionDecisionApproveForLocationKind = "approve-for-location" ) -type PermissionDecisionApproveOnceKind string +type PermissionDecisionApproveForSessionApprovalCommandsKind string const ( - PermissionDecisionApproveOnceKindApproveOnce PermissionDecisionApproveOnceKind = "approve-once" + PermissionDecisionApproveForSessionApprovalCommandsKindCommands PermissionDecisionApproveForSessionApprovalCommandsKind = "commands" ) -type PermissionDecisionApprovePermanentlyKind string +type PermissionDecisionApproveForSessionApprovalCustomToolKind string const ( - PermissionDecisionApprovePermanentlyKindApprovePermanently PermissionDecisionApprovePermanentlyKind = "approve-permanently" + PermissionDecisionApproveForSessionApprovalCustomToolKindCustomTool PermissionDecisionApproveForSessionApprovalCustomToolKind = "custom-tool" ) -type PermissionDecisionRejectKind string +type PermissionDecisionApproveForSessionApprovalExtensionManagementKind string const ( - PermissionDecisionRejectKindReject PermissionDecisionRejectKind = "reject" + PermissionDecisionApproveForSessionApprovalExtensionManagementKindExtensionManagement PermissionDecisionApproveForSessionApprovalExtensionManagementKind = "extension-management" ) -type PermissionDecisionUserNotAvailableKind string +type PermissionDecisionApproveForSessionApprovalExtensionPermissionAccessKind string const ( - PermissionDecisionUserNotAvailableKindUserNotAvailable PermissionDecisionUserNotAvailableKind = "user-not-available" + PermissionDecisionApproveForSessionApprovalExtensionPermissionAccessKindExtensionPermissionAccess PermissionDecisionApproveForSessionApprovalExtensionPermissionAccessKind = "extension-permission-access" ) -// Error classification -type SessionFSErrorCode string +// Kind discriminator for PermissionDecisionApproveForSessionApproval. +type PermissionDecisionApproveForSessionApprovalKind string const ( - SessionFSErrorCodeENOENT SessionFSErrorCode = "ENOENT" - SessionFSErrorCodeUNKNOWN SessionFSErrorCode = "UNKNOWN" + PermissionDecisionApproveForSessionApprovalKindCommands PermissionDecisionApproveForSessionApprovalKind = "commands" + PermissionDecisionApproveForSessionApprovalKindCustomTool PermissionDecisionApproveForSessionApprovalKind = "custom-tool" + PermissionDecisionApproveForSessionApprovalKindExtensionManagement PermissionDecisionApproveForSessionApprovalKind = "extension-management" + PermissionDecisionApproveForSessionApprovalKindExtensionPermissionAccess PermissionDecisionApproveForSessionApprovalKind = "extension-permission-access" + PermissionDecisionApproveForSessionApprovalKindMcp PermissionDecisionApproveForSessionApprovalKind = "mcp" + PermissionDecisionApproveForSessionApprovalKindMcpSampling PermissionDecisionApproveForSessionApprovalKind = "mcp-sampling" + PermissionDecisionApproveForSessionApprovalKindMemory PermissionDecisionApproveForSessionApprovalKind = "memory" + PermissionDecisionApproveForSessionApprovalKindRead PermissionDecisionApproveForSessionApprovalKind = "read" + PermissionDecisionApproveForSessionApprovalKindWrite PermissionDecisionApproveForSessionApprovalKind = "write" ) -// Entry type -type SessionFSReaddirWithTypesEntryType string +type PermissionDecisionApproveForSessionApprovalMcpKind string const ( - SessionFSReaddirWithTypesEntryTypeDirectory SessionFSReaddirWithTypesEntryType = "directory" - SessionFSReaddirWithTypesEntryTypeFile SessionFSReaddirWithTypesEntryType = "file" + PermissionDecisionApproveForSessionApprovalMcpKindMcp PermissionDecisionApproveForSessionApprovalMcpKind = "mcp" ) -// Path conventions used by this filesystem -type SessionFSSetProviderConventions string +type PermissionDecisionApproveForSessionApprovalMcpSamplingKind string const ( - SessionFSSetProviderConventionsPosix SessionFSSetProviderConventions = "posix" - SessionFSSetProviderConventionsWindows SessionFSSetProviderConventions = "windows" + PermissionDecisionApproveForSessionApprovalMcpSamplingKindMcpSampling PermissionDecisionApproveForSessionApprovalMcpSamplingKind = "mcp-sampling" ) -// Signal to send (default: SIGTERM) -type ShellKillSignal string +type PermissionDecisionApproveForSessionApprovalMemoryKind string const ( - ShellKillSignalSIGINT ShellKillSignal = "SIGINT" - ShellKillSignalSIGKILL ShellKillSignal = "SIGKILL" - ShellKillSignalSIGTERM ShellKillSignal = "SIGTERM" + PermissionDecisionApproveForSessionApprovalMemoryKindMemory PermissionDecisionApproveForSessionApprovalMemoryKind = "memory" ) -// How the agent is currently being managed by the runtime -// -// Whether the shell command is currently sync-waited or background-managed -type TaskInfoExecutionMode string +type PermissionDecisionApproveForSessionApprovalReadKind string const ( - TaskInfoExecutionModeBackground TaskInfoExecutionMode = "background" - TaskInfoExecutionModeSync TaskInfoExecutionMode = "sync" + PermissionDecisionApproveForSessionApprovalReadKindRead PermissionDecisionApproveForSessionApprovalReadKind = "read" ) -// Current lifecycle status of the task -type TaskInfoStatus string +type PermissionDecisionApproveForSessionApprovalWriteKind string const ( - TaskInfoStatusCancelled TaskInfoStatus = "cancelled" - TaskInfoStatusCompleted TaskInfoStatus = "completed" - TaskInfoStatusIdle TaskInfoStatus = "idle" - TaskInfoStatusFailed TaskInfoStatus = "failed" - TaskInfoStatusRunning TaskInfoStatus = "running" + PermissionDecisionApproveForSessionApprovalWriteKindWrite PermissionDecisionApproveForSessionApprovalWriteKind = "write" ) -type TaskAgentInfoType string +// Approved and remembered for the rest of the session +type PermissionDecisionApproveForSessionKind string const ( - TaskAgentInfoTypeAgent TaskAgentInfoType = "agent" + PermissionDecisionApproveForSessionKindApproveForSession PermissionDecisionApproveForSessionKind = "approve-for-session" ) -// Whether the shell runs inside a managed PTY session or as an independent background -// process -type TaskShellInfoAttachmentMode string +// The permission request was approved for this one instance +type PermissionDecisionApproveOnceKind string const ( - TaskShellInfoAttachmentModeAttached TaskShellInfoAttachmentMode = "attached" - TaskShellInfoAttachmentModeDetached TaskShellInfoAttachmentMode = "detached" + PermissionDecisionApproveOnceKindApproveOnce PermissionDecisionApproveOnceKind = "approve-once" +) + +// Approved and persisted across sessions +type PermissionDecisionApprovePermanentlyKind string + +const ( + PermissionDecisionApprovePermanentlyKindApprovePermanently PermissionDecisionApprovePermanentlyKind = "approve-permanently" +) + +// Kind discriminator for PermissionDecision. +type PermissionDecisionKind string + +const ( + PermissionDecisionKindApproveForLocation PermissionDecisionKind = "approve-for-location" + PermissionDecisionKindApproveForSession PermissionDecisionKind = "approve-for-session" + PermissionDecisionKindApproveOnce PermissionDecisionKind = "approve-once" + PermissionDecisionKindApprovePermanently PermissionDecisionKind = "approve-permanently" + PermissionDecisionKindReject PermissionDecisionKind = "reject" + PermissionDecisionKindUserNotAvailable PermissionDecisionKind = "user-not-available" +) + +// Denied by the user during an interactive prompt +type PermissionDecisionRejectKind string + +const ( + PermissionDecisionRejectKindReject PermissionDecisionRejectKind = "reject" +) + +// Denied because user confirmation was unavailable +type PermissionDecisionUserNotAvailableKind string + +const ( + PermissionDecisionUserNotAvailableKindUserNotAvailable PermissionDecisionUserNotAvailableKind = "user-not-available" +) + +// Error classification +type SessionFsErrorCode string + +const ( + SessionFsErrorCodeENOENT SessionFsErrorCode = "ENOENT" + SessionFsErrorCodeUNKNOWN SessionFsErrorCode = "UNKNOWN" +) + +// Entry type +type SessionFsReaddirWithTypesEntryType string + +const ( + SessionFsReaddirWithTypesEntryTypeDirectory SessionFsReaddirWithTypesEntryType = "directory" + SessionFsReaddirWithTypesEntryTypeFile SessionFsReaddirWithTypesEntryType = "file" +) + +// Path conventions used by this filesystem +type SessionFsSetProviderConventions string + +const ( + SessionFsSetProviderConventionsPosix SessionFsSetProviderConventions = "posix" + SessionFsSetProviderConventionsWindows SessionFsSetProviderConventions = "windows" +) + +// Log severity level. Determines how the message is displayed in the timeline. Defaults to +// "info". +type SessionLogLevel string + +const ( + SessionLogLevelError SessionLogLevel = "error" + SessionLogLevelInfo SessionLogLevel = "info" + SessionLogLevelWarning SessionLogLevel = "warning" +) + +// The agent mode. Valid values: "interactive", "plan", "autopilot". +type SessionMode string + +const ( + SessionModeAutopilot SessionMode = "autopilot" + SessionModeInteractive SessionMode = "interactive" + SessionModePlan SessionMode = "plan" +) + +// Signal to send (default: SIGTERM) +type ShellKillSignal string + +const ( + ShellKillSignalSIGINT ShellKillSignal = "SIGINT" + ShellKillSignalSIGKILL ShellKillSignal = "SIGKILL" + ShellKillSignalSIGTERM ShellKillSignal = "SIGTERM" ) +// How the agent is currently being managed by the runtime +type TaskAgentInfoExecutionMode string + +const ( + TaskAgentInfoExecutionModeBackground TaskAgentInfoExecutionMode = "background" + TaskAgentInfoExecutionModeSync TaskAgentInfoExecutionMode = "sync" +) + +// Current lifecycle status of the task +type TaskAgentInfoStatus string + +const ( + TaskAgentInfoStatusCancelled TaskAgentInfoStatus = "cancelled" + TaskAgentInfoStatusCompleted TaskAgentInfoStatus = "completed" + TaskAgentInfoStatusFailed TaskAgentInfoStatus = "failed" + TaskAgentInfoStatusIdle TaskAgentInfoStatus = "idle" + TaskAgentInfoStatusRunning TaskAgentInfoStatus = "running" +) + +// Task kind +type TaskAgentInfoType string + +const ( + TaskAgentInfoTypeAgent TaskAgentInfoType = "agent" +) + +// Type discriminator for TaskInfo. type TaskInfoType string const ( @@ -2503,6 +2482,35 @@ const ( TaskInfoTypeShell TaskInfoType = "shell" ) +// Whether the shell runs inside a managed PTY session or as an independent background +// process +type TaskShellInfoAttachmentMode string + +const ( + TaskShellInfoAttachmentModeAttached TaskShellInfoAttachmentMode = "attached" + TaskShellInfoAttachmentModeDetached TaskShellInfoAttachmentMode = "detached" +) + +// Whether the shell command is currently sync-waited or background-managed +type TaskShellInfoExecutionMode string + +const ( + TaskShellInfoExecutionModeBackground TaskShellInfoExecutionMode = "background" + TaskShellInfoExecutionModeSync TaskShellInfoExecutionMode = "sync" +) + +// Current lifecycle status of the task +type TaskShellInfoStatus string + +const ( + TaskShellInfoStatusCancelled TaskShellInfoStatus = "cancelled" + TaskShellInfoStatusCompleted TaskShellInfoStatus = "completed" + TaskShellInfoStatusFailed TaskShellInfoStatus = "failed" + TaskShellInfoStatusIdle TaskShellInfoStatus = "idle" + TaskShellInfoStatusRunning TaskShellInfoStatus = "running" +) + +// Task kind type TaskShellInfoType string const ( @@ -2521,6 +2529,40 @@ const ( UIElicitationArrayEnumFieldItemsTypeString UIElicitationArrayEnumFieldItemsType = "string" ) +type UIElicitationArrayEnumFieldType string + +const ( + UIElicitationArrayEnumFieldTypeArray UIElicitationArrayEnumFieldType = "array" +) + +// The user's response: accept (submitted), decline (rejected), or cancel (dismissed) +type UIElicitationResponseAction string + +const ( + UIElicitationResponseActionAccept UIElicitationResponseAction = "accept" + UIElicitationResponseActionCancel UIElicitationResponseAction = "cancel" + UIElicitationResponseActionDecline UIElicitationResponseAction = "decline" +) + +type UIElicitationSchemaPropertyBooleanType string + +const ( + UIElicitationSchemaPropertyBooleanTypeBoolean UIElicitationSchemaPropertyBooleanType = "boolean" +) + +type UIElicitationSchemaPropertyItemsType string + +const ( + UIElicitationSchemaPropertyItemsTypeString UIElicitationSchemaPropertyItemsType = "string" +) + +type UIElicitationSchemaPropertyNumberType string + +const ( + UIElicitationSchemaPropertyNumberTypeInteger UIElicitationSchemaPropertyNumberType = "integer" + UIElicitationSchemaPropertyNumberTypeNumber UIElicitationSchemaPropertyNumberType = "number" +) + type UIElicitationSchemaPropertyStringFormat string const ( @@ -2530,207 +2572,201 @@ const ( UIElicitationSchemaPropertyStringFormatURI UIElicitationSchemaPropertyStringFormat = "uri" ) +type UIElicitationSchemaPropertyStringType string + +const ( + UIElicitationSchemaPropertyStringTypeString UIElicitationSchemaPropertyStringType = "string" +) + type UIElicitationSchemaPropertyType string const ( - UIElicitationSchemaPropertyTypeInteger UIElicitationSchemaPropertyType = "integer" - UIElicitationSchemaPropertyTypeNumber UIElicitationSchemaPropertyType = "number" UIElicitationSchemaPropertyTypeArray UIElicitationSchemaPropertyType = "array" UIElicitationSchemaPropertyTypeBoolean UIElicitationSchemaPropertyType = "boolean" + UIElicitationSchemaPropertyTypeInteger UIElicitationSchemaPropertyType = "integer" + UIElicitationSchemaPropertyTypeNumber UIElicitationSchemaPropertyType = "number" UIElicitationSchemaPropertyTypeString UIElicitationSchemaPropertyType = "string" ) +// Schema type indicator (always 'object') type UIElicitationSchemaType string const ( UIElicitationSchemaTypeObject UIElicitationSchemaType = "object" ) -// The user's response: accept (submitted), decline (rejected), or cancel (dismissed) -type UIElicitationResponseAction string +type UIElicitationStringEnumFieldType string const ( - UIElicitationResponseActionAccept UIElicitationResponseAction = "accept" - UIElicitationResponseActionCancel UIElicitationResponseAction = "cancel" - UIElicitationResponseActionDecline UIElicitationResponseAction = "decline" + UIElicitationStringEnumFieldTypeString UIElicitationStringEnumFieldType = "string" ) -type UIElicitationSchemaPropertyBooleanType string +type UIElicitationStringOneOfFieldType string const ( - UIElicitationSchemaPropertyBooleanTypeBoolean UIElicitationSchemaPropertyBooleanType = "boolean" + UIElicitationStringOneOfFieldTypeString UIElicitationStringOneOfFieldType = "string" ) -type UIElicitationSchemaPropertyNumberTypeEnum string +type WorkspacesGetWorkspaceResultWorkspaceHostType string const ( - UIElicitationSchemaPropertyNumberTypeEnumInteger UIElicitationSchemaPropertyNumberTypeEnum = "integer" - UIElicitationSchemaPropertyNumberTypeEnumNumber UIElicitationSchemaPropertyNumberTypeEnum = "number" + WorkspacesGetWorkspaceResultWorkspaceHostTypeAdo WorkspacesGetWorkspaceResultWorkspaceHostType = "ado" + WorkspacesGetWorkspaceResultWorkspaceHostTypeGithub WorkspacesGetWorkspaceResultWorkspaceHostType = "github" ) -type HostType string - -const ( - HostTypeAdo HostType = "ado" - HostTypeGithub HostType = "github" -) - -// Tool call result (string or expanded result object) -type ExternalToolResult struct { - ExternalToolTextResultForLlm *ExternalToolTextResultForLlm - String *string -} - -type FilterMapping struct { - Enum *FilterMappingString - EnumMap map[string]FilterMappingString -} - -type UIElicitationFieldValue struct { - Bool *bool - Double *float64 - String *string - StringArray []string -} - type serverApi struct { client *jsonrpc2.Client } -type ServerModelsApi serverApi +type ServerAccountApi serverApi -func (a *ServerModelsApi) List(ctx context.Context, params *ModelsListRequest) (*ModelList, error) { - raw, err := a.client.Request("models.list", params) +func (a *ServerAccountApi) GetQuota(ctx context.Context, params *AccountGetQuotaRequest) (*AccountGetQuotaResult, error) { + raw, err := a.client.Request("account.getQuota", params) if err != nil { return nil, err } - var result ModelList + var result AccountGetQuotaResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ServerToolsApi serverApi +type ServerMcpApi serverApi -func (a *ServerToolsApi) List(ctx context.Context, params *ToolsListRequest) (*ToolList, error) { - raw, err := a.client.Request("tools.list", params) +func (a *ServerMcpApi) Discover(ctx context.Context, params *McpDiscoverRequest) (*McpDiscoverResult, error) { + raw, err := a.client.Request("mcp.discover", params) if err != nil { return nil, err } - var result ToolList + var result McpDiscoverResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ServerAccountApi serverApi +type ServerMcpConfigApi serverApi -func (a *ServerAccountApi) GetQuota(ctx context.Context, params *AccountGetQuotaRequest) (*AccountGetQuotaResult, error) { - raw, err := a.client.Request("account.getQuota", params) +func (a *ServerMcpConfigApi) Add(ctx context.Context, params *McpConfigAddRequest) (*McpConfigAddResult, error) { + raw, err := a.client.Request("mcp.config.add", params) if err != nil { return nil, err } - var result AccountGetQuotaResult + var result McpConfigAddResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ServerMcpApi serverApi - -func (a *ServerMcpApi) Discover(ctx context.Context, params *MCPDiscoverRequest) (*MCPDiscoverResult, error) { - raw, err := a.client.Request("mcp.discover", params) +func (a *ServerMcpConfigApi) Disable(ctx context.Context, params *McpConfigDisableRequest) (*McpConfigDisableResult, error) { + raw, err := a.client.Request("mcp.config.disable", params) if err != nil { return nil, err } - var result MCPDiscoverResult + var result McpConfigDisableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ServerMcpConfigApi serverApi +func (a *ServerMcpConfigApi) Enable(ctx context.Context, params *McpConfigEnableRequest) (*McpConfigEnableResult, error) { + raw, err := a.client.Request("mcp.config.enable", params) + if err != nil { + return nil, err + } + var result McpConfigEnableResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} -func (a *ServerMcpConfigApi) List(ctx context.Context) (*MCPConfigList, error) { +func (a *ServerMcpConfigApi) List(ctx context.Context) (*McpConfigList, error) { raw, err := a.client.Request("mcp.config.list", nil) if err != nil { return nil, err } - var result MCPConfigList + var result McpConfigList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ServerMcpConfigApi) Add(ctx context.Context, params *MCPConfigAddRequest) (*MCPConfigAddResult, error) { - raw, err := a.client.Request("mcp.config.add", params) +func (a *ServerMcpConfigApi) Remove(ctx context.Context, params *McpConfigRemoveRequest) (*McpConfigRemoveResult, error) { + raw, err := a.client.Request("mcp.config.remove", params) if err != nil { return nil, err } - var result MCPConfigAddResult + var result McpConfigRemoveResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ServerMcpConfigApi) Update(ctx context.Context, params *MCPConfigUpdateRequest) (*MCPConfigUpdateResult, error) { +func (a *ServerMcpConfigApi) Update(ctx context.Context, params *McpConfigUpdateRequest) (*McpConfigUpdateResult, error) { raw, err := a.client.Request("mcp.config.update", params) if err != nil { return nil, err } - var result MCPConfigUpdateResult + var result McpConfigUpdateResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ServerMcpConfigApi) Remove(ctx context.Context, params *MCPConfigRemoveRequest) (*MCPConfigRemoveResult, error) { - raw, err := a.client.Request("mcp.config.remove", params) +func (s *ServerMcpApi) Config() *ServerMcpConfigApi { + return (*ServerMcpConfigApi)(s) +} + +type ServerModelsApi serverApi + +func (a *ServerModelsApi) List(ctx context.Context, params *ModelsListRequest) (*ModelList, error) { + raw, err := a.client.Request("models.list", params) if err != nil { return nil, err } - var result MCPConfigRemoveResult + var result ModelList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ServerMcpConfigApi) Enable(ctx context.Context, params *MCPConfigEnableRequest) (*MCPConfigEnableResult, error) { - raw, err := a.client.Request("mcp.config.enable", params) +type ServerSessionFsApi serverApi + +func (a *ServerSessionFsApi) SetProvider(ctx context.Context, params *SessionFsSetProviderRequest) (*SessionFsSetProviderResult, error) { + raw, err := a.client.Request("sessionFs.setProvider", params) if err != nil { return nil, err } - var result MCPConfigEnableResult + var result SessionFsSetProviderResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ServerMcpConfigApi) Disable(ctx context.Context, params *MCPConfigDisableRequest) (*MCPConfigDisableResult, error) { - raw, err := a.client.Request("mcp.config.disable", params) +// Experimental: ServerSessionsApi contains experimental APIs that may change or be removed. +type ServerSessionsApi serverApi + +func (a *ServerSessionsApi) Fork(ctx context.Context, params *SessionsForkRequest) (*SessionsForkResult, error) { + raw, err := a.client.Request("sessions.fork", params) if err != nil { return nil, err } - var result MCPConfigDisableResult + var result SessionsForkResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (s *ServerMcpApi) Config() *ServerMcpConfigApi { - return (*ServerMcpConfigApi)(s) -} - type ServerSkillsApi serverApi func (a *ServerSkillsApi) Discover(ctx context.Context, params *SkillsDiscoverRequest) (*ServerSkillList, error) { @@ -2763,29 +2799,14 @@ func (s *ServerSkillsApi) Config() *ServerSkillsConfigApi { return (*ServerSkillsConfigApi)(s) } -type ServerSessionFsApi serverApi - -func (a *ServerSessionFsApi) SetProvider(ctx context.Context, params *SessionFSSetProviderRequest) (*SessionFSSetProviderResult, error) { - raw, err := a.client.Request("sessionFs.setProvider", params) - if err != nil { - return nil, err - } - var result SessionFSSetProviderResult - if err := json.Unmarshal(raw, &result); err != nil { - return nil, err - } - return &result, nil -} - -// Experimental: ServerSessionsApi contains experimental APIs that may change or be removed. -type ServerSessionsApi serverApi +type ServerToolsApi serverApi -func (a *ServerSessionsApi) Fork(ctx context.Context, params *SessionsForkRequest) (*SessionsForkResult, error) { - raw, err := a.client.Request("sessions.fork", params) +func (a *ServerToolsApi) List(ctx context.Context, params *ToolsListRequest) (*ToolList, error) { + raw, err := a.client.Request("tools.list", params) if err != nil { return nil, err } - var result SessionsForkResult + var result ToolList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } @@ -2794,15 +2815,16 @@ func (a *ServerSessionsApi) Fork(ctx context.Context, params *SessionsForkReques // ServerRpc provides typed server-scoped RPC methods. type ServerRpc struct { - common serverApi // Reuse a single struct instead of allocating one for each service on the heap. + // Reuse a single struct instead of allocating one for each service on the heap. + common serverApi - Models *ServerModelsApi - Tools *ServerToolsApi Account *ServerAccountApi Mcp *ServerMcpApi - Skills *ServerSkillsApi + Models *ServerModelsApi SessionFs *ServerSessionFsApi Sessions *ServerSessionsApi + Skills *ServerSkillsApi + Tools *ServerToolsApi } func (a *ServerRpc) Ping(ctx context.Context, params *PingRequest) (*PingResult, error) { @@ -2820,13 +2842,13 @@ func (a *ServerRpc) Ping(ctx context.Context, params *PingRequest) (*PingResult, func NewServerRpc(client *jsonrpc2.Client) *ServerRpc { r := &ServerRpc{} r.common = serverApi{client: client} - r.Models = (*ServerModelsApi)(&r.common) - r.Tools = (*ServerToolsApi)(&r.common) r.Account = (*ServerAccountApi)(&r.common) r.Mcp = (*ServerMcpApi)(&r.common) - r.Skills = (*ServerSkillsApi)(&r.common) + r.Models = (*ServerModelsApi)(&r.common) r.SessionFs = (*ServerSessionFsApi)(&r.common) r.Sessions = (*ServerSessionsApi)(&r.common) + r.Skills = (*ServerSkillsApi)(&r.common) + r.Tools = (*ServerToolsApi)(&r.common) return r } @@ -2834,13 +2856,15 @@ type internalServerApi struct { client *jsonrpc2.Client } -// InternalServerRpc provides internal SDK server-scoped RPC methods (handshake helpers etc.). Not part of the public API. +// InternalServerRpc provides internal SDK server-scoped RPC methods (handshake helpers +// etc.). Not part of the public API. type InternalServerRpc struct { - common internalServerApi // Reuse a single struct instead of allocating one for each service on the heap. - + // Reuse a single struct instead of allocating one for each service on the heap. + common internalServerApi } -// Internal: Connect is part of the SDK's internal handshake/plumbing; external callers should not use it. +// Internal: Connect is part of the SDK's internal handshake/plumbing; external callers +// should not use it. func (a *InternalServerRpc) Connect(ctx context.Context, params *ConnectRequest) (*ConnectResult, error) { raw, err := a.common.client.Request("connect", params) if err != nil { @@ -2864,219 +2888,221 @@ type sessionApi struct { sessionID string } -type AuthApi sessionApi +// Experimental: AgentApi contains experimental APIs that may change or be removed. +type AgentApi sessionApi -func (a *AuthApi) GetStatus(ctx context.Context) (*SessionAuthStatus, error) { +func (a *AgentApi) Deselect(ctx context.Context) (*AgentDeselectResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.auth.getStatus", req) + raw, err := a.client.Request("session.agent.deselect", req) if err != nil { return nil, err } - var result SessionAuthStatus + var result AgentDeselectResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ModelApi sessionApi - -func (a *ModelApi) GetCurrent(ctx context.Context) (*CurrentModel, error) { +func (a *AgentApi) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.model.getCurrent", req) + raw, err := a.client.Request("session.agent.getCurrent", req) if err != nil { return nil, err } - var result CurrentModel + var result AgentGetCurrentResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ModelApi) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (*ModelSwitchToResult, error) { +func (a *AgentApi) List(ctx context.Context) (*AgentList, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["modelId"] = params.ModelID - if params.ReasoningEffort != nil { - req["reasoningEffort"] = *params.ReasoningEffort - } - if params.ModelCapabilities != nil { - req["modelCapabilities"] = *params.ModelCapabilities - } - } - raw, err := a.client.Request("session.model.switchTo", req) + raw, err := a.client.Request("session.agent.list", req) if err != nil { return nil, err } - var result ModelSwitchToResult + var result AgentList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ModeApi sessionApi - -func (a *ModeApi) Get(ctx context.Context) (*SessionMode, error) { +func (a *AgentApi) Reload(ctx context.Context) (*AgentReloadResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.mode.get", req) + raw, err := a.client.Request("session.agent.reload", req) if err != nil { return nil, err } - var result SessionMode + var result AgentReloadResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ModeApi) Set(ctx context.Context, params *ModeSetRequest) (*ModeSetResult, error) { +func (a *AgentApi) Select(ctx context.Context, params *AgentSelectRequest) (*AgentSelectResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["mode"] = params.Mode + req["name"] = params.Name } - raw, err := a.client.Request("session.mode.set", req) + raw, err := a.client.Request("session.agent.select", req) if err != nil { return nil, err } - var result ModeSetResult + var result AgentSelectResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type NameApi sessionApi +type AuthApi sessionApi -func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) { +func (a *AuthApi) GetStatus(ctx context.Context) (*SessionAuthStatus, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.name.get", req) + raw, err := a.client.Request("session.auth.getStatus", req) if err != nil { return nil, err } - var result NameGetResult + var result SessionAuthStatus if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*NameSetResult, error) { +type CommandsApi sessionApi + +func (a *CommandsApi) HandlePendingCommand(ctx context.Context, params *CommandsHandlePendingCommandRequest) (*CommandsHandlePendingCommandResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["name"] = params.Name + if params.Error != nil { + req["error"] = *params.Error + } + req["requestId"] = params.RequestID } - raw, err := a.client.Request("session.name.set", req) + raw, err := a.client.Request("session.commands.handlePendingCommand", req) if err != nil { return nil, err } - var result NameSetResult + var result CommandsHandlePendingCommandResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type PlanApi sessionApi +// Experimental: ExtensionsApi contains experimental APIs that may change or be removed. +type ExtensionsApi sessionApi -func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) { +func (a *ExtensionsApi) Disable(ctx context.Context, params *ExtensionsDisableRequest) (*ExtensionsDisableResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.plan.read", req) + if params != nil { + req["id"] = params.ID + } + raw, err := a.client.Request("session.extensions.disable", req) if err != nil { return nil, err } - var result PlanReadResult + var result ExtensionsDisableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *PlanApi) Update(ctx context.Context, params *PlanUpdateRequest) (*PlanUpdateResult, error) { +func (a *ExtensionsApi) Enable(ctx context.Context, params *ExtensionsEnableRequest) (*ExtensionsEnableResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["content"] = params.Content + req["id"] = params.ID } - raw, err := a.client.Request("session.plan.update", req) + raw, err := a.client.Request("session.extensions.enable", req) if err != nil { return nil, err } - var result PlanUpdateResult + var result ExtensionsEnableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *PlanApi) Delete(ctx context.Context) (*PlanDeleteResult, error) { +func (a *ExtensionsApi) List(ctx context.Context) (*ExtensionList, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.plan.delete", req) + raw, err := a.client.Request("session.extensions.list", req) if err != nil { return nil, err } - var result PlanDeleteResult + var result ExtensionList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type WorkspacesApi sessionApi - -func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspaceResult, error) { +func (a *ExtensionsApi) Reload(ctx context.Context) (*ExtensionsReloadResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.workspaces.getWorkspace", req) + raw, err := a.client.Request("session.extensions.reload", req) if err != nil { return nil, err } - var result WorkspacesGetWorkspaceResult + var result ExtensionsReloadResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResult, error) { +// Experimental: FleetApi contains experimental APIs that may change or be removed. +type FleetApi sessionApi + +func (a *FleetApi) Start(ctx context.Context, params *FleetStartRequest) (*FleetStartResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.workspaces.listFiles", req) + if params != nil { + if params.Prompt != nil { + req["prompt"] = *params.Prompt + } + } + raw, err := a.client.Request("session.fleet.start", req) if err != nil { return nil, err } - var result WorkspacesListFilesResult + var result FleetStartResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFileRequest) (*WorkspacesReadFileResult, error) { +// Experimental: HistoryApi contains experimental APIs that may change or be removed. +type HistoryApi sessionApi + +func (a *HistoryApi) Compact(ctx context.Context) (*HistoryCompactResult, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["path"] = params.Path - } - raw, err := a.client.Request("session.workspaces.readFile", req) + raw, err := a.client.Request("session.history.compact", req) if err != nil { return nil, err } - var result WorkspacesReadFileResult + var result HistoryCompactResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreateFileRequest) (*WorkspacesCreateFileResult, error) { +func (a *HistoryApi) Truncate(ctx context.Context, params *HistoryTruncateRequest) (*HistoryTruncateResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["path"] = params.Path - req["content"] = params.Content + req["eventId"] = params.EventID } - raw, err := a.client.Request("session.workspaces.createFile", req) + raw, err := a.client.Request("session.history.truncate", req) if err != nil { return nil, err } - var result WorkspacesCreateFileResult + var result HistoryTruncateResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } @@ -3098,681 +3124,679 @@ func (a *InstructionsApi) GetSources(ctx context.Context) (*InstructionsGetSourc return &result, nil } -// Experimental: FleetApi contains experimental APIs that may change or be removed. -type FleetApi sessionApi +// Experimental: McpApi contains experimental APIs that may change or be removed. +type McpApi sessionApi -func (a *FleetApi) Start(ctx context.Context, params *FleetStartRequest) (*FleetStartResult, error) { +func (a *McpApi) Disable(ctx context.Context, params *McpDisableRequest) (*McpDisableResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - if params.Prompt != nil { - req["prompt"] = *params.Prompt - } + req["serverName"] = params.ServerName } - raw, err := a.client.Request("session.fleet.start", req) + raw, err := a.client.Request("session.mcp.disable", req) if err != nil { return nil, err } - var result FleetStartResult + var result McpDisableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: AgentApi contains experimental APIs that may change or be removed. -type AgentApi sessionApi - -func (a *AgentApi) List(ctx context.Context) (*AgentList, error) { +func (a *McpApi) Enable(ctx context.Context, params *McpEnableRequest) (*McpEnableResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.agent.list", req) + if params != nil { + req["serverName"] = params.ServerName + } + raw, err := a.client.Request("session.mcp.enable", req) if err != nil { return nil, err } - var result AgentList + var result McpEnableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *AgentApi) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, error) { +func (a *McpApi) List(ctx context.Context) (*McpServerList, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.agent.getCurrent", req) + raw, err := a.client.Request("session.mcp.list", req) if err != nil { return nil, err } - var result AgentGetCurrentResult + var result McpServerList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *AgentApi) Select(ctx context.Context, params *AgentSelectRequest) (*AgentSelectResult, error) { +func (a *McpApi) Reload(ctx context.Context) (*McpReloadResult, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["name"] = params.Name - } - raw, err := a.client.Request("session.agent.select", req) + raw, err := a.client.Request("session.mcp.reload", req) if err != nil { return nil, err } - var result AgentSelectResult + var result McpReloadResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *AgentApi) Deselect(ctx context.Context) (*AgentDeselectResult, error) { +// Experimental: McpOauthApi contains experimental APIs that may change or be removed. +type McpOauthApi sessionApi + +func (a *McpOauthApi) Login(ctx context.Context, params *McpOauthLoginRequest) (*McpOauthLoginResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.agent.deselect", req) + if params != nil { + if params.CallbackSuccessMessage != nil { + req["callbackSuccessMessage"] = *params.CallbackSuccessMessage + } + if params.ClientName != nil { + req["clientName"] = *params.ClientName + } + if params.ForceReauth != nil { + req["forceReauth"] = *params.ForceReauth + } + req["serverName"] = params.ServerName + } + raw, err := a.client.Request("session.mcp.oauth.login", req) if err != nil { return nil, err } - var result AgentDeselectResult + var result McpOauthLoginResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *AgentApi) Reload(ctx context.Context) (*AgentReloadResult, error) { +// Experimental: Oauth returns experimental APIs that may change or be removed. +func (s *McpApi) Oauth() *McpOauthApi { + return (*McpOauthApi)(s) +} + +type ModeApi sessionApi + +func (a *ModeApi) Get(ctx context.Context) (*SessionMode, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.agent.reload", req) + raw, err := a.client.Request("session.mode.get", req) if err != nil { return nil, err } - var result AgentReloadResult + var result SessionMode if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: TasksApi contains experimental APIs that may change or be removed. -type TasksApi sessionApi - -func (a *TasksApi) StartAgent(ctx context.Context, params *TasksStartAgentRequest) (*TasksStartAgentResult, error) { +func (a *ModeApi) Set(ctx context.Context, params *ModeSetRequest) (*ModeSetResult, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["agentType"] = params.AgentType - req["prompt"] = params.Prompt - req["name"] = params.Name - if params.Description != nil { - req["description"] = *params.Description - } - if params.Model != nil { - req["model"] = *params.Model - } + if params != nil { + req["mode"] = params.Mode } - raw, err := a.client.Request("session.tasks.startAgent", req) + raw, err := a.client.Request("session.mode.set", req) if err != nil { return nil, err } - var result TasksStartAgentResult + var result ModeSetResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *TasksApi) List(ctx context.Context) (*TaskList, error) { +type ModelApi sessionApi + +func (a *ModelApi) GetCurrent(ctx context.Context) (*CurrentModel, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.tasks.list", req) + raw, err := a.client.Request("session.model.getCurrent", req) if err != nil { return nil, err } - var result TaskList + var result CurrentModel if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *TasksApi) PromoteToBackground(ctx context.Context, params *TasksPromoteToBackgroundRequest) (*TasksPromoteToBackgroundResult, error) { +func (a *ModelApi) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (*ModelSwitchToResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["id"] = params.ID + if params.ModelCapabilities != nil { + req["modelCapabilities"] = *params.ModelCapabilities + } + req["modelId"] = params.ModelID + if params.ReasoningEffort != nil { + req["reasoningEffort"] = *params.ReasoningEffort + } } - raw, err := a.client.Request("session.tasks.promoteToBackground", req) + raw, err := a.client.Request("session.model.switchTo", req) if err != nil { return nil, err } - var result TasksPromoteToBackgroundResult + var result ModelSwitchToResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *TasksApi) Cancel(ctx context.Context, params *TasksCancelRequest) (*TasksCancelResult, error) { +type NameApi sessionApi + +func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["id"] = params.ID - } - raw, err := a.client.Request("session.tasks.cancel", req) + raw, err := a.client.Request("session.name.get", req) if err != nil { return nil, err } - var result TasksCancelResult + var result NameGetResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *TasksApi) Remove(ctx context.Context, params *TasksRemoveRequest) (*TasksRemoveResult, error) { +func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*NameSetResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["id"] = params.ID + req["name"] = params.Name } - raw, err := a.client.Request("session.tasks.remove", req) + raw, err := a.client.Request("session.name.set", req) if err != nil { return nil, err } - var result TasksRemoveResult + var result NameSetResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *TasksApi) SendMessage(ctx context.Context, params *TasksSendMessageRequest) (*TasksSendMessageResult, error) { +type PermissionsApi sessionApi + +func (a *PermissionsApi) HandlePendingPermissionRequest(ctx context.Context, params *PermissionDecisionRequest) (*PermissionRequestResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["id"] = params.ID - req["message"] = params.Message - if params.FromAgentID != nil { - req["fromAgentId"] = *params.FromAgentID - } + req["requestId"] = params.RequestID + req["result"] = params.Result } - raw, err := a.client.Request("session.tasks.sendMessage", req) + raw, err := a.client.Request("session.permissions.handlePendingPermissionRequest", req) if err != nil { return nil, err } - var result TasksSendMessageResult + var result PermissionRequestResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: SkillsApi contains experimental APIs that may change or be removed. -type SkillsApi sessionApi - -func (a *SkillsApi) List(ctx context.Context) (*SkillList, error) { +func (a *PermissionsApi) ResetSessionApprovals(ctx context.Context) (*PermissionsResetSessionApprovalsResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.skills.list", req) + raw, err := a.client.Request("session.permissions.resetSessionApprovals", req) if err != nil { return nil, err } - var result SkillList + var result PermissionsResetSessionApprovalsResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *SkillsApi) Enable(ctx context.Context, params *SkillsEnableRequest) (*SkillsEnableResult, error) { +func (a *PermissionsApi) SetApproveAll(ctx context.Context, params *PermissionsSetApproveAllRequest) (*PermissionsSetApproveAllResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["name"] = params.Name + req["enabled"] = params.Enabled } - raw, err := a.client.Request("session.skills.enable", req) + raw, err := a.client.Request("session.permissions.setApproveAll", req) if err != nil { return nil, err } - var result SkillsEnableResult + var result PermissionsSetApproveAllResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *SkillsApi) Disable(ctx context.Context, params *SkillsDisableRequest) (*SkillsDisableResult, error) { +type PlanApi sessionApi + +func (a *PlanApi) Delete(ctx context.Context) (*PlanDeleteResult, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["name"] = params.Name - } - raw, err := a.client.Request("session.skills.disable", req) + raw, err := a.client.Request("session.plan.delete", req) if err != nil { return nil, err } - var result SkillsDisableResult + var result PlanDeleteResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *SkillsApi) Reload(ctx context.Context) (*SkillsReloadResult, error) { +func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.skills.reload", req) + raw, err := a.client.Request("session.plan.read", req) if err != nil { return nil, err } - var result SkillsReloadResult + var result PlanReadResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: McpApi contains experimental APIs that may change or be removed. -type McpApi sessionApi - -func (a *McpApi) List(ctx context.Context) (*MCPServerList, error) { +func (a *PlanApi) Update(ctx context.Context, params *PlanUpdateRequest) (*PlanUpdateResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.mcp.list", req) + if params != nil { + req["content"] = params.Content + } + raw, err := a.client.Request("session.plan.update", req) if err != nil { return nil, err } - var result MCPServerList + var result PlanUpdateResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *McpApi) Enable(ctx context.Context, params *MCPEnableRequest) (*MCPEnableResult, error) { +// Experimental: PluginsApi contains experimental APIs that may change or be removed. +type PluginsApi sessionApi + +func (a *PluginsApi) List(ctx context.Context) (*PluginList, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["serverName"] = params.ServerName - } - raw, err := a.client.Request("session.mcp.enable", req) + raw, err := a.client.Request("session.plugins.list", req) if err != nil { return nil, err } - var result MCPEnableResult + var result PluginList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *McpApi) Disable(ctx context.Context, params *MCPDisableRequest) (*MCPDisableResult, error) { +// Experimental: RemoteApi contains experimental APIs that may change or be removed. +type RemoteApi sessionApi + +func (a *RemoteApi) Disable(ctx context.Context) (*RemoteDisableResult, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["serverName"] = params.ServerName - } - raw, err := a.client.Request("session.mcp.disable", req) + raw, err := a.client.Request("session.remote.disable", req) if err != nil { return nil, err } - var result MCPDisableResult + var result RemoteDisableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *McpApi) Reload(ctx context.Context) (*MCPReloadResult, error) { +func (a *RemoteApi) Enable(ctx context.Context) (*RemoteEnableResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.mcp.reload", req) + raw, err := a.client.Request("session.remote.enable", req) if err != nil { return nil, err } - var result MCPReloadResult + var result RemoteEnableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: McpOauthApi contains experimental APIs that may change or be removed. -type McpOauthApi sessionApi +type ShellApi sessionApi -func (a *McpOauthApi) Login(ctx context.Context, params *MCPOauthLoginRequest) (*MCPOauthLoginResult, error) { +func (a *ShellApi) Exec(ctx context.Context, params *ShellExecRequest) (*ShellExecResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["serverName"] = params.ServerName - if params.ForceReauth != nil { - req["forceReauth"] = *params.ForceReauth - } - if params.ClientName != nil { - req["clientName"] = *params.ClientName + req["command"] = params.Command + if params.Cwd != nil { + req["cwd"] = *params.Cwd } - if params.CallbackSuccessMessage != nil { - req["callbackSuccessMessage"] = *params.CallbackSuccessMessage + if params.Timeout != nil { + req["timeout"] = *params.Timeout } } - raw, err := a.client.Request("session.mcp.oauth.login", req) + raw, err := a.client.Request("session.shell.exec", req) if err != nil { return nil, err } - var result MCPOauthLoginResult + var result ShellExecResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: Oauth returns experimental APIs that may change or be removed. -func (s *McpApi) Oauth() *McpOauthApi { - return (*McpOauthApi)(s) -} - -// Experimental: PluginsApi contains experimental APIs that may change or be removed. -type PluginsApi sessionApi - -func (a *PluginsApi) List(ctx context.Context) (*PluginList, error) { +func (a *ShellApi) Kill(ctx context.Context, params *ShellKillRequest) (*ShellKillResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.plugins.list", req) + if params != nil { + req["processId"] = params.ProcessID + if params.Signal != nil { + req["signal"] = *params.Signal + } + } + raw, err := a.client.Request("session.shell.kill", req) if err != nil { return nil, err } - var result PluginList + var result ShellKillResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: ExtensionsApi contains experimental APIs that may change or be removed. -type ExtensionsApi sessionApi +// Experimental: SkillsApi contains experimental APIs that may change or be removed. +type SkillsApi sessionApi -func (a *ExtensionsApi) List(ctx context.Context) (*ExtensionList, error) { +func (a *SkillsApi) Disable(ctx context.Context, params *SkillsDisableRequest) (*SkillsDisableResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.extensions.list", req) + if params != nil { + req["name"] = params.Name + } + raw, err := a.client.Request("session.skills.disable", req) if err != nil { return nil, err } - var result ExtensionList + var result SkillsDisableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ExtensionsApi) Enable(ctx context.Context, params *ExtensionsEnableRequest) (*ExtensionsEnableResult, error) { +func (a *SkillsApi) Enable(ctx context.Context, params *SkillsEnableRequest) (*SkillsEnableResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["id"] = params.ID + req["name"] = params.Name } - raw, err := a.client.Request("session.extensions.enable", req) + raw, err := a.client.Request("session.skills.enable", req) if err != nil { return nil, err } - var result ExtensionsEnableResult + var result SkillsEnableResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ExtensionsApi) Disable(ctx context.Context, params *ExtensionsDisableRequest) (*ExtensionsDisableResult, error) { +func (a *SkillsApi) List(ctx context.Context) (*SkillList, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["id"] = params.ID - } - raw, err := a.client.Request("session.extensions.disable", req) + raw, err := a.client.Request("session.skills.list", req) if err != nil { return nil, err } - var result ExtensionsDisableResult + var result SkillList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ExtensionsApi) Reload(ctx context.Context) (*ExtensionsReloadResult, error) { +func (a *SkillsApi) Reload(ctx context.Context) (*SkillsReloadResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.extensions.reload", req) + raw, err := a.client.Request("session.skills.reload", req) if err != nil { return nil, err } - var result ExtensionsReloadResult + var result SkillsReloadResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ToolsApi sessionApi +// Experimental: TasksApi contains experimental APIs that may change or be removed. +type TasksApi sessionApi -func (a *ToolsApi) HandlePendingToolCall(ctx context.Context, params *HandlePendingToolCallRequest) (*HandlePendingToolCallResult, error) { +func (a *TasksApi) Cancel(ctx context.Context, params *TasksCancelRequest) (*TasksCancelResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["requestId"] = params.RequestID - if params.Result != nil { - req["result"] = *params.Result - } - if params.Error != nil { - req["error"] = *params.Error - } + req["id"] = params.ID } - raw, err := a.client.Request("session.tools.handlePendingToolCall", req) + raw, err := a.client.Request("session.tasks.cancel", req) if err != nil { return nil, err } - var result HandlePendingToolCallResult + var result TasksCancelResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type CommandsApi sessionApi - -func (a *CommandsApi) HandlePendingCommand(ctx context.Context, params *CommandsHandlePendingCommandRequest) (*CommandsHandlePendingCommandResult, error) { +func (a *TasksApi) List(ctx context.Context) (*TaskList, error) { req := map[string]any{"sessionId": a.sessionID} - if params != nil { - req["requestId"] = params.RequestID - if params.Error != nil { - req["error"] = *params.Error - } - } - raw, err := a.client.Request("session.commands.handlePendingCommand", req) + raw, err := a.client.Request("session.tasks.list", req) if err != nil { return nil, err } - var result CommandsHandlePendingCommandResult + var result TaskList if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type UIApi sessionApi - -func (a *UIApi) Elicitation(ctx context.Context, params *UIElicitationRequest) (*UIElicitationResponse, error) { +func (a *TasksApi) PromoteToBackground(ctx context.Context, params *TasksPromoteToBackgroundRequest) (*TasksPromoteToBackgroundResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["message"] = params.Message - req["requestedSchema"] = params.RequestedSchema + req["id"] = params.ID } - raw, err := a.client.Request("session.ui.elicitation", req) + raw, err := a.client.Request("session.tasks.promoteToBackground", req) if err != nil { return nil, err } - var result UIElicitationResponse + var result TasksPromoteToBackgroundResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *UIApi) HandlePendingElicitation(ctx context.Context, params *UIHandlePendingElicitationRequest) (*UIElicitationResult, error) { +func (a *TasksApi) Remove(ctx context.Context, params *TasksRemoveRequest) (*TasksRemoveResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["requestId"] = params.RequestID - req["result"] = params.Result + req["id"] = params.ID } - raw, err := a.client.Request("session.ui.handlePendingElicitation", req) + raw, err := a.client.Request("session.tasks.remove", req) if err != nil { return nil, err } - var result UIElicitationResult + var result TasksRemoveResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type PermissionsApi sessionApi - -func (a *PermissionsApi) HandlePendingPermissionRequest(ctx context.Context, params *PermissionDecisionRequest) (*PermissionRequestResult, error) { +func (a *TasksApi) SendMessage(ctx context.Context, params *TasksSendMessageRequest) (*TasksSendMessageResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["requestId"] = params.RequestID - req["result"] = params.Result + if params.FromAgentID != nil { + req["fromAgentId"] = *params.FromAgentID + } + req["id"] = params.ID + req["message"] = params.Message } - raw, err := a.client.Request("session.permissions.handlePendingPermissionRequest", req) + raw, err := a.client.Request("session.tasks.sendMessage", req) if err != nil { return nil, err } - var result PermissionRequestResult + var result TasksSendMessageResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *PermissionsApi) SetApproveAll(ctx context.Context, params *PermissionsSetApproveAllRequest) (*PermissionsSetApproveAllResult, error) { +func (a *TasksApi) StartAgent(ctx context.Context, params *TasksStartAgentRequest) (*TasksStartAgentResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["enabled"] = params.Enabled + req["agentType"] = params.AgentType + if params.Description != nil { + req["description"] = *params.Description + } + if params.Model != nil { + req["model"] = *params.Model + } + req["name"] = params.Name + req["prompt"] = params.Prompt } - raw, err := a.client.Request("session.permissions.setApproveAll", req) + raw, err := a.client.Request("session.tasks.startAgent", req) if err != nil { return nil, err } - var result PermissionsSetApproveAllResult + var result TasksStartAgentResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *PermissionsApi) ResetSessionApprovals(ctx context.Context) (*PermissionsResetSessionApprovalsResult, error) { +type ToolsApi sessionApi + +func (a *ToolsApi) HandlePendingToolCall(ctx context.Context, params *HandlePendingToolCallRequest) (*HandlePendingToolCallResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.permissions.resetSessionApprovals", req) + if params != nil { + if params.Error != nil { + req["error"] = *params.Error + } + req["requestId"] = params.RequestID + if params.Result != nil { + req["result"] = *params.Result + } + } + raw, err := a.client.Request("session.tools.handlePendingToolCall", req) if err != nil { return nil, err } - var result PermissionsResetSessionApprovalsResult + var result HandlePendingToolCallResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -type ShellApi sessionApi +type UIApi sessionApi -func (a *ShellApi) Exec(ctx context.Context, params *ShellExecRequest) (*ShellExecResult, error) { +func (a *UIApi) Elicitation(ctx context.Context, params *UIElicitationRequest) (*UIElicitationResponse, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["command"] = params.Command - if params.Cwd != nil { - req["cwd"] = *params.Cwd - } - if params.Timeout != nil { - req["timeout"] = *params.Timeout - } + req["message"] = params.Message + req["requestedSchema"] = params.RequestedSchema } - raw, err := a.client.Request("session.shell.exec", req) + raw, err := a.client.Request("session.ui.elicitation", req) if err != nil { return nil, err } - var result ShellExecResult + var result UIElicitationResponse if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *ShellApi) Kill(ctx context.Context, params *ShellKillRequest) (*ShellKillResult, error) { +func (a *UIApi) HandlePendingElicitation(ctx context.Context, params *UIHandlePendingElicitationRequest) (*UIElicitationResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["processId"] = params.ProcessID - if params.Signal != nil { - req["signal"] = *params.Signal - } + req["requestId"] = params.RequestID + req["result"] = params.Result } - raw, err := a.client.Request("session.shell.kill", req) + raw, err := a.client.Request("session.ui.handlePendingElicitation", req) if err != nil { return nil, err } - var result ShellKillResult + var result UIElicitationResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: HistoryApi contains experimental APIs that may change or be removed. -type HistoryApi sessionApi +// Experimental: UsageApi contains experimental APIs that may change or be removed. +type UsageApi sessionApi -func (a *HistoryApi) Compact(ctx context.Context) (*HistoryCompactResult, error) { +func (a *UsageApi) GetMetrics(ctx context.Context) (*UsageGetMetricsResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.history.compact", req) + raw, err := a.client.Request("session.usage.getMetrics", req) if err != nil { return nil, err } - var result HistoryCompactResult + var result UsageGetMetricsResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *HistoryApi) Truncate(ctx context.Context, params *HistoryTruncateRequest) (*HistoryTruncateResult, error) { +type WorkspacesApi sessionApi + +func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreateFileRequest) (*WorkspacesCreateFileResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { - req["eventId"] = params.EventID + req["content"] = params.Content + req["path"] = params.Path } - raw, err := a.client.Request("session.history.truncate", req) + raw, err := a.client.Request("session.workspaces.createFile", req) if err != nil { return nil, err } - var result HistoryTruncateResult + var result WorkspacesCreateFileResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: UsageApi contains experimental APIs that may change or be removed. -type UsageApi sessionApi - -func (a *UsageApi) GetMetrics(ctx context.Context) (*UsageGetMetricsResult, error) { +func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspaceResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.usage.getMetrics", req) + raw, err := a.client.Request("session.workspaces.getWorkspace", req) if err != nil { return nil, err } - var result UsageGetMetricsResult + var result WorkspacesGetWorkspaceResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: RemoteApi contains experimental APIs that may change or be removed. -type RemoteApi sessionApi - -func (a *RemoteApi) Enable(ctx context.Context) (*RemoteEnableResult, error) { +func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.remote.enable", req) + raw, err := a.client.Request("session.workspaces.listFiles", req) if err != nil { return nil, err } - var result RemoteEnableResult + var result WorkspacesListFilesResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *RemoteApi) Disable(ctx context.Context) (*RemoteDisableResult, error) { +func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFileRequest) (*WorkspacesReadFileResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.remote.disable", req) + if params != nil { + req["path"] = params.Path + } + raw, err := a.client.Request("session.workspaces.readFile", req) if err != nil { return nil, err } - var result RemoteDisableResult + var result WorkspacesReadFileResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } @@ -3781,55 +3805,43 @@ func (a *RemoteApi) Disable(ctx context.Context) (*RemoteDisableResult, error) { // SessionRpc provides typed session-scoped RPC methods. type SessionRpc struct { - common sessionApi // Reuse a single struct instead of allocating one for each service on the heap. + // Reuse a single struct instead of allocating one for each service on the heap. + common sessionApi + Agent *AgentApi Auth *AuthApi - Model *ModelApi + Commands *CommandsApi + Extensions *ExtensionsApi + Fleet *FleetApi + History *HistoryApi + Instructions *InstructionsApi + Mcp *McpApi Mode *ModeApi + Model *ModelApi Name *NameApi + Permissions *PermissionsApi Plan *PlanApi - Workspaces *WorkspacesApi - Instructions *InstructionsApi - Fleet *FleetApi - Agent *AgentApi - Tasks *TasksApi - Skills *SkillsApi - Mcp *McpApi Plugins *PluginsApi - Extensions *ExtensionsApi + Remote *RemoteApi + Shell *ShellApi + Skills *SkillsApi + Tasks *TasksApi Tools *ToolsApi - Commands *CommandsApi UI *UIApi - Permissions *PermissionsApi - Shell *ShellApi - History *HistoryApi Usage *UsageApi - Remote *RemoteApi -} - -func (a *SessionRpc) Suspend(ctx context.Context) (*SuspendResult, error) { - req := map[string]any{"sessionId": a.common.sessionID} - raw, err := a.common.client.Request("session.suspend", req) - if err != nil { - return nil, err - } - var result SuspendResult - if err := json.Unmarshal(raw, &result); err != nil { - return nil, err - } - return &result, nil + Workspaces *WorkspacesApi } func (a *SessionRpc) Log(ctx context.Context, params *LogRequest) (*LogResult, error) { req := map[string]any{"sessionId": a.common.sessionID} if params != nil { - req["message"] = params.Message - if params.Level != nil { - req["level"] = *params.Level - } if params.Ephemeral != nil { req["ephemeral"] = *params.Ephemeral } + if params.Level != nil { + req["level"] = *params.Level + } + req["message"] = params.Message if params.URL != nil { req["url"] = *params.URL } @@ -3845,45 +3857,58 @@ func (a *SessionRpc) Log(ctx context.Context, params *LogRequest) (*LogResult, e return &result, nil } +func (a *SessionRpc) Suspend(ctx context.Context) (*SuspendResult, error) { + req := map[string]any{"sessionId": a.common.sessionID} + raw, err := a.common.client.Request("session.suspend", req) + if err != nil { + return nil, err + } + var result SuspendResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + func NewSessionRpc(client *jsonrpc2.Client, sessionID string) *SessionRpc { r := &SessionRpc{} r.common = sessionApi{client: client, sessionID: sessionID} + r.Agent = (*AgentApi)(&r.common) r.Auth = (*AuthApi)(&r.common) - r.Model = (*ModelApi)(&r.common) + r.Commands = (*CommandsApi)(&r.common) + r.Extensions = (*ExtensionsApi)(&r.common) + r.Fleet = (*FleetApi)(&r.common) + r.History = (*HistoryApi)(&r.common) + r.Instructions = (*InstructionsApi)(&r.common) + r.Mcp = (*McpApi)(&r.common) r.Mode = (*ModeApi)(&r.common) + r.Model = (*ModelApi)(&r.common) r.Name = (*NameApi)(&r.common) + r.Permissions = (*PermissionsApi)(&r.common) r.Plan = (*PlanApi)(&r.common) - r.Workspaces = (*WorkspacesApi)(&r.common) - r.Instructions = (*InstructionsApi)(&r.common) - r.Fleet = (*FleetApi)(&r.common) - r.Agent = (*AgentApi)(&r.common) - r.Tasks = (*TasksApi)(&r.common) - r.Skills = (*SkillsApi)(&r.common) - r.Mcp = (*McpApi)(&r.common) r.Plugins = (*PluginsApi)(&r.common) - r.Extensions = (*ExtensionsApi)(&r.common) + r.Remote = (*RemoteApi)(&r.common) + r.Shell = (*ShellApi)(&r.common) + r.Skills = (*SkillsApi)(&r.common) + r.Tasks = (*TasksApi)(&r.common) r.Tools = (*ToolsApi)(&r.common) - r.Commands = (*CommandsApi)(&r.common) r.UI = (*UIApi)(&r.common) - r.Permissions = (*PermissionsApi)(&r.common) - r.Shell = (*ShellApi)(&r.common) - r.History = (*HistoryApi)(&r.common) r.Usage = (*UsageApi)(&r.common) - r.Remote = (*RemoteApi)(&r.common) + r.Workspaces = (*WorkspacesApi)(&r.common) return r } type SessionFsHandler interface { - ReadFile(request *SessionFSReadFileRequest) (*SessionFSReadFileResult, error) - WriteFile(request *SessionFSWriteFileRequest) (*SessionFSError, error) - AppendFile(request *SessionFSAppendFileRequest) (*SessionFSError, error) - Exists(request *SessionFSExistsRequest) (*SessionFSExistsResult, error) - Stat(request *SessionFSStatRequest) (*SessionFSStatResult, error) - Mkdir(request *SessionFSMkdirRequest) (*SessionFSError, error) - Readdir(request *SessionFSReaddirRequest) (*SessionFSReaddirResult, error) - ReaddirWithTypes(request *SessionFSReaddirWithTypesRequest) (*SessionFSReaddirWithTypesResult, error) - Rm(request *SessionFSRmRequest) (*SessionFSError, error) - Rename(request *SessionFSRenameRequest) (*SessionFSError, error) + AppendFile(request *SessionFsAppendFileRequest) (*SessionFsError, error) + Exists(request *SessionFsExistsRequest) (*SessionFsExistsResult, error) + Mkdir(request *SessionFsMkdirRequest) (*SessionFsError, error) + Readdir(request *SessionFsReaddirRequest) (*SessionFsReaddirResult, error) + ReaddirWithTypes(request *SessionFsReaddirWithTypesRequest) (*SessionFsReaddirWithTypesResult, error) + ReadFile(request *SessionFsReadFileRequest) (*SessionFsReadFileResult, error) + Rename(request *SessionFsRenameRequest) (*SessionFsError, error) + Rm(request *SessionFsRmRequest) (*SessionFsError, error) + Stat(request *SessionFsStatRequest) (*SessionFsStatResult, error) + WriteFile(request *SessionFsWriteFileRequest) (*SessionFsError, error) } // ClientSessionApiHandlers provides all client session API handler groups for a session. @@ -3902,10 +3927,11 @@ func clientSessionHandlerError(err error) *jsonrpc2.Error { return &jsonrpc2.Error{Code: -32603, Message: err.Error()} } -// RegisterClientSessionApiHandlers registers handlers for server-to-client session API calls. +// RegisterClientSessionApiHandlers registers handlers for server-to-client session API +// calls. func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(sessionID string) *ClientSessionApiHandlers) { - client.SetRequestHandler("sessionFs.readFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSReadFileRequest + client.SetRequestHandler("sessionFs.appendFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsAppendFileRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -3913,7 +3939,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.ReadFile(&request) + result, err := handlers.SessionFs.AppendFile(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -3923,8 +3949,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.writeFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSWriteFileRequest + client.SetRequestHandler("sessionFs.exists", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsExistsRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -3932,7 +3958,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.WriteFile(&request) + result, err := handlers.SessionFs.Exists(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -3942,8 +3968,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.appendFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSAppendFileRequest + client.SetRequestHandler("sessionFs.mkdir", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsMkdirRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -3951,7 +3977,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.AppendFile(&request) + result, err := handlers.SessionFs.Mkdir(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -3961,8 +3987,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.exists", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSExistsRequest + client.SetRequestHandler("sessionFs.readdir", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsReaddirRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -3970,7 +3996,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.Exists(&request) + result, err := handlers.SessionFs.Readdir(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -3980,8 +4006,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.stat", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSStatRequest + client.SetRequestHandler("sessionFs.readdirWithTypes", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsReaddirWithTypesRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -3989,7 +4015,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.Stat(&request) + result, err := handlers.SessionFs.ReaddirWithTypes(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -3999,8 +4025,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.mkdir", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSMkdirRequest + client.SetRequestHandler("sessionFs.readFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsReadFileRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -4008,7 +4034,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.Mkdir(&request) + result, err := handlers.SessionFs.ReadFile(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -4018,8 +4044,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.readdir", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSReaddirRequest + client.SetRequestHandler("sessionFs.rename", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsRenameRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -4027,7 +4053,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.Readdir(&request) + result, err := handlers.SessionFs.Rename(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -4037,8 +4063,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.readdirWithTypes", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSReaddirWithTypesRequest + client.SetRequestHandler("sessionFs.rm", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsRmRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -4046,7 +4072,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.ReaddirWithTypes(&request) + result, err := handlers.SessionFs.Rm(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -4056,8 +4082,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.rm", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSRmRequest + client.SetRequestHandler("sessionFs.stat", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsStatRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -4065,7 +4091,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.Rm(&request) + result, err := handlers.SessionFs.Stat(&request) if err != nil { return nil, clientSessionHandlerError(err) } @@ -4075,8 +4101,8 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( } return raw, nil }) - client.SetRequestHandler("sessionFs.rename", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { - var request SessionFSRenameRequest + client.SetRequestHandler("sessionFs.writeFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request SessionFsWriteFileRequest if err := json.Unmarshal(params, &request); err != nil { return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)} } @@ -4084,7 +4110,7 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func( if handlers == nil || handlers.SessionFs == nil { return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)} } - result, err := handlers.SessionFs.Rename(&request) + result, err := handlers.SessionFs.WriteFile(&request) if err != nil { return nil, clientSessionHandlerError(err) } diff --git a/go/rpc/generated_rpc_union_test.go b/go/rpc/generated_rpc_union_test.go new file mode 100644 index 000000000..c0afbe911 --- /dev/null +++ b/go/rpc/generated_rpc_union_test.go @@ -0,0 +1,101 @@ +package rpc + +import ( + "encoding/json" + "testing" +) + +func TestExternalToolResultJSONUnion(t *testing.T) { + stringResult := ExternalToolResult{String: stringPtr("tool result")} + raw, err := json.Marshal(stringResult) + if err != nil { + t.Fatalf("marshal string result: %v", err) + } + if string(raw) != `"tool result"` { + t.Fatalf("marshal string result = %s", raw) + } + + var decodedString ExternalToolResult + if err := json.Unmarshal([]byte(`"tool result"`), &decodedString); err != nil { + t.Fatalf("unmarshal string result: %v", err) + } + if decodedString.String == nil || *decodedString.String != "tool result" { + t.Fatalf("unmarshal string result = %#v", decodedString) + } + + objectResult := ExternalToolResult{ExternalToolTextResultForLlm: &ExternalToolTextResultForLlm{TextResultForLlm: "expanded"}} + raw, err = json.Marshal(objectResult) + if err != nil { + t.Fatalf("marshal object result: %v", err) + } + if string(raw) != `{"textResultForLlm":"expanded"}` { + t.Fatalf("marshal object result = %s", raw) + } + + var decodedObject ExternalToolResult + if err := json.Unmarshal([]byte(`{"textResultForLlm":"expanded"}`), &decodedObject); err != nil { + t.Fatalf("unmarshal object result: %v", err) + } + if decodedObject.ExternalToolTextResultForLlm == nil || decodedObject.ExternalToolTextResultForLlm.TextResultForLlm != "expanded" { + t.Fatalf("unmarshal object result = %#v", decodedObject) + } +} + +func TestFilterMappingJSONUnion(t *testing.T) { + mapping := FilterMapping{EnumMap: map[string]FilterMappingValue{"secret": FilterMappingValueHiddenCharacters}} + raw, err := json.Marshal(mapping) + if err != nil { + t.Fatalf("marshal filter mapping map: %v", err) + } + if string(raw) != `{"secret":"hidden_characters"}` { + t.Fatalf("marshal filter mapping map = %s", raw) + } + + var decodedMap FilterMapping + if err := json.Unmarshal([]byte(`{"secret":"hidden_characters"}`), &decodedMap); err != nil { + t.Fatalf("unmarshal filter mapping map: %v", err) + } + if decodedMap.EnumMap["secret"] != FilterMappingValueHiddenCharacters { + t.Fatalf("unmarshal filter mapping map = %#v", decodedMap) + } + + enumValue := FilterMappingStringMarkdown + raw, err = json.Marshal(FilterMapping{Enum: &enumValue}) + if err != nil { + t.Fatalf("marshal filter mapping enum: %v", err) + } + if string(raw) != `"markdown"` { + t.Fatalf("marshal filter mapping enum = %s", raw) + } + + var decodedEnum FilterMapping + if err := json.Unmarshal([]byte(`"markdown"`), &decodedEnum); err != nil { + t.Fatalf("unmarshal filter mapping enum: %v", err) + } + if decodedEnum.Enum == nil || *decodedEnum.Enum != FilterMappingStringMarkdown { + t.Fatalf("unmarshal filter mapping enum = %#v", decodedEnum) + } +} + +func TestUIElicitationFieldValueJSONUnion(t *testing.T) { + boolValue := true + raw, err := json.Marshal(UIElicitationFieldValue{Bool: &boolValue}) + if err != nil { + t.Fatalf("marshal bool value: %v", err) + } + if string(raw) != `true` { + t.Fatalf("marshal bool value = %s", raw) + } + + var decodedArray UIElicitationFieldValue + if err := json.Unmarshal([]byte(`["a","b"]`), &decodedArray); err != nil { + t.Fatalf("unmarshal string array value: %v", err) + } + if len(decodedArray.StringArray) != 2 || decodedArray.StringArray[0] != "a" || decodedArray.StringArray[1] != "b" { + t.Fatalf("unmarshal string array value = %#v", decodedArray) + } +} + +func stringPtr(value string) *string { + return &value +} diff --git a/go/rpc/result_union.go b/go/rpc/result_union.go deleted file mode 100644 index 3387dce1b..000000000 --- a/go/rpc/result_union.go +++ /dev/null @@ -1,35 +0,0 @@ -package rpc - -import "encoding/json" - -// MarshalJSON serializes ExternalToolResult as the appropriate JSON variant: -// a plain string when String is set, or the ExternalToolTextResultForLlm object otherwise. -// The generated struct has no custom marshaler, so without this the Go -// struct fields would serialize as {"ExternalToolTextResultForLlm":...,"String":...} -// instead of the union the server expects. -func (r ExternalToolResult) MarshalJSON() ([]byte, error) { - if r.String != nil { - return json.Marshal(*r.String) - } - if r.ExternalToolTextResultForLlm != nil { - return json.Marshal(*r.ExternalToolTextResultForLlm) - } - return []byte("null"), nil -} - -// UnmarshalJSON deserializes a JSON value into the appropriate ExternalToolResult variant. -func (r *ExternalToolResult) UnmarshalJSON(data []byte) error { - // Try string first - var s string - if err := json.Unmarshal(data, &s); err == nil { - r.String = &s - return nil - } - // Try ExternalToolTextResultForLlm object - var rr ExternalToolTextResultForLlm - if err := json.Unmarshal(data, &rr); err == nil { - r.ExternalToolTextResultForLlm = &rr - return nil - } - return nil -} diff --git a/go/session.go b/go/session.go index 884a3773d..0b70950c4 100644 --- a/go/session.go +++ b/go/session.go @@ -746,7 +746,6 @@ func (ui *SessionUI) Confirm(ctx context.Context, message string) (bool, error) if err := ui.session.assertElicitation(); err != nil { return false, err } - defaultTrue := &rpc.UIElicitationFieldValue{Bool: Bool(true)} rpcResult, err := ui.session.RPC.UI.Elicitation(ctx, &rpc.UIElicitationRequest{ Message: message, RequestedSchema: rpc.UIElicitationSchema{ @@ -754,7 +753,7 @@ func (ui *SessionUI) Confirm(ctx context.Context, message string) (bool, error) Properties: map[string]rpc.UIElicitationSchemaProperty{ "confirmed": { Type: rpc.UIElicitationSchemaPropertyTypeBoolean, - Default: defaultTrue, + Default: toRPCContent(true), }, }, Required: []string{"confirmed"}, @@ -828,7 +827,7 @@ func (ui *SessionUI) Input(ctx context.Context, message string, opts *InputOptio prop.Format = &format } if opts.Default != "" { - prop.Default = &rpc.UIElicitationFieldValue{String: &opts.Default} + prop.Default = toRPCContent(opts.Default) } } rpcResult, err := ui.session.RPC.UI.Elicitation(ctx, &rpc.UIElicitationRequest{ diff --git a/go/session_fs_provider.go b/go/session_fs_provider.go index eb7107581..197b3fc20 100644 --- a/go/session_fs_provider.go +++ b/go/session_fs_provider.go @@ -38,7 +38,7 @@ type SessionFsProvider interface { Readdir(path string) ([]string, error) // ReaddirWithTypes lists entries with type information. // Return os.ErrNotExist if the directory does not exist. - ReaddirWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error) + ReaddirWithTypes(path string) ([]rpc.SessionFsReaddirWithTypesEntry, error) // Rm removes a file or directory. If recursive is true, remove contents too. // If force is true, do not return an error when the path does not exist. Rm(path string, recursive bool, force bool) error @@ -56,7 +56,7 @@ type SessionFsFileInfo struct { } // sessionFsAdapter wraps a SessionFsProvider to implement rpc.SessionFsHandler, -// converting idiomatic Go errors into SessionFSError results. +// converting idiomatic Go errors into SessionFsError results. type sessionFsAdapter struct { provider SessionFsProvider } @@ -65,15 +65,15 @@ func newSessionFsAdapter(provider SessionFsProvider) rpc.SessionFsHandler { return &sessionFsAdapter{provider: provider} } -func (a *sessionFsAdapter) ReadFile(request *rpc.SessionFSReadFileRequest) (*rpc.SessionFSReadFileResult, error) { +func (a *sessionFsAdapter) ReadFile(request *rpc.SessionFsReadFileRequest) (*rpc.SessionFsReadFileResult, error) { content, err := a.provider.ReadFile(request.Path) if err != nil { - return &rpc.SessionFSReadFileResult{Error: toSessionFsError(err)}, nil + return &rpc.SessionFsReadFileResult{Error: toSessionFsError(err)}, nil } - return &rpc.SessionFSReadFileResult{Content: content}, nil + return &rpc.SessionFsReadFileResult{Content: content}, nil } -func (a *sessionFsAdapter) WriteFile(request *rpc.SessionFSWriteFileRequest) (*rpc.SessionFSError, error) { +func (a *sessionFsAdapter) WriteFile(request *rpc.SessionFsWriteFileRequest) (*rpc.SessionFsError, error) { var mode *int if request.Mode != nil { m := int(*request.Mode) @@ -85,7 +85,7 @@ func (a *sessionFsAdapter) WriteFile(request *rpc.SessionFSWriteFileRequest) (*r return nil, nil } -func (a *sessionFsAdapter) AppendFile(request *rpc.SessionFSAppendFileRequest) (*rpc.SessionFSError, error) { +func (a *sessionFsAdapter) AppendFile(request *rpc.SessionFsAppendFileRequest) (*rpc.SessionFsError, error) { var mode *int if request.Mode != nil { m := int(*request.Mode) @@ -97,20 +97,20 @@ func (a *sessionFsAdapter) AppendFile(request *rpc.SessionFSAppendFileRequest) ( return nil, nil } -func (a *sessionFsAdapter) Exists(request *rpc.SessionFSExistsRequest) (*rpc.SessionFSExistsResult, error) { +func (a *sessionFsAdapter) Exists(request *rpc.SessionFsExistsRequest) (*rpc.SessionFsExistsResult, error) { exists, err := a.provider.Exists(request.Path) if err != nil { - return &rpc.SessionFSExistsResult{Exists: false}, nil + return &rpc.SessionFsExistsResult{Exists: false}, nil } - return &rpc.SessionFSExistsResult{Exists: exists}, nil + return &rpc.SessionFsExistsResult{Exists: exists}, nil } -func (a *sessionFsAdapter) Stat(request *rpc.SessionFSStatRequest) (*rpc.SessionFSStatResult, error) { +func (a *sessionFsAdapter) Stat(request *rpc.SessionFsStatRequest) (*rpc.SessionFsStatResult, error) { info, err := a.provider.Stat(request.Path) if err != nil { - return &rpc.SessionFSStatResult{Error: toSessionFsError(err)}, nil + return &rpc.SessionFsStatResult{Error: toSessionFsError(err)}, nil } - return &rpc.SessionFSStatResult{ + return &rpc.SessionFsStatResult{ IsFile: info.IsFile, IsDirectory: info.IsDirectory, Size: info.Size, @@ -119,7 +119,7 @@ func (a *sessionFsAdapter) Stat(request *rpc.SessionFSStatRequest) (*rpc.Session }, nil } -func (a *sessionFsAdapter) Mkdir(request *rpc.SessionFSMkdirRequest) (*rpc.SessionFSError, error) { +func (a *sessionFsAdapter) Mkdir(request *rpc.SessionFsMkdirRequest) (*rpc.SessionFsError, error) { recursive := request.Recursive != nil && *request.Recursive var mode *int if request.Mode != nil { @@ -132,23 +132,23 @@ func (a *sessionFsAdapter) Mkdir(request *rpc.SessionFSMkdirRequest) (*rpc.Sessi return nil, nil } -func (a *sessionFsAdapter) Readdir(request *rpc.SessionFSReaddirRequest) (*rpc.SessionFSReaddirResult, error) { +func (a *sessionFsAdapter) Readdir(request *rpc.SessionFsReaddirRequest) (*rpc.SessionFsReaddirResult, error) { entries, err := a.provider.Readdir(request.Path) if err != nil { - return &rpc.SessionFSReaddirResult{Error: toSessionFsError(err)}, nil + return &rpc.SessionFsReaddirResult{Error: toSessionFsError(err)}, nil } - return &rpc.SessionFSReaddirResult{Entries: entries}, nil + return &rpc.SessionFsReaddirResult{Entries: entries}, nil } -func (a *sessionFsAdapter) ReaddirWithTypes(request *rpc.SessionFSReaddirWithTypesRequest) (*rpc.SessionFSReaddirWithTypesResult, error) { +func (a *sessionFsAdapter) ReaddirWithTypes(request *rpc.SessionFsReaddirWithTypesRequest) (*rpc.SessionFsReaddirWithTypesResult, error) { entries, err := a.provider.ReaddirWithTypes(request.Path) if err != nil { - return &rpc.SessionFSReaddirWithTypesResult{Error: toSessionFsError(err)}, nil + return &rpc.SessionFsReaddirWithTypesResult{Error: toSessionFsError(err)}, nil } - return &rpc.SessionFSReaddirWithTypesResult{Entries: entries}, nil + return &rpc.SessionFsReaddirWithTypesResult{Entries: entries}, nil } -func (a *sessionFsAdapter) Rm(request *rpc.SessionFSRmRequest) (*rpc.SessionFSError, error) { +func (a *sessionFsAdapter) Rm(request *rpc.SessionFsRmRequest) (*rpc.SessionFsError, error) { recursive := request.Recursive != nil && *request.Recursive force := request.Force != nil && *request.Force if err := a.provider.Rm(request.Path, recursive, force); err != nil { @@ -157,18 +157,18 @@ func (a *sessionFsAdapter) Rm(request *rpc.SessionFSRmRequest) (*rpc.SessionFSEr return nil, nil } -func (a *sessionFsAdapter) Rename(request *rpc.SessionFSRenameRequest) (*rpc.SessionFSError, error) { +func (a *sessionFsAdapter) Rename(request *rpc.SessionFsRenameRequest) (*rpc.SessionFsError, error) { if err := a.provider.Rename(request.Src, request.Dest); err != nil { return toSessionFsError(err), nil } return nil, nil } -func toSessionFsError(err error) *rpc.SessionFSError { - code := rpc.SessionFSErrorCodeUNKNOWN +func toSessionFsError(err error) *rpc.SessionFsError { + code := rpc.SessionFsErrorCodeUNKNOWN if errors.Is(err, os.ErrNotExist) { - code = rpc.SessionFSErrorCodeENOENT + code = rpc.SessionFsErrorCodeENOENT } msg := err.Error() - return &rpc.SessionFSError{Code: code, Message: &msg} + return &rpc.SessionFsError{Code: code, Message: &msg} } diff --git a/go/types.go b/go/types.go index ee973a069..74ef3a2c3 100644 --- a/go/types.go +++ b/go/types.go @@ -565,7 +565,7 @@ type SessionFsConfig struct { // session-scoped files such as events, checkpoints, and temp files. SessionStatePath string // Conventions identifies the path conventions used by this filesystem provider. - Conventions rpc.SessionFSSetProviderConventions + Conventions rpc.SessionFsSetProviderConventions } // SessionConfig configures a new session diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 81fe4ba21..ef3bb3fcf 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1260,6 +1260,7 @@ "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -1299,6 +1300,7 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -1627,6 +1629,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1954,6 +1957,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -2862,6 +2866,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3280,6 +3285,7 @@ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -3313,6 +3319,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3380,6 +3387,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", diff --git a/scripts/codegen/go.ts b/scripts/codegen/go.ts index d75c568df..c72d91e27 100644 --- a/scripts/codegen/go.ts +++ b/scripts/codegen/go.ts @@ -9,33 +9,31 @@ import { execFile } from "child_process"; import fs from "fs/promises"; import type { JSONSchema7 } from "json-schema"; -import { FetchingJSONSchemaStore, InputData, JSONSchemaInput, quicktype } from "quicktype-core"; import { promisify } from "util"; +import wordwrap from "wordwrap"; import { cloneSchemaForCodegen, + collectDefinitionCollections, filterNodeByVisibility, fixNullableRequiredRefsInApiSchema, getApiSchemaPath, + getNullableInner, getRpcSchemaTypeName, getSessionEventsSchemaPath, + getSessionEventVariantSchemas, + getSharedSessionEventEnvelopeProperties, hasSchemaPayload, - isNodeFullyExperimental, isNodeFullyDeprecated, + isNodeFullyExperimental, + isRpcMethod, isSchemaDeprecated, isVoidSchema, - getNullableInner, - isRpcMethod, postProcessSchema, - stripBooleanLiterals, - writeGeneratedFile, - collectDefinitionCollections, - resolveObjectSchema, - resolveSchema, - withSharedDefinitions, refTypeName, + resolveObjectSchema, resolveRef, - getSessionEventVariantSchemas, - getSharedSessionEventEnvelopeProperties, + resolveSchema, + writeGeneratedFile, type ApiSchema, type DefinitionCollections, type RpcMethod, @@ -48,6 +46,8 @@ const execFileAsync = promisify(execFile); // Go initialisms that should be all-caps const goInitialisms = new Set(["id", "ui", "uri", "url", "api", "http", "https", "json", "xml", "html", "css", "sql", "ssh", "tcp", "udp", "ip", "rpc", "mime"]); +const goCommentTextWrapLength = 90; +const wrapGoCommentText = wordwrap(goCommentTextWrapLength); function toPascalCase(s: string): string { return s @@ -56,135 +56,96 @@ function toPascalCase(s: string): string { .join(""); } +function toGoSchemaTypeName(s: string): string { + return toPascalCase(splitGoIdentifierWords(s).join("_")); +} + function toGoFieldName(jsonName: string): string { // Handle camelCase field names like "modelId" -> "ModelID" - return jsonName - .replace(/([a-z])([A-Z])/g, "$1_$2") - .split("_") + return splitGoIdentifierWords(jsonName) .map((w) => goInitialisms.has(w.toLowerCase()) ? w.toUpperCase() : w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()) .join(""); } -/** - * Post-process Go enum constants so every constant follows the canonical - * Go `TypeNameValue` convention. quicktype disambiguates collisions with - * whimsical prefixes (Purple, Fluffy, …) that we replace. - */ -function postProcessEnumConstants(code: string): string { - const renames = new Map(); - - // Match constant declarations inside const ( … ) blocks. - const constLineRe = /^\s+(\w+)\s+(\w+)\s*=\s*"([^"]+)"/gm; - let m; - while ((m = constLineRe.exec(code)) !== null) { - const [, constName, typeName, value] = m; - if (constName.startsWith(typeName)) continue; - - // Use the same initialism logic as toPascalCase so "url" → "URL", "mcp" → "MCP", etc. - const valuePascal = value - .split(/[._-]/) - .map((w) => goInitialisms.has(w.toLowerCase()) ? w.toUpperCase() : w.charAt(0).toUpperCase() + w.slice(1)) - .join(""); - const desired = typeName + valuePascal; - if (constName !== desired) { - renames.set(constName, desired); - } - } +function compareGoFieldNames(left: string, right: string): number { + return left.localeCompare(right); +} - // Replace each const block in place, then fix switch-case references - // in marshal/unmarshal functions. This avoids renaming struct fields. +function sortByGoFieldName(entries: [string, T][]): [string, T][] { + return entries.sort(([left], [right]) => compareGoFieldNames(toGoFieldName(left), toGoFieldName(right))); +} - // Phase 1: Rename inside const ( … ) blocks - code = code.replace(/^(const \([\s\S]*?\n\))/gm, (block) => { - let b = block; - for (const [oldName, newName] of renames) { - b = b.replace(new RegExp(`\\b${oldName}\\b`, "g"), newName); - } - return b; - }); - - // Phase 2: Rename inside func bodies (marshal/unmarshal helpers use case statements) - code = code.replace(/^(func \([\s\S]*?\n\})/gm, (funcBlock) => { - let b = funcBlock; - for (const [oldName, newName] of renames) { - b = b.replace(new RegExp(`\\b${oldName}\\b`, "g"), newName); - } - return b; - }); +function sortByPascalName(entries: [string, T][]): [string, T][] { + return entries.sort(([left], [right]) => toPascalCase(left).localeCompare(toPascalCase(right))); +} - return code; +function compareRpcMethodsByGoName(left: RpcMethod, right: RpcMethod): number { + return clientHandlerMethodName(left.rpcMethod).localeCompare(clientHandlerMethodName(right.rpcMethod)); } -function collapsePlaceholderGoStructs(code: string, knownDefinitionNames?: Set): string { - const structBlockRe = /((?:\/\/.*\r?\n)*)type\s+(\w+)\s+struct\s*\{[\s\S]*?^\}/gm; - const matches = [...code.matchAll(structBlockRe)].map((match) => ({ - fullBlock: match[0], - name: match[2], - normalizedBody: normalizeGoStructBlock(match[0], match[2]), - })); - const groups = new Map(); +function splitGoIdentifierWords(name: string): string[] { + return name + .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2") + .replace(/([a-z0-9])([A-Z])/g, "$1_$2") + .split(/[._-]/) + .filter((word) => word.length > 0); +} - for (const match of matches) { - const group = groups.get(match.normalizedBody) ?? []; - group.push(match); - groups.set(match.normalizedBody, group); - } +function isStringEnumDefinition(definition: JSONSchema7): definition is JSONSchema7 & { enum: string[] } { + return Array.isArray(definition.enum) && definition.enum.every((value) => typeof value === "string"); +} - for (const group of groups.values()) { - if (group.length < 2) continue; +function pushGoComment(lines: string[], text: string, indent = "", wrap = true): void { + lines.push(...goCommentLines(text, indent, wrap)); +} - const canonical = chooseCanonicalPlaceholderDuplicate(group.map(({ name }) => name), knownDefinitionNames); - if (!canonical) continue; +function pushGoCommentForContext(lines: string[], text: string, ctx: GoCodegenCtx, indent = ""): void { + pushGoComment(lines, text, indent, ctx.wrapComments !== false); +} - for (const duplicate of group) { - if (duplicate.name === canonical) continue; - // Only collapse types that quicktype invented (Class suffix or not - // in the schema's named definitions). Preserve intentionally-named types. - if (!isPlaceholderTypeName(duplicate.name) && knownDefinitionNames?.has(duplicate.name.toLowerCase())) continue; +function goCommentLines(text: string, indent = "", wrap = true): string[] { + const prefix = `${indent}//`; + const lines: string[] = []; - code = code.replace(duplicate.fullBlock, ""); - code = code.replace(new RegExp(`\\b${duplicate.name}\\b`, "g"), canonical); + for (const paragraph of text.split(/\r?\n/)) { + const trimmed = paragraph.trim(); + if (trimmed.length === 0) { + lines.push(prefix); + continue; + } + const commentLines = wrap + ? wrapGoCommentText(trimmed).split("\n").map((wrappedLine: string) => wrappedLine.trim()) + : [trimmed]; + for (const line of commentLines) { + lines.push(`${prefix} ${line}`); } } - return code.replace(/\n{3,}/g, "\n\n"); + return lines; } -function normalizeGoStructBlock(block: string, name: string): string { - return block - .replace(/^\s*\/\/.*\r?\n/gm, "") - .replace(new RegExp(`^type\\s+${name}\\s+struct\\s*\\{`, "m"), "type struct {") +function wrapGeneratedGoComments(code: string): string { + return code .split(/\r?\n/) - .map((line) => line.trim()) - .filter((line) => line.length > 0) + .flatMap((line) => { + const match = /^(\s*)\/\/\s?(.*)$/.exec(line); + if (!match) return [line]; + const [, indent, text] = match; + if (text.length <= goCommentTextWrapLength) return [line]; + return goCommentLines(text, indent); + }) .join("\n"); } -function chooseCanonicalPlaceholderDuplicate(names: string[], knownDefinitionNames?: Set): string | undefined { - // Prefer the name that matches a schema definition — it's intentionally named. - if (knownDefinitionNames) { - const definedName = names.find((name) => knownDefinitionNames.has(name.toLowerCase())); - if (definedName) return definedName; - } - // Fallback for Class-suffix placeholders: pick the non-placeholder name. - const specificNames = names.filter((name) => !isPlaceholderTypeName(name)); - if (specificNames.length === 0) return undefined; - return specificNames[0]; -} - -function isPlaceholderTypeName(name: string): boolean { - return name.endsWith("Class"); -} - /** * Extract a mapping from (structName, jsonFieldName) → goFieldName - * so the wrapper code references the actual quicktype-generated field names. + * so the wrapper code references the generated Go field names. */ -function extractFieldNames(qtCode: string): Map> { +function extractFieldNames(generatedTypeCode: string): Map> { const result = new Map>(); const structRe = /^type\s+(\w+)\s+struct\s*\{([^}]*)\}/gm; let sm; - while ((sm = structRe.exec(qtCode)) !== null) { + while ((sm = structRe.exec(generatedTypeCode)) !== null) { const [, structName, body] = sm; const fields = new Map(); const fieldRe = /^\s+(\w+)\s+[^`\n]+`json:"([^",]+)/gm; @@ -197,133 +158,6 @@ function extractFieldNames(qtCode: string): Map> { return result; } -/** - * Add `,omitempty` to JSON tags for optional fields in quicktype-generated structs. - * - * Quicktype's Go renderer emits `omitempty` for most optional fields, but it can miss - * some — notably fields whose type is `*Foo` where `Foo` is a `$ref` to an `anyOf` union - * (e.g., `FilterMapping`). When such a pointer field is left without `omitempty`, the Go - * struct serializes the nil pointer as `"foo": null`, which the runtime's Zod schema - * rejects with a validation error. - * - * This pass walks each known struct (whose schema is in `definitions`) and rewrites any - * `json:"propName"` tag (no comma, no modifier) to `json:"propName,omitempty"` when - * `propName` is not listed in the schema's `required` array. - */ -function addMissingOmitemptyToQuicktypeStructs( - qtCode: string, - definitions: Record -): string { - // Build a case-insensitive lookup from emitted Go type name → schema definition. - const defByLower = new Map(); - for (const [name, def] of Object.entries(definitions)) { - defByLower.set(name.toLowerCase(), def); - } - - return qtCode.replace( - /^(type\s+(\w+)\s+struct\s*\{)([\s\S]*?)^\}/gm, - (match, header: string, typeName: string, body: string) => { - const def = defByLower.get(typeName.toLowerCase()); - if (!def || typeof def !== "object") return match; - - // Build the union of (properties, required) across the schema. For a regular - // object schema this is just (properties, required). For a discriminated union - // (anyOf with $ref variants), quicktype emits a flat struct merging all variant - // fields — we need to consider a property required only if it is required in - // every variant and present in every variant. - const merged = mergeSchemaPropertiesForOmitempty(def, defByLower); - if (!merged) return match; - const { properties, required } = merged; - - const newBody = body.replace( - /(`json:")([a-zA-Z0-9_]+)("`)/g, - (tagMatch: string, open: string, propName: string, close: string) => { - if (required.has(propName)) return tagMatch; - if (!(propName in properties)) return tagMatch; - return `${open}${propName},omitempty${close}`; - } - ); - return `${header}${newBody}}`; - } - ); -} - -function mergeSchemaPropertiesForOmitempty( - def: JSONSchema7, - defByLower: Map -): { properties: Record; required: Set } | undefined { - if (def.properties) { - return { - properties: def.properties as Record, - required: new Set(def.required || []), - }; - } - if (Array.isArray(def.anyOf)) { - const variantSchemas: JSONSchema7[] = []; - for (const v of def.anyOf as JSONSchema7[]) { - if (typeof v !== "object" || v === null) continue; - if (v.$ref) { - const refName = v.$ref.split("/").pop(); - if (!refName) continue; - const resolved = defByLower.get(refName.toLowerCase()); - if (resolved && resolved.properties) variantSchemas.push(resolved); - } else if (v.properties) { - variantSchemas.push(v); - } - } - if (variantSchemas.length === 0) return undefined; - - const properties: Record = {}; - const presenceCount = new Map(); - const requiredEverywhere = new Set(); - let firstVariant = true; - for (const variant of variantSchemas) { - const variantRequired = new Set(variant.required || []); - const propNames = Object.keys(variant.properties || {}); - if (firstVariant) { - for (const name of variantRequired) requiredEverywhere.add(name); - firstVariant = false; - } else { - for (const name of [...requiredEverywhere]) { - if (!variantRequired.has(name)) requiredEverywhere.delete(name); - } - } - for (const name of propNames) { - presenceCount.set(name, (presenceCount.get(name) ?? 0) + 1); - if (!(name in properties)) { - properties[name] = (variant.properties as Record)[name]; - } - } - } - const required = new Set(); - for (const name of requiredEverywhere) { - if ((presenceCount.get(name) ?? 0) === variantSchemas.length) required.add(name); - } - return { properties, required }; - } - return undefined; -} - -function extractQuicktypeImports(qtCode: string): { code: string; imports: string[] } { - const collectedImports: string[] = []; - let code = qtCode.replace(/^import \(\n([\s\S]*?)^\)\n+/m, (_match, block: string) => { - for (const line of block.split(/\r?\n/)) { - const trimmed = line.trim(); - if (trimmed.length > 0) { - collectedImports.push(trimmed); - } - } - return ""; - }); - - code = code.replace(/^import ("[^"]+")\n+/m, (_match, singleImport: string) => { - collectedImports.push(singleImport.trim()); - return ""; - }); - - return { code, imports: collectedImports }; -} - async function formatGoFile(filePath: string): Promise { try { await execFileAsync("go", ["fmt", filePath]); @@ -335,7 +169,7 @@ async function formatGoFile(filePath: string): Promise { function collectRpcMethods(node: Record): RpcMethod[] { const results: RpcMethod[] = []; - for (const value of Object.values(node)) { + for (const [, value] of sortByPascalName(Object.entries(node))) { if (isRpcMethod(value)) { results.push(value); } else if (typeof value === "object" && value !== null) { @@ -362,9 +196,9 @@ function schemaSourceForNamedDefinition( if (schema?.$ref && resolvedSchema) { return resolvedSchema; } - // When the schema is an anyOf/oneOf wrapper (e.g., Zod optional params producing - // `anyOf: [{ not: {} }, { $ref }]`), use the resolved object schema to avoid - // generating self-referential type aliases that crash quicktype. + // When a method wrapper is named the same as the referenced schema inside an + // anyOf/oneOf, store the resolved object shape so the definition map does not + // create a self-referential alias. if ((schema?.anyOf || schema?.oneOf) && resolvedSchema?.properties) { return resolvedSchema; } @@ -430,6 +264,7 @@ interface GoCodegenCtx { enumsByName: Map; // enumName → enumName (dedup by type name, not values) generatedNames: Set; definitions?: DefinitionCollections; + wrapComments?: boolean; } function extractGoEventVariants(schema: JSONSchema7): GoEventVariant[] { @@ -471,17 +306,19 @@ function getGoSharedEventEnvelopeProperties(schema: JSONSchema7, ctx: GoCodegenC }); } -function emitGoEnvelopeStructField(property: GoEventEnvelopeProperty, includeComment: boolean): string[] { +function emitGoEnvelopeStructField(property: GoEventEnvelopeProperty, includeComment: boolean, wrapComments = true): string[] { const lines: string[] = []; if (includeComment && property.description) { - for (const line of property.description.split(/\r?\n/)) { - lines.push(`\t// ${line}`); - } + pushGoComment(lines, property.description, "\t", wrapComments); } lines.push(`\t${property.fieldName} ${property.typeName} \`${property.jsonTag}\``); return lines; } +function sortedGoEventEnvelopeProperties(properties: GoEventEnvelopeProperty[]): GoEventEnvelopeProperty[] { + return [...properties].sort((left, right) => compareGoFieldNames(left.fieldName, right.fieldName)); +} + /** * Find a const-valued discriminator property shared by all anyOf variants. */ @@ -527,25 +364,18 @@ function getOrCreateGoEnum( const lines: string[] = []; if (description) { - for (const line of description.split(/\r?\n/)) { - lines.push(`// ${line}`); - } + pushGoCommentForContext(lines, description, ctx); } if (deprecated) { - lines.push(`// Deprecated: ${enumName} is deprecated and will be removed in a future version.`); + pushGoCommentForContext(lines, `Deprecated: ${enumName} is deprecated and will be removed in a future version.`, ctx); } lines.push(`type ${enumName} string`); lines.push(``); lines.push(`const (`); - for (const value of values) { - const constSuffix = value - .split(/[-_.]/) - .map((w) => - goInitialisms.has(w.toLowerCase()) - ? w.toUpperCase() - : w.charAt(0).toUpperCase() + w.slice(1) - ) - .join(""); + const consts = values + .map((value) => ({ value, constSuffix: goEnumConstSuffix(value) })) + .sort((left, right) => `${enumName}${left.constSuffix}`.localeCompare(`${enumName}${right.constSuffix}`)); + for (const { value, constSuffix } of consts) { lines.push(`\t${enumName}${constSuffix} ${enumName} = "${value}"`); } lines.push(`)`); @@ -555,6 +385,35 @@ function getOrCreateGoEnum( return enumName; } +function goEnumConstSuffix(value: string): string { + return value + .split(/[-_.]/) + .map((word) => + goInitialisms.has(word.toLowerCase()) + ? word.toUpperCase() + : word.charAt(0).toUpperCase() + word.slice(1) + ) + .join(""); +} + +function schemaForConstValue(value: unknown): JSONSchema7 { + if (value === null) return { type: "null" }; + if (Array.isArray(value)) return { type: "array", items: {} }; + + switch (typeof value) { + case "boolean": + return { type: "boolean" }; + case "number": + return { type: Number.isInteger(value) ? "integer" : "number" }; + case "string": + return { type: "string" }; + case "object": + return { type: "object", additionalProperties: true }; + default: + return {}; + } +} + /** * Resolve a JSON Schema property to a Go type string. * Emits nested struct/enum definitions into ctx as a side effect. @@ -581,6 +440,10 @@ function resolveGoPropertyType( emitGoStruct(typeName, resolved, ctx); return isRequired ? typeName : `*${typeName}`; } + if (resolved.anyOf || resolved.oneOf) { + emitGoRpcDefinition(refTypeName(propSchema.$ref, ctx.definitions), resolved, ctx); + return isRequired ? typeName : `*${typeName}`; + } return resolveGoPropertyType(resolved, parentTypeName, jsonPropName, isRequired, ctx); } // Fallback: use the type name directly @@ -593,7 +456,6 @@ function resolveGoPropertyType( if (nullableInnerSchema) { // anyOf [T, null/{not:{}}] → nullable T const innerType = resolveGoPropertyType(nullableInnerSchema, parentTypeName, jsonPropName, true, ctx); - if (isRequired) return innerType; // Pointer-wrap if not already a pointer, slice, or map if (innerType.startsWith("*") || innerType.startsWith("[]") || innerType.startsWith("map[")) { return innerType; @@ -628,6 +490,11 @@ function resolveGoPropertyType( emitGoFlatDiscriminatedUnion(unionName, disc.property, disc.mapping, ctx, propSchema.description); return isRequired && !hasNull ? unionName : `*${unionName}`; } + if (canFlattenGoObjectUnion(resolvedVariants, ctx)) { + const unionName = (propSchema.title as string) || nestedName; + emitGoFlattenedObjectUnion(unionName, resolvedVariants, ctx, propSchema.description); + return isRequired && !hasNull ? unionName : `*${unionName}`; + } // Non-discriminated multi-type union → any return "any"; } @@ -639,9 +506,14 @@ function resolveGoPropertyType( return isRequired ? enumType : `*${enumType}`; } - // Handle const (discriminator markers) — just use string + // Handle const values. String consts stay enum-like to preserve generated names for + // discriminators; other const values use their underlying JSON type. if (propSchema.const !== undefined) { - return isRequired ? "string" : "*string"; + if (typeof propSchema.const !== "string") { + return resolveGoPropertyType(schemaForConstValue(propSchema.const), parentTypeName, jsonPropName, isRequired, ctx); + } + const enumType = getOrCreateGoEnum((propSchema.title as string) || nestedName, [propSchema.const], ctx, propSchema.description, isSchemaDeprecated(propSchema)); + return isRequired ? enumType : `*${enumType}`; } const type = propSchema.type; @@ -712,7 +584,15 @@ function resolveGoPropertyType( emitGoStruct(valueName, ap, ctx); return `map[string]${valueName}`; } - const valueType = resolveGoPropertyType(ap, parentTypeName, jsonPropName + "Value", true, ctx); + let valueType = resolveGoPropertyType(ap, parentTypeName, jsonPropName + "Value", true, ctx); + const resolvedValueType = ap.$ref ? resolveRef(ap.$ref, ctx.definitions) : undefined; + if (resolvedValueType?.anyOf || resolvedValueType?.oneOf) { + const unionMembers = goNonNullUnionMembers(resolvedValueType) + .map((member) => resolveGoUnionMember(member, ctx.definitions)); + if (!canFlattenGoObjectUnion(unionMembers, ctx) && !valueType.startsWith("*") && !valueType.startsWith("[]") && !valueType.startsWith("map[")) { + valueType = `*${valueType}`; + } + } return `map[string]${valueType}`; } return "map[string]any"; @@ -740,16 +620,14 @@ function emitGoStruct( const lines: string[] = []; const desc = description || schema.description; if (desc) { - for (const line of desc.split(/\r?\n/)) { - lines.push(`// ${line}`); - } + pushGoCommentForContext(lines, desc, ctx); } if (isSchemaDeprecated(schema)) { - lines.push(`// Deprecated: ${typeName} is deprecated and will be removed in a future version.`); + pushGoCommentForContext(lines, `Deprecated: ${typeName} is deprecated and will be removed in a future version.`, ctx); } lines.push(`type ${typeName} struct {`); - for (const [propName, propSchema] of Object.entries(schema.properties || {}).sort(([a], [b]) => a.localeCompare(b))) { + for (const [propName, propSchema] of sortByGoFieldName(Object.entries(schema.properties || {}))) { if (typeof propSchema !== "object") continue; const prop = propSchema as JSONSchema7; const isReq = required.has(propName); @@ -758,10 +636,10 @@ function emitGoStruct( const omit = isReq ? "" : ",omitempty"; if (prop.description) { - lines.push(`\t// ${prop.description}`); + pushGoCommentForContext(lines, prop.description, ctx, "\t"); } if (isSchemaDeprecated(prop)) { - lines.push(`\t// Deprecated: ${goName} is deprecated.`); + pushGoCommentForContext(lines, `Deprecated: ${goName} is deprecated.`, ctx, "\t"); } lines.push(`\t${goName} ${goType} \`json:"${propName}${omit}"\``); } @@ -834,27 +712,238 @@ function emitGoFlatDiscriminatedUnion( const lines: string[] = []; if (description) { - for (const line of description.split(/\r?\n/)) { - lines.push(`// ${line}`); - } + pushGoCommentForContext(lines, description, ctx); } lines.push(`type ${typeName} struct {`); - // Emit discriminator field first - lines.push(`\t// ${discGoName} discriminator`); - lines.push(`\t${discGoName} ${discEnumName} \`json:"${discriminatorProp}"\``); - - // Emit remaining fields - for (const [propName, info] of [...allProps.entries()].sort(([a], [b]) => a.localeCompare(b))) { - if (propName === discriminatorProp) continue; + for (const [propName, info] of sortByGoFieldName([...allProps.entries()])) { const goName = toGoFieldName(propName); - const goType = resolveGoPropertyType(info.schema, typeName, propName, info.requiredInAll, ctx); + const goType = propName === discriminatorProp + ? discEnumName + : resolveGoPropertyType(info.schema, typeName, propName, info.requiredInAll, ctx); const omit = info.requiredInAll ? "" : ",omitempty"; - if (info.schema.description) { - lines.push(`\t// ${info.schema.description}`); + if (propName === discriminatorProp) { + lines.push(`\t// ${discGoName} discriminator`); + } else if (info.schema.description) { + pushGoCommentForContext(lines, info.schema.description, ctx, "\t"); } if (isSchemaDeprecated(info.schema)) { - lines.push(`\t// Deprecated: ${goName} is deprecated.`); + pushGoCommentForContext(lines, `Deprecated: ${goName} is deprecated.`, ctx, "\t"); + } + lines.push(`\t${goName} ${goType} \`json:"${propName}${omit}"\``); + } + + lines.push(`}`); + ctx.structs.push(lines.join("\n")); +} + +function stableStringify(value: unknown): string { + if (Array.isArray(value)) { + return `[${value.map((item) => stableStringify(item)).join(",")}]`; + } + if (value && typeof value === "object") { + const entries = Object.entries(value as Record).sort(([a], [b]) => a.localeCompare(b)); + return `{${entries.map(([key, entryValue]) => `${JSON.stringify(key)}:${stableStringify(entryValue)}`).join(",")}}`; + } + return JSON.stringify(value); +} + +function normalizeSchemaForMatch(schema: JSONSchema7, ctx: GoCodegenCtx): unknown { + const resolved = resolveSchema(schema, ctx.definitions) ?? schema; + if (Array.isArray(resolved)) { + return resolved.map((item) => typeof item === "object" && item !== null + ? normalizeSchemaForMatch(item as JSONSchema7, ctx) + : item); + } + if (!resolved || typeof resolved !== "object") return resolved; + + const entries = Object.entries(resolved) + .filter(([key]) => !["title", "description", "default"].includes(key)) + .map(([key, value]) => { + if ((key === "anyOf" || key === "oneOf") && Array.isArray(value)) { + const members = value + .map((member) => normalizeSchemaForMatch(member as JSONSchema7, ctx)) + .sort((left, right) => stableStringify(left).localeCompare(stableStringify(right))); + return [key, members] as const; + } + if (key === "enum" && Array.isArray(value)) { + return [key, [...value].sort()] as const; + } + if (key === "type" && Array.isArray(value)) { + return [key, [...value].sort()] as const; + } + if (value && typeof value === "object") { + return [key, normalizeSchemaForMatch(value as JSONSchema7, ctx)] as const; + } + return [key, value] as const; + }); + + return Object.fromEntries(entries.sort(([left], [right]) => left.localeCompare(right))); +} + +function dedupeGoSchemasForMatch(schemas: JSONSchema7[], ctx: GoCodegenCtx): JSONSchema7[] { + const seen = new Set(); + const result: JSONSchema7[] = []; + for (const schema of schemas) { + const key = stableStringify(normalizeSchemaForMatch(schema, ctx)); + if (seen.has(key)) continue; + seen.add(key); + result.push(schema); + } + return result; +} + +function goDefinitionRefForEquivalentSchema(schema: JSONSchema7, ctx: GoCodegenCtx): string | undefined { + const schemaKey = stableStringify(normalizeSchemaForMatch(schema, ctx)); + const definitions = { + ...(ctx.definitions?.definitions ?? {}), + ...(ctx.definitions?.$defs ?? {}), + }; + for (const [definitionName, definition] of Object.entries(definitions)) { + if (!definition || typeof definition !== "object") continue; + const definitionKey = stableStringify(normalizeSchemaForMatch(definition as JSONSchema7, ctx)); + if (definitionKey === schemaKey) { + return `#/definitions/${definitionName}`; + } + } + return undefined; +} + +function goDefinitionName(definitionName: string): string { + return toGoSchemaTypeName(definitionName); +} + +function goNonNullUnionMembers(schema: JSONSchema7): JSONSchema7[] { + return ((schema.anyOf ?? schema.oneOf) as JSONSchema7[] | undefined) + ?.filter((member) => { + if (!member || typeof member !== "object") return false; + if (member.type === "null") return false; + if (member.not && typeof member.not === "object" && Object.keys(member.not).length === 0) return false; + return true; + }) ?? []; +} + +function resolveGoUnionMember(member: JSONSchema7, definitions: DefinitionCollections | undefined): JSONSchema7 { + if (member.$ref) { + return resolveRef(member.$ref, definitions) ?? member; + } + return member; +} + +function goObjectUnionMemberSchema(member: JSONSchema7, ctx: GoCodegenCtx): JSONSchema7 | undefined { + const resolved = resolveGoUnionMember(member, ctx.definitions); + const objectSchema = resolveObjectSchema(resolved, ctx.definitions) ?? resolveSchema(resolved, ctx.definitions) ?? resolved; + if (objectSchema?.properties && (objectSchema.type === "object" || objectSchema.type === undefined)) { + return objectSchema; + } + return undefined; +} + +function canFlattenGoObjectUnion(members: JSONSchema7[], ctx: GoCodegenCtx): boolean { + return members.length > 0 && members.every((member) => goObjectUnionMemberSchema(member, ctx) !== undefined); +} + +function goStringEnumValues(schema: JSONSchema7, ctx: GoCodegenCtx): string[] | undefined { + const resolved = resolveSchema(schema, ctx.definitions) ?? schema; + if (typeof resolved.const === "string") return [resolved.const]; + if (isStringEnumDefinition(resolved)) return resolved.enum; + + const unionMembers = goNonNullUnionMembers(resolved); + if (unionMembers.length > 0) { + const values: string[] = []; + for (const member of unionMembers) { + const memberValues = goStringEnumValues(member, ctx); + if (!memberValues) return undefined; + values.push(...memberValues); + } + return [...new Set(values)]; + } + + return undefined; +} + +function mergeGoFlattenedPropertySchema( + typeName: string, + propName: string, + schemas: JSONSchema7[], + ctx: GoCodegenCtx +): JSONSchema7 { + if (schemas.length === 1) return schemas[0]; + + const enumValues = schemas.map((schema) => goStringEnumValues(schema, ctx)); + if (enumValues.every((values): values is string[] => values !== undefined)) { + return { + type: "string", + enum: [...new Set(enumValues.flat())], + title: typeName + toGoFieldName(propName), + }; + } + + const firstSchemaKey = stableStringify(resolveSchema(schemas[0], ctx.definitions) ?? schemas[0]); + if (schemas.every((schema) => stableStringify(resolveSchema(schema, ctx.definitions) ?? schema) === firstSchemaKey)) { + return schemas[0]; + } + + const unionSchema = { anyOf: dedupeGoSchemasForMatch(schemas, ctx) }; + const definitionRef = goDefinitionRefForEquivalentSchema(unionSchema, ctx); + if (definitionRef) return { $ref: definitionRef }; + + return unionSchema; +} + +function emitGoFlattenedObjectUnion( + typeName: string, + variants: JSONSchema7[], + ctx: GoCodegenCtx, + description?: string +): void { + if (ctx.generatedNames.has(typeName)) return; + ctx.generatedNames.add(typeName); + + const objectVariants = variants + .map((variant) => goObjectUnionMemberSchema(variant, ctx)) + .filter((variant): variant is JSONSchema7 => variant !== undefined); + const allProps = new Map(); + + for (const variant of objectVariants) { + const required = new Set(variant.required || []); + for (const [propName, propSchema] of Object.entries(variant.properties || {})) { + if (typeof propSchema !== "object") continue; + const existing = allProps.get(propName); + if (existing) { + existing.schemas.push(propSchema as JSONSchema7); + existing.presentCount++; + if (!required.has(propName)) { + existing.requiredInAll = false; + } + } else { + allProps.set(propName, { + schemas: [propSchema as JSONSchema7], + requiredInAll: required.has(propName), + presentCount: 1, + }); + } + } + } + + const lines: string[] = []; + if (description) { + pushGoCommentForContext(lines, description, ctx); + } + lines.push(`type ${typeName} struct {`); + + for (const [propName, info] of sortByGoFieldName([...allProps.entries()])) { + const goName = toGoFieldName(propName); + const mergedSchema = mergeGoFlattenedPropertySchema(typeName, propName, info.schemas, ctx); + const requiredInAll = info.requiredInAll && info.presentCount === objectVariants.length; + const goType = resolveGoPropertyType(mergedSchema, typeName, propName, requiredInAll, ctx); + const omit = requiredInAll ? "" : ",omitempty"; + const description = info.schemas.find((schema) => schema.description)?.description; + if (description) { + pushGoCommentForContext(lines, description, ctx, "\t"); + } + if (info.schemas.some((schema) => isSchemaDeprecated(schema))) { + pushGoCommentForContext(lines, `Deprecated: ${goName} is deprecated.`, ctx, "\t"); } lines.push(`\t${goName} ${goType} \`json:"${propName}${omit}"\``); } @@ -863,6 +952,225 @@ function emitGoFlatDiscriminatedUnion( ctx.structs.push(lines.join("\n")); } +function goUnionFieldName(member: JSONSchema7, ctx: GoCodegenCtx): string { + if (member.$ref) { + const resolved = resolveRef(member.$ref, ctx.definitions); + if (resolved?.enum) return "Enum"; + return goDefinitionName(refTypeName(member.$ref, ctx.definitions)); + } + + if (member.enum) return "Enum"; + + if (member.type === "object" && member.additionalProperties && typeof member.additionalProperties === "object") { + const valueSchema = member.additionalProperties as JSONSchema7; + if (valueSchema.$ref) { + const resolved = resolveRef(valueSchema.$ref, ctx.definitions); + if (resolved?.enum) return "EnumMap"; + return `${goDefinitionName(refTypeName(valueSchema.$ref, ctx.definitions))}Map`; + } + return `${goPrimitiveUnionFieldName(valueSchema)}Map`; + } + + if (member.type === "array") { + const items = member.items && typeof member.items === "object" && !Array.isArray(member.items) + ? member.items as JSONSchema7 + : undefined; + return `${items ? goUnionFieldName(items, ctx) : "Any"}Array`; + } + + return goPrimitiveUnionFieldName(member); +} + +function goPrimitiveUnionFieldName(schema: JSONSchema7): string { + switch (schema.type) { + case "boolean": return "Bool"; + case "integer": return "Integer"; + case "number": return "Double"; + case "string": return "String"; + case "object": return "Object"; + default: return "Any"; + } +} + +function goUnionFieldType(member: JSONSchema7, fieldName: string, parentTypeName: string, ctx: GoCodegenCtx): string { + const memberType = resolveGoPropertyType(member, parentTypeName, fieldName, true, ctx); + if (memberType.startsWith("*") || memberType.startsWith("[]") || memberType.startsWith("map[")) { + return memberType; + } + return `*${memberType}`; +} + +function goUnionFieldMarshalIsSet(fieldName: string, fieldType: string): string { + if (fieldType.startsWith("*") || fieldType.startsWith("[]") || fieldType.startsWith("map[")) { + return `r.${fieldName} != nil`; + } + return "true"; +} + +function goUnionFieldUnmarshalType(fieldType: string): string { + if (fieldType.startsWith("*")) { + return fieldType.slice(1); + } + return fieldType; +} + +function goUnionFieldUnmarshalAssignment(typeName: string, fieldName: string, fieldType: string): string { + if (fieldType.startsWith("*")) { + return `*r = ${typeName}{${fieldName}: &value}`; + } + return `*r = ${typeName}{${fieldName}: value}`; +} + +function emitGoUnionStruct(typeName: string, schema: JSONSchema7, ctx: GoCodegenCtx): void { + if (ctx.generatedNames.has(typeName)) return; + ctx.generatedNames.add(typeName); + + const members = goNonNullUnionMembers(schema); + const lines: string[] = []; + if (schema.description) { + pushGoCommentForContext(lines, schema.description, ctx); + } + if (isSchemaDeprecated(schema)) { + pushGoCommentForContext(lines, `Deprecated: ${typeName} is deprecated and will be removed in a future version.`, ctx); + } + lines.push(`type ${typeName} struct {`); + + const emittedFields = new Set(); + const fields: { name: string; type: string }[] = []; + for (const member of members) { + const fieldNameBase = goUnionFieldName(member, ctx); + let fieldName = fieldNameBase; + let suffix = 2; + while (emittedFields.has(fieldName)) { + fieldName = `${fieldNameBase}${suffix++}`; + } + emittedFields.add(fieldName); + const fieldType = goUnionFieldType(member, fieldName, typeName, ctx); + fields.push({ name: fieldName, type: fieldType }); + } + + fields.sort((left, right) => compareGoFieldNames(left.name, right.name)); + for (const field of fields) { + lines.push(`\t${field.name} ${field.type}`); + } + + lines.push(`}`); + lines.push(``); + lines.push(`func (r ${typeName}) MarshalJSON() ([]byte, error) {`); + for (const field of fields) { + lines.push(`\tif ${goUnionFieldMarshalIsSet(field.name, field.type)} {`); + lines.push(`\t\treturn json.Marshal(r.${field.name})`); + lines.push(`\t}`); + } + lines.push(`\treturn []byte("null"), nil`); + lines.push(`}`); + lines.push(``); + lines.push(`func (r *${typeName}) UnmarshalJSON(data []byte) error {`); + lines.push(`\tif string(data) == "null" {`); + lines.push(`\t\t*r = ${typeName}{}`); + lines.push(`\t\treturn nil`); + lines.push(`\t}`); + for (const field of fields) { + lines.push(`\t{`); + lines.push(`\t\tvar value ${goUnionFieldUnmarshalType(field.type)}`); + lines.push(`\t\tif err := json.Unmarshal(data, &value); err == nil {`); + lines.push(`\t\t\t${goUnionFieldUnmarshalAssignment(typeName, field.name, field.type)}`); + lines.push(`\t\t\treturn nil`); + lines.push(`\t\t}`); + lines.push(`\t}`); + } + lines.push(`\treturn errors.New("data did not match any union variant for ${typeName}")`); + lines.push(`}`); + ctx.structs.push(lines.join("\n")); +} + +function emitGoAlias(typeName: string, schema: JSONSchema7, ctx: GoCodegenCtx): void { + if (ctx.generatedNames.has(typeName)) return; + ctx.generatedNames.add(typeName); + + const lines: string[] = []; + if (schema.description) { + pushGoCommentForContext(lines, schema.description, ctx); + } + if (isSchemaDeprecated(schema)) { + pushGoCommentForContext(lines, `Deprecated: ${typeName} is deprecated and will be removed in a future version.`, ctx); + } + lines.push(`type ${typeName} ${resolveGoPropertyType(schema, typeName, "Value", true, ctx)}`); + ctx.structs.push(lines.join("\n")); +} + +function emitGoRpcDefinition(definitionName: string, schema: JSONSchema7, ctx: GoCodegenCtx): string { + const typeName = goDefinitionName(definitionName); + const effectiveSchema = resolveObjectSchema(schema, ctx.definitions) ?? resolveSchema(schema, ctx.definitions) ?? schema; + + if (isStringEnumDefinition(effectiveSchema)) { + getOrCreateGoEnum(typeName, effectiveSchema.enum, ctx, effectiveSchema.description, isSchemaDeprecated(effectiveSchema)); + return typeName; + } + + if (isNamedGoObjectSchema(effectiveSchema)) { + emitGoStruct(typeName, effectiveSchema, ctx); + return typeName; + } + + const unionMembers = goNonNullUnionMembers(effectiveSchema); + if (unionMembers.length > 0) { + const resolvedVariants = unionMembers.map((member) => resolveGoUnionMember(member, ctx.definitions)); + const discriminator = findGoDiscriminator(resolvedVariants); + if (discriminator) { + emitGoFlatDiscriminatedUnion(typeName, discriminator.property, discriminator.mapping, ctx, (effectiveSchema as JSONSchema7).description); + } else if (canFlattenGoObjectUnion(resolvedVariants, ctx)) { + emitGoFlattenedObjectUnion(typeName, resolvedVariants, ctx, (effectiveSchema as JSONSchema7).description); + } else { + emitGoUnionStruct(typeName, effectiveSchema, ctx); + } + return typeName; + } + + emitGoAlias(typeName, effectiveSchema, ctx); + return typeName; +} + +function generateGoRpcTypeCode(definitions: Record, definitionCollections: DefinitionCollections): string { + const ctx: GoCodegenCtx = { + structs: [], + enums: [], + enumsByName: new Map(), + generatedNames: new Set(), + definitions: definitionCollections, + }; + const schemaKeysByTypeName = new Map(); + const entries = Object.entries(definitions) + .sort(([left], [right]) => goDefinitionName(left).localeCompare(goDefinitionName(right))); + + for (const [definitionName, definition] of entries) { + const typeName = goDefinitionName(definitionName); + const schemaKey = stableStringify(resolveSchema(definition, definitionCollections) ?? definition); + const existingSchemaKey = schemaKeysByTypeName.get(typeName); + if (existingSchemaKey && existingSchemaKey !== schemaKey) { + throw new Error(`Conflicting Go RPC type name "${typeName}" for different schemas. Add a schema title/withTypeName to disambiguate.`); + } + schemaKeysByTypeName.set(typeName, schemaKey); + emitGoRpcDefinition(definitionName, definition, ctx); + } + + const lines: string[] = []; + for (const typeCode of ctx.structs.sort((left, right) => goDeclaredTypeName(left).localeCompare(goDeclaredTypeName(right)))) { + lines.push(typeCode); + lines.push(``); + } + for (const typeCode of ctx.enums.sort((left, right) => goDeclaredTypeName(left).localeCompare(goDeclaredTypeName(right)))) { + lines.push(typeCode); + lines.push(``); + } + + return lines.join("\n").replace(/\n+$/, ""); +} + +function goDeclaredTypeName(code: string): string { + return /^type\s+(\w+)\b/m.exec(code)?.[1] ?? code; +} + /** * Generate the complete Go session-events file content. */ @@ -874,8 +1182,45 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { enumsByName: new Map(), generatedNames: new Set(), definitions: collectDefinitionCollections(schema as Record), + wrapComments: false, }; const envelopeProperties = getGoSharedEventEnvelopeProperties(schema, ctx); + const sessionEventStructFields = [ + ...envelopeProperties.map((property) => ({ + fieldName: property.fieldName, + lines: emitGoEnvelopeStructField(property, true, ctx.wrapComments !== false), + })), + { + fieldName: "Data", + lines: [ + ...goCommentLines("Typed event payload. Use a type switch to access per-event fields.", "\t", ctx.wrapComments !== false), + `\tData SessionEventData \`json:"-"\``, + ], + }, + { + fieldName: "Type", + lines: [ + ...goCommentLines("The event type discriminator.", "\t", ctx.wrapComments !== false), + `\tType SessionEventType \`json:"type"\``, + ], + }, + ].sort((left, right) => compareGoFieldNames(left.fieldName, right.fieldName)); + const rawEventUnmarshalFields = [ + ...envelopeProperties.map((property) => ({ + fieldName: property.fieldName, + lines: emitGoEnvelopeStructField(property, false, ctx.wrapComments !== false), + })), + { fieldName: "Data", lines: [`\tData json.RawMessage \`json:"data"\``] }, + { fieldName: "Type", lines: [`\tType SessionEventType \`json:"type"\``] }, + ].sort((left, right) => compareGoFieldNames(left.fieldName, right.fieldName)); + const rawEventMarshalFields = [ + ...envelopeProperties.map((property) => ({ + fieldName: property.fieldName, + lines: emitGoEnvelopeStructField(property, false, ctx.wrapComments !== false), + })), + { fieldName: "Data", lines: [`\tData any \`json:"data"\``] }, + { fieldName: "Type", lines: [`\tType SessionEventType \`json:"type"\``] }, + ].sort((left, right) => compareGoFieldNames(left.fieldName, right.fieldName)); // Generate per-event data structs const dataStructs: string[] = []; @@ -884,15 +1229,13 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { const lines: string[] = []; if (variant.dataDescription) { - for (const line of variant.dataDescription.split(/\r?\n/)) { - lines.push(`// ${line}`); - } + pushGoCommentForContext(lines, variant.dataDescription, ctx); } else { - lines.push(`// ${variant.dataClassName} holds the payload for ${variant.typeName} events.`); + pushGoCommentForContext(lines, `${variant.dataClassName} holds the payload for ${variant.typeName} events.`, ctx); } lines.push(`type ${variant.dataClassName} struct {`); - for (const [propName, propSchema] of Object.entries(variant.dataSchema.properties || {}).sort(([a], [b]) => a.localeCompare(b))) { + for (const [propName, propSchema] of sortByGoFieldName(Object.entries(variant.dataSchema.properties || {}))) { if (typeof propSchema !== "object") continue; const prop = propSchema as JSONSchema7; const isReq = required.has(propName); @@ -901,10 +1244,10 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { const omit = isReq ? "" : ",omitempty"; if (prop.description) { - lines.push(`\t// ${prop.description}`); + pushGoCommentForContext(lines, prop.description, ctx, "\t"); } if (isSchemaDeprecated(prop)) { - lines.push(`\t// Deprecated: ${goName} is deprecated.`); + pushGoCommentForContext(lines, `Deprecated: ${goName} is deprecated.`, ctx, "\t"); } lines.push(`\t${goName} ${goType} \`json:"${propName}${omit}"\``); } @@ -922,18 +1265,21 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { eventTypeEnum.push(`type SessionEventType string`); eventTypeEnum.push(``); eventTypeEnum.push(`const (`); - for (const variant of variants) { - const constName = - "SessionEventType" + - variant.typeName + const eventTypeConsts = variants + .map((variant) => ({ + constName: "SessionEventType" + variant.typeName .split(/[._]/) .map((w) => goInitialisms.has(w.toLowerCase()) ? w.toUpperCase() : w.charAt(0).toUpperCase() + w.slice(1) ) - .join(""); - eventTypeEnum.push(`\t${constName} SessionEventType = "${variant.typeName}"`); + .join(""), + typeName: variant.typeName, + })) + .sort((left, right) => left.constName.localeCompare(right.constName)); + for (const { constName, typeName } of eventTypeConsts) { + eventTypeEnum.push(`\t${constName} SessionEventType = "${typeName}"`); } eventTypeEnum.push(`)`); @@ -947,6 +1293,7 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { // Imports — time is always needed for SessionEvent.Timestamp out.push(`import (`); + out.push(`\t"errors"`); out.push(`\t"encoding/json"`); out.push(`\t"time"`); out.push(`)`); @@ -974,13 +1321,9 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { // SessionEvent struct out.push(`// SessionEvent represents a single session event with a typed data payload.`); out.push(`type SessionEvent struct {`); - for (const property of envelopeProperties) { - out.push(...emitGoEnvelopeStructField(property, true)); + for (const field of sessionEventStructFields) { + out.push(...field.lines); } - out.push(`\t// The event type discriminator.`); - out.push(`\tType SessionEventType \`json:"type"\``); - out.push(`\t// Typed event payload. Use a type switch to access per-event fields.`); - out.push(`\tData SessionEventData \`json:"-"\``); out.push(`}`); out.push(``); @@ -1003,37 +1346,38 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { // Custom UnmarshalJSON out.push(`func (e *SessionEvent) UnmarshalJSON(data []byte) error {`); out.push(`\ttype rawEvent struct {`); - for (const property of envelopeProperties) { - for (const line of emitGoEnvelopeStructField(property, false)) { + for (const field of rawEventUnmarshalFields) { + for (const line of field.lines) { out.push(`\t${line}`); } } - out.push(`\t\tType SessionEventType \`json:"type"\``); - out.push(`\t\tData json.RawMessage \`json:"data"\``); out.push(`\t}`); out.push(`\tvar raw rawEvent`); out.push(`\tif err := json.Unmarshal(data, &raw); err != nil {`); out.push(`\t\treturn err`); out.push(`\t}`); - for (const property of envelopeProperties) { + for (const property of sortedGoEventEnvelopeProperties(envelopeProperties)) { out.push(`\te.${property.fieldName} = raw.${property.fieldName}`); } out.push(`\te.Type = raw.Type`); out.push(``); out.push(`\tswitch raw.Type {`); - for (const variant of variants) { - const constName = - "SessionEventType" + - variant.typeName + const eventCases = variants + .map((variant) => ({ + constName: "SessionEventType" + variant.typeName .split(/[._]/) .map((w) => goInitialisms.has(w.toLowerCase()) ? w.toUpperCase() : w.charAt(0).toUpperCase() + w.slice(1) ) - .join(""); + .join(""), + dataClassName: variant.dataClassName, + })) + .sort((left, right) => left.constName.localeCompare(right.constName)); + for (const { constName, dataClassName } of eventCases) { out.push(`\tcase ${constName}:`); - out.push(`\t\tvar d ${variant.dataClassName}`); + out.push(`\t\tvar d ${dataClassName}`); out.push(`\t\tif err := json.Unmarshal(raw.Data, &d); err != nil {`); out.push(`\t\t\treturn err`); out.push(`\t\t}`); @@ -1049,20 +1393,21 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { // Custom MarshalJSON out.push(`func (e SessionEvent) MarshalJSON() ([]byte, error) {`); out.push(`\ttype rawEvent struct {`); - for (const property of envelopeProperties) { - for (const line of emitGoEnvelopeStructField(property, false)) { + for (const field of rawEventMarshalFields) { + for (const line of field.lines) { out.push(`\t${line}`); } } - out.push(`\t\tType SessionEventType \`json:"type"\``); - out.push(`\t\tData any \`json:"data"\``); out.push(`\t}`); out.push(`\treturn json.Marshal(rawEvent{`); - for (const property of envelopeProperties) { - out.push(`\t\t${property.fieldName}: e.${property.fieldName},`); + const rawEventValues = [ + ...envelopeProperties.map((property) => property.fieldName), + "Data", + "Type", + ].sort(compareGoFieldNames); + for (const fieldName of rawEventValues) { + out.push(`\t\t${fieldName}: e.${fieldName},`); } - out.push(`\t\tType: e.Type,`); - out.push(`\t\tData: e.Data,`); out.push(`\t})`); out.push(`}`); out.push(``); @@ -1078,13 +1423,13 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { } // Nested structs - for (const s of ctx.structs.sort()) { + for (const s of ctx.structs.sort((left, right) => goDeclaredTypeName(left).localeCompare(goDeclaredTypeName(right)))) { out.push(s); out.push(``); } // Enums - for (const e of ctx.enums.sort()) { + for (const e of ctx.enums.sort((left, right) => goDeclaredTypeName(left).localeCompare(goDeclaredTypeName(right)))) { out.push(e); out.push(``); } @@ -1105,14 +1450,14 @@ function generateGoSessionEventsCode(schema: JSONSchema7): string { }; out.push(`// Type aliases for convenience.`); out.push(`type (`); - for (const [alias, target] of Object.entries(TYPE_ALIASES)) { + for (const [alias, target] of Object.entries(TYPE_ALIASES).sort(([left], [right]) => left.localeCompare(right))) { out.push(`\t${alias} = ${target}`); } out.push(`)`); out.push(``); out.push(`// Constant aliases for convenience.`); out.push(`const (`); - for (const [alias, target] of Object.entries(CONST_ALIASES)) { + for (const [alias, target] of Object.entries(CONST_ALIASES).sort(([left], [right]) => left.localeCompare(right))) { out.push(`\t${alias} = ${target}`); } out.push(`)`); @@ -1148,17 +1493,19 @@ async function generateRpc(schemaPath?: string): Promise { ...collectRpcMethods(schema.server || {}), ...collectRpcMethods(schema.session || {}), ...collectRpcMethods(schema.clientSession || {}), - ]; + ].sort((left, right) => left.rpcMethod.localeCompare(right.rpcMethod)); - // Build a combined schema for quicktype — prefix types to avoid conflicts. - // Include shared definitions from the API schema for $ref resolution. + // Build a combined definition map, including shared API definitions plus + // method-specific request/result wrapper types. rpcDefinitions = collectDefinitionCollections(schema as Record); - const combinedSchema = withSharedDefinitions( - { - $schema: "http://json-schema.org/draft-07/schema#", - }, - rpcDefinitions - ); + const allDefinitions: Record = { + ...Object.fromEntries( + Object.entries(rpcDefinitions.$defs ?? {}).filter(([, value]) => typeof value === "object" && value !== null) + ) as Record, + ...Object.fromEntries( + Object.entries(rpcDefinitions.definitions ?? {}).filter(([, value]) => typeof value === "object" && value !== null) + ) as Record, + }; for (const method of allMethods) { const resultSchema = getMethodResultSchema(method); @@ -1168,14 +1515,14 @@ async function generateRpc(schemaPath?: string): Promise { // the inner type is already in definitions via shared hoisting. } else if (isVoidSchema(resultSchema)) { // Emit an empty struct for void results (forward-compatible with adding fields later) - combinedSchema.definitions![goResultTypeName(method)] = { + allDefinitions[goResultTypeName(method)] = { title: goResultTypeName(method), type: "object", properties: {}, additionalProperties: false, }; } else if (method.result) { - combinedSchema.definitions![goResultTypeName(method)] = withRootTitle( + allDefinitions[goResultTypeName(method)] = withRootTitle( schemaSourceForNamedDefinition(method.result, resultSchema), goResultTypeName(method) ); @@ -1192,13 +1539,13 @@ async function generateRpc(schemaPath?: string): Promise { required: resolvedParams.required?.filter((r) => r !== "sessionId"), }; if (hasSchemaPayload(filtered)) { - combinedSchema.definitions![goParamsTypeName(method)] = withRootTitle( + allDefinitions[goParamsTypeName(method)] = withRootTitle( filtered, goParamsTypeName(method) ); } } else { - combinedSchema.definitions![goParamsTypeName(method)] = withRootTitle( + allDefinitions[goParamsTypeName(method)] = withRootTitle( schemaSourceForNamedDefinition(method.params, resolvedParams), goParamsTypeName(method) ); @@ -1206,56 +1553,27 @@ async function generateRpc(schemaPath?: string): Promise { } } - const allDefinitions = combinedSchema.definitions! as Record; const allDefinitionCollections: DefinitionCollections = { - definitions: { ...(combinedSchema.$defs ?? {}), ...allDefinitions }, - $defs: { ...allDefinitions, ...(combinedSchema.$defs ?? {}) }, + definitions: { ...(rpcDefinitions.$defs ?? {}), ...allDefinitions }, + $defs: { ...allDefinitions, ...(rpcDefinitions.$defs ?? {}) }, }; + rpcDefinitions = allDefinitionCollections; - // Generate types via quicktype — use a single combined schema source so quicktype - // sees each definition exactly once, preventing whimsical prefix disambiguation. - const schemaInput = new JSONSchemaInput(new FetchingJSONSchemaStore()); - const singleSchema: JSONSchema7 = { - $schema: "http://json-schema.org/draft-07/schema#", - type: "object", - definitions: stripBooleanLiterals(allDefinitions) as Record, - properties: Object.fromEntries( - Object.keys(allDefinitions).map((name) => [name, { $ref: `#/definitions/${name}` }]) - ), - required: Object.keys(allDefinitions), - }; - await schemaInput.addSource({ name: "RpcTypes", schema: JSON.stringify(singleSchema) }); - - const inputData = new InputData(); - inputData.addInput(schemaInput); - - const qtResult = await quicktype({ - inputData, - lang: "go", - rendererOptions: { package: "copilot", "just-types": "true" }, - }); - - // Post-process quicktype output: hoist quicktype's imports into the file-level import block - let qtCode = qtResult.lines.filter((l) => !l.startsWith("package ")).join("\n"); - const quicktypeImports = extractQuicktypeImports(qtCode); - qtCode = quicktypeImports.code; - qtCode = postProcessEnumConstants(qtCode); - const knownDefNames = new Set(Object.keys(allDefinitions).map((n) => n.toLowerCase())); - qtCode = collapsePlaceholderGoStructs(qtCode, knownDefNames); - // Strip trailing whitespace from quicktype output (gofmt requirement) - qtCode = qtCode.replace(/[ \t]+$/gm, ""); - - // Extract actual type names generated by quicktype (may differ from toPascalCase) + let generatedTypeCode = generateGoRpcTypeCode(allDefinitions, allDefinitionCollections); + // Strip trailing whitespace from generated output (gofmt requirement) + generatedTypeCode = generatedTypeCode.replace(/[ \t]+$/gm, ""); + + // Extract generated type names. Some may differ from toPascalCase due explicit schema titles. const actualTypeNames = new Map(); const typeRe = /^type\s+(\w+)\b/gm; let sm; - while ((sm = typeRe.exec(qtCode)) !== null) { + while ((sm = typeRe.exec(generatedTypeCode)) !== null) { actualTypeNames.set(sm[1].toLowerCase(), sm[1]); } const resolveType = (name: string): string => actualTypeNames.get(name.toLowerCase()) ?? name; - // Extract field name mappings (quicktype may rename fields to avoid Go keyword conflicts) - const fieldNames = extractFieldNames(qtCode); + // Extract field name mappings so wrappers use the emitted Go field names. + const fieldNames = extractFieldNames(generatedTypeCode); // Annotate experimental data types const experimentalTypeNames = new Set(); @@ -1268,7 +1586,7 @@ async function generateRpc(schemaPath?: string): Promise { } } for (const typeName of experimentalTypeNames) { - qtCode = qtCode.replace( + generatedTypeCode = generatedTypeCode.replace( new RegExp(`^(type ${typeName} struct)`, "m"), `// Experimental: ${typeName} is part of an experimental API and may change or be removed.\n$1` ); @@ -1289,7 +1607,7 @@ async function generateRpc(schemaPath?: string): Promise { } } for (const typeName of deprecatedTypeNames) { - qtCode = qtCode.replace( + generatedTypeCode = generatedTypeCode.replace( new RegExp(`^(type ${typeName} struct)`, "m"), `// Deprecated: ${typeName} is deprecated and will be removed in a future version.\n$1` ); @@ -1304,22 +1622,13 @@ async function generateRpc(schemaPath?: string): Promise { } } for (const typeName of internalTypeNames) { - qtCode = qtCode.replace( + generatedTypeCode = generatedTypeCode.replace( new RegExp(`^(type ${typeName} struct)`, "m"), `// Internal: ${typeName} is an internal SDK API and is not part of the public surface.\n$1` ); } - // Remove trailing blank lines from quicktype output before appending - qtCode = qtCode.replace(/\n+$/, ""); - // Replace interface{} with any (quicktype emits the pre-1.18 form) - qtCode = qtCode.replace(/\binterface\{\}/g, "any"); - - // Post-process: add ,omitempty to optional fields that quicktype emitted without it. - // Quicktype's Go renderer correctly emits omitempty for most optional fields, but it - // misses some (notably $ref-to-anyOf union types like FilterMapping). For each struct - // type we know from the schema, walk its fields and add omitempty if the field is not - // listed in `required` and the tag does not already include any modifier. - qtCode = addMissingOmitemptyToQuicktypeStructs(qtCode, allDefinitions); + // Remove trailing blank lines before appending. + generatedTypeCode = generatedTypeCode.replace(/\n+$/, ""); // Build method wrappers const lines: string[] = []; @@ -1329,10 +1638,8 @@ async function generateRpc(schemaPath?: string): Promise { lines.push(`package rpc`); lines.push(``); const imports = [`"context"`, `"encoding/json"`]; - for (const imp of quicktypeImports.imports) { - if (!imports.includes(imp)) { - imports.push(imp); - } + if (generatedTypeCode.includes("time.Time")) { + imports.push(`"time"`); } if (schema.clientSession) { imports.push(`"errors"`, `"fmt"`); @@ -1346,7 +1653,7 @@ async function generateRpc(schemaPath?: string): Promise { lines.push(`)`); lines.push(``); - lines.push(qtCode); + lines.push(generatedTypeCode); lines.push(``); // Emit ServerRpc @@ -1369,7 +1676,7 @@ async function generateRpc(schemaPath?: string): Promise { emitClientSessionApiRegistration(lines, schema.clientSession, resolveType); } - const outPath = await writeGeneratedFile("go/rpc/generated_rpc.go", lines.join("\n")); + const outPath = await writeGeneratedFile("go/rpc/generated_rpc.go", wrapGeneratedGoComments(lines.join("\n"))); console.log(` ✓ ${outPath}`); await formatGoFile(outPath); @@ -1386,18 +1693,19 @@ function emitApiGroup( groupExperimental: boolean, groupDeprecated: boolean = false ): void { - const subGroups = Object.entries(node).filter(([, v]) => typeof v === "object" && v !== null && !isRpcMethod(v)); + const subGroups = sortByPascalName(Object.entries(node).filter(([, v]) => typeof v === "object" && v !== null && !isRpcMethod(v))); + const methods = sortByPascalName(Object.entries(node).filter(([, v]) => isRpcMethod(v))); if (groupDeprecated) { - lines.push(`// Deprecated: ${apiName} contains deprecated APIs that will be removed in a future version.`); + pushGoComment(lines, `Deprecated: ${apiName} contains deprecated APIs that will be removed in a future version.`); } if (groupExperimental) { - lines.push(`// Experimental: ${apiName} contains experimental APIs that may change or be removed.`); + pushGoComment(lines, `Experimental: ${apiName} contains experimental APIs that may change or be removed.`); } lines.push(`type ${apiName} ${serviceName}`); lines.push(``); - for (const [key, value] of Object.entries(node)) { + for (const [key, value] of methods) { if (!isRpcMethod(value)) continue; emitMethod(lines, apiName, key, value, isSession, resolveType, fieldNames, groupExperimental, false, groupDeprecated); } @@ -1409,7 +1717,7 @@ function emitApiGroup( emitApiGroup(lines, subApiName, subGroupNode as Record, isSession, serviceName, resolveType, fieldNames, subGroupExperimental, subGroupDeprecated); if (subGroupExperimental) { - lines.push(`// Experimental: ${toPascalCase(subGroupName)} returns experimental APIs that may change or be removed.`); + pushGoComment(lines, `Experimental: ${toPascalCase(subGroupName)} returns experimental APIs that may change or be removed.`); } lines.push(`func (s *${apiName}) ${toPascalCase(subGroupName)}() *${subApiName} {`); lines.push(`\treturn (*${subApiName})(s)`); @@ -1419,8 +1727,8 @@ function emitApiGroup( } function emitRpcWrapper(lines: string[], node: Record, isSession: boolean, resolveType: (name: string) => string, fieldNames: Map>, classPrefix: string = ""): void { - const groups = Object.entries(node).filter(([, v]) => typeof v === "object" && v !== null && !isRpcMethod(v)); - const topLevelMethods = Object.entries(node).filter(([, v]) => isRpcMethod(v)); + const groups = sortByPascalName(Object.entries(node).filter(([, v]) => typeof v === "object" && v !== null && !isRpcMethod(v))); + const topLevelMethods = sortByPascalName(Object.entries(node).filter(([, v]) => isRpcMethod(v))); const wrapperName = classPrefix + (isSession ? "SessionRpc" : "ServerRpc"); const apiSuffix = "Api"; @@ -1453,11 +1761,15 @@ function emitRpcWrapper(lines: string[], node: Record, isSessio const pad = (name: string) => name.padEnd(maxFieldLen); // Emit wrapper struct - lines.push(classPrefix === "Internal" - ? `// ${wrapperName} provides internal SDK ${isSession ? "session" : "server"}-scoped RPC methods (handshake helpers etc.). Not part of the public API.` - : `// ${wrapperName} provides typed ${isSession ? "session" : "server"}-scoped RPC methods.`); + pushGoComment( + lines, + classPrefix === "Internal" + ? `${wrapperName} provides internal SDK ${isSession ? "session" : "server"}-scoped RPC methods (handshake helpers etc.). Not part of the public API.` + : `${wrapperName} provides typed ${isSession ? "session" : "server"}-scoped RPC methods.` + ); lines.push(`type ${wrapperName} struct {`); - lines.push(`\t${pad("common")} ${serviceName} // Reuse a single struct instead of allocating one for each service on the heap.`); + pushGoComment(lines, `Reuse a single struct instead of allocating one for each service on the heap.`, "\t"); + lines.push(`\t${pad("common")} ${serviceName}`); lines.push(``); for (const [groupName] of groups) { const prefix = classPrefix + (isSession ? "" : "Server"); @@ -1501,7 +1813,9 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc const effectiveParams = getMethodParamsSchema(method); const paramProps = effectiveParams?.properties || {}; const requiredParams = new Set(effectiveParams?.required || []); - const nonSessionParams = Object.keys(paramProps).filter((k) => k !== "sessionId"); + const nonSessionParams = Object.keys(paramProps) + .filter((k) => k !== "sessionId") + .sort((left, right) => compareGoFieldNames(toGoFieldName(left), toGoFieldName(right))); const hasParams = isSession ? nonSessionParams.length > 0 : hasSchemaPayload(effectiveParams); const paramsType = hasParams ? resolveType(goParamsTypeName(method)) : ""; @@ -1510,13 +1824,13 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc const sessionIDRef = isWrapper ? "a.common.sessionID" : "a.sessionID"; if (method.deprecated && !groupDeprecated) { - lines.push(`// Deprecated: ${methodName} is deprecated and will be removed in a future version.`); + pushGoComment(lines, `Deprecated: ${methodName} is deprecated and will be removed in a future version.`); } if (method.stability === "experimental" && !groupExperimental) { - lines.push(`// Experimental: ${methodName} is an experimental API and may change or be removed in future versions.`); + pushGoComment(lines, `Experimental: ${methodName} is an experimental API and may change or be removed in future versions.`); } if (method.visibility === "internal") { - lines.push(`// Internal: ${methodName} is part of the SDK's internal handshake/plumbing; external callers should not use it.`); + pushGoComment(lines, `Internal: ${methodName} is part of the SDK's internal handshake/plumbing; external callers should not use it.`); } const sig = hasParams ? `func (a *${receiver}) ${methodName}(ctx context.Context, params *${paramsType}) (*${resultType}, error)` @@ -1568,12 +1882,12 @@ interface ClientGroup { function collectClientGroups(node: Record): ClientGroup[] { const groups: ClientGroup[] = []; - for (const [groupName, groupNode] of Object.entries(node)) { + for (const [groupName, groupNode] of sortByPascalName(Object.entries(node))) { if (typeof groupNode === "object" && groupNode !== null) { groups.push({ groupName, groupNode: groupNode as Record, - methods: collectRpcMethods(groupNode as Record), + methods: collectRpcMethods(groupNode as Record).sort(compareRpcMethodsByGoName), }); } } @@ -1596,18 +1910,18 @@ function emitClientSessionApiRegistration(lines: string[], clientSchema: Record< const groupExperimental = isNodeFullyExperimental(groupNode); const groupDeprecated = isNodeFullyDeprecated(groupNode); if (groupDeprecated) { - lines.push(`// Deprecated: ${interfaceName} contains deprecated APIs that will be removed in a future version.`); + pushGoComment(lines, `Deprecated: ${interfaceName} contains deprecated APIs that will be removed in a future version.`); } if (groupExperimental) { - lines.push(`// Experimental: ${interfaceName} contains experimental APIs that may change or be removed.`); + pushGoComment(lines, `Experimental: ${interfaceName} contains experimental APIs that may change or be removed.`); } lines.push(`type ${interfaceName} interface {`); for (const method of methods) { if (method.deprecated && !groupDeprecated) { - lines.push(`\t// Deprecated: ${clientHandlerMethodName(method.rpcMethod)} is deprecated and will be removed in a future version.`); + pushGoComment(lines, `Deprecated: ${clientHandlerMethodName(method.rpcMethod)} is deprecated and will be removed in a future version.`, "\t"); } if (method.stability === "experimental" && !groupExperimental) { - lines.push(`\t// Experimental: ${clientHandlerMethodName(method.rpcMethod)} is an experimental API and may change or be removed in future versions.`); + pushGoComment(lines, `Experimental: ${clientHandlerMethodName(method.rpcMethod)} is an experimental API and may change or be removed in future versions.`, "\t"); } const paramsType = resolveType(goParamsTypeName(method)); const resultSchema = getMethodResultSchema(method); diff --git a/scripts/codegen/package-lock.json b/scripts/codegen/package-lock.json index 46804c886..ff7c16f93 100644 --- a/scripts/codegen/package-lock.json +++ b/scripts/codegen/package-lock.json @@ -9,7 +9,8 @@ "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "quicktype-core": "^23.2.6", - "tsx": "^4.20.6" + "tsx": "^4.20.6", + "wordwrap": "^1.0.0" } }, "node_modules/@apidevtools/json-schema-ref-parser": { @@ -794,6 +795,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, diff --git a/scripts/codegen/package.json b/scripts/codegen/package.json index c42713d84..c942b1c93 100644 --- a/scripts/codegen/package.json +++ b/scripts/codegen/package.json @@ -14,6 +14,7 @@ "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "quicktype-core": "^23.2.6", - "tsx": "^4.20.6" + "tsx": "^4.20.6", + "wordwrap": "^1.0.0" } } diff --git a/scripts/codegen/types.d.ts b/scripts/codegen/types.d.ts new file mode 100644 index 000000000..bc3b2f657 --- /dev/null +++ b/scripts/codegen/types.d.ts @@ -0,0 +1,3 @@ +declare module "wordwrap" { + export default function wordwrap(width: number): (text: string) => string; +} diff --git a/scripts/codegen/utils.ts b/scripts/codegen/utils.ts index bbbeb877c..a071dc6ae 100644 --- a/scripts/codegen/utils.ts +++ b/scripts/codegen/utils.ts @@ -8,10 +8,10 @@ import { execFile } from "child_process"; import fs from "fs/promises"; +import type { JSONSchema7, JSONSchema7Definition } from "json-schema"; import path from "path"; import { fileURLToPath } from "url"; import { promisify } from "util"; -import type { JSONSchema7, JSONSchema7Definition } from "json-schema"; export const execFileAsync = promisify(execFile); @@ -65,7 +65,7 @@ export async function getApiSchemaPath(cliArg?: string): Promise { // ── Schema processing ─────────────────────────────────────────────────────── /** - * Post-process JSON Schema for quicktype compatibility. + * Post-process JSON Schema for code generators that expect enum-style literals. * Converts boolean const values to enum. */ export function postProcessSchema(schema: JSONSchema7): JSONSchema7 { @@ -136,12 +136,12 @@ export function postProcessSchema(schema: JSONSchema7): JSONSchema7 { /** * Strip boolean literal constraints (`const: true/false`, `enum: [true]`, `enum: [false]`) - * from a schema, recursively. quicktype's Python and Go renderers attempt to derive + * from a schema, recursively. quicktype's Python renderer attempts to derive * identifier names from enum values; deriving a name from a boolean throws inside * `snakeNameStyle` (TypeError: s.codePointAt is not a function). * - * The literal narrowing isn't expressible in Python/Go anyway, so we drop it and - * keep just `type: "boolean"`. TypeScript/C# codegen runs on the original schema. + * The literal narrowing isn't expressible in Python anyway, so we drop it and + * keep just `type: "boolean"`. Other codegen runs on the original schema. */ export function stripBooleanLiterals(schema: T): T { if (typeof schema !== "object" || schema === null) return schema;