docs(gateway): gateway 剩余文件注释改中文(逐行 1:1,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批: 已推库 16 个文件 + 本批剩余文件)。 校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0); 全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
This commit is contained in:
1 parent
91e8d7a029
commit
074ffc4ebf
73 files changed
+2529
-2529
No files matched your search
@@ -14,10 +14,10 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||||
)
|
||||
|
||||
// tokenTTL is how long an issued JWT remains valid.
|
||||
// tokenTTL 是已签发 JWT 的有效时长。
|
||||
const tokenTTL = 24 * time.Hour
|
||||
|
||||
// PersonaSummary is the wire shape of a persona in REST/admin list responses.
|
||||
// PersonaSummary 是 REST/管理列表响应中一个人格的线上结构。
|
||||
type PersonaSummary struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -26,53 +26,53 @@ type PersonaSummary struct {
|
||||
Mode string `json:"mode"`
|
||||
MemoryNS string `json:"memoryNamespace"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
// ChatBackground holds per-orientation wallpaper; a role's own, never another's.
|
||||
// ChatBackground 持有分方向的壁纸;是本角色自己的,绝不是别人的。
|
||||
ChatBackground ChatBackgroundSummary `json:"chatBackground,omitempty"`
|
||||
// Mood is the role's current emotion state (design/01 §2: emotion follows the
|
||||
// role, never a session). "" means the role has no tracked emotion — an honest
|
||||
// empty, never a fabricated default. Clients seed their mood badge from it so a
|
||||
// refresh no longer flashes an empty mood.
|
||||
// Mood 是该角色的当前情绪状态(design/01 §2:情绪跟随角色,
|
||||
// 绝不是会话)。"" 意味着该角色没有受跟踪的情绪 —— 诚实的
|
||||
// 空值,绝不是编造的默认。客户端从它给 mood 角标播种,因此
|
||||
// 刷新不再闪出空 mood。
|
||||
Mood string `json:"mood"`
|
||||
// Thinking carries the persona's optional reasoning/presentation block
|
||||
// (design/01 §2.1). It is nil — and so absent from the JSON — when the persona
|
||||
// configures none, mirroring the write side's "an omitted block keeps the
|
||||
// stored one". Admin list only: these are model-call knobs, not user-UI state
|
||||
// (the user list takes Mood and leaves the knobs to the panel).
|
||||
// Thinking 携带人格可选的推理/呈现块
|
||||
// (design/01 §2.1)。人格未配置时它是 nil —— 因而从 JSON 中缺席 ——
|
||||
// 与写侧「省略的块保留
|
||||
// 已存块」。仅管理列表:这些是模型调用开关,不是用户 UI 状态
|
||||
// (用户列表取 Mood,把开关留给面板)。
|
||||
Thinking *PersonaThinkingSummary `json:"thinking,omitempty"`
|
||||
}
|
||||
|
||||
// PersonaThinkingSummary mirrors a persona's `thinking` block on the wire
|
||||
// (design/01 §2.1; provider mapping in design/04 §3.2).
|
||||
// PersonaThinkingSummary 在线上镜像人格的 `thinking` 块
|
||||
// (design/01 §2.1;provider 映射见 design/04 §3.2)。
|
||||
type PersonaThinkingSummary struct {
|
||||
// BudgetTokens is the reasoning budget (Anthropic thinking.budget_tokens).
|
||||
// BudgetTokens 是推理预算(Anthropic thinking.budget_tokens)。
|
||||
BudgetTokens int `json:"budgetTokens"`
|
||||
// Effort is the provider-specific reasoning strength (reasoning_effort). The
|
||||
// model layer validates it against the active provider's whitelist and WARNs
|
||||
// when it is dropped — this side just reports what is stored.
|
||||
// Effort 是 provider 特有的推理强度(reasoning_effort)。
|
||||
// 模型层会按活动 provider 的白名单校验它,并在它被丢弃时
|
||||
// 打 WARN —— 这一侧只报告已存的内容。
|
||||
Effort string `json:"effort"`
|
||||
// ShowToUser is TRI-STATE and stays that way on the wire: null = not
|
||||
// configured (thinking frames keep flowing — the pre-existing behavior),
|
||||
// true/false = an explicit choice. A plain bool would flatten "unset" onto
|
||||
// "off" and lose the distinction the write side keeps with *bool.
|
||||
// ShowToUser 是三态的,且在线上保持如此:null = 未
|
||||
// 配置(thinking 帧继续流出 —— 既有行为),
|
||||
// true/false = 显式选择。普通 bool 会把「未设置」压平到
|
||||
// 「关闭」上,丢掉写侧用 *bool 保持的区分。
|
||||
ShowToUser *bool `json:"showToUser"`
|
||||
// Mode is the explicit hard switch: default | on | off ("" = default).
|
||||
// Mode 是显式的硬开关:default | on | off("" = default)。
|
||||
Mode string `json:"mode"`
|
||||
}
|
||||
|
||||
// ChatBackgroundSummary mirrors the persona chatBackground on the wire.
|
||||
// ChatBackgroundSummary 在线上镜像人格的 chatBackground。
|
||||
type ChatBackgroundSummary struct {
|
||||
Landscape string `json:"landscape,omitempty"`
|
||||
Portrait string `json:"portrait,omitempty"`
|
||||
}
|
||||
|
||||
// MemorySummary is the wire shape of a memory entry in the admin list response.
|
||||
// MemorySummary 是管理列表响应中一条记忆条目的线上结构。
|
||||
type MemorySummary struct {
|
||||
ID string `json:"id"`
|
||||
Scope string `json:"scope"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// SessionSummary is the wire shape of a channel session in list responses.
|
||||
// SessionSummary 是列表响应中一个渠道会话的线上结构。
|
||||
type SessionSummary struct {
|
||||
Platform string `json:"platform"`
|
||||
ChannelID string `json:"channelId"`
|
||||
@@ -83,15 +83,15 @@ type SessionSummary struct {
|
||||
MemWrite bool `json:"memWritable"`
|
||||
}
|
||||
|
||||
// loginRequest is the POST /api/v1/auth/login body.
|
||||
// loginRequest 是 POST /api/v1/auth/login 的请求体。
|
||||
type loginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// loginResponse is the login success payload. RefreshToken is the opaque
|
||||
// long-lived credential (POST /auth/refresh) added by B2; it is omitted when no
|
||||
// refresh store is wired so the pre-B2 contract is unchanged.
|
||||
// loginResponse 是登录成功的载荷。RefreshToken 是 B2 新增的非透明
|
||||
// 长期凭据(POST /auth/refresh);未接线 refresh 存储时被省略,
|
||||
// 因此 B2 之前的契约不变。
|
||||
type loginResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
@@ -99,15 +99,15 @@ type loginResponse struct {
|
||||
RefreshToken string `json:"refreshToken,omitempty"`
|
||||
}
|
||||
|
||||
// chatRequest is the POST /api/v1/chat body. When Stream is true the gateway
|
||||
// triggers streaming over the WebSocket channel and returns immediately. Image is
|
||||
// an optional base64 data: URI or http(s) URL attached for the vision path; the
|
||||
// loop routes it through the vision/OCR tool or the main model (design/06 §0).
|
||||
// DeviceID is the client-produced identifier of the sending browser/device
|
||||
// (design/16 §4.5), e.g. "web:chrome:a1b2c3"; it is optional and persisted as-is.
|
||||
// Mode is the behavior mode the client sent the turn in (design/01 §3, design/16
|
||||
// §5.1); it is optional and persisted per message for bubble rendering, falling
|
||||
// back to "chat" when omitted.
|
||||
// chatRequest 是 POST /api/v1/chat 的请求体。Stream 为 true 时网关
|
||||
// 经 WebSocket 通道触发流式并立即返回。Image 是
|
||||
// 为视觉路径附带的可选 base64 data: URI 或 http(s) URL;
|
||||
// loop 把它经视觉/OCR 工具或主模型路由(design/06 §0)。
|
||||
// DeviceID 是客户端产出的发送浏览器/设备标识
|
||||
// (design/16 §4.5),例如 "web:chrome:a1b2c3";它可选且按原样持久化。
|
||||
// Mode 是客户端发送该回合时的行为模式(design/01 §3、design/16
|
||||
// §5.1);它可选,并按消息持久化以供气泡渲染,省略时
|
||||
// 回退到 "chat"。
|
||||
type chatRequest struct {
|
||||
SessionID string `json:"sessionId"`
|
||||
Text string `json:"text"`
|
||||
@@ -117,19 +117,19 @@ type chatRequest struct {
|
||||
Stream bool `json:"stream"`
|
||||
}
|
||||
|
||||
// chatResponse is the synchronous chat reply payload.
|
||||
// chatResponse 是同步聊天回复的载荷。
|
||||
type chatResponse struct {
|
||||
Reply string `json:"reply"`
|
||||
Steps int `json:"steps"`
|
||||
StopReason string `json:"stopReason"`
|
||||
}
|
||||
|
||||
// handleHealth reports liveness. It is unauthenticated because it is a probe.
|
||||
// handleHealth 报告存活。它不认证,因为它是探针。
|
||||
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"status": "ok"})
|
||||
}
|
||||
|
||||
// handleLogin exchanges the admin username/password for a signed JWT.
|
||||
// handleLogin 用管理用户名/密码换取已签名的 JWT。
|
||||
func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
var req loginRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -152,9 +152,9 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
ExpiresAt: time.Now().Add(tokenTTL).Unix(),
|
||||
Role: string(auth.RoleOwner),
|
||||
}
|
||||
// Issue the long-lived refresh credential alongside the access token. A store
|
||||
// failure fails the login rather than silently handing back a login without
|
||||
// the advertised refresh token; the plaintext is never logged.
|
||||
// 在签发访问令牌的同时签发长期 refresh 凭据。存储失败会让
|
||||
// 登录失败,而不是静默交回一个没有所声称 refresh token 的
|
||||
// 登录;明文绝不记日志。
|
||||
if s.refresh != nil {
|
||||
refreshToken, _, rerr := s.refresh.Issue(r.Context(), req.Username, auth.RoleOwner, s.refreshTTL())
|
||||
if rerr != nil {
|
||||
@@ -167,7 +167,7 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// handleChat runs one synchronous agent turn (or triggers streaming).
|
||||
// handleChat 运行一次同步 agent 回合(或触发流式)。
|
||||
func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
var req chatRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -190,9 +190,9 @@ func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
if req.SessionID == "" {
|
||||
req.SessionID = "web"
|
||||
}
|
||||
// The Web main session is the owner's private conversation (JWT = owner), so
|
||||
// it binds the full-access env: memory read+write, unchanged behavior. The role
|
||||
// comes from the session's binding (design/22 §4.5).
|
||||
// Web 主会话是主人的私密对话(JWT = owner),因此它绑定
|
||||
// 全访问 env:记忆读+写,行为不变。角色
|
||||
// 来自会话的绑定(design/22 §4.5)。
|
||||
msgs := userChatMessages(req.Text, req.Image)
|
||||
env := s.envResolver.owner(r.Context(), req.SessionID)
|
||||
if s.hub.orchestrator != nil {
|
||||
@@ -205,8 +205,8 @@ func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
return
|
||||
}
|
||||
// A busy session returns a non-blocking ack (design/15 §2.1) instead of
|
||||
// blocking the request on a turn that may run for a while.
|
||||
// 忙碌会话返回非阻塞 ack(design/15 §2.1),而不是
|
||||
// 让请求阻塞在一个可能跑一阵子的回合上。
|
||||
if sr.Pending {
|
||||
writeJSON(w, http.StatusAccepted, map[string]any{"queued": true, "queueDepth": sr.QueueDepth})
|
||||
return
|
||||
@@ -219,8 +219,8 @@ func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, chatResponse{Reply: res.Text, Steps: res.Steps, StopReason: res.StopReason})
|
||||
return
|
||||
}
|
||||
// Legacy synchronous path when no orchestrator is wired (a hub built without
|
||||
// one keeps the exact pre-design/15 reply contract).
|
||||
// 未接线编排器时的旧同步路径(未接线的 hub
|
||||
// 保持完全与 design/15 之前相同的回复契约)。
|
||||
res, err := s.runner.Run(loop.WithSessionEnv(r.Context(), env), req.SessionID, msgs)
|
||||
if err != nil {
|
||||
s.log.Error("chat run", "err", err, "session", req.SessionID)
|
||||
@@ -230,10 +230,10 @@ func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, chatResponse{Reply: res.Text, Steps: res.Steps, StopReason: res.StopReason})
|
||||
}
|
||||
|
||||
// handleListSessions returns the persistent chat-history sessions (main + sub) when a
|
||||
// history store is wired, otherwise falls back to the channel-session view. The fallback
|
||||
// keeps the pre-design/16 contract: a server built without history still lists the known
|
||||
// channel sessions (or [] when no store is wired).
|
||||
// handleListSessions 在接线了 history 存储时返回持久化聊天历史会话
|
||||
// (main + sub),否则回退到渠道会话视图。回退保持
|
||||
// design/16 之前的契约:未接 history 的服务器仍列出已知的
|
||||
// 渠道会话(未接线任何存储时为 [])。
|
||||
func (s *Server) handleListSessions(w http.ResponseWriter, r *http.Request) {
|
||||
if s.history != nil {
|
||||
s.handleHistorySessions(w, r)
|
||||
@@ -254,16 +254,16 @@ func (s *Server) handleListSessions(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, out)
|
||||
}
|
||||
|
||||
// handleListPersonas returns the personas (or [] when no store is wired). It is
|
||||
// the user-side shape: the role-level mood rides along, the admin-only thinking
|
||||
// knobs do not.
|
||||
// handleListPersonas 返回人格(未接线存储时为 [])。它是
|
||||
// 用户侧形状:角色级 mood 一并带上,仅管理的 thinking
|
||||
// 开关则不然。
|
||||
func (s *Server) handleListPersonas(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, s.collectPersonas(false))
|
||||
}
|
||||
|
||||
// collectPersonas returns a non-nil persona slice from the configured store.
|
||||
// withThinking adds the admin-only `thinking` block; mood is always reported
|
||||
// because the user UI renders the badge.
|
||||
// collectPersonas 从已配置的存储返回非 nil 的人格切片。
|
||||
// withThinking 加上仅管理的 `thinking` 块;mood 总是报告,
|
||||
// 因为用户 UI 要渲染角标。
|
||||
func (s *Server) collectPersonas(withThinking bool) []PersonaSummary {
|
||||
out := make([]PersonaSummary, 0)
|
||||
if s.personas == nil {
|
||||
@@ -282,9 +282,9 @@ func (s *Server) collectPersonas(withThinking bool) []PersonaSummary {
|
||||
Mode: firstMode(c.Modes),
|
||||
Mood: s.moodOf(id),
|
||||
}
|
||||
// Read this persona's own visual assets (avatar / chat background). Each
|
||||
// role carries its own; a missing persona or unset visual yields empty,
|
||||
// never another role's — the frontend falls back to a neutral default.
|
||||
// 读取该人格自己的视觉资产(头像 / 聊天背景)。每个
|
||||
// 角色携带自己的;人格缺失或视觉未设置得到空,
|
||||
// 绝不是别的角色的 —— 前端回退到中性默认。
|
||||
if p, ok := s.personas.Persona(id); ok && p != nil {
|
||||
if p.Visual.Avatar != "" {
|
||||
sum.Avatar = p.Visual.Avatar
|
||||
@@ -302,10 +302,10 @@ func (s *Server) collectPersonas(withThinking bool) []PersonaSummary {
|
||||
return out
|
||||
}
|
||||
|
||||
// moodOf reports the role's current emotion state. Emotion is owned by the
|
||||
// persona store (design/01 §2), read through the optional PersonaMoodStore
|
||||
// capability; a store that does not track emotion, or a role with no machine,
|
||||
// reports "" instead of a made-up mood.
|
||||
// moodOf 报告该角色的当前情绪状态。情绪归
|
||||
// 人格存储所有(design/01 §2),经可选的 PersonaMoodStore
|
||||
// 能力读取;不跟踪情绪的存储,或没有情绪机的角色,
|
||||
// 报告 "" 而不是编造一个 mood。
|
||||
func (s *Server) moodOf(id string) string {
|
||||
store, ok := s.personas.(PersonaMoodStore)
|
||||
if !ok {
|
||||
@@ -322,11 +322,11 @@ func (s *Server) moodOf(id string) string {
|
||||
return string(machine.Current())
|
||||
}
|
||||
|
||||
// thinkingSummaryOf maps a stored thinking block onto the wire. It returns nil
|
||||
// when the persona configures none — the key is then absent, so a client can tell
|
||||
// "not configured" from an explicit value (the read-side mirror of the write-side
|
||||
// rule that an omitted block keeps the stored one). include is false for the
|
||||
// user-side list, which does not carry these knobs.
|
||||
// thinkingSummaryOf 把已存 thinking 块映射到线上。人格未配置时
|
||||
// 它返回 nil —— 该键因而缺席,使客户端能把「未配置」
|
||||
// 与显式取值区分开(写侧「省略的块保留已存块」规则的
|
||||
// 读侧镜像)。用户侧列表的 include 为 false,
|
||||
// 因为用户侧不携带这些开关。
|
||||
func thinkingSummaryOf(t loader.ThinkingParams, include bool) *PersonaThinkingSummary {
|
||||
if !include || !thinkingConfigured(t) {
|
||||
return nil
|
||||
@@ -339,13 +339,13 @@ func thinkingSummaryOf(t loader.ThinkingParams, include bool) *PersonaThinkingSu
|
||||
}
|
||||
}
|
||||
|
||||
// thinkingConfigured reports whether any thinking knob is set. An empty block
|
||||
// must read as "not configured" rather than as an all-zero object.
|
||||
// thinkingConfigured 报告是否有任何 thinking 开关被设置。空块
|
||||
// 必须读作「未配置」,而不是全零对象。
|
||||
func thinkingConfigured(t loader.ThinkingParams) bool {
|
||||
return t.BudgetTokens != 0 || t.Effort != "" || t.ShowToUser != nil || t.Mode != ""
|
||||
}
|
||||
|
||||
// firstMode returns the first declared behavior mode, or "" when none are set.
|
||||
// firstMode 返回首个声明的行为模式,未设置时返回 ""。
|
||||
func firstMode(modes []string) string {
|
||||
if len(modes) == 0 {
|
||||
return ""
|
||||
@@ -353,9 +353,9 @@ func firstMode(modes []string) string {
|
||||
return modes[0]
|
||||
}
|
||||
|
||||
// userChatMessages builds the user turn for a chat / stream request. When image is
|
||||
// present the turn becomes an image message (with optional text); otherwise a
|
||||
// plain text message. An empty text with an image yields an image-only turn.
|
||||
// userChatMessages 为 chat / stream 请求构建用户回合。image
|
||||
// 存在时该回合成为图片消息(可带文本);否则是
|
||||
// 纯文本消息。空文本加图片得到仅图片的回合。
|
||||
func userChatMessages(text, image string) []model.Message {
|
||||
if strings.TrimSpace(image) != "" {
|
||||
return []model.Message{model.ImageMessage(model.RoleUser, text, image)}
|
||||
@@ -363,7 +363,7 @@ func userChatMessages(text, image string) []model.Message {
|
||||
return []model.Message{model.TextMessage(model.RoleUser, text)}
|
||||
}
|
||||
|
||||
// summaryOfSession maps a session.Session to its wire shape.
|
||||
// summaryOfSession 把 session.Session 映射为其线上结构。
|
||||
func summaryOfSession(sess session.Session) SessionSummary {
|
||||
return SessionSummary{
|
||||
Platform: sess.Platform,
|
||||
@@ -376,15 +376,15 @@ func summaryOfSession(sess session.Session) SessionSummary {
|
||||
}
|
||||
}
|
||||
|
||||
// writeJSON encodes v as the {data: v} envelope with the given status.
|
||||
// writeJSON 把 v 编码为 {data: v} 信封并带上给定状态。
|
||||
func writeJSON(w http.ResponseWriter, status int, v any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"data": v})
|
||||
}
|
||||
|
||||
// writeError encodes err as the {error:{code,message}} envelope with the status
|
||||
// resolved by apperr.HTTPStatus.
|
||||
// writeError 把 err 编码为 {error:{code,message}} 信封,状态由
|
||||
// apperr.HTTPStatus 解析。
|
||||
func writeError(w http.ResponseWriter, err error) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(apperr.HTTPStatus(err))
|
||||
|
||||
Reference in new issue
Block a user