Read-only query interface for historical session data.
Provides cross-session search, aggregation, and export capabilities beyond the single-session cursor reads in SessionStore.
Callbacks
search_sessions/2— Search sessions with filters and cursor paginationget_session_stats/2— Aggregate statistics for a sessionsearch_runs/2— Search runs across sessionsget_usage_summary/2— Token usage summary by providerget_cost_summary/2— Cost summary by provider/modelsearch_events/2— Search events across sessionscount_events/2— Count events matching filtersexport_session/3— Export complete session data
Usage
{:ok, %{sessions: sessions, cursor: cursor}} =
QueryAPI.search_sessions({EctoQueryAPI, MyApp.Repo}, agent_id: "agent-1", limit: 20)
{:ok, stats} = QueryAPI.get_session_stats({EctoQueryAPI, MyApp.Repo}, "ses_abc123")
Summary
Callbacks
Count events matching filters without loading them.
Export a session's complete data (session + runs + events) as a map.
Get cost summary across runs.
Get aggregate statistics for a session.
Get token usage summary across runs.
Search events across sessions with rich filters.
Search runs across sessions.
Search sessions with rich filters.
Types
Callbacks
@callback count_events( context(), keyword() ) :: {:ok, non_neg_integer()} | {:error, AgentSessionManager.Core.Error.t()}
Count events matching filters without loading them.
Same filter options as search_events/2.
@callback export_session(context(), session_id :: String.t(), keyword()) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
Export a session's complete data (session + runs + events) as a map.
Options
:include_artifacts— include artifact metadata (default: false)
@callback get_cost_summary( context(), keyword() ) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
Get cost summary across runs.
Options
:session_id— scope to session:agent_id— scope to agent:provider— filter by provider:since— DateTime lower bound:until— DateTime upper bound:pricing_table— override default pricing (optional)
Returns a map with:
total_cost_usd— floatrun_count— integerby_provider— per-provider cost breakdownby_model— per-model cost breakdownunmapped_runs— count of runs without cost
@callback get_session_stats(context(), session_id :: String.t()) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
Get aggregate statistics for a session.
Returns a map with:
event_count— total eventsrun_count— total runstoken_totals—%{input_tokens: n, output_tokens: n, total_tokens: n}providers_used— list of provider namesfirst_event_at— earliest event timestamplast_event_at— latest event timestampstatus_counts—%{completed: 3, failed: 1, ...}(run statuses)
@callback get_usage_summary( context(), keyword() ) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
Get token usage summary across runs.
Options
:session_id— scope to session:provider— filter by provider:since— DateTime lower bound:until— DateTime upper bound
Returns a map with:
total_input_tokens— integertotal_output_tokens— integertotal_tokens— integerrun_count— integerby_provider—%{"claude" => %{...}, "codex" => %{...}}
@callback search_events( context(), keyword() ) :: {:ok, %{events: [AgentSessionManager.Core.Event.t()], cursor: cursor()}} | {:error, AgentSessionManager.Core.Error.t()}
Search events across sessions with rich filters.
Options
:session_ids— list of session IDs:run_ids— filter by specific runs:types— filter by event types (atom or list):providers— filter by provider:since— events after this DateTime:until— events before this DateTime:correlation_id— filter by correlation ID:order_by—:sequence_asc(default) |:timestamp_asc|:timestamp_desc:limit— max results (default: 100):cursor— opaque cursor from previous page
@callback search_runs( context(), keyword() ) :: {:ok, %{runs: [AgentSessionManager.Core.Run.t()], cursor: cursor()}} | {:error, AgentSessionManager.Core.Error.t()}
Search runs across sessions.
Options
:session_id— scope to single session:provider— filter by provider:status— filter by status:started_after— runs started after this DateTime:started_before— runs started before this DateTime:min_tokens— minimum total_tokens:order_by—:started_at_desc(default) |:started_at_asc|:token_usage_desc:limit— max results (default: 50):cursor— opaque cursor from previous page
@callback search_sessions( context(), keyword() ) :: {:ok, %{ sessions: [AgentSessionManager.Core.Session.t()], cursor: cursor(), total_count: non_neg_integer() }} | {:error, AgentSessionManager.Core.Error.t()}
Search sessions with rich filters.
Options
:agent_id— filter by agent:status— filter by status (atom or list):provider— filter by provider that executed runs in this session:tags— filter by tags (all must match):created_after— sessions created after this DateTime:created_before— sessions created before this DateTime:include_deleted— include soft-deleted sessions (default: false):order_by—:created_at_asc|:created_at_desc|:updated_at_desc(default):limit— max results (default: 50):cursor— opaque cursor from previous page
Functions
@spec count_events( query_ref(), keyword() ) :: {:ok, non_neg_integer()} | {:error, AgentSessionManager.Core.Error.t()}
@spec export_session(query_ref(), String.t(), keyword()) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
@spec get_cost_summary( query_ref(), keyword() ) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
@spec get_session_stats(query_ref(), String.t()) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
@spec get_usage_summary( query_ref(), keyword() ) :: {:ok, map()} | {:error, AgentSessionManager.Core.Error.t()}
@spec search_events( query_ref(), keyword() ) :: {:ok, %{events: [AgentSessionManager.Core.Event.t()], cursor: cursor()}} | {:error, AgentSessionManager.Core.Error.t()}
@spec search_runs( query_ref(), keyword() ) :: {:ok, %{runs: [AgentSessionManager.Core.Run.t()], cursor: cursor()}} | {:error, AgentSessionManager.Core.Error.t()}
@spec search_sessions( query_ref(), keyword() ) :: {:ok, %{ sessions: [AgentSessionManager.Core.Session.t()], cursor: cursor(), total_count: non_neg_integer() }} | {:error, AgentSessionManager.Core.Error.t()}