docs(comments): 注释中文化 · internal/runtime/history(15 文件,纯替换)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 只翻注释/文档字符串:剥离注释后代码行逐字节不变(机械校验只剩 4 条行尾注释的翻译,代码前缀全等)
- 交叉引用(design/16 §4.6、D4/B3、0010 迁移文件名)逐字保留
- 保留未译技术词:DDL/rowid/LIKE/LEFT JOIN/DTO/rune/WS/actor 及全部标识符与表名
- 顺带副作用:store.go、session_persona_test.go 由注释文字改变而变得 gofmt 干净(未运行 gofmt -w)
This commit is contained in:
AskaEth committed 2026-10-04 12:28:48 +08:00
1 parent b0fbb8bc0d
commit 09fba77f87
15 files changed
+430 -516

No files matched your search

+21 -26
View File
@@ -8,20 +8,18 @@ import (
"strings"
)
// This file owns the single-message operations behind the Android collaboration batch
// ③a (D2 search, D3 edit/delete) plus the id-scoped read the D delete broadcast needs.
// All are strictly session-scoped or id-scoped: a message is only ever reached through
// the session it belongs to (Search) or its own opaque id (GetMessage/UpdateMessage/
// DeleteMessage), so an isolated group/stranger session can never surface in another
// session's results (project red line).
// 本文件负责 Android 协同批次 ③a 背后的单条消息操作(D2 搜索、D3 编辑/删除),
// 以及 D 删除广播所需的按 id 读取。它们都严格限定在会话作用域或 id 作用域:
// 消息只能经由它所属的会话(Search)或它自己不透明的 id(GetMessage/
// UpdateMessage/DeleteMessage)到达,因此隔离的群聊/陌生人会话绝不浮现在
// 另一个会话的结果中(项目红线)。
// Search returns up to limit messages for sessionID whose content contains query,
// newest first. The match is a case-insensitive ASCII LIKE (SQLite's default for
// LIKE) with the query's %/_/\ escaped so they match literally; before is the same
// millisecond cursor as List (strictly older than before) and limit is clamped to
// [1, maxPageLimit]. rowid breaks created_at ties so same-millisecond messages keep a
// stable order. An empty query returns an empty (non-nil) slice — the caller uses
// List for plain paging instead. Search never crosses the session boundary.
// Search 按最新优先返回 sessionID 中内容包含 query 的至多 limit 条消息。匹配
// 是 ASCII 大小写不敏感的 LIKE(SQLite 对 LIKE 的默认行为),并把 query 中的
// %/_/\ 转义使它们按字面匹配;before 与 List 是同一个毫秒游标(严格早于
// before),limit 钳制到 [1, maxPageLimit]。rowid 打破 created_at 的并列,使
// 同一毫秒的消息保持稳定顺序。空 query 返回空(非 nil)切片 —— 调用方改用
// List 做普通翻页。Search 绝不跨越会话边界。
func (s *Store) Search(ctx context.Context, sessionID, query string, before int64, limit int) ([]Message, error) {
limit = clampLimit(limit)
if query == "" {
@@ -57,10 +55,9 @@ func (s *Store) Search(ctx context.Context, sessionID, query string, before int6
return msgs, nil
}
// UpdateMessage replaces the content of the message with id and returns the updated
// message (like AppendFull, so the caller can return/broadcast it without a second
// read). Only content changes; role, platform, timestamps and the rest stay as stored.
// An unknown id returns ErrMessageNotFound.
// UpdateMessage 替换 id 所指消息的内容并返回更新后的消息(与 AppendFull
// 一样,使调用方能无需二次读取就返回/广播它)。只有 content 变化;role、
// platform、时间戳及其余字段保持已存值。未知 id 返回 ErrMessageNotFound。
func (s *Store) UpdateMessage(ctx context.Context, id, content string) (Message, error) {
res, err := s.db.ExecContext(ctx, `UPDATE chat_messages SET content = ? WHERE id = ?`, content, id)
if err != nil {
@@ -76,7 +73,7 @@ func (s *Store) UpdateMessage(ctx context.Context, id, content string) (Message,
return s.messageByID(ctx, id)
}
// DeleteMessage removes a single message. An unknown id returns ErrMessageNotFound.
// DeleteMessage 删除单条消息。未知 id 返回 ErrMessageNotFound。
func (s *Store) DeleteMessage(ctx context.Context, id string) error {
res, err := s.db.ExecContext(ctx, `DELETE FROM chat_messages WHERE id = ?`, id)
if err != nil {
@@ -92,16 +89,14 @@ func (s *Store) DeleteMessage(ctx context.Context, id string) error {
return nil
}
// GetMessage reads the message with id, returning ErrMessageNotFound when no such
// row exists. It is the id-scoped read the transport uses before removing a
// message: DeleteMessage leaves nothing to ask afterwards, yet the broadcast that
// tells other clients to drop the row is session-scoped.
// GetMessage 读取 id 所指消息,没有该行时返回 ErrMessageNotFound。它是传输层
// 在移除消息之前使用的按 id 读取:DeleteMessage 之后已无从再问,而那条告知
// 其他客户端丢弃该行的广播是按会话划分的。
func (s *Store) GetMessage(ctx context.Context, id string) (Message, error) {
return s.messageByID(ctx, id)
}
// messageByID reads one message by id, returning ErrMessageNotFound when the row is
// absent.
// messageByID 按 id 读取一条消息,行不存在时返回 ErrMessageNotFound。
func (s *Store) messageByID(ctx context.Context, id string) (Message, error) {
row := s.db.QueryRowContext(ctx, `SELECT id, session_id, role, content, mode, mood, image, thinking, platform, device_id, sender_name, adapter_id, persona_id, created_at
FROM chat_messages WHERE id = ?`, id)
@@ -115,8 +110,8 @@ func (s *Store) messageByID(ctx context.Context, id string) (Message, error) {
return m, nil
}
// escapeLike escapes the LIKE wildcards in a user query so %, _ and \ match literally
// (the caller pairs it with ESCAPE '\'). It is applied before the %...% wrapping.
// escapeLike 转义用户查询中的 LIKE 通配符,使 %、_ 与 \ 按字面匹配(调用方
// 配合 ESCAPE '\' 使用)。它在 %...% 包裹之前应用。
func escapeLike(query string) string {
return strings.NewReplacer(`\`, `\\`, `%`, `\%`, `_`, `\_`).Replace(query)
}