syntax = "proto3";

package nominal.ai.v1;

import 'google/protobuf/timestamp.proto';

// AIAgentService provides AI-powered assistance for general operations
service AIAgentService {
  // StreamChat handles bidirectional streaming chat for AI agent
  rpc StreamChat(StreamChatRequest) returns (stream StreamChatResponse);
  // GetConversation handles getting a complete conversation list, with an optional limit on number of messages returned
  rpc GetConversation(GetConversationRequest) returns (GetConversationResponse);
  // ListConversations handles getting the list of conversation ids ordered by most recently updated
  rpc ListConversations(ListConversationsRequest) returns (ListConversationsResponse);
  // CreateConversation handles creating a conversation and assigning it a conversation rid
  rpc CreateConversation(CreateConversationRequest) returns (CreateConversationResponse);
  // UpdateConversationMetadata handles updating any metadata associated with a conversation
  rpc UpdateConversationMetadata(UpdateConversationMetadataRequest) returns (UpdateConversationMetadataResponse);
  // DeleteConversation handles deleting a specific conversation by conversation rid
  rpc DeleteConversation(DeleteConversationRequest) returns (DeleteConversationResponse);
}

// StreamChatRequest is a request to stream chat messages for AI agent
message StreamChatRequest {
  // The conversation ID
  string conversation_rid = 1;
  // The user message to append to the conversation
  UserModelMessage message = 2;
  // Optional: image files to provide to the agent
  repeated ImagePart images = 3;
  // Context-specific fields based on the oneofKind.
  oneof context {
    WorkbookContext workbook = 4;
    GlobalContext global = 5;
  }
}

// WorkbookContext contains workbook-specific context fields
message WorkbookContext {
  // RID of the workbook to use for context
  string workbook_rid = 1;
  // Optional: the user's presence in the workbook
  optional WorkbookUserPresence user_presence = 2;
}

// DefaultContext (no context)
message GlobalContext {}

// WorkbookUserPresence contains the user's presence in the workbook
// which is used to describe what the user is viewing at the time of the message.
message WorkbookUserPresence {
  optional int32 tab_index = 1;
  optional TimeRange range = 2;
}

// CreateConversation request will create a new conversation thread
// if old conversation id is not set, a brand new, clear chat is created
// If old conversation id is set without a previous message id, the full conversation thread will be copied
// if previous message id is set with a previous message id, the conversation thread up until that message will be copied
// the above case is useful for branching a conversation into a new thread
message CreateConversationRequest {
  string title = 1;
  string workspace_rid = 2;
  optional string old_conversation_rid = 3;
  optional string previous_message_id = 4;
}

// CreateConversationResponse will return the conversation id for the new conversation
message CreateConversationResponse {
  string new_conversation_rid = 1;
}

message UpdateConversationMetadataRequest {
  string title = 1;
  string conversation_rid = 2;
}

message UpdateConversationMetadataResponse {}

message DeleteConversationRequest {
  string conversation_rid = 1;
}

message DeleteConversationResponse {}

// a GetConversationRequest allows you to retrieve a subset of messages from a conversation thread represented
// by provided rid. To start from a particular message - you can also provide a message id.
message GetConversationRequest {
  string conversation_rid = 1;
  optional string page_start_message_id = 2;
  optional int32 max_message_count = 3;
}

// Model message with id allows you to identify the message ID of a given message
message ModelMessageWithId {
  oneof content {
    ModelMessage message = 1;
    ToolAction tool_action = 2;
  }
  string message_id = 3;
}

message GetConversationResponse {
  repeated ModelMessageWithId ordered_messages = 1;
  ConversationMetadata conversation_metadata = 2;
}

// Will generate all conversation threads that this user has in this workspace
message ListConversationsRequest {
  string workspace_rid = 1;
}

message ConversationMetadata {
  string conversation_rid = 1;
  string title = 2;
  google.protobuf.Timestamp created_at = 3;
  google.protobuf.Timestamp last_updated_at = 4;
}

// ListConversationsResponse is a list of conversations that can be used in a call to GetConversationRequest
// to get a full conversation from storage. These are ordered by creation time.
message ListConversationsResponse {
  repeated ConversationMetadata conversations = 1;
}

message TimeRange {
  Timestamp range_start = 1;
  Timestamp range_end = 2;
}

message Timestamp {
  int32 seconds = 1;
  int32 nanoseconds = 2;
}

// ModelMessage is a discriminated union of system, user, assistant, and tool messages.
// Each message type has its own structure and content.
message ModelMessage {
  oneof kind {
    UserModelMessage user = 1;
    AssistantModelMessage assistant = 2;
  }
}

// A user message containing text
message UserModelMessage {
  repeated UserContentPart text = 1;
}

