syntax = "proto3";
package steer.agent.v1;

import "google/protobuf/timestamp.proto";
import "steer/common/v1/common.proto";
import "steer/remote_workspace/v1/remote_workspace.proto";

service AgentService {
  // Session management
  rpc CreateSession(CreateSessionRequest) returns (CreateSessionResponse);
  rpc ListSessions(ListSessionsRequest) returns (ListSessionsResponse);
  rpc GetSession(GetSessionRequest) returns (stream GetSessionResponse);
  rpc DeleteSession(DeleteSessionRequest) returns (DeleteSessionResponse);

  // Event subscription (replaces bidirectional streaming)
  rpc SubscribeSessionEvents(SubscribeSessionEventsRequest) returns (stream SessionEvent);

  // User actions (all unary)
  rpc SendMessage(SendMessageRequest) returns (SendMessageResponse);
  rpc EditMessage(EditMessageRequest) returns (EditMessageResponse);
  rpc ApproveTool(ApproveToolRequest) returns (ApproveToolResponse);
  rpc SwitchPrimaryAgent(SwitchPrimaryAgentRequest) returns (SwitchPrimaryAgentResponse);
  rpc CancelOperation(CancelOperationRequest) returns (CancelOperationResponse);
  rpc CompactSession(CompactSessionRequest) returns (CompactSessionResponse);
  rpc ExecuteBashCommand(ExecuteBashCommandRequest) returns (ExecuteBashCommandResponse);
  rpc DequeueQueuedItem(DequeueQueuedItemRequest) returns (DequeueQueuedItemResponse);

  // Utility RPCs
  rpc GetConversation(GetConversationRequest) returns (stream GetConversationResponse);
  rpc ListFiles(ListFilesRequest) returns (stream ListFilesResponse);
  rpc GetMcpServers(GetMcpServersRequest) returns (GetMcpServersResponse);
  rpc ListProviders(ListProvidersRequest) returns (ListProvidersResponse);
  rpc ListModels(ListModelsRequest) returns (ListModelsResponse);
  rpc ResolveModel(ResolveModelRequest) returns (ResolveModelResponse);
  rpc GetDefaultModel(GetDefaultModelRequest) returns (GetDefaultModelResponse);
  rpc GetProviderAuthStatus(GetProviderAuthStatusRequest) returns (GetProviderAuthStatusResponse);

  rpc StartAuth(StartAuthRequest) returns (StartAuthResponse);
  rpc SendAuthInput(SendAuthInputRequest) returns (SendAuthInputResponse);
  rpc GetAuthProgress(GetAuthProgressRequest) returns (GetAuthProgressResponse);
  rpc CancelAuth(CancelAuthRequest) returns (CancelAuthResponse);

  // Workspace orchestration
  rpc ResolveRepo(ResolveRepoRequest) returns (ResolveRepoResponse);
  rpc ListRepos(ListReposRequest) returns (ListReposResponse);
  rpc CreateWorkspace(CreateWorkspaceRequest) returns (CreateWorkspaceResponse);
  rpc ListWorkspaces(ListWorkspacesRequest) returns (ListWorkspacesResponse);
  rpc GetWorkspaceStatus(GetWorkspaceStatusRequest) returns (GetWorkspaceStatusResponse);
  rpc DeleteWorkspace(DeleteWorkspaceRequest) returns (DeleteWorkspaceResponse);

  // Environment management
  rpc CreateEnvironment(CreateEnvironmentRequest) returns (CreateEnvironmentResponse);
  rpc GetEnvironment(GetEnvironmentRequest) returns (GetEnvironmentResponse);
  rpc DeleteEnvironment(DeleteEnvironmentRequest) returns (DeleteEnvironmentResponse);
}

// Event subscription
message SubscribeSessionEventsRequest {
  string session_id = 1;
  optional uint64 since_sequence = 2;  // For replay after reconnect
}

