Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ local.properties
# MCP 配置
config/mcp.json

# Local Prompt include files (may contain private identity/authority data)
config/prompts/*.local.*

# Agent intro auto generation
src/Undefined/skills/agents/**/intro.generated.md

Expand Down
1 change: 1 addition & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户
### 资源加载与提示词安全

- **资源加载**:提示词与预置文案通过 `src/Undefined/utils/resources.py` 读取,优先从运行目录加载同名 `res/...`(便于覆盖),若不存在再回退到安装包自带资源,并提供仓库结构兜底,避免依赖启动时的工作目录。
- **本地 Prompt 插槽**:两份主 Prompt 提供 P0/P1/P2/P3/summary 稳定插槽;`[prompt.file_includes]` 指向的 UTF-8 文件在每次请求构建时检查修改时间,未变化时复用缓存、变化时重新读取,支持内容与配置路径热更新。推荐的 `config/prompts/*.local.*` 同时从 Git 与构建产物排除。
- **提示词结构安全**:结构化 Prompt/历史消息注入使用 `src/Undefined/utils/xml.py` 做必要的 XML 转义,降低用户输入破坏结构或干扰解析的风险。

---
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## v3.11.0 主 Prompt 本地自定义与 Tool Call 兼容

本版本将部署者私有的身份、权限与人格补充从仓库主 Prompt 中解耦,新增可热更新的本地文件插槽,让不同部署可以在不修改受版本控制提示词的情况下完成定制;同时补充 `function` / `parameters` 文本 Tool Call 封包兼容。

- 新增 `[prompt.file_includes]` 主 Prompt 本地文件插槽。支持在 `p0`、`p1`、`p2`、`p3` 与 `summary` 五个稳定位置分别插入一个 UTF-8 文件;空路径表示禁用,未配置的标记会从最终 Prompt 中移除。每次请求检查文件路径与纳秒级修改时间,未变化时复用缓存、变化时重新读取,配置路径修改沿用现有热更新链路。
- 完善本地文件加载边界。多个已配置文件并行读取,只展开一轮,不递归处理文件内的插槽标记;文件缺失、不可读或编码无效时记录警告并跳过,不中断主请求。相对路径以 Bot 启动工作目录为基准,并支持 `~` 用户目录。
- 分离公开项目信息与部署者私有信息。两份主 Prompt 只保留简洁的创造者说明以及 MIT 许可证、公开仓库地址等可分发元数据,详细身份与权限规则迁移到本地文件;`config/prompts/*.local.*` 同时加入 Git 忽略和 wheel/sdist 构建排除,避免私有文件被误提交或打包。README、配置示例、部署说明、架构和消息批处理文档同步补充定制方式与模型供应商可见性边界。
- 扩展文本 Tool Call 后备解析。兼容 `{"function":"end","parameters":{"memo":"...","observations":[]}}` 形式,并通用于其他当前可用工具;`parameters` 可以是 JSON 对象或编码该对象的字符串,也可与既有 `tool`、`name` 封包连续混排。恢复出的调用继续经过工具可见性、权限检查、原生执行与续轮回放,非对象参数及额外字段仍会被严格拒绝。
- 同步 Python 包、Undefined Console、Undefined Chat、Tauri 配置及 uv/npm/Cargo 锁文件版本至 3.11.0,并补充配置解析、热更新、模板同步、Prompt 约束、构建排除和主 Chat 执行链回归测试。

---

## v3.10.1 扁平 JSON Tool Call 参数兼容