// An assistant message containing text
message AssistantModelMessage {
  repeated AssistantContentPart content_parts = 1;
}

message UserContentPart {
  oneof part {
    TextPart text = 1;
  }
}

// Content part for assistant messages: can be text, reasoning, or mutation.
message AssistantContentPart {
  oneof part {
    TextPart text = 1;
    ReasoningPart reasoning = 2;
  }
}

// Text part for user or assistant messages.
message TextPart {
  string text = 1;
}

// User-supplied image part.
message ImagePart {
  // The base64-encoded image data
  bytes data = 1;
  // The media type of the image (e.g. "image/png", "image/jpeg")
  optional string media_type = 2;
  // Optional: the filename of the image
  optional string filename = 3;
}

// Reasoning part for assistant messages.
message ReasoningPart {
  string reasoning = 1;
}

// StreamChatResponse is a discriminated union response to a StreamChatRequest
message StreamChatResponse {
  oneof response {
    Finish finish = 1;
    Error error = 2;
    TextStart text_start = 3;
    TextDelta text_delta = 4;
    TextEnd text_end = 5;
    ReasoningStart reasoning_start = 6;
    ReasoningDelta reasoning_delta = 7;
    ReasoningEnd reasoning_end = 8;
    // this will be deprecated in favor of MCP-based mutations
    WorkbookMutation workbook_mutation = 9;
    ToolAction tool_action = 10;
  }
}

// Indicates the end of a chat session
message Finish {
  // The message ids in order of all generated messages for this agent run
  // These ids can be used to branch a message from that specific message
  repeated string ordered_message_ids = 1;

  // In the case that this is the first agent run in a conversation thread, we also
  // return the new conversation title generated
  optional string new_title = 2;
}

// An error that occurred during the chat session
message Error {
  string message = 1;
}

// Indicates the start of a text message from the agent
message TextStart {
  // uniquely identifies the text message (e.g. uuid) so that the client can
  // merge parallel message streams (if it happens).
  string id = 1;
}

// A delta (continuation) of a text message from the agent
message TextDelta {
  string id = 1;
  // The next chunk of text
  string delta = 2;
}

// Indicates the end of a text message from the agent
message TextEnd {
  string id = 1;
}

// Indicates the start of a reasoning message from the agent
message ReasoningStart {
  string id = 1;
}

// A delta (continuation) of a reasoning message from the agent
message ReasoningDelta {
  string id = 1;
  // The next chunk of reasoning
  string delta = 2;
}

// Indicates the end of a reasoning message from the agent
message ReasoningEnd {
  string id = 1;
}

// Add a new tab to the workbook
message AddTabMutation {
  // if tab_name is not provided, we'll name it "New Tab"
  optional string tab_name = 1;
}

// this is the "result" of the mutation
message AddOrUpdatePanelMutation {
  // JSON-serialized representation of IVizDefinition
  string panel_as_json = 1;
  string panel_id = 2;
  int32 tab_index = 3;
}

message RemovePanelsMutation {
  repeated string panel_ids = 1;
}

// AddOrReplaceVariableMutation is a mutation to add or replace a variable in the workbook
message AddOrReplaceVariableMutation {
  // scout_compute_api_ComputeSpecWithContext (this needs to be resolved)
  // be careful: this uses the scout_compute_api version of ComputeSpecWithContext, which stores the spec as "seriesNode"
  // and is NOT the same as ComputeSpecWithContext that is stored in INotebook.
  string compute_spec_as_json = 1;
  // if variable_name is not provided, we'll assume it's a new variable and auto-generate a unique name
  optional string variable_name = 2;
  optional string display_name = 3;
}

// DeleteVariablesMutation is a mutation to delete variables from the workbook
message DeleteVariablesMutation {
  repeated string variable_names = 1;
}

// WorkbookMutation is a mutation to the workbook
message WorkbookMutation {
  string id = 1;

  oneof mutation {
    AddTabMutation add_tab = 2;
    AddOrUpdatePanelMutation add_or_update_panel = 3;
    RemovePanelsMutation remove_panels = 4;
    AddOrReplaceVariableMutation add_or_replace_variable = 5;
    DeleteVariablesMutation delete_variables = 6;
  }
}

// this is a concise description of a tool call that the agent is making internally
// without revealing too much detail about the tool call, it informs the user what the agent is doing
// at a high level. the format is: `{tool_action_verb} {tool_target}` for example:
// "Search channels for My Datasource"
message ToolAction {
  string id = 1;
  string tool_action_verb = 2; // "Thought", "Read", "Find", "Look-up", etc.
  optional string tool_target = 3; // "workbook", "channel", "variable", "panel", etc.
}