// Session event - streamed to clients
message SessionEvent {
  uint64 sequence_num = 1;
  google.protobuf.Timestamp timestamp = 2;

  oneof event {
    AssistantMessageAddedEvent assistant_message_added = 3;
    UserMessageAddedEvent user_message_added = 16;
    ToolMessageAddedEvent tool_message_added = 17;
    MessageUpdatedEvent message_updated = 4;
    ToolCallStartedEvent tool_call_started = 6;
    ToolCallCompletedEvent tool_call_completed = 7;
    ToolCallFailedEvent tool_call_failed = 8;
    ProcessingStartedEvent processing_started = 9;
    ProcessingCompletedEvent processing_completed = 10;
    RequestToolApprovalEvent request_tool_approval = 11;
    OperationCancelledEvent operation_cancelled = 12;
    ErrorEvent error = 14;
    WorkspaceChangedEvent workspace_changed = 15;
    ConversationCompactedEvent conversation_compacted = 19;
    StreamDeltaEvent stream_delta = 20;
    CompactResultEvent compact_result = 21;
    McpServerStateChangedEvent mcp_server_state_changed = 22;
    SessionConfigUpdatedEvent session_config_updated = 23;
    QueueUpdatedEvent queue_updated = 24;
    LlmUsageUpdatedEvent llm_usage_updated = 25;
  }

  reserved 13;
  reserved "model_changed";
}

// Event message definitions
// Assistant message - corresponds to a model response
message AssistantMessageAddedEvent {
  string id = 1;
  AssistantMessage message = 2;
  ModelSpec model = 3;
}

// User-authored message - no model attribution
message UserMessageAddedEvent {
  string id = 1;
  UserMessage message = 2;
}

message SessionConfigUpdatedEvent {
  SessionConfig config = 1;
  string primary_agent_id = 2;
}

// Tool result message - no model attribution
message ToolMessageAddedEvent {
  string id = 1;
  ToolMessage message = 2;
}

message MessageUpdatedEvent {
  Message message = 1;
}

message ToolCallStartedEvent {
  string name = 1;
  string id = 2;
  ModelSpec model = 3;
  string parameters_json = 4;  // JSON-encoded serde_json::Value
}

message ToolCallCompletedEvent {
  string name = 1;
  ToolResult result = 2;
  string id = 3;
  ModelSpec model = 4;
}

message ToolCallFailedEvent {
  string name = 1;
  string error = 2;
  string id = 3;
  ModelSpec model = 4;
}

message RequestToolApprovalEvent {
  string name = 1;
  string parameters_json = 2;  // JSON-encoded serde_json::Value
  string id = 3;
}

message ProcessingStartedEvent {
  string op_id = 1;  // Operation ID (UUID)
}

message ProcessingCompletedEvent {
  string op_id = 1;  // Operation ID (UUID)
}

enum UsageUpdateKind {
  USAGE_UPDATE_KIND_UNSPECIFIED = 0;
  USAGE_UPDATE_KIND_PARTIAL = 1;
  USAGE_UPDATE_KIND_FINAL = 2;
}

message LlmUsageUpdatedEvent {
  string op_id = 1;  // Operation ID (UUID)
  ModelSpec model = 2;
  Usage usage = 3;
  optional ContextWindowUtilization context_window = 4;
  UsageUpdateKind kind = 5;
}

message ErrorEvent {
  string message = 1;
}

message OperationCancelledEvent {
  CancellationInfo info = 1;
  string op_id = 2;
  optional QueuedWorkItem popped_queued_item = 3;
}

message StreamDeltaEvent {
  string op_id = 1;
  string message_id = 2;
  reserved 3;
  reserved "is_first";
  uint64 delta_sequence = 7;

  oneof delta_type {
    TextDelta text = 4;
    ThinkingDelta thinking = 5;
    ToolCallDelta tool_call = 6;
    ResetDelta reset = 8;
  }
}

message TextDelta {
  string content = 1;
}

message ThinkingDelta {
  string content = 1;
}

message ToolCallDelta {
  string tool_call_id = 1;
  oneof delta {
    string name = 2;
    string argument_chunk = 3;
  }
}

message ResetDelta {}

message ConversationCompactedEvent {
  CompactionRecord record = 1;
}

message CompactResultEvent {
  CompactResult result = 1;
  CompactTrigger trigger = 2;
}

message CompactResult {
  oneof result {
    CompactSuccess success = 1;
    CompactCancelled cancelled = 2;
    CompactInsufficientMessages insufficient_messages = 3;
    CompactFailed failed = 4;
  }
}

message CompactSuccess {
  string summary = 1;
}

