session-logs

session-logs

热门

使用 jq 搜索和分析你自己的会话日志(旧/父对话)。

38万Star
8.1万Fork
更新于 2026/7/24
SKILL.md
readonly只读
name
session-logs
description

使用 jq 搜索和分析你自己的会话日志(旧/父对话)。

session-logs

搜索存储在会话 JSONL 文件中的完整对话历史。当用户引用旧/父对话或询问之前说过什么时使用此技能。

触发条件

当用户询问之前的聊天、父对话或不在记忆文件中的历史上下文时,使用此技能。

位置

会话日志位于活动状态目录下:
$OPENCLAW_STATE_DIR/agents/<agentId>/sessions/(默认:~/.openclaw/agents/<agentId>/sessions/)。
使用系统提示 Runtime 行中的 agent=<id> 值。

  • sessions.json - 将会话键映射到会话 ID 的索引
  • <session-id>.jsonl - 每个会话的完整对话记录
  • <session-id>.jsonl.reset.<timestamp>Z - 通过 /new/reset 归档的记录
  • <session-id>.jsonl.deleted.<timestamp>Z - 会话删除时归档的记录

搜索历史时,也要包含归档的变体(.reset.*.deleted.*)——它们仍然包含真实的对话内容。下面的普通通配符示例只捕获活动的 *.jsonl 文件;当需要完整回忆时,请使用“包含归档记录”代码片段。

结构

每个 .jsonl 文件包含带有以下字段的消息:

  • type:"session"(元数据)或 "message"
  • timestamp:ISO 时间戳
  • message.role:"user"、"assistant" 或 "toolResult"
  • message.content[]:文本、思考或工具调用(过滤 type=="text" 获取人类可读内容)
  • message.usage.cost.total:每次响应的成本

常见查询

包含归档记录(.reset.*.deleted.*

# Bash 辅助函数,输出每个可搜索的记录路径——包括活动和归档的。
# 本地保存并恢复 `nullglob`,以免干扰调用者的 shell 选项。
AGENT_ID="<agentId>"
SESSION_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/agents/$AGENT_ID/sessions"
list_session_transcripts() {
  local _nullglob_state
  _nullglob_state=$(shopt -p nullglob 2>/dev/null)
  shopt -s nullglob
  for f in "$SESSION_DIR"/*.jsonl \
           "$SESSION_DIR"/*.jsonl.reset.*Z \
           "$SESSION_DIR"/*.jsonl.deleted.*Z; do
    [ -f "$f" ] && printf '%s\n' "$f"
  done
  eval "$_nullglob_state"
}

如果需要包含归档会话,请在下面显示普通 *.jsonl 通配符的地方使用 list_session_transcripts(或等效的 find 调用):

find "$SESSION_DIR" -maxdepth 1 -type f \
  \( -name '*.jsonl' -o -name '*.jsonl.reset.*Z' -o -name '*.jsonl.deleted.*Z' \) -print

按日期和大小列出所有会话

AGENT_ID="<agentId>"
SESSION_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/agents/$AGENT_ID/sessions"
for f in "$SESSION_DIR"/*.jsonl; do
  date=$(head -1 "$f" | jq -r '.timestamp' | cut -dT -f1)
  size=$(ls -lh "$f" | awk '{print $5}')
  echo "$date $size $(basename $f)"
done | sort -r

提示: 当你也想在列表中包含归档的 .reset / .deleted 文件时,将 for f in ... 行替换为对 list_session_transcriptswhile-read 循环(见上面的代码片段)。while-read 模式对于包含空格或其他 IFS 字符的路径是安全的:

while IFS= read -r f; do
  date=$(head -1 "$f" | jq -r '.timestamp' | cut -dT -f1)
  size=$(ls -lh "$f" | awk '{print $5}')
  echo "$date $size $(basename "$f")"
done < <(list_session_transcripts) | sort -r

查找特定日期的会话

AGENT_ID="<agentId>"
SESSION_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/agents/$AGENT_ID/sessions"
for f in "$SESSION_DIR"/*.jsonl; do
  head -1 "$f" | jq -r '.timestamp' | grep -q "2026-01-06" && echo "$f"
done

从会话中提取用户消息

jq -r 'select(.message.role == "user") | .message.content[]? | select(.type == "text") | .text' <session>.jsonl

在助手回复中搜索关键词

jq -r 'select(.message.role == "assistant") | .message.content[]? | select(.type == "text") | .text' <session>.jsonl | rg -i "keyword"

获取会话的总成本

jq -s '[.[] | .message.usage.cost.total // 0] | add' <session>.jsonl

每日成本汇总

AGENT_ID="<agentId>"
SESSION_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/agents/$AGENT_ID/sessions"
for f in "$SESSION_DIR"/*.jsonl; do
  date=$(head -1 "$f" | jq -r '.timestamp' | cut -dT -f1)
  cost=$(jq -s '[.[] | .message.usage.cost.total // 0] | add' "$f")
  echo "$date $cost"
done | awk '{a[$1]+=$2} END {for(d in a) print d, "$"a[d]}' | sort -r

统计会话中的消息数和 token 数

jq -s '{
  messages: length,
  user: [.[] | select(.message.role == "user")] | length,
  assistant: [.[] | select(.message.role == "assistant")] | length,
  first: .[0].timestamp,
  last: .[-1].timestamp
}' <session>.jsonl

工具使用情况分解

jq -r '.message.content[]? | select(.type == "toolCall") | .name' <session>.jsonl | sort | uniq -c | sort -rn

在所有会话中搜索短语

AGENT_ID="<agentId>"
SESSION_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/agents/$AGENT_ID/sessions"

# 仅活动会话:
rg -l "phrase" "$SESSION_DIR"/*.jsonl

# 活动 + 归档(`.reset.*`、`.deleted.*`)——在检查可能已被压缩/重置/删除的内容时使用:
rg -l "phrase" "$SESSION_DIR"/*.jsonl \
               "$SESSION_DIR"/*.jsonl.reset.*Z \
               "$SESSION_DIR"/*.jsonl.deleted.*Z 2>/dev/null

提示

  • 会话是仅追加的 JSONL(每行一个 JSON 对象)
  • 大型会话可能有几 MB——使用 head/tail 进行采样
  • sessions.json 索引将聊天提供者(discord、whatsapp 等)映射到会话 ID
  • 重置/压缩的会话 带有 .jsonl.reset.<timestamp>Z 后缀——仍然包含完整记录并且可搜索。
  • 已删除的会话 带有 .jsonl.deleted.<timestamp>Z 后缀——同样可搜索。
  • 普通的 *.jsonl 通配符会 遗漏 这两种归档形式。当需要完整历史时,请显式包含它们(见上面的“包含归档记录”代码片段)。

快速纯文本提示(低噪音)

AGENT_ID="<agentId>"
SESSION_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/agents/$AGENT_ID/sessions"
jq -r 'select(.type=="message") | .message.content[]? | select(.type=="text") | .text' "$SESSION_DIR"/<id>.jsonl | rg 'keyword'