Store.Project.Conversation (fnord v0.9.40)

View Source

Conversations are stored per project under conversations/ in the project store.

The canonical on-disk shape is a v1 JSON object written by Store.Project.Conversation.Format. That payload includes:

  • version
  • timestamp
  • messages
  • metadata
  • memory
  • tasks

Legacy v0 timestamp-prefixed files are still readable, but new writes go out through the v1 format path.

Existing conversations are retrieved by their UUID identifier.

Summary

Functions

Deletes the conversation from the store. If the conversation does not exist, returns an error tuple.

Returns true if the conversation exists on disk, false otherwise.

Forks the given conversation, returning a new conversation with a new UUID and identical messages. Saves the forked conversation to disk with the current timestamp.

Lists all conversations in the given project in ascending order by timestamp.

Create a new conversation with a new UUID identifier and the globally selected project.

Create a new conversation from an existing UUID identifier and the globally selected project.

Create a new conversation from an existing UUID identifier and an explicitly specified project.

Returns the number of messages in the conversation. If the conversation does not exist, returns 0.

Returns the user's prompting message in the conversation. This is considered to be the first "user" role message in the conversation.

Reads the conversation from the store.

Returns the timestamp of the conversation. If the conversation has not yet been saved to the store, returns 0. v0 files yield their timestamp from the numeric prefix (cheap); v1 files require a full JSON decode (paid once a v1 file is encountered).

Saves the conversation in the store.

Types

data()

@type data() :: %{
  timestamp: DateTime.t(),
  messages: AI.Util.msg_list(),
  metadata: map(),
  memory: list(),
  tasks: %{
    required(binary()) => %{
      description: binary() | nil,
      tasks: Services.Task.task_list()
    }
  }
}

t()

@type t() :: %Store.Project.Conversation{
  id: term(),
  project_home: term(),
  store_path: term()
}

Functions

delete(conversation)

@spec delete(t()) :: :ok | {:error, :not_found}

Deletes the conversation from the store. If the conversation does not exist, returns an error tuple.

exists?(conversation)

@spec exists?(t()) :: boolean()

Returns true if the conversation exists on disk, false otherwise.

fork(conversation)

@spec fork(t()) :: {:ok, t()} | {:error, any()}

Forks the given conversation, returning a new conversation with a new UUID and identical messages. Saves the forked conversation to disk with the current timestamp.

list(project_home)

@spec list(Store.Project.t()) :: [t()]
@spec list(binary()) :: [t()]

Lists all conversations in the given project in ascending order by timestamp.

new()

Create a new conversation with a new UUID identifier and the globally selected project.

new(id)

Create a new conversation from an existing UUID identifier and the globally selected project.

new(id, project_home)

Create a new conversation from an existing UUID identifier and an explicitly specified project.

num_messages(conversation)

@spec num_messages(t()) :: non_neg_integer()

Returns the number of messages in the conversation. If the conversation does not exist, returns 0.

question(conversation)

@spec question(t()) :: {:ok, binary()} | {:error, :no_question}

Returns the user's prompting message in the conversation. This is considered to be the first "user" role message in the conversation.

read(conversation)

@spec read(t()) :: {:ok, data()} | {:error, any()}

Reads the conversation from the store.

Returns the canonical conversation map with timestamp, messages, metadata, memory, and tasks.

Delegates to Store.Project.Conversation.Format.read/1, which transparently handles both v0 (legacy timestamp-prefixed) and v1 (pure JSON with version: 1) file shapes. See that module for the cross-worktree migration strategy.

timestamp(conversation)

@spec timestamp(t()) :: DateTime.t() | 0

Returns the timestamp of the conversation. If the conversation has not yet been saved to the store, returns 0. v0 files yield their timestamp from the numeric prefix (cheap); v1 files require a full JSON decode (paid once a v1 file is encountered).

write(conversation, data \\ %{})

@spec write(t(), map()) :: {:ok, t()} | {:error, any()}

Saves the conversation in the store.

New conversations get a fresh timestamp and default empty fields for messages, metadata, memory, and tasks.

Existing conversations are read first so the stored messages, metadata, memory, and tasks can be merged with the incoming data. The timestamp is reused when the merged message list is unchanged; otherwise a fresh timestamp is written.