message CompactCancelled {
}

message CompactInsufficientMessages {
}

message CompactFailed {
  string error = 1;
}

enum CompactTrigger {
  COMPACT_TRIGGER_UNSPECIFIED = 0;
  COMPACT_TRIGGER_MANUAL = 1;
  COMPACT_TRIGGER_AUTO = 2;
}

message AutoCompactionConfig {
  bool enabled = 1;
  uint32 threshold_percent = 2;
}

message CompactionRecord {
  string id = 1;
  string summary_message_id = 2;
  string compacted_head_message_id = 3;
  optional string previous_active_message_id = 4;
  string model = 5;
  google.protobuf.Timestamp created_at = 6;
}

message WorkspaceChangedEvent {
  // No fields needed - just signals that workspace files have changed
}
// Request/Response message definitions

message CreateSessionRequest {
  reserved 1;  // formerly tool_policy (redundant with tool_config.approval_policy)
  reserved 5, 7, 8, 9, 10, 11;
  reserved "system_prompt", "workspace_id", "workspace_ref", "parent_session_id", "workspace_name", "repo_ref";
  map<string, string> metadata = 2;
  optional SessionToolConfig tool_config = 3;
  optional WorkspaceConfig workspace_config = 4;
  ModelSpec default_model = 6;  // Required: default model for the session
  optional string primary_agent_id = 12;
  optional SessionPolicyOverrides policy_overrides = 13;
  optional AutoCompactionConfig auto_compaction = 14;
}

message CreateSessionResponse {
  SessionInfo session = 1;
}

message SendMessageRequest {
  string session_id = 1;
  string message = 2;  // Deprecated fallback for legacy clients
  optional ModelSpec model = 3;  // Optional; falls back to session's default_model
  repeated UserContent content = 4;
}

message SendMessageResponse {
  Operation operation = 1;
}

message EditMessageRequest {
  string session_id = 1;
  string message_id = 2;
  string new_content = 3;
  optional ModelSpec model = 4;  // Optional; falls back to session's default_model
  repeated UserContent content = 5;
}

message EditMessageResponse {
  // Empty - success indicated by OK status
}

message ApproveToolRequest {
  string session_id = 1;
  string tool_call_id = 2;
  ApprovalDecision decision = 3;
}

message ApproveToolResponse {
  // Empty response
}

message SwitchPrimaryAgentRequest {
  string session_id = 1;
  string primary_agent_id = 2;
}

message SwitchPrimaryAgentResponse {
  // Empty response
}

message CancelOperationRequest {
  string session_id = 1;
}

message CancelOperationResponse {
  // Empty response
}

message CompactSessionRequest {
  string session_id = 1;
  ModelSpec model = 2;
}

message CompactSessionResponse {
  // Empty - success indicated by OK status
}

message ExecuteBashCommandRequest {
  string session_id = 1;
  string command = 2;
  reserved 3;
  reserved "model";
}

message ExecuteBashCommandResponse {
  // Empty - results come via events
}

message ListSessionsRequest {
  optional SessionFilter filter = 1;
  optional uint32 page_size = 2;
  optional string page_token = 3;
}

message ListSessionsResponse {
  repeated SessionInfo sessions = 1;
  optional string next_page_token = 2;
}

message QueuedWorkItem {
  enum Kind {
    KIND_UNSPECIFIED = 0;
    KIND_USER_MESSAGE = 1;
    KIND_DIRECT_BASH = 2;
  }
  Kind kind = 1;
  string content = 2;
  optional ModelSpec model = 3;
  uint64 queued_at = 4;
  string op_id = 5;
  string message_id = 6;
  uint32 attachment_count = 7;
}

message QueueUpdatedEvent {
  optional QueuedWorkItem head = 1;
  uint32 count = 2;
}

message DequeueQueuedItemRequest {
  string session_id = 1;
}

message DequeueQueuedItemResponse {}

message GetSessionRequest {
  string session_id = 1;
}

message GetSessionResponse {
  oneof chunk {
    SessionStateHeader header = 1;
    Message message = 2;
    SessionStateFooter footer = 4;
  }
}

message SessionStateHeader {
  string id = 1;
  google.protobuf.Timestamp created_at = 2;
  google.protobuf.Timestamp updated_at = 3;
  SessionConfig config = 4;
  uint64 last_event_sequence = 5;
}



