refactor: 全面改名为 HologramAgent + 提示词技术内容下沉到 skill/工具描述 + 修 21 处乱码

## ① 全面改名 HomeAgent → HologramAgent

仓库已改名,但代码与文档里仍有大量旧名。本次按"用户能看到的优先"全量替换:

- 用户可见:登录页标题/页脚、默认人格第一句、CLI 状态输出、启动日志、
  plugin_install 的工具描述、AI 图片插件的 User-Agent
- 文档与脚本:README、assets/docs、docs/zh、deploy/*.sh、.github/workflows
- 鸿蒙工程:cmd/ohos/HomeAgent → cmd/ohos/HologramAgent(git mv)
  目录内的 module/app 描述同步;**证书路径原样保留**
  (default_HomeAgent_xxx.cer/p7b/p12 是签名材料的实际文件名,改了会找不到证书)
- 插件元数据:plugin.json 的 author

★ 必须保持原样的两处(改了会坏):
  · legacySeededPromptSignature = "你是 HomeAgent 的看板娘「小宅」…"
    —— 那是识别历史播种人格卡的**原文锚点**,改了就识别不出旧数据
  · 公开 SDK 的 ProxyAuthHomeAgent = "homeagent"
    —— 那是 SDK 契约里的值,属独立仓库,本仓不改

## ② 修 21 处乱码(U+FFFD)

这些是历史编辑留下的编码破坏,全在注释里,例如:
  「赌注重下���遍」→「赌注重下一遍」
  「「不��滤」」  →「「不过滤」」
  「**待��退场**」→「**待退场**」

★ 保留 providers/chineseclip/tokenizer.go 里的 2 处:那是**故意**用
  U+FFFD 演示"非法 UTF-8 字节被归一成 U+FFFD",不是乱码。

## ③ 提示词技术内容下沉(用户:技术性内容应该收敛到 skill 与 -help 中)

实测系统提示词 2309 字,其中两段几乎全是**模型无法据以行动的实现细节**:

  【工具执行顺序】1272 字(ParallelSafe 声明、批内降级、batchRunnable 判据…)
  【三层记忆】   1069 字(L1/L2/L3 编号、消费式删除、向量空间、指纹…)

收敛后 **2309 → 1723 字(-25%)**,保留的全是"模型据此做什么不同的事":

  工具顺序:默认并行 / 不要依赖先后 / 同通道保序 / 写类工具可能串行
  三层记忆:时序里能看最近 / doc_query 把历史事件按原始时间戳插回时序 /
           关系用 memory_recall / 成文知识用 knowledge_search

判断口径写进判据:新加一段提示词前先问"模型会据此做什么不同的事",
答不上来就该进 skill 或工具描述。

## 判据

prompt_memory_test.go 新增 2 条:
- TestSystemPromptHasNoImplementationJargon
  黑名单:ParallelSafe / batchRunnable / 消费式 / DenseCosine / fingerprint /
  向量空间 / 批内降级 / 自激
- TestSystemPromptStaysCompact:上限 2000 字(当前 1723)

变异:把 "ParallelSafe 声明、批内降级" 加回工具顺序段 ⇒ 第一条立刻红。

## 验证

- go build ./... / go vet ./... 干净
- go test ./... -count=1:58 包 0 失败
- make check-client-versions:客户端与内核版本一致
This commit is contained in:
JianFeeeee
2026-10-22 20:49:44 +08:00
parent 6bea130639
commit f256098c9f
204 changed files with 310 additions and 252 deletions

View File

@ -0,0 +1,216 @@
export interface ConnectionConfig {
id: string;
name: string;
url: string;
apiKey: string;
type: string; // 'webui' | 'cli'
}
export interface ToolCallInfo {
name: string;
args: string;
result?: string;
plugin?: string;
status?: string; // 'ok' | 'error' | 'denied' | 'running'
open?: boolean;
}
export interface ChatMessage {
id: number;
role: string; // 'user' | 'assistant'
content: string;
reasoningContent?: string;
reasoningOpen?: boolean;
isStreaming?: boolean;
isFinal?: boolean;
toolCalls?: ToolCallInfo[];
/** 消息来源通道:'webui' | 'channel' | 'webui/<device_id>' 等;用于区分设备/渠道消息 */
source?: string;
/**
* 服务端单调递增序号(后端 ChatMsg.seq)。
*
* 它是与后端增量查询(/chat/history?after=<seq>)对账的唯一定位符:
* 本地乐观消息没有 seq,服务端回显后靠 seq 认领并去重。
* 没有它就只能拿“正文内容”去重,一旦同一句话发两次就会误删。
*/
seq?: number;
/** 图片/文件附件(后端 ChatMsg.attachment) */
attachment?: ChatAttachment;
}
export interface HistoryMessage {
role: string;
content: string;
source?: string;
timestamp?: string;
attachment?: ChatAttachment;
}
export interface AgentStatus {
version?: string;
uptime_ms?: number;
agent?: string;
provider?: string;
memory_events?: number;
}
export interface DeviceInfo {
deviceId: string;
name: string;
kind: string;
online: boolean;
authorized: boolean;
caps: string[];
hostname?: string;
platform?: string;
}
export interface PluginInfo {
name: string;
nameZh?: string;
nameEn?: string;
version?: string;
description?: string;
author?: string;
deprecated?: boolean;
builtin: boolean;
loaded: boolean;
disabled: boolean;
tools?: string[];
}
/**
* One row in the merged plugin list:
* kernel.plugins ∪ installed(/plugins) ∪ disabled(/plugins/disabled),
* 与 WebGUI renderPlugins 的合并口径一致。
*/
export interface PluginRow {
name: string;
/** /kernel.plugins 里出现且 loaded=true 才算已加载 */
loaded: boolean;
/** 出现在 /plugins/disabled 列表里 */
disabled: boolean;
/** 已安装的外部插件(/plugins 返回) */
external: boolean;
version?: string;
description?: string;
tools?: string[];
}
/**
* GET /plugins/{name} 返回的插件清单明细。
* 字段与后端 pluginmgr 的 pluginInfo 一一对应;
* WebGUI 只把它 JSON.stringify 到 <pre> 里,这里改为结构化展示。
*/
export interface PluginDetail {
name: string;
version: string;
description: string;
author: string;
license: string;
homepage: string;
repository: string;
entry: string;
minVersion: string;
tags: string[];
deprecated: boolean;
files: string[];
}
export function emptyPluginDetail(): PluginDetail {
const d: PluginDetail = {
name: '',
version: '',
description: '',
author: '',
license: '',
homepage: '',
repository: '',
entry: '',
minVersion: '',
tags: [],
deprecated: false,
files: [],
};
return d;
}
/**
* 聊天消息附件。字段与后端 webui 的 Attachment 严格一致,只有四个:
* type / url / size / name —— 后端不提供 mime、尺寸、本地路径。
*/
export interface ChatAttachment {
/** 'image' | 'file' */
type: string;
/** /files/<name>、/uploads/<name> 或远程 http(s) 地址 */
url: string;
/** 字节数;远程 URL 为 0 */
size: number;
/** 展示用文件名 */
name: string;
}
export interface AppSettings {
lang: string; // 'zh' | 'en'
theme: string; // 'dark' | 'light' | 'system'
currentConnId: string;
/** 自定义背景图路径(应用沙箱内文件路径),空串表示未设置 */
bgImage: string;
/** 背景图不透明度 0..1 */
bgOpacity: number;
}
export function emptySettings(): AppSettings {
const s: AppSettings = {
lang: 'zh',
theme: 'dark',
currentConnId: '',
bgImage: '',
bgOpacity: 0.25,
};
return s;
}
/**
* 规范化用户填写的后端地址。
*
* 用户习惯直接敲域名(homeagent.example.xyz)或粘贴带路径的地址。
* 三件事必须在存库前做掉,否则请求会以各种方式失败:
*
* 1) 补协议,且默认 https。
* 很多反代把 http 整站 302 到别的主机(例如门户站 www.xxx),
* 重定向后的主机没有 API,客户端只会拿到 404 页面而不是 401/200,
* 表现为"连接直接失败"且看不出原因。默认 https 可以绕过整类问题。
* 只有明确写了 http:// 的内网地址才走明文。
* 2) 去掉结尾斜杠,避免拼出 //api/v1。
* 3) 去掉用户误粘的 /api/v1 后缀,避免拼成 /api/v1/api/v1。
*/
export function normalizeBaseUrl(raw: string): string {
let u: string = raw.trim();
if (u.length === 0) {
return '';
}
const lower: string = u.toLowerCase();
if (!lower.startsWith('http://') && !lower.startsWith('https://')) {
u = 'https://' + u;
}
u = u.replace(/\/+$/, '');
u = u.replace(/\/api\/v1$/, '');
return u;
}
/**
* 新建连接用的空白模板。
* 这里不能写死任何地址或密钥:源码是公开的,硬编码等于把内网地址和访问凭据一起发布。
* 地址与 API Key 由用户在「设置 - 连接」里填写,未配置时各页面统一提示(见 UserError.MSG_NO_CONN)。
*/
export function defaultConnection(): ConnectionConfig {
const c: ConnectionConfig = {
id: '',
name: 'HologramAgent',
url: '',
apiKey: '',
type: 'webui',
};
return c;
}