本版本补充文本 Tool Call 后备解析对顶层平铺参数的兼容,解决部分模型未生成 `arguments` 封包时无法恢复工具调用的问题。
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<a href="https://pypi.org/project/Undefined-bot"><img src="https://img.shields.io/pypi/v/Undefined-bot.svg" alt="PyPI"></a>
<a href="https://deepwiki.com/69gg/Undefined"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
<br/><br/>
<p>大鹏一日同风起,扶摇直上九万里。</p>
<i>大鹏一日同风起,扶摇直上九万里。</i>
</div>
<h3>项目简介</h3>
<p>
Expand Down Expand Up @@ -61,6 +61,7 @@ Console 和 Chat 都需要连接到已经运行的 Undefined 服务。首次部
- **Tool Search 按需工具加载**:可在 `[skills]` 下设置 `tool_search_enabled = true`,让主 AI 首轮只接收基础工具、虚拟 `tool_search` 和已检索工具的完整 schema,其余能力仅以名称目录提示,并在检索后的下一模型轮加载。该功能默认关闭,只减少模型上下文中的工具声明,不改变本地注册表、会话权限或子 Agent 的私有工具集。详见 [Tool Search 按需工具加载](docs/tool-search.md)。
- **可嵌入 Python 库**:`pip install Undefined-bot` 后可 import 配置、`AIClient`、Skills 与认知记忆等组件,无需启动 Bot CLI。详见 [Python 库 API 参考](docs/python-api.md)。
- **Skills 热重载**:自动扫描 `skills/` 目录,检测到变更后即时重载工具与 Agent,无需重启服务。
- **主 Prompt 本地自定义**:通过 `[prompt.file_includes]` 将身份、权限或人格补充文件插入 `p0`、`p1`、`p2`、`p3`、`summary` 五个稳定位置,无需修改仓库内的主提示词;配置路径和文件内容均支持热更新,推荐使用受 Git 与构建忽略规则保护的 `config/prompts/*.local.*` 文件。详见 [Prompt 本地文件插槽](docs/configuration.md#4112-promptfile_includes-主-prompt-本地文件插槽)。
- **三层分层记忆架构**:创新的分层记忆系统,模拟人类记忆机制——
- **短期记忆**(`end.memo`):每轮对话结束自动记录便签备忘,最近 N 条始终注入,保持短期连续性,零配置开箱即用
- **认知记忆**(`end.observations` + `cognitive.*`):核心层,AI 在每轮对话中主动观察并提取用户/群聊事实及有价值的自身行为,经后台史官异步改写后存入向量数据库;支持语义检索、时间衰减加权排序、MMR 多样性去重、跨群记忆联动与用户/群聊自动侧写(合并时注入历史事件防止特征丢失),前台零延迟
Expand Down
4 changes: 2 additions & 2 deletions apps/undefined-chat/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-chat/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "undefined-chat",
"private": true,
"version": "3.10.1",
"version": "3.11.0",
"type": "module",
"scripts": {
"tauri": "tauri",
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-chat/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-chat/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "undefined_chat"
version = "3.10.1"
version = "3.11.0"
description = "Undefined native chat client"
authors = ["Undefined contributors"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-chat/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Undefined Chat",
"version": "3.10.1",
"version": "3.11.0",
"identifier": "com.undefined.chat",
"build": {
"beforeDevCommand": "npm run dev",
Expand Down
4 changes: 2 additions & 2 deletions apps/undefined-console/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-console/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "undefined-console",
"private": true,
"version": "3.10.1",
"version": "3.11.0",
"type": "module",
"scripts": {
"tauri": "tauri",
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-console/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-console/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "undefined_console"
version = "3.10.1"
version = "3.11.0"
description = "Undefined cross-platform management console"
authors = ["Undefined contributors"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-console/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Undefined Console",
"version": "3.10.1",
"version": "3.11.0",
"identifier": "com.undefined.console",
"build": {
"beforeDevCommand": "npm run dev",
Expand Down
11 changes: 11 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,17 @@ tool_search_always_loaded = ["send_message", "end"]
# en: Maximum matches loaded by one tool search (minimum 1).
tool_search_max_results = 5

# zh: 主 Prompt 固定插槽对应的本地 UTF-8 文件。路径为空时不注入。
# en: Local UTF-8 files mapped to stable main-Prompt slots. Empty paths disable injection.
[prompt.file_includes]
# zh: P0 / P1 / P2 / P3 分别位于对应优先级区块开头;summary 位于总结区块开头。
# en: P0-P3 are placed at the start of their priority sections; summary is placed at the start of the summary section.
p0 = ""
p1 = ""
p2 = ""
p3 = ""
summary = ""

# zh: Prompt 系统信息注入。总开关默认关闭;开启后各子项默认展示,可逐项关闭。
# en: Prompt system information injection. The master switch is disabled by default; enabled sub-items are shown by default and can be disabled individually.
[prompt.system_info]
Expand Down
7 changes: 4 additions & 3 deletions config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

本目录存放配置示例与 MCP 配置样例,便于快速搭建运行环境。

- `config.toml.example`:主配置示例文件
- `../config.toml.example`:仓库根目录的主配置示例文件
- `mcp.json.example`:MCP 服务器配置示例

使用方式:
1. 复制 `config.toml.example` 为 `config.toml` 并填入实际参数
1. 在仓库根目录复制 `config.toml.example` 为 `config.toml` 并填入实际参数
2. 如需 MCP,复制 `config/mcp.json.example` 为 `config/mcp.json`,并在 `config.toml` 中配置 `[mcp].config_path`
3. 如需补充本地 Prompt,把 UTF-8 文件放在 `config/prompts/*.local.*`,并配置 `[prompt.file_includes]` 的固定插槽

推荐关注的新增配置:
注意事项:
- `config.local.json` 为运行时自动生成文件,请勿提交
- `config/prompts/*.local.*` 可能包含身份或权限信息,已被 Git 和构建配置排除;文件内容仍会发送给模型供应商
- 请妥善保护日志路径、Token 等敏感信息
29 changes: 29 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,35 @@ Prompt caching 补充:

---

### 4.11.2 `[prompt.file_includes]` 主 Prompt 本地文件插槽

该表把五个稳定插槽映射到本地 UTF-8 文件,适合保存部署者自己的身份、权限、人格补充等不应进入仓库的内容。开源许可证、公开仓库地址等可随项目分发的信息应保留在主 Prompt 中,不必放入本地文件:

```toml
[prompt.file_includes]
p0 = "config/prompts/creator.local.xml"
p1 = ""
p2 = ""
p3 = ""
summary = ""
```

| 字段 | 插入位置 | 默认值 |
|---|---|---:|
| `p0` | `<absolute_priority level="P0">` 开头 | `""` |
| `p1` | `<core_rules level="P1">` 开头 | `""` |
| `p2` | `<important_rules level="P2">` 开头 | `""` |
| `p3` | `<optimization_rules level="P3">` 开头 | `""` |
| `summary` | `<summary>` 开头 | `""` |

每个插槽只对应一个文件,空路径表示禁用。相对路径以 Bot 启动工作目录为基准,支持 `~` 用户目录。文件内容按原文插入当前主 system Prompt,只展开一轮,不把文件内出现的插槽标记继续递归展开。

热更新语义:每次主 AI 请求都会检查文件路径与纳秒级修改时间;修改时间未变时复用已加载内容,变化时重新读取,因此文件内容修改无需重启。修改路径后,沿用现有配置热更新的轮询与去抖时间。已经开始执行的请求使用创建时的快照。文件缺失、不是 UTF-8 或暂时不可读时会记录警告、清空对应插槽并继续本轮请求。

源码仓库推荐把私有文件命名为 `config/prompts/*.local.*`。该模式同时受 `.gitignore` 和 wheel/sdist 构建排除规则保护。此保护只避免提交与打包;插入后的内容仍会发送给当前配置的模型供应商,放入凭据、密钥或不应离开本机的数据前必须自行评估。

---

### 4.12 `[search]` 搜索

| 字段 | 默认值 | 说明 |
Expand Down
29 changes: 26 additions & 3 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,31 @@ cp config.toml.example config.toml

#### 源码部署的自定义指南

- **自定义提示词/预置文案**:直接修改仓库根目录的 `res/`(例如 `res/prompts/`)。
- **局部扩展主提示词(推荐)**:使用 `[prompt.file_includes]` 把本地文件放入 P0/P1/P2/P3/summary 固定插槽,不需要修改受 Git 跟踪的主提示词。
- **完整覆盖提示词/预置文案**:需要替换整份资源时再修改仓库根目录的 `res/`(例如 `res/prompts/`)。
- **自定义图片资源**:修改 `img/` 下的对应文件(例如 `img/xlwy.jpg`)。
- **优先级**:若你希望“运行目录覆盖优先”:在启动目录放置 `./res/...`,会优先于默认资源生效(便于一套安装,多套运行配置)。

主 Prompt 局部扩展示例:

```bash
mkdir -p config/prompts
# 创建并编辑 config/prompts/identity.local.xml
```

```toml
[prompt.file_includes]
p0 = "config/prompts/identity.local.xml"
p1 = ""
p2 = ""
p3 = ""
summary = ""
```

源码仓库已忽略并从构建产物中排除 `config/prompts/*.local.*`。每次 AI 请求都会检查文件修改时间,未变化时复用缓存、变化时重新读取;配置路径修改后按现有配置热更新间隔生效。文件缺失或读取失败时会记录警告并跳过该插槽,不会阻止请求。完整配置与插槽位置见[配置说明](configuration.md#4112-promptfile_includes-主-prompt-本地文件插槽)。

> Git 与构建排除只防止私有文件被提交或打包;插入后的内容仍会作为 system Prompt 发送给模型供应商,不要在其中保存 API Key 等凭据。

### 5. 启动运行

启动方式(二选一):
Expand Down Expand Up @@ -193,14 +214,16 @@ wheel 会自带 `res/**` 与 `img/**`。为了便于自定义,程序读取资
1. 优先加载运行目录下的同名文件(例如 `./res/prompts/...`)
2. 若不存在,再使用安装包自带的资源文件

因此你无需改动 site-packages,直接在运行目录放置覆盖文件即可,例如:
只需要局部补充主 Prompt 时,优先使用上文的 `[prompt.file_includes]`:它会在每次请求检查运行目录中的本地文件并在修改后重新读取,也不会复制整份默认 Prompt。

确实需要完整覆盖资源时,无需改动 site-packages,直接在运行目录放置覆盖文件即可,例如:

```bash
mkdir -p res/prompts
# 然后把你想改的提示词放到对应路径(文件名与目录层级保持一致)
```

如果你希望直接修改“默认提示词/默认文案”(而不是每个运行目录做覆盖),推荐使用上面的“源码部署”,在仓库里修改 `res/` 后运行;不建议直接修改已安装环境的 `site-packages/res`(升级会被覆盖)。
完整资源覆盖在进程内会走资源缓存,修改后应重启 Bot。若希望直接修改“默认提示词/默认文案”(而不是每个运行目录做覆盖),推荐使用上面的“源码部署”,在仓库里修改 `res/` 后运行;不建议直接修改已安装环境的 `site-packages/res`(升级会被覆盖)。

如果你不知道安装包内默认提示词文件在哪,可以用下面方式打印路径(用于复制一份出来改):

Expand Down
2 changes: 1 addition & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ src/Undefined/
├── ai/ # AI 运行时核心
│ ├── client/ # AIClient 组合:setup / queue / ask_loop
│ ├── llm/ # ModelRequester、streaming、thinking、sanitize
│ ├── prompts/ # PromptBuilder、system_context、cognitive 片段
│ ├── prompts/ # PromptBuilder、system_context、文件插槽与 cognitive 片段
│ └── multimodal/# 多模态检测、解析与分析
├── attachments/ # 附件注册、渲染、作用域隔离
├── arxiv/ # arXiv 论文解析、元信息获取、PDF 下载与发送
Expand Down
2 changes: 1 addition & 1 deletion docs/message-batching.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

长工具链中的记忆优先级不会改变:每次搜索、Agent 或其他工具返回后,下一步行动仍应重新以整个当前输入批次为事实基准。召回内容即使带有命令语气、规则名称、旧参数或历史成功结果,也不能替用户改写本轮意图;与当前输入冲突或由记忆额外补出的部分应被忽略,除非当前输入明确要求沿用过去信息。

Prompt 构建顺序按缓存命中友好设计:固定系统提示词、运行环境配置、Skills 元数据和强制规则尽量放在前面;会频繁变化的 memory / cognitive / end 摘要 / history / 可选系统信息 / 当前时间 / 当前输入批次放在后面。`system_prompt_as_user=true` 时,系统块会合并进首条 user,但合并后的文本仍保留这个顺序,且当前输入批次仍在最后。
Prompt 构建顺序按缓存命中友好设计:固定系统提示词骨架及其中 P0/P1/P2/P3/summary 五个稳定的 `[prompt.file_includes]` 插槽、运行环境配置、Skills 元数据和强制规则尽量放在前面;会频繁变化的 memory / cognitive / end 摘要 / history / 可选系统信息 / 当前时间 / 当前输入批次放在后面。本地插槽文件会在每次新请求构建时检查路径与修改时间;修改时间未变时复用已加载内容,变化时重新读取,内容修改无需重启。`system_prompt_as_user=true` 时,系统块会合并进首条 user,但合并后的文本仍保留这个顺序,且当前输入批次仍在最后。

其中 history 使用批次发车时冻结的深拷贝快照,而不是在慢速认知检索结束后重新读取实时历史。快照会优先按 `message_id` 从任意位置剔除当前输入批次自身的记录,因此即使批次消息之间或其后出现其他人的消息,也不会把当前输入重复注入;显式调用 `messages.get_recent_messages` 仍按工具调用时读取实时历史。

Expand Down
8 changes: 7 additions & 1 deletion docs/model-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@ Undefined 将“是否请求模型思考”和“是否在下一轮回放已有
{"name":"end","arguments":{"memo":"搜索 m2u 的《君往何处》","observations":[]}}
```

JSON 对象可以单独出现,也可以由空白分隔后连续出现;`tool` 的嵌套参数形式、平铺参数形式与 `name` 封包允许混排。`arguments` 可以是对象或编码该对象的 JSON 字符串;`name` 形式要求显式提供 `arguments`,避免把普通的名称 JSON 误判为工具调用。
还兼容部分模型输出的 `function` + `parameters` 字段形式:

```text
{"function":"end","parameters":{"memo":"已回应","observations":[]}}
```

JSON 对象可以单独出现,也可以由空白分隔后连续出现;`tool` 的嵌套参数形式、平铺参数形式、`name` 封包与 `function` 封包允许混排。`arguments` / `parameters` 可以是对象或编码该对象的 JSON 字符串;`name` 形式要求显式提供 `arguments`,`function` 形式要求显式提供 `parameters`,避免把普通 JSON 误判为工具调用。`function` 封包只能包含这两个字段。

### `tool_calls` JSON 封包

Expand Down
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "Undefined-bot"
version = "3.10.1"
version = "3.11.0"
description = "QQ bot platform with cognitive memory architecture and multi-agent Skills, via OneBot V11."
readme = "README.md"
authors = [
Expand Down Expand Up @@ -90,6 +90,9 @@ only-include = [
"config",
"config.toml.example",
]
exclude = [
"/config/prompts/*.local.*",
]
sources = ["src"]

[tool.hatch.build.targets.wheel.force-include]
Expand All @@ -108,6 +111,9 @@ include = [
"/ARCHITECTURE.md",
"/LICENSE",
]
exclude = [
"/config/prompts/*.local.*",
]

[tool.mypy]
python_version = "3.12"
Expand Down
Loading
Loading