message SessionStateFooter {
  repeated string approved_tools = 1;
  reserved 2;  // was last_event_sequence, now in SessionStateHeader
  map<string, string> metadata = 3;
  optional QueuedWorkItem queued_head = 4;
  uint32 queued_count = 5;
}

message DeleteSessionRequest {
  string session_id = 1;
}

message DeleteSessionResponse {
  // Empty response
}

message GetConversationRequest {
  string session_id = 1;
}

message GetConversationResponse {
  oneof chunk {
    Message message = 1;
    GetConversationFooter footer = 2;
  }
}

message GetConversationFooter {
  repeated string approved_tools = 1;
  repeated string compaction_summary_ids = 2;
}

message ListFilesRequest {
  string session_id = 1;   // target session
  string query = 2;        // optional fuzzy query (empty = full list)
  uint32 max_results = 3;  // 0 = unlimited
}

message ListFilesResponse {
  repeated string paths = 1; // workspace-relative paths
}

message GetMcpServersRequest {
  string session_id = 1;
}

message GetMcpServersResponse {
  repeated McpServerInfo servers = 1;
}

message ListProvidersRequest {
  // Empty for now, might add filters later
}

message ListProvidersResponse {
  repeated ProviderInfo providers = 1;
}

message ListModelsRequest {
  optional string provider_id = 1;  // Filter by provider
}

message ListModelsResponse {
  repeated ProviderModel models = 1;
}

message ResolveModelRequest {
  string input = 1;  // Can be "provider/model", "alias", etc.
}

message ResolveModelResponse {
  ModelSpec model = 1;
}

message GetDefaultModelRequest {}

message GetDefaultModelResponse {
  ModelSpec model = 1;
}

message GetProviderAuthStatusRequest {
  optional string provider_id = 1; // if omitted, return all providers
}

message GetProviderAuthStatusResponse {
  repeated ProviderAuthStatus statuses = 1;
}

message StartAuthRequest {
  string provider_id = 1;
}

message StartAuthResponse {
  string flow_id = 1;
  AuthProgress progress = 2;
}

message SendAuthInputRequest {
  string flow_id = 1;
  string input = 2;
}

message SendAuthInputResponse {
  AuthProgress progress = 1;
}

message GetAuthProgressRequest {
  string flow_id = 1;
}

message GetAuthProgressResponse {
  AuthProgress progress = 1;
}

message CancelAuthRequest {
  string flow_id = 1;
}

message CancelAuthResponse {}

// Core data types

message SessionInfo {
  string id = 1;
  google.protobuf.Timestamp created_at = 2;
  google.protobuf.Timestamp updated_at = 3;
  SessionStatus status = 4;
  SessionMetadata metadata = 5;
}

message SessionState {
  string id = 1;
  google.protobuf.Timestamp created_at = 2;
  google.protobuf.Timestamp updated_at = 3;
  SessionConfig config = 4;
  repeated Message messages = 5;
  reserved 6;  // was tool_calls, tool state derived from messages
  repeated string approved_tools = 7;
  uint64 last_event_sequence = 8;
  map<string, string> metadata = 9;
}

message SessionConfig {
  reserved 1;  // formerly tool_policy (redundant with tool_config.approval_policy)
  SessionToolConfig tool_config = 2;
  map<string, string> metadata = 3;
  WorkspaceConfig workspace_config = 4;
  optional string system_prompt = 5;
  ModelSpec default_model = 6;
  optional string workspace_id = 7;
  optional WorkspaceRef workspace_ref = 8;
  optional string parent_session_id = 9;
  optional string workspace_name = 10;
  optional RepoRef repo_ref = 11;
  optional string primary_agent_id = 12;
  optional SessionPolicyOverrides policy_overrides = 13;
  optional AutoCompactionConfig auto_compaction = 14;
}

// Environment management
message CreateEnvironmentRequest {
  optional string root_path = 1;
  optional string name = 2;
}

message EnvironmentDescriptor {
  string environment_id = 1;
  string root_path = 2;
}

message CreateEnvironmentResponse {
  EnvironmentDescriptor environment = 1;
}

message GetEnvironmentRequest {
  string environment_id = 1;
}

