Documentation
¶
Overview ¶
Package hermes reads the sessions of Hermes Agent (NousResearch/hermes-agent), the Python agent behind the hermes CLI, its TUI and its messaging gateway. Hermes keeps every session of a profile in one SQLite database, state.db, under its home directory (~/.hermes/state.db, and ~/.hermes/profiles/<name>/state.db for each further profile): the sessions table, a row per session, the messages table, a row per message in OpenAI's chat-completions shape, and the tables beside them a conversion reads, system_prompts, session_model_usage and async_delegations.
It imports the standard library alone, so it does not open a database itself: the hermes/sqlite package opens one and yields its rows as this package's types, through the Store interface. Rows are read by column name, since Hermes adds columns to its tables as it needs them and an older database lacks the newer ones; a column this package does not know is kept with the row. The schema version the database records is read too, and the reading rules that depend on it are this package's.
A row that cannot be read is a Stray, never an error. The package does not interpret what the model saw: Classify tells a child session's relation to its parent as Hermes does, and the convert subpackage rebuilds each session's context; docs/formats/hermes.md is the mapping. Not read here: the ShareGPT trajectories, the trace export, the session JSON and JSONL files Hermes falls back to when the database is unavailable, and the export of hermes sessions export.
Index ¶
- Constants
- Variables
- func Databases(dir string) []string
- func Epoch(f float64) (time.Time, bool)
- func FindSessions(root string) ([]string, error)
- func IsHome(dir string) bool
- func IsNull(raw json.RawMessage) bool
- func ResultAliases(id string) []string
- func StoreOf(path string) (string, bool)
- type Column
- type Columns
- func (cs Columns) Flag(name string, def bool) bool
- func (cs Columns) Float(name string) (float64, bool)
- func (cs Columns) Get(name string) (any, bool)
- func (cs Columns) Has(name string) bool
- func (cs Columns) Int(name string) (int64, bool)
- func (cs Columns) JSON() json.RawMessage
- func (cs Columns) String(name string) string
- func (cs Columns) Text(name string) (string, bool)
- func (cs Columns) Without(names ...string) Columns
- type Content
- type Database
- type Delegation
- type Function
- type Members
- type Memory
- func (m *Memory) Delegations() ([]*Delegation, error)
- func (m *Memory) Messages(id string) ([]*Message, error)
- func (m *Memory) ModelUsage(id string) ([]Columns, error)
- func (m *Memory) Name() string
- func (m *Memory) Orphans(known map[string]bool) ([]*Stray, error)
- func (m *Memory) Sessions() ([]*Session, []*Stray, error)
- func (m *Memory) SystemPrompt(hash string) (string, bool)
- func (m *Memory) Version() (int, bool)
- type Message
- type Relation
- type Session
- type Store
- type Stray
- type ToolCall
Constants ¶
const ( RoleUser = "user" RoleAssistant = "assistant" RoleTool = "tool" RoleSystem = "system" // RoleSessionMeta is the gateway's first-turn marker, transcript // bookkeeping that no model reads. RoleSessionMeta = "session_meta" )
Message roles Hermes writes.
const ( MarkerBranch = "_branched_from" MarkerDelegate = "_delegate_from" MarkerReset = "_reset_from" )
Model config markers that tie a child session to its parent.
const ContentPrefix = "\x00json:"
ContentPrefix marks content Hermes stored as JSON, multimodal parts or a dict, rather than text: SessionDB._CONTENT_JSON_PREFIX.
const DatabaseName = "state.db"
DatabaseName is the name of Hermes' database in its home directory and in each profile's.
const DirProfiles = "profiles"
DirProfiles is the directory of a home's further profiles, each a directory holding its own state.db.
const SchemaVersion = 31
SchemaVersion is the newest schema version this package was written against: hermes_state_common.SCHEMA_VERSION at hermes-agent 848fc0ad8b.
Variables ¶
var ResetEndReasons = map[string]bool{ "session_reset": true, "session_switch": true, "idle": true, "daily": true, "suspended": true, "resume_pending_expired": true, }
ResetEndReasons are the end reasons of a parent that a legacy reset child follows: hermes_state_common._RESET_END_REASONS.
Functions ¶
func Databases ¶
Databases lists the databases a home holds: its own state.db and each profile's, ~/.hermes/profiles/<name>/state.db, in name order.
func Epoch ¶
Epoch is a Hermes timestamp, REAL seconds since the epoch, as a time; false outside the window Hermes itself accepts (hermes_cli.timefmt's EPOCH_MIN and EPOCH_MAX, 0 to 4.2e9), where a damaged or foreign cell lies.
func FindSessions ¶
FindSessions lists the Hermes databases under root: each state.db, a home's and each of its profiles'. A file root is returned as it is. A database is converted whole: Hermes keeps every session of a profile in one. Directories that cannot be read are passed over, and symbolic links are not followed.
func IsNull ¶
func IsNull(raw json.RawMessage) bool
IsNull reports whether a raw value is absent or null.
func ResultAliases ¶
ResultAliases are the spellings a tool row's tool_call_id names a call by (tool_result_id_variants).
Types ¶
type Column ¶
Column is one column of a database row: its name and its value as database/sql scans it, an int64, float64, string, []byte or nil.
type Columns ¶
type Columns []Column
Columns is a row of a table, in the table's column order.
func (Columns) Flag ¶
Flag returns an integer column as a flag: true when it is non-zero, and def when the column is absent or null.
func (Columns) Float ¶
Float returns a numeric column. Text that spells a number is not one: SQLite would store a REAL value as such.
func (Columns) JSON ¶
func (cs Columns) JSON() json.RawMessage
JSON writes the row as one JSON object, a member per column in the table's order: a JSON text column as the value it holds when it holds one, text as a string, a number as a number, null as null, and a blob as base64 text.
type Content ¶
type Content struct {
// Text is the content when it is text.
Text string
// Parts holds structured content, each part as written; a dict is
// one part.
Parts []json.RawMessage
// Structured says the content is Parts; Null that the column is
// null.
Structured, Null bool
}
Content is a message's content as Hermes stores it: text, or JSON behind ContentPrefix, multimodal parts or a dict.
func DecodeContent ¶
DecodeContent reads a content column as SessionDB._decode_content does: text behind ContentPrefix is JSON, and a reserved prefix holding no valid JSON stays the text it is. ok is false for such text.
type Delegation ¶
type Delegation struct {
ID string
ParentSessionID string
OriginSessionID string
State string
Cols Columns
}
Delegation is the parent session of a background delegation, from a row of async_delegations.
type Function ¶
type Function struct {
Name string `json:"name"`
Arguments json.RawMessage `json:"arguments"`
Members
}
Function is a call's function: its name and arguments, a JSON string as OpenAI writes them or an object as some providers do.
func (Function) MarshalJSON ¶
MarshalJSON writes the function back as it was read.
func (*Function) UnmarshalJSON ¶
UnmarshalJSON decodes the function, keeping undeclared members.
type Members ¶
Members is embedded in every JSON object this package decodes. It keeps the members the Go type does not declare, so an object decoded and encoded again is the same JSON value.
type Memory ¶
type Memory struct {
StoreName string
Schema int
SessionRows []*Session
Strays []*Stray
MessagesOf map[string][]*Message
Prompts map[string]string
Usage map[string][]Columns
Delegated []*Delegation
// Loose are rows of messages whose session is not in
// SessionRows.
Loose []*Message
}
Memory is a store held in memory, for tests and fuzzing: a database's rows, decoded.
func (*Memory) Delegations ¶
func (m *Memory) Delegations() ([]*Delegation, error)
Delegations implements Store.
func (*Memory) ModelUsage ¶
ModelUsage implements Store.
func (*Memory) SystemPrompt ¶
SystemPrompt implements Store.
type Message ¶
type Message struct {
// Unit names the row in findings: <database>:messages/<id>.
Unit string
ID int64
SessionID string
Role string
Content Content
// ToolCalls is an assistant's calls, those that decoded; BadCalls
// the entries of the column that are not objects.
ToolCalls []*ToolCall
BadCalls []json.RawMessage
ToolCallID string
ToolName string
Time time.Time
// FinishReason is the provider's, as Hermes recorded it.
FinishReason string
// Reasoning and ReasoningContent are the reasoning texts; a nil
// ReasoningContent is a null column, which Hermes tells from an
// empty one.
Reasoning string
ReasoningContent *string
// ReasoningDetails, CodexReasoningItems and CodexMessageItems are
// the reasoning carriers, as JSON arrays when they hold one.
ReasoningDetails json.RawMessage
CodexReasoningItems json.RawMessage
CodexMessageItems json.RawMessage
// APIContent is the text Hermes sent in place of the content, and
// HasAPIContent says the row holds a non-empty one.
APIContent string
HasAPIContent bool
DisplayKind string
// DisplayMetadata is the display_metadata column when it holds a
// JSON object, once unwrapped from the string layer rows written
// before Hermes guarded it hold.
DisplayMetadata json.RawMessage
// Active and Compacted are the row's flags; a database without
// the columns has every row active. Summary is
// _compressed_summary, and HasSummary says the database has the
// column.
Active, Compacted bool
Summary, HasSummary bool
Observed bool
// Cols is the row as read.
Cols Columns
// Problems lists the columns that do not hold what Hermes writes,
// each kept as written and read as Hermes reads it.
Problems []string
// Err says why the row cannot be read.
Err error
}
Message is one row of the messages table: the columns a converter reads, and the row itself.
func DecodeMessageRow ¶
DecodeMessageRow reads a row of the messages table.
type Relation ¶
type Relation int
Relation is how a session relates to the session its parent_session_id names, as Hermes tells it.
const ( // Root is a session with no parent. Root Relation = iota // Continuation is a compression child: its parent ended with // end_reason "compression" and it carries the conversation on. Continuation // Branch is a /branch copy: model_config._branched_from names the // parent, or, before the marker, the parent ended "branched" no // later than the child started. Branch // Reset is a reset child: a new conversation on the parent's chat, // marked by _reset_from, or, before the marker, a parent ended at a // reset boundary on the child's routing key. Reset // Delegate is a sub-agent's session: _delegate_from names the // parent, its source is "subagent", or nothing else tells it. Delegate // Tool is a session a tool ran, source "tool". Tool )
func Classify ¶
Classify tells a session's relation to its parent, the row its parent_session_id names, which may be nil when the database does not hold it. It follows Hermes' predicates: _is_explicit_fork_child_row (a tool session, or a marker that names the parent), then _is_compression_child_row (a parent ended "compression"), then the legacy branch and reset heuristics of _BRANCH_CHILD_SQL and _legacy_reset_child_sql, and else a sub-agent run, as _ephemeral_child_sql takes every other child. One rule is this package's: a session whose source is "subagent" is a sub-agent whatever its parent's end, unless its parent is one too, whose compression child it may be. marked says the relation was told by a marker or a source rather than by a heuristic.
type Session ¶
type Session struct {
// Unit names the row in findings: <database>:sessions/<id>.
Unit string
ID string
Source string
ParentID string
Model string
// ModelConfig is the model_config column when it holds a JSON
// object.
ModelConfig json.RawMessage
// SystemPrompt is the prompt column of the row, and
// SystemPromptHash the key of system_prompts it names, from schema
// version 25.
SystemPrompt string
SystemPromptHash string
Started time.Time
Ended time.Time
EndReason string
SessionKey string
CWD string
GitBranch string
GitRepoRoot string
Title string
// Cols is the row as read.
Cols Columns
// Problems lists the columns that do not hold what Hermes writes,
// each kept as written.
Problems []string
// Err says why the row cannot be read; only Unit and, when the row
// gave one, ID are then set.
Err error
}
Session is one row of the sessions table: the columns a converter reads, and the row itself.
func DecodeSessionRow ¶
DecodeSessionRow reads a row of the sessions table.
type Store ¶
type Store interface {
// Name names the store in findings: the database's file name.
Name() string
// Version is the schema version the database records; false when
// it records none.
Version() (int, bool)
// Sessions lists every row of sessions, and the rows that cannot
// be read as one.
Sessions() ([]*Session, []*Stray, error)
// Messages reads a session's rows of messages in id order, Hermes'
// order, never the timestamps'.
Messages(sessionID string) ([]*Message, error)
// SystemPrompt reads system_prompts' prompt of a hash.
SystemPrompt(hash string) (string, bool)
// ModelUsage reads a session's rows of session_model_usage.
ModelUsage(sessionID string) ([]Columns, error)
// Delegations reads async_delegations.
Delegations() ([]*Delegation, error)
// Orphans lists the rows of messages whose session is none of the
// set.
Orphans(sessions map[string]bool) ([]*Stray, error)
}
Store is the rows of one Hermes database. Rows are read on demand, a session at a time.
type Stray ¶
type Stray struct {
Unit string
// Session names the session it was read with, when it was.
Session string
// Kind says what the row is: "session" or "message".
Kind string
Why string
// Malformed says the row could not be read at all.
Malformed bool
}
Stray is a row read that belongs to no session it can be converted with, or that cannot be read.
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
CallID string `json:"call_id"`
Type string `json:"type"`
Function *Function `json:"function"`
Members
}
ToolCall is one entry of an assistant row's tool_calls: OpenAI's {id, type, function: {name, arguments}}, and on a Responses route the call_id the pairing uses. Undeclared members are kept.
func DecodeToolCalls ¶
func DecodeToolCalls(data []byte) (calls []*ToolCall, bad []json.RawMessage, err error)
DecodeToolCalls reads a tool_calls column: a JSON array of calls. An entry that is not an object is returned in bad. err is set when the column is not a JSON array, which Hermes reads as no calls; a single object is read as a list of one, as _as_list does.
func (*ToolCall) Aliases ¶
Aliases are every spelling that names the call, as Hermes pairs a result with it (agent/message_sanitization.py tool_call_id_variants): its call_id, id and response_item_id, trimmed, and each part of one of the form "a|b".
func (*ToolCall) ArgumentsText ¶
ArgumentsText is the call's arguments as the string a function call carries: a JSON string's text, any other JSON value compacted, "{}" for none.
func (ToolCall) MarshalJSON ¶
MarshalJSON writes the call back as it was read.
func (*ToolCall) PairingID ¶
PairingID is the call's ID as Hermes pairs its result: coalesce_tool_call_id, call_id before id, and of a bridge ID "<call_id>|<item id>" the part before the bar.
func (*ToolCall) UnmarshalJSON ¶
UnmarshalJSON decodes the call, keeping undeclared members and members of another JSON type.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package convert converts Hermes Agent's sessions into the Agent Session Format: every session of a state.db, each with the continuations its compressions started and the sub-agents it ran.
|
Package convert converts Hermes Agent's sessions into the Agent Session Format: every session of a state.db, each with the continuations its compressions started and the sub-agents it ran. |
|
Package sqlite opens Hermes Agent's database, state.db, and reads its rows as the hermes package's types: sessions, messages, system_prompts, session_model_usage and async_delegations.
|
Package sqlite opens Hermes Agent's database, state.db, and reads its rows as the hermes package's types: sessions, messages, system_prompts, session_model_usage and async_delegations. |