syntax = "proto3";

package codex.thread_store.v1;

service ThreadStore {
  rpc CreateThread(CreateThreadRequest) returns (Empty);
  rpc ResumeThread(ResumeThreadRequest) returns (Empty);
  rpc AppendItems(AppendThreadItemsRequest) returns (Empty);
  rpc PersistThread(ThreadIdRequest) returns (Empty);
  rpc FlushThread(ThreadIdRequest) returns (Empty);
  rpc ShutdownThread(ThreadIdRequest) returns (Empty);
  rpc DiscardThread(ThreadIdRequest) returns (Empty);
  rpc LoadHistory(LoadThreadHistoryRequest) returns (StoredThreadHistory);
  rpc ReadThread(ReadThreadRequest) returns (StoredThreadResponse);
  rpc ListThreads(ListThreadsRequest) returns (ListThreadsResponse);
  rpc UpdateThreadMetadata(UpdateThreadMetadataRequest) returns (StoredThreadResponse);
  rpc ArchiveThread(ArchiveThreadRequest) returns (Empty);
  rpc UnarchiveThread(ArchiveThreadRequest) returns (StoredThreadResponse);
}

message Empty {}

message ThreadIdRequest {
  string thread_id = 1;
}

message CreateThreadRequest {
  string thread_id = 1;
  optional string forked_from_id = 2;
  SessionSource source = 3;
  string base_instructions_json = 4;
  repeated string dynamic_tools_json = 5;
  ThreadEventPersistenceMode event_persistence_mode = 6;
}

message ResumeThreadRequest {
  string thread_id = 1;
  optional string rollout_path = 2;
  repeated string history_json = 3;
  bool has_history = 4;
  bool include_archived = 5;
  ThreadEventPersistenceMode event_persistence_mode = 6;
}

message AppendThreadItemsRequest {
  string thread_id = 1;
  repeated string items_json = 2;
}

message LoadThreadHistoryRequest {
  string thread_id = 1;
  bool include_archived = 2;
}

message ReadThreadRequest {
  string thread_id = 1;
  bool include_archived = 2;
  bool include_history = 3;
}

message ListThreadsRequest {
  uint32 page_size = 1;
  optional string cursor = 2;
  ThreadSortKey sort_key = 3;
  repeated SessionSource allowed_sources = 4;
  optional ModelProviderFilter model_provider_filter = 5;
  bool archived = 6;
  optional string search_term = 7;
  optional CwdFilter cwd_filter = 8;
  bool use_state_db_only = 9;
  SortDirection sort_direction = 10;
}

message ModelProviderFilter {
  repeated string values = 1;
}

message CwdFilter {
  repeated string values = 1;
}

enum ThreadSortKey {
  THREAD_SORT_KEY_CREATED_AT = 0;
  THREAD_SORT_KEY_UPDATED_AT = 1;
}

enum SortDirection {
  SORT_DIRECTION_ASC = 0;
  SORT_DIRECTION_DESC = 1;
}

message ListThreadsResponse {
  repeated StoredThread threads = 1;
  optional string next_cursor = 2;
}

message StoredThreadResponse {
  StoredThread thread = 1;
}

message StoredThreadHistory {
  string thread_id = 1;
  repeated string items_json = 2;
}

message StoredThread {
  // Mirrors Rust's StoredThread. Domain types that are not protobuf-native,
  // such as ThreadId, DateTime<Utc>, and PathBuf, are represented as their
  // stable scalar forms on the wire.
  string thread_id = 1;
  optional string forked_from_id = 2;
  string preview = 3;
  optional string name = 4;
  string model_provider = 5;
  optional string model = 6;
  int64 created_at = 7;
  int64 updated_at = 8;
  optional int64 archived_at = 9;
  string cwd = 10;
  string cli_version = 11;
  SessionSource source = 12;
  optional GitInfo git_info = 13;
  optional string agent_nickname = 14;
  optional string agent_role = 15;
  optional string agent_path = 16;
  optional string reasoning_effort = 17;
  optional string first_user_message = 18;
  optional string rollout_path = 19;
  optional string approval_mode_json = 20;
  optional string sandbox_policy_json = 21;
  optional string token_usage_json = 22;
  optional StoredThreadHistory history = 23;
}

message SessionSource {
  SessionSourceKind kind = 1;
  optional string custom = 2;
  optional string sub_agent_parent_thread_id = 3;
  optional int32 sub_agent_depth = 4;
  optional string sub_agent_other = 5;
  optional string sub_agent_path = 6;
  optional string sub_agent_nickname = 7;
  optional string sub_agent_role = 8;
}

enum SessionSourceKind {
  SESSION_SOURCE_KIND_UNKNOWN = 0;
  SESSION_SOURCE_KIND_CLI = 1;
  SESSION_SOURCE_KIND_VSCODE = 2;
  SESSION_SOURCE_KIND_EXEC = 3;
  SESSION_SOURCE_KIND_APP_SERVER = 4;
  SESSION_SOURCE_KIND_CUSTOM = 5;
  SESSION_SOURCE_KIND_SUB_AGENT_REVIEW = 6;
  SESSION_SOURCE_KIND_SUB_AGENT_COMPACT = 7;
  SESSION_SOURCE_KIND_SUB_AGENT_THREAD_SPAWN = 8;
  SESSION_SOURCE_KIND_SUB_AGENT_MEMORY_CONSOLIDATION = 9;
  SESSION_SOURCE_KIND_SUB_AGENT_OTHER = 10;
}

message GitInfo {
  optional string sha = 1;
  optional string branch = 2;
  optional string origin_url = 3;
}

message UpdateThreadMetadataRequest {
  string thread_id = 1;
  ThreadMetadataPatch patch = 2;
  bool include_archived = 3;
}

message ThreadMetadataPatch {
  optional string name = 1;
  optional ThreadMemoryMode memory_mode = 2;
  optional GitInfoPatch git_info = 3;
}

enum ThreadMemoryMode {
  THREAD_MEMORY_MODE_ENABLED = 0;
  THREAD_MEMORY_MODE_DISABLED = 1;
}

message GitInfoPatch {
  OptionalStringPatch sha = 1;
  OptionalStringPatch branch = 2;
  OptionalStringPatch origin_url = 3;
}

message OptionalStringPatch {
  OptionalStringPatchKind kind = 1;
  optional string value = 2;
}

enum OptionalStringPatchKind {
  OPTIONAL_STRING_PATCH_KIND_UNSET = 0;
  OPTIONAL_STRING_PATCH_KIND_CLEAR = 1;
  OPTIONAL_STRING_PATCH_KIND_SET = 2;
}

message ArchiveThreadRequest {
  string thread_id = 1;
}

enum ThreadEventPersistenceMode {
  THREAD_EVENT_PERSISTENCE_MODE_LIMITED = 0;
  THREAD_EVENT_PERSISTENCE_MODE_EXTENDED = 1;
}