message GetEnvironmentResponse {
  EnvironmentDescriptor environment = 1;
}

enum EnvironmentDeletePolicy {
  ENVIRONMENT_DELETE_POLICY_UNSPECIFIED = 0;
  ENVIRONMENT_DELETE_POLICY_HARD = 1;
  ENVIRONMENT_DELETE_POLICY_SOFT = 2;
}

message DeleteEnvironmentRequest {
  string environment_id = 1;
  EnvironmentDeletePolicy policy = 2;
}

message DeleteEnvironmentResponse {}

// Repo management
message RepoRef {
  string environment_id = 1;
  string repo_id = 2;
  string root_path = 3;
  optional steer.remote_workspace.v1.VcsKind vcs_kind = 4;
}

message RepoInfo {
  string repo_id = 1;
  string environment_id = 2;
  string root_path = 3;
  optional steer.remote_workspace.v1.VcsKind vcs_kind = 4;
}

message ResolveRepoRequest {
  string environment_id = 1;
  string path = 2;
}

message ResolveRepoResponse {
  RepoInfo repo = 1;
}

message ListReposRequest {
  string environment_id = 1;
}

message ListReposResponse {
  repeated RepoInfo repos = 1;
}

// Workspace orchestration
message WorkspaceRef {
  string environment_id = 1;
  string workspace_id = 2;
  string repo_id = 3;
  reserved 4;
  reserved "path", "vcs_kind";
}

message WorkspaceInfo {
  string workspace_id = 1;
  string environment_id = 2;
  optional string parent_workspace_id = 3;
  optional string name = 4;
  string path = 5;
  string repo_id = 6;
  reserved 7;
  reserved "vcs_kind";
}

message WorkspaceStatus {
  string workspace_id = 1;
  string environment_id = 2;
  string path = 3;
  optional steer.remote_workspace.v1.VcsInfo vcs = 4;
  string repo_id = 5;
}

enum WorkspaceCreateStrategy {
  WORKSPACE_CREATE_STRATEGY_UNSPECIFIED = 0;
  WORKSPACE_CREATE_STRATEGY_JJ_WORKSPACE = 1;
  WORKSPACE_CREATE_STRATEGY_GIT_WORKTREE = 2;
}

message CreateWorkspaceRequest {
  string repo_id = 1;
  optional string name = 2;
  optional string parent_workspace_id = 3;
  WorkspaceCreateStrategy strategy = 4;
  reserved 5;
  reserved "base";
}

message CreateWorkspaceResponse {
  WorkspaceInfo workspace = 1;
}

message ListWorkspacesRequest {
  string environment_id = 1;
  reserved 2;
  reserved "include_deleted";
}

message ListWorkspacesResponse {
  repeated WorkspaceInfo workspaces = 1;
}

message GetWorkspaceStatusRequest {
  string workspace_id = 1;
}

message GetWorkspaceStatusResponse {
  WorkspaceStatus status = 1;
}

message DeleteWorkspaceRequest {
  string workspace_id = 1;
  reserved 2;
  reserved "policy";
}

message DeleteWorkspaceResponse {}

message SessionMetadata {
  map<string, string> labels = 1;
  map<string, string> annotations = 2;
}

message SessionFilter {
  repeated string session_ids = 1;
  map<string, string> metadata_filters = 2;
  SessionStatus status = 3;
  google.protobuf.Timestamp created_after = 4;
  google.protobuf.Timestamp created_before = 5;
}

message Operation {
  string id = 1;
  string session_id = 2;
  OperationType type = 3;
  OperationStatus status = 4;
  google.protobuf.Timestamp created_at = 5;
  optional google.protobuf.Timestamp completed_at = 6;
  map<string, string> metadata = 7;
}

message Message {
  string id = 1;
  oneof message {
    UserMessage user = 2;
    AssistantMessage assistant = 3;
    ToolMessage tool = 4;
  }
  google.protobuf.Timestamp created_at = 5;
  map<string, string> metadata = 6;
}

message UserMessage {
  repeated UserContent content = 1;
  uint64 timestamp = 2;
  optional string parent_message_id = 3;
}

message UserContent {
  oneof content {
    string text = 1;
    CommandExecution command_execution = 2;
    ImageContent image = 3;
  }
}

message ImageContent {
  string mime_type = 1;
  oneof source {
    SessionFileSource session_file = 2;
    DataUrlSource data_url = 3;
    UrlSource url = 4;
  }
  optional uint32 width = 5;
  optional uint32 height = 6;
  optional uint64 bytes = 7;
  optional string sha256 = 8;
}

message SessionFileSource {
  string relative_path = 1;
}

message DataUrlSource {
  string data_url = 1;
}

message UrlSource {
  string url = 1;
}

message CommandExecution {
  string command = 1;
  string stdout = 2;
  string stderr = 3;
  int32 exit_code = 4;
}

message AssistantMessage {
  repeated AssistantContent content = 1;
  uint64 timestamp = 2;
  optional string parent_message_id = 3;
}

message AssistantContent {
  oneof content {
    string text = 1;
    ToolCall tool_call = 2;
    ThoughtContent thought = 3;
    ImageContent image = 4;
  }
}

message ThoughtContent {
  oneof thought_type {
    SimpleThought simple = 1;
    SignedThought signed = 2;
    RedactedThought redacted = 3;
  }
}

message SimpleThought {
  string text = 1;
}

message SignedThought {
  string text = 1;
  string signature = 2;
}

message RedactedThought {
  string data = 1;
}

message ToolMessage {
  string tool_use_id = 1;
  ToolResult result = 2;
  uint64 timestamp = 3;
  optional string parent_message_id = 4;
}

message ToolCall {
  string id = 1;
  string name = 2;
  string parameters_json = 3; // JSON-encoded parameters
}

message ToolResult {
  oneof result {
    steer.common.v1.SearchResult search = 1;
    steer.common.v1.FileListResult file_list = 2;
    steer.common.v1.FileContentResult file_content = 3;
    steer.common.v1.EditResult edit = 4;
    steer.common.v1.BashResult bash = 5;
    steer.common.v1.GlobResult glob = 6;
    steer.common.v1.TodoListResult todo_read = 7;
    steer.common.v1.TodoWriteResult todo_write = 8;
    FetchResult fetch = 9;
    AgentResult agent = 10;
    ExternalResult external = 50;
    ToolError error = 99;
  }
}

message FetchResult {
  string url = 1;
  string content = 2;
}

message AgentWorkspaceRevision {
  string vcs_kind = 1;
  string revision_id = 2;
  string summary = 3;
  string change_id = 4;
}

message AgentWorkspaceInfo {
  string workspace_id = 1;
  AgentWorkspaceRevision revision = 2;
}

message AgentResult {
  string content = 1;
  AgentWorkspaceInfo workspace = 2;
  string session_id = 3;
}

message ExternalResult {
  string tool_name = 1;
  string payload = 2;
}

message ToolError {
  oneof error_type {
    string unknown_tool = 1;
    InvalidParamsError invalid_params = 2;
    ExecutionError execution = 3;
    string cancelled = 4;
    string timeout = 5;
    string denied_by_user = 6;
    string internal_error = 7;
    IoError io = 8;
    string denied_by_policy = 9;
  }
}

message InvalidParamsError {
  string tool_name = 1;
  string message = 2;
}

message ExecutionError {
  string tool_name = 1;
  string message = 2;
}

message IoError {
  string tool_name = 1;
  string message = 2;
}

message McpConnectionFailedError {
  string server_name = 1;
  string message = 2;
}

message Usage {
  uint32 input_tokens = 1;
  uint32 output_tokens = 2;
  uint32 total_tokens = 3;
  optional double cost_usd = 4;
}

message ContextWindowUtilization {
  optional uint32 max_tokens = 1;
  optional uint32 remaining_tokens = 2;
  optional double utilization_ratio = 3;
  bool estimated = 4;
}

message ActiveToolInfo {
  string name = 1;
  string id = 2;
}

message CancellationInfo {
  bool api_call_in_progress = 1;
  repeated ActiveToolInfo active_tools = 2;
  bool pending_tool_approvals = 3;
}

message ApprovalDecision {
  oneof decision_type {
    bool deny = 1;
    bool once = 2;  // One-time approval
    bool always_tool = 3;  // Always approve this tool
    string always_bash_pattern = 4;  // Always approve this bash pattern
  }
}

// Tool configuration
message SessionToolConfig {
  repeated BackendConfig backends = 1;
  map<string, string> metadata = 2;
  ToolVisibility visibility = 3;
  ToolApprovalPolicy approval_policy = 4;
  reserved 5;  // formerly tools (moved into approval_policy)
}

message ToolVisibility {
  oneof visibility {
    bool all = 1;
    bool read_only = 2;
    ToolWhitelist whitelist = 3;
    ToolBlacklist blacklist = 4;
  }
}

message ToolWhitelist {
  repeated string tools = 1;
}

message ToolBlacklist {
  repeated string tools = 1;
}

message BackendConfig {
  oneof backend {
    LocalBackendConfig local = 1;
    McpBackendConfig mcp = 2;
  }
}

message ToolFilter {
  oneof filter {
    bool all = 1;
    IncludeFilter include = 2;
    ExcludeFilter exclude = 3;
  }
}

message IncludeFilter {
  repeated string tools = 1;
}

message ExcludeFilter {
  repeated string tools = 1;
}

message LocalBackendConfig {
  ToolFilter tool_filter = 1;
}

message McpBackendConfig {
  string server_name = 1;
  string transport = 2;
  string command = 3;
  repeated string args = 4;
  ToolFilter tool_filter = 5;
}

message RemoteAuth {
  oneof auth {
    string bearer_token = 1;
    string api_key = 2;
  }
}

// Approval policy
enum UnapprovedBehavior {
  UNAPPROVED_BEHAVIOR_UNSPECIFIED = 0;
  UNAPPROVED_BEHAVIOR_PROMPT = 1;
  UNAPPROVED_BEHAVIOR_DENY = 2;
  UNAPPROVED_BEHAVIOR_ALLOW = 3;
}

message ToolRule {
  oneof rule {
    BashRule bash = 1;
    DispatchAgentRule dispatch_agent = 2;
  }
}

message BashRule {
  repeated string patterns = 1;
}

message DispatchAgentRule {
  repeated string agent_patterns = 1;
}

message ApprovalRules {
  repeated string tools = 1;
  map<string, ToolRule> per_tool = 2;
}

message ToolApprovalPolicy {
  UnapprovedBehavior default_behavior = 1;
  ApprovalRules preapproved = 2;
}

message ApprovalRulesOverrides {
  repeated string tools = 1;
  map<string, ToolRule> per_tool = 2;
}

message ToolApprovalPolicyOverrides {
  optional UnapprovedBehavior default_behavior = 1;
  optional ApprovalRulesOverrides preapproved = 2;
}

message SessionPolicyOverrides {
  optional ModelSpec default_model = 1;
  optional ToolVisibility tool_visibility = 2;
  optional ToolApprovalPolicyOverrides approval_policy = 3;
}

// Workspace configuration
message WorkspaceConfig {
  oneof config {
    LocalWorkspaceConfig local = 1;
    RemoteWorkspaceConfig remote = 2;
  }
}

message LocalWorkspaceConfig {
  string path = 1;
}

message RemoteWorkspaceConfig {
  string agent_address = 1;
  optional RemoteAuth auth = 2;
}

// MCP server status
message McpServerStateChangedEvent {
  string server_name = 1;
  McpConnectionState state = 2;
}

message McpServerInfo {
  string server_name = 1;
  McpTransportInfo transport = 2;
  McpConnectionState state = 3;
  google.protobuf.Timestamp last_updated = 4;
}

message McpTransportInfo {
  oneof transport {
    McpStdioTransport stdio = 1;
    McpTcpTransport tcp = 2;
    McpUnixTransport unix = 3;
    McpSseTransport sse = 4;
    McpHttpTransport http = 5;
  }
}

message McpStdioTransport {
  string command = 1;
  repeated string args = 2;
}

message McpTcpTransport {
  string host = 1;
  uint32 port = 2;
}

message McpUnixTransport {
  string path = 1;
}

message McpSseTransport {
  string url = 1;
  map<string, string> headers = 2;
}

message McpHttpTransport {
  string url = 1;
  map<string, string> headers = 2;
}

message McpConnectionState {
  oneof state {
    McpConnecting connecting = 1;
    McpConnected connected = 2;
    McpFailed failed = 3;
    McpDisconnected disconnected = 4;
  }
}

message McpConnecting {
  // No fields needed
}

message McpConnected {
  repeated string tool_names = 1;
}

message McpFailed {
  string error = 1;
}

message McpDisconnected {
  optional string reason = 1;
}

// Provider and model configuration
message ProviderInfo {
  string id = 1;  // "anthropic", "openai", "gemini", "xai", or custom name
  string name = 2;  // Display name
}

message ProviderModel {
  string provider_id = 1;  // References ProviderInfo.id
  string model_id = 2;  // Model identifier (e.g., "claude-3-5-sonnet-20241022")
  string display_name = 3;  // User-friendly name
  bool supports_thinking = 4;  // Whether model supports thinking/reasoning
  repeated string aliases = 5;  // Short aliases like "sonnet", "opus"
  optional uint32 context_window_tokens = 6;
}

message ModelSpec {
  string provider_id = 1;  // Provider identifier
  string model_id = 2;  // Model identifier
}

message ProviderAuthStatus {
  string provider_id = 1;
  AuthSource auth_source = 2;
}

message AuthSource {
  oneof source {
    AuthSourceApiKey api_key = 1;
    AuthSourcePlugin plugin = 2;
    AuthSourceNone none = 3;
  }
}

message AuthSourceApiKey {
  ApiKeyOrigin origin = 1;
}

message AuthSourcePlugin {
  AuthMethod method = 1;
}

message AuthSourceNone {}

message AuthProgress {
  oneof state {
    AuthNeedInput need_input = 1;
    AuthInProgress in_progress = 2;
    AuthOAuthStarted oauth_started = 3;
    AuthComplete complete = 4;
    AuthError error = 5;
  }
}

message AuthNeedInput {
  string prompt = 1;
}

message AuthInProgress {
  string message = 1;
}

message AuthOAuthStarted {
  string auth_url = 1;
}

message AuthComplete {}

message AuthError {
  string message = 1;
}

// Enums
enum SessionStatus {
  SESSION_STATUS_UNSPECIFIED = 0;
  SESSION_STATUS_ACTIVE = 1;
  SESSION_STATUS_INACTIVE = 2;
}

enum OperationType {
  OPERATION_TYPE_UNSPECIFIED = 0;
  OPERATION_TYPE_SEND_MESSAGE = 1;
  OPERATION_TYPE_TOOL_EXECUTION = 2;
}

enum OperationStatus {
  OPERATION_STATUS_UNSPECIFIED = 0;
  OPERATION_STATUS_PENDING = 1;
  OPERATION_STATUS_RUNNING = 2;
  OPERATION_STATUS_COMPLETED = 3;
  OPERATION_STATUS_FAILED = 4;
  OPERATION_STATUS_CANCELLED = 5;
}

enum MessageRole {
  MESSAGE_ROLE_UNSPECIFIED = 0;
  MESSAGE_ROLE_USER = 1;
  MESSAGE_ROLE_ASSISTANT = 2;
  MESSAGE_ROLE_SYSTEM = 3;
  MESSAGE_ROLE_TOOL = 4;
}

enum ToolCallStatus {
  TOOL_CALL_STATUS_UNSPECIFIED = 0;
  TOOL_CALL_STATUS_PENDING_APPROVAL = 1;
  TOOL_CALL_STATUS_APPROVED = 2;
  TOOL_CALL_STATUS_DENIED = 3;
  TOOL_CALL_STATUS_EXECUTING = 4;
  TOOL_CALL_STATUS_COMPLETED = 5;
  TOOL_CALL_STATUS_FAILED = 6;
}

enum McpTransport {
  MCP_TRANSPORT_UNSPECIFIED = 0;
  MCP_TRANSPORT_STDIO = 1;
  MCP_TRANSPORT_HTTP = 2;
  MCP_TRANSPORT_WEBSOCKET = 3;
}

enum AuthMethod {
  AUTH_METHOD_UNSPECIFIED = 0;
  AUTH_METHOD_OAUTH = 1;
  AUTH_METHOD_API_KEY = 2;
}

enum ApiKeyOrigin {
  API_KEY_ORIGIN_UNSPECIFIED = 0;
  API_KEY_ORIGIN_ENV = 1;
  API_KEY_ORIGIN_STORED = 2;
}
