1741 lines
29 KiB
Markdown
1741 lines
29 KiB
Markdown
# DesktopPet 本地工作区 Agent 开发文档
|
|
|
|
## 0. 文档目标
|
|
|
|
本次开发目标不是继续维护旧版“文件操作 v1”,而是将其重构升级为一个类似 Codex / Claude Code 思路的 **本地工作区 Agent**。
|
|
|
|
新的功能定位:
|
|
|
|
> 用户选择一个本地工作区目录后,桌宠可以读取、搜索、分析该目录内的文件,并在用户确认后创建、修改、移动、重命名或删除文件。
|
|
|
|
注意:
|
|
|
|
1. 不允许 AI 直接获得全盘文件权限。
|
|
2. 不允许 AI 自由执行系统命令。
|
|
3. 不允许永久删除文件。
|
|
4. 不允许绕过用户确认修改本地文件。
|
|
5. 所有写操作必须先生成计划,展示路径和风险,用户确认后才能执行。
|
|
6. 当前阶段优先实现文件级工具,不做 shell 命令执行。
|
|
|
|
------
|
|
|
|
## 1. 当前项目背景
|
|
|
|
当前项目是 QtDesktopPet,技术栈为:
|
|
|
|
- C++17
|
|
- Qt 6 Widgets
|
|
- Qt 6 Network
|
|
- Qt 6 Multimedia
|
|
- CMake
|
|
- Windows 优先
|
|
|
|
当前项目已有:
|
|
|
|
- 桌宠窗口
|
|
- 动画状态
|
|
- AI 对话
|
|
- 天气
|
|
- 提醒
|
|
- 本地应用启动
|
|
- 简单文件操作 v1
|
|
|
|
旧版文件操作 v1 只适合简单功能,例如:
|
|
|
|
- 读取文本文件
|
|
- 列出文件夹
|
|
- 复制文件
|
|
- 备份文件
|
|
- 重命名文件
|
|
|
|
新的目标不是在旧版基础上打补丁,而是设计一个独立的工作区系统。
|
|
|
|
------
|
|
|
|
## 2. 总体开发原则
|
|
|
|
### 2.1 先新增,后替换
|
|
|
|
不要一上来删除旧文件。
|
|
|
|
推荐流程:
|
|
|
|
```text
|
|
新增 workspace 模块
|
|
↓
|
|
实现只读能力
|
|
↓
|
|
实现写入计划和确认
|
|
↓
|
|
接入 PetWindow
|
|
↓
|
|
确认能编译运行
|
|
↓
|
|
替换旧 FileOperationManager
|
|
↓
|
|
最后删除旧文件操作模块
|
|
```
|
|
|
|
### 2.2 PetWindow 不承载业务逻辑
|
|
|
|
`PetWindow` 只负责 UI 展示和用户交互,不应该直接处理复杂文件逻辑。
|
|
|
|
新的业务逻辑应放到:
|
|
|
|
```text
|
|
src/workspace/
|
|
src/assistant/
|
|
```
|
|
|
|
`PetWindow` 只调用控制器,例如:
|
|
|
|
```cpp
|
|
m_workspaceController->handleUserMessage(message);
|
|
```
|
|
|
|
### 2.3 AI 不直接操作文件
|
|
|
|
AI 不能直接拿到文件系统权限。
|
|
|
|
正确流程是:
|
|
|
|
```text
|
|
用户输入
|
|
↓
|
|
WorkspaceAgent 分析任务
|
|
↓
|
|
生成文件操作计划
|
|
↓
|
|
展示计划
|
|
↓
|
|
用户确认
|
|
↓
|
|
WorkspaceTool 执行
|
|
↓
|
|
返回结果
|
|
```
|
|
|
|
------
|
|
|
|
## 3. 功能范围
|
|
|
|
## 3.1 第一阶段必须实现
|
|
|
|
第一阶段目标:**只读工作区分析 + 安全文件操作基础能力**。
|
|
|
|
必须支持:
|
|
|
|
```text
|
|
选择工作区
|
|
显示当前工作区
|
|
扫描工作区文件树
|
|
搜索文件名
|
|
搜索文本内容
|
|
读取文本文件
|
|
分析项目结构
|
|
总结文件内容
|
|
打开文件
|
|
打开文件夹
|
|
显示文件所在位置
|
|
创建文本文件
|
|
创建文件夹
|
|
修改文本文件
|
|
复制文件
|
|
移动文件
|
|
重命名文件
|
|
删除到回收站
|
|
记录最近操作
|
|
```
|
|
|
|
其中:
|
|
|
|
- 读操作可以直接执行。
|
|
- 打开文件建议确认。
|
|
- 创建、修改、移动、重命名、删除必须确认。
|
|
- 删除只能移动到回收站。
|
|
- 修改文件必须备份或使用安全写入策略。
|
|
|
|
------
|
|
|
|
## 3.2 第一阶段禁止实现
|
|
|
|
以下功能第一阶段不要做:
|
|
|
|
```text
|
|
全盘搜索
|
|
永久删除
|
|
批量删除
|
|
批量移动
|
|
批量重命名
|
|
执行 shell 命令
|
|
运行脚本
|
|
运行 exe
|
|
自动 git commit
|
|
自动安装依赖
|
|
自动联网下载并执行文件
|
|
读取系统敏感目录
|
|
读取工作区外文件
|
|
```
|
|
|
|
后续如果需要运行命令,应作为第二阶段或第三阶段功能,并单独设计命令白名单和权限系统。
|
|
|
|
------
|
|
|
|
# 4. 新模块目录结构
|
|
|
|
新增目录:
|
|
|
|
```text
|
|
src/workspace/
|
|
├── WorkspaceTypes.h
|
|
├── WorkspaceSession.h
|
|
├── WorkspaceSession.cpp
|
|
├── WorkspaceIndex.h
|
|
├── WorkspaceIndex.cpp
|
|
├── WorkspaceScanner.h
|
|
├── WorkspaceScanner.cpp
|
|
├── WorkspaceAccessPolicy.h
|
|
├── WorkspaceAccessPolicy.cpp
|
|
├── WorkspaceTool.h
|
|
├── WorkspaceToolRegistry.h
|
|
├── WorkspaceToolRegistry.cpp
|
|
├── WorkspaceAgent.h
|
|
├── WorkspaceAgent.cpp
|
|
├── WorkspaceController.h
|
|
├── WorkspaceController.cpp
|
|
├── WorkspaceHistory.h
|
|
├── WorkspaceHistory.cpp
|
|
└── tools/
|
|
├── ListFilesTool.h
|
|
├── ListFilesTool.cpp
|
|
├── ReadFileTool.h
|
|
├── ReadFileTool.cpp
|
|
├── SearchFilesTool.h
|
|
├── SearchFilesTool.cpp
|
|
├── SearchTextTool.h
|
|
├── SearchTextTool.cpp
|
|
├── OpenFileTool.h
|
|
├── OpenFileTool.cpp
|
|
├── CreateFileTool.h
|
|
├── CreateFileTool.cpp
|
|
├── CreateDirectoryTool.h
|
|
├── CreateDirectoryTool.cpp
|
|
├── WriteFileTool.h
|
|
├── WriteFileTool.cpp
|
|
├── CopyFileTool.h
|
|
├── CopyFileTool.cpp
|
|
├── MoveFileTool.h
|
|
├── MoveFileTool.cpp
|
|
├── RenameFileTool.h
|
|
├── RenameFileTool.cpp
|
|
├── DeleteToTrashTool.h
|
|
└── DeleteToTrashTool.cpp
|
|
```
|
|
|
|
旧目录 `src/fileops/` 暂时不要删除。等新模块完全接入后,再移除旧模块。
|
|
|
|
------
|
|
|
|
# 5. 核心类型设计
|
|
|
|
## 5.1 WorkspacePermissionMode
|
|
|
|
```cpp
|
|
enum class WorkspacePermissionMode
|
|
{
|
|
ReadOnly,
|
|
ConfirmBeforeWrite,
|
|
Advanced
|
|
};
|
|
```
|
|
|
|
说明:
|
|
|
|
- `ReadOnly`:只能读、搜索、分析。
|
|
- `ConfirmBeforeWrite`:允许写,但每次写操作都必须确认。
|
|
- `Advanced`:预留,不在第一阶段实现自动写入。
|
|
|
|
第一阶段默认使用:
|
|
|
|
```cpp
|
|
WorkspacePermissionMode::ConfirmBeforeWrite
|
|
```
|
|
|
|
但所有写操作仍然必须确认。
|
|
|
|
------
|
|
|
|
## 5.2 WorkspaceToolRisk
|
|
|
|
```cpp
|
|
enum class WorkspaceToolRisk
|
|
{
|
|
ReadOnly,
|
|
Low,
|
|
Medium,
|
|
High,
|
|
Dangerous
|
|
};
|
|
```
|
|
|
|
风险等级说明:
|
|
|
|
```text
|
|
ReadOnly:
|
|
搜索、列目录、读取普通文本文件。
|
|
|
|
Low:
|
|
打开文件夹、显示文件所在位置。
|
|
|
|
Medium:
|
|
打开普通文件、创建文件、创建文件夹、复制文件。
|
|
|
|
High:
|
|
修改文件、移动文件、重命名文件、删除到回收站。
|
|
|
|
Dangerous:
|
|
永久删除、执行命令、运行脚本、修改系统目录。
|
|
```
|
|
|
|
第一阶段遇到 `Dangerous` 直接拒绝。
|
|
|
|
------
|
|
|
|
## 5.3 WorkspaceFileInfo
|
|
|
|
```cpp
|
|
struct WorkspaceFileInfo
|
|
{
|
|
QString relativePath;
|
|
QString absolutePath;
|
|
QString fileName;
|
|
QString suffix;
|
|
qint64 sizeBytes = 0;
|
|
QDateTime lastModified;
|
|
bool isDirectory = false;
|
|
bool isTextFile = false;
|
|
bool isHidden = false;
|
|
};
|
|
```
|
|
|
|
用途:
|
|
|
|
- 文件树展示
|
|
- 文件名搜索
|
|
- 后缀过滤
|
|
- 快速判断是否可读
|
|
|
|
------
|
|
|
|
## 5.4 WorkspaceActionPlan
|
|
|
|
```cpp
|
|
enum class WorkspaceActionType
|
|
{
|
|
Unknown,
|
|
|
|
ListFiles,
|
|
SearchFiles,
|
|
SearchText,
|
|
ReadFile,
|
|
|
|
OpenFile,
|
|
OpenDirectory,
|
|
RevealInExplorer,
|
|
|
|
CreateFile,
|
|
CreateDirectory,
|
|
WriteFile,
|
|
|
|
CopyFile,
|
|
MoveFile,
|
|
RenameFile,
|
|
DeleteToTrash
|
|
};
|
|
|
|
struct WorkspaceActionPlan
|
|
{
|
|
QString id;
|
|
WorkspaceActionType type = WorkspaceActionType::Unknown;
|
|
WorkspaceToolRisk risk = WorkspaceToolRisk::ReadOnly;
|
|
|
|
QString title;
|
|
QString description;
|
|
|
|
QString sourcePath;
|
|
QString targetPath;
|
|
QString relativeSourcePath;
|
|
QString relativeTargetPath;
|
|
|
|
QString content;
|
|
QString searchKeyword;
|
|
QStringList warnings;
|
|
|
|
bool requiresConfirmation = false;
|
|
bool allowOverwrite = false;
|
|
bool confirmed = false;
|
|
};
|
|
```
|
|
|
|
注意:
|
|
|
|
- 所有路径都必须是工作区内路径。
|
|
- `sourcePath` 和 `targetPath` 必须经过 `WorkspaceAccessPolicy` 校验。
|
|
- 写操作默认 `requiresConfirmation = true`。
|
|
- 第一阶段禁止覆盖文件,所以 `allowOverwrite` 默认必须是 false。
|
|
|
|
------
|
|
|
|
## 5.5 WorkspaceToolResult
|
|
|
|
```cpp
|
|
struct WorkspaceToolResult
|
|
{
|
|
bool success = false;
|
|
QString message;
|
|
QString errorMessage;
|
|
QString outputText;
|
|
QString targetPath;
|
|
QVector<WorkspaceFileInfo> files;
|
|
};
|
|
```
|
|
|
|
------
|
|
|
|
# 6. WorkspaceAccessPolicy 设计
|
|
|
|
这是最重要的安全模块。
|
|
|
|
## 6.1 职责
|
|
|
|
`WorkspaceAccessPolicy` 负责:
|
|
|
|
```text
|
|
路径标准化
|
|
判断路径是否在工作区内
|
|
阻止 ../ 跳出工作区
|
|
阻止符号链接跳出工作区
|
|
阻止系统目录
|
|
阻止危险文件类型
|
|
阻止敏感文件默认读取
|
|
限制写入行为
|
|
限制删除行为
|
|
```
|
|
|
|
------
|
|
|
|
## 6.2 必须实现的方法
|
|
|
|
```cpp
|
|
class WorkspaceAccessPolicy
|
|
{
|
|
public:
|
|
explicit WorkspaceAccessPolicy(const QString &workspaceRoot);
|
|
|
|
QString workspaceRoot() const;
|
|
|
|
QString normalizePath(const QString &path) const;
|
|
QString toAbsolutePath(const QString &relativeOrAbsolutePath) const;
|
|
QString toRelativePath(const QString &absolutePath) const;
|
|
|
|
bool isInsideWorkspace(const QString &path, QString *errorMessage = nullptr) const;
|
|
bool hasSymlinkSegment(const QString &path, QString *errorMessage = nullptr) const;
|
|
|
|
bool isSystemPath(const QString &path) const;
|
|
bool isDangerousSuffix(const QString &path) const;
|
|
bool isSensitiveFile(const QString &path) const;
|
|
bool isSupportedTextFile(const QString &path) const;
|
|
|
|
bool canReadFile(const QString &path, QString *errorMessage = nullptr) const;
|
|
bool canReadDirectory(const QString &path, QString *errorMessage = nullptr) const;
|
|
bool canCreateFile(const QString &path, QString *errorMessage = nullptr) const;
|
|
bool canCreateDirectory(const QString &path, QString *errorMessage = nullptr) const;
|
|
bool canWriteFile(const QString &path, QString *errorMessage = nullptr) const;
|
|
bool canMoveFile(const QString &sourcePath, const QString &targetPath, QString *errorMessage = nullptr) const;
|
|
bool canDeleteToTrash(const QString &path, QString *errorMessage = nullptr) const;
|
|
};
|
|
```
|
|
|
|
------
|
|
|
|
## 6.3 路径限制
|
|
|
|
所有操作必须满足:
|
|
|
|
```text
|
|
目标路径在 workspaceRoot 内
|
|
不能包含符号链接路径段
|
|
不能是 Windows 系统目录
|
|
不能是 Program Files
|
|
不能是 ProgramData
|
|
不能是回收站目录
|
|
不能是工作区外路径
|
|
```
|
|
|
|
禁止通过以下方式绕过:
|
|
|
|
```text
|
|
../
|
|
..\
|
|
符号链接
|
|
快捷方式跳转
|
|
相对路径混淆
|
|
大小写混淆
|
|
```
|
|
|
|
------
|
|
|
|
## 6.4 危险后缀
|
|
|
|
第一阶段默认禁止写入、打开或执行以下文件:
|
|
|
|
```text
|
|
.exe
|
|
.bat
|
|
.cmd
|
|
.ps1
|
|
.vbs
|
|
.msi
|
|
.scr
|
|
.reg
|
|
.com
|
|
.pif
|
|
.lnk
|
|
```
|
|
|
|
其中 `.lnk` 不要直接打开,因为它可能指向工作区外路径或脚本。
|
|
|
|
------
|
|
|
|
## 6.5 敏感文件
|
|
|
|
以下文件读取时必须强确认,第一阶段可以先默认拒绝:
|
|
|
|
```text
|
|
.env
|
|
*.pem
|
|
*.key
|
|
id_rsa
|
|
id_ed25519
|
|
*.pfx
|
|
*.p12
|
|
credentials.json
|
|
secrets.json
|
|
token.json
|
|
```
|
|
|
|
如果文件名包含以下关键词,也视为敏感:
|
|
|
|
```text
|
|
secret
|
|
token
|
|
password
|
|
credential
|
|
private
|
|
apikey
|
|
api_key
|
|
```
|
|
|
|
------
|
|
|
|
# 7. WorkspaceScanner 和 WorkspaceIndex
|
|
|
|
## 7.1 WorkspaceScanner
|
|
|
|
负责扫描工作区。
|
|
|
|
建议使用:
|
|
|
|
```cpp
|
|
QDirIterator
|
|
```
|
|
|
|
扫描规则:
|
|
|
|
```text
|
|
最大递归深度:8
|
|
最大文件数量:5000
|
|
跳过隐藏目录
|
|
跳过 build 目录
|
|
跳过 .git 目录
|
|
跳过 node_modules
|
|
跳过 dist
|
|
跳过 release_packages
|
|
跳过 .vs
|
|
跳过 .vscode 可选
|
|
```
|
|
|
|
建议跳过目录:
|
|
|
|
```text
|
|
.git
|
|
.vs
|
|
.idea
|
|
build
|
|
cmake-build-debug
|
|
cmake-build-release
|
|
node_modules
|
|
dist
|
|
release
|
|
release_packages
|
|
logs
|
|
```
|
|
|
|
------
|
|
|
|
## 7.2 WorkspaceIndex
|
|
|
|
负责保存扫描结果。
|
|
|
|
```cpp
|
|
class WorkspaceIndex
|
|
{
|
|
public:
|
|
void clear();
|
|
void setFiles(const QVector<WorkspaceFileInfo> &files);
|
|
|
|
QVector<WorkspaceFileInfo> allFiles() const;
|
|
QVector<WorkspaceFileInfo> findByName(const QString &keyword, int maxResults) const;
|
|
QVector<WorkspaceFileInfo> findBySuffix(const QStringList &suffixes, int maxResults) const;
|
|
QVector<WorkspaceFileInfo> recentFiles(int maxResults) const;
|
|
|
|
private:
|
|
QVector<WorkspaceFileInfo> m_files;
|
|
};
|
|
```
|
|
|
|
第一版不需要数据库,不需要向量索引,内存索引即可。
|
|
|
|
------
|
|
|
|
# 8. 工具系统设计
|
|
|
|
## 8.1 WorkspaceTool 抽象
|
|
|
|
```cpp
|
|
class WorkspaceTool
|
|
{
|
|
public:
|
|
virtual ~WorkspaceTool() = default;
|
|
|
|
virtual QString name() const = 0;
|
|
virtual QString displayName() const = 0;
|
|
virtual WorkspaceToolRisk risk() const = 0;
|
|
|
|
virtual WorkspaceToolResult run(const WorkspaceActionPlan &plan) = 0;
|
|
};
|
|
```
|
|
|
|
所有工具必须通过 `WorkspaceAccessPolicy` 校验路径。
|
|
|
|
------
|
|
|
|
## 8.2 ListFilesTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
列出工作区某个目录下的文件和文件夹。
|
|
```
|
|
|
|
限制:
|
|
|
|
```text
|
|
只允许工作区内目录
|
|
最多显示 200 项
|
|
不递归或浅递归
|
|
```
|
|
|
|
------
|
|
|
|
## 8.3 ReadFileTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
读取文本文件。
|
|
```
|
|
|
|
限制:
|
|
|
|
```text
|
|
只读文本文件
|
|
最大读取 128KB
|
|
超出部分截断
|
|
敏感文件默认拒绝或强确认
|
|
不读取二进制文件
|
|
```
|
|
|
|
支持后缀:
|
|
|
|
```text
|
|
.cpp
|
|
.h
|
|
.hpp
|
|
.c
|
|
cc
|
|
py
|
|
js
|
|
ts
|
|
json
|
|
md
|
|
txt
|
|
ini
|
|
xml
|
|
yaml
|
|
yml
|
|
cmake
|
|
pro
|
|
css
|
|
html
|
|
```
|
|
|
|
------
|
|
|
|
## 8.4 SearchFilesTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
按文件名搜索。
|
|
```
|
|
|
|
限制:
|
|
|
|
```text
|
|
只搜索当前工作区索引
|
|
最多返回 30 个结果
|
|
按相关性和最近修改时间排序
|
|
```
|
|
|
|
------
|
|
|
|
## 8.5 SearchTextTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
在文本文件中搜索关键词。
|
|
```
|
|
|
|
限制:
|
|
|
|
```text
|
|
最多扫描 1000 个文本文件
|
|
单文件最大读取 128KB
|
|
最多返回 50 条匹配
|
|
每条匹配显示文件路径、行号、片段
|
|
```
|
|
|
|
------
|
|
|
|
## 8.6 OpenFileTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
用系统默认程序打开文件。
|
|
```
|
|
|
|
实现建议:
|
|
|
|
```cpp
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
|
```
|
|
|
|
限制:
|
|
|
|
```text
|
|
只能打开工作区内文件
|
|
危险后缀拒绝
|
|
敏感文件需要确认
|
|
```
|
|
|
|
打开文件夹同理。
|
|
|
|
------
|
|
|
|
## 8.7 RevealInExplorer
|
|
|
|
功能:
|
|
|
|
```text
|
|
在资源管理器中显示文件所在位置。
|
|
```
|
|
|
|
Windows 可使用:
|
|
|
|
```cpp
|
|
explorer.exe /select,"path"
|
|
```
|
|
|
|
但第一阶段如果不想涉及命令,可以先打开所在文件夹。
|
|
|
|
------
|
|
|
|
## 8.8 CreateFileTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
创建文本文件。
|
|
```
|
|
|
|
限制:
|
|
|
|
```text
|
|
只能在工作区内创建
|
|
目标文件不能已存在
|
|
文件名必须合法
|
|
危险后缀拒绝
|
|
写操作必须确认
|
|
```
|
|
|
|
建议使用 `QSaveFile` 或 `QFile` 创建。
|
|
|
|
------
|
|
|
|
## 8.9 WriteFileTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
写入文本文件。
|
|
```
|
|
|
|
第一阶段建议只支持:
|
|
|
|
```text
|
|
新建文件写入
|
|
或
|
|
修改已有文本文件,但写入前自动备份
|
|
```
|
|
|
|
要求:
|
|
|
|
```text
|
|
写入前必须确认
|
|
写入前创建备份
|
|
禁止覆盖二进制文件
|
|
禁止写敏感文件
|
|
禁止写危险后缀
|
|
```
|
|
|
|
备份目录建议:
|
|
|
|
```text
|
|
<workspaceRoot>/.desktoppet/backups/
|
|
```
|
|
|
|
备份文件名建议:
|
|
|
|
```text
|
|
relative_path.replace("/", "__") + "." + timestamp + ".bak"
|
|
```
|
|
|
|
------
|
|
|
|
## 8.10 CopyFileTool
|
|
|
|
限制:
|
|
|
|
```text
|
|
只能复制单文件
|
|
不能覆盖目标文件
|
|
源和目标都必须在工作区内
|
|
写操作必须确认
|
|
```
|
|
|
|
------
|
|
|
|
## 8.11 MoveFileTool
|
|
|
|
限制:
|
|
|
|
```text
|
|
只能移动单文件
|
|
不能覆盖目标文件
|
|
源和目标都必须在工作区内
|
|
写操作必须确认
|
|
```
|
|
|
|
------
|
|
|
|
## 8.12 RenameFileTool
|
|
|
|
限制:
|
|
|
|
```text
|
|
只能在同目录内重命名
|
|
不能覆盖目标文件
|
|
文件名不能包含路径分隔符
|
|
写操作必须确认
|
|
```
|
|
|
|
------
|
|
|
|
## 8.13 DeleteToTrashTool
|
|
|
|
功能:
|
|
|
|
```text
|
|
移动到系统回收站。
|
|
```
|
|
|
|
实现建议:
|
|
|
|
```cpp
|
|
QFile file(path);
|
|
file.moveToTrash();
|
|
```
|
|
|
|
或根据 Qt 版本使用对应的 `moveToTrash` 方法。
|
|
|
|
限制:
|
|
|
|
```text
|
|
只允许工作区内文件
|
|
不做永久删除
|
|
删除文件夹需要强确认
|
|
删除敏感文件需要强确认
|
|
删除危险后缀文件需要强确认
|
|
```
|
|
|
|
第一阶段禁止批量删除。
|
|
|
|
------
|
|
|
|
# 9. WorkspaceAgent 设计
|
|
|
|
## 9.1 第一版采用半自动 Agent
|
|
|
|
第一版不要急着实现复杂 function calling。
|
|
|
|
建议采用半自动流程:
|
|
|
|
```text
|
|
用户输入
|
|
↓
|
|
WorkspaceController 判断是否是工作区任务
|
|
↓
|
|
程序先根据关键词和工作区索引检索相关文件
|
|
↓
|
|
读取少量相关文件
|
|
↓
|
|
把文件树摘要、相关文件内容、用户问题交给模型
|
|
↓
|
|
模型返回分析结果或修改建议
|
|
↓
|
|
涉及写操作时生成 WorkspaceActionPlan
|
|
↓
|
|
用户确认
|
|
↓
|
|
执行工具
|
|
```
|
|
|
|
这样比完全由模型自由调用工具更容易控制。
|
|
|
|
------
|
|
|
|
## 9.2 后续可升级为工具循环
|
|
|
|
未来可以升级为:
|
|
|
|
```text
|
|
model
|
|
↓
|
|
tool call
|
|
↓
|
|
tool result
|
|
↓
|
|
model
|
|
↓
|
|
tool call
|
|
↓
|
|
...
|
|
```
|
|
|
|
但第一版不强制做。
|
|
|
|
------
|
|
|
|
## 9.3 工作区模式系统提示词
|
|
|
|
工作区模式不要使用普通桌宠聊天提示词。
|
|
|
|
新增工作区专用提示词:
|
|
|
|
```text
|
|
你是 QtDesktopPet 的本地工作区助手。
|
|
|
|
你只能基于用户授权的工作区文件进行分析。
|
|
你不能假设自己看过未读取的文件。
|
|
你不能要求访问工作区外路径。
|
|
你不能执行系统命令。
|
|
你不能生成危险操作指令。
|
|
涉及创建、修改、移动、重命名、删除文件时,必须先生成清晰的操作计划,等待用户确认。
|
|
涉及敏感文件、密钥、凭证时,必须提醒风险。
|
|
回答代码问题时要引用具体文件路径。
|
|
当信息不足时,说明还需要读取哪些文件。
|
|
```
|
|
|
|
------
|
|
|
|
# 10. WorkspaceController 设计
|
|
|
|
`WorkspaceController` 负责连接 UI 和工作区 Agent。
|
|
|
|
建议接口:
|
|
|
|
```cpp
|
|
class WorkspaceController
|
|
{
|
|
public:
|
|
explicit WorkspaceController();
|
|
|
|
bool hasWorkspace() const;
|
|
QString workspaceRoot() const;
|
|
|
|
bool openWorkspace(const QString &rootPath, QString *errorMessage = nullptr);
|
|
void closeWorkspace();
|
|
|
|
WorkspaceToolResult scanWorkspace();
|
|
|
|
WorkspaceToolResult handleMessage(const QString &message);
|
|
|
|
bool hasPendingPlan() const;
|
|
WorkspaceActionPlan pendingPlan() const;
|
|
WorkspaceToolResult confirmPendingPlan();
|
|
void cancelPendingPlan();
|
|
|
|
private:
|
|
WorkspaceSession m_session;
|
|
WorkspaceAgent m_agent;
|
|
std::optional<WorkspaceActionPlan> m_pendingPlan;
|
|
};
|
|
```
|
|
|
|
说明:
|
|
|
|
- `handleMessage` 不直接执行高风险写操作。
|
|
- 如果需要确认,则保存到 `m_pendingPlan`。
|
|
- UI 调用 `confirmPendingPlan` 后才执行。
|
|
|
|
------
|
|
|
|
# 11. UI 接入建议
|
|
|
|
## 11.1 PetWindow 入口
|
|
|
|
在聊天系统中增加:
|
|
|
|
```text
|
|
工作区模式
|
|
```
|
|
|
|
可以通过以下方式触发:
|
|
|
|
```text
|
|
打开工作区
|
|
选择工作区
|
|
分析这个项目
|
|
搜索当前工作区
|
|
```
|
|
|
|
如果用户没有选择工作区,则提示选择目录。
|
|
|
|
第一版可以直接用:
|
|
|
|
```cpp
|
|
QFileDialog::getExistingDirectory(...)
|
|
```
|
|
|
|
让用户选择工作区。
|
|
|
|
------
|
|
|
|
## 11.2 气泡显示策略
|
|
|
|
桌宠气泡只显示简短状态:
|
|
|
|
```text
|
|
已打开工作区。
|
|
正在扫描文件。
|
|
找到了 12 个相关文件。
|
|
需要你确认修改计划。
|
|
操作已完成。
|
|
```
|
|
|
|
复杂结果不要全部塞进气泡。
|
|
|
|
------
|
|
|
|
## 11.3 工作区面板
|
|
|
|
建议新增:
|
|
|
|
```text
|
|
WorkspacePanel
|
|
```
|
|
|
|
第一版可以晚点做,先用对话框和聊天历史展示。
|
|
|
|
最终面板建议显示:
|
|
|
|
```text
|
|
当前工作区路径
|
|
文件树
|
|
搜索结果
|
|
读取过的文件
|
|
AI 分析结果
|
|
待确认操作计划
|
|
执行结果
|
|
最近操作历史
|
|
```
|
|
|
|
------
|
|
|
|
# 12. 和旧文件操作的迁移关系
|
|
|
|
当前旧入口可能是:
|
|
|
|
```cpp
|
|
handleFileOperationChatMessage(...)
|
|
```
|
|
|
|
新方案中应改为:
|
|
|
|
```cpp
|
|
handleWorkspaceMessage(...)
|
|
```
|
|
|
|
迁移步骤:
|
|
|
|
```text
|
|
第一步:
|
|
新增 workspace 模块,不改旧 fileops。
|
|
|
|
第二步:
|
|
CMakeLists.txt 加入 workspace 新文件。
|
|
|
|
第三步:
|
|
在 PetWindow 中新增 WorkspaceController 成员。
|
|
|
|
第四步:
|
|
IntentRouter 中把文件相关意图改为 Workspace。
|
|
|
|
第五步:
|
|
handleFileOperationChatMessage 内部临时转发到 WorkspaceController。
|
|
|
|
第六步:
|
|
确认新模块可用后,删除旧 FileOperationManager 相关调用。
|
|
|
|
第七步:
|
|
删除旧 src/fileops 旧文件并更新 CMakeLists.txt。
|
|
```
|
|
|
|
注意:删除旧文件前必须确认没有任何 include 或成员变量引用旧类。
|
|
|
|
------
|
|
|
|
# 13. IntentRouter 调整
|
|
|
|
当前 `IntentRouter` 只按关键词判断文件操作,后续应改成更宽泛的工作区意图。
|
|
|
|
建议:
|
|
|
|
```cpp
|
|
enum class UserIntentType
|
|
{
|
|
Chat,
|
|
Reminder,
|
|
Weather,
|
|
Workspace,
|
|
LaunchApp
|
|
};
|
|
```
|
|
|
|
工作区关键词:
|
|
|
|
```text
|
|
文件
|
|
文件夹
|
|
目录
|
|
项目
|
|
代码
|
|
源码
|
|
工作区
|
|
分析这个项目
|
|
搜索
|
|
读取
|
|
打开文件
|
|
创建文件
|
|
修改文件
|
|
删除文件
|
|
移动文件
|
|
重命名
|
|
```
|
|
|
|
注意:
|
|
|
|
```text
|
|
打开微信
|
|
打开浏览器
|
|
打开 QQ
|
|
```
|
|
|
|
这类应该走 `LaunchApp`,不要误判成 Workspace。
|
|
|
|
建议优先级:
|
|
|
|
```text
|
|
Reminder
|
|
Weather
|
|
Workspace
|
|
LaunchApp
|
|
Chat
|
|
```
|
|
|
|
但如果文本中出现明确应用名,可优先 LaunchApp。
|
|
|
|
------
|
|
|
|
# 14. CMake 修改计划
|
|
|
|
新增 workspace 文件后,需要在 `CMakeLists.txt` 中加入:
|
|
|
|
```text
|
|
src/workspace/WorkspaceTypes.h
|
|
src/workspace/WorkspaceSession.h
|
|
src/workspace/WorkspaceSession.cpp
|
|
src/workspace/WorkspaceIndex.h
|
|
src/workspace/WorkspaceIndex.cpp
|
|
src/workspace/WorkspaceScanner.h
|
|
src/workspace/WorkspaceScanner.cpp
|
|
src/workspace/WorkspaceAccessPolicy.h
|
|
src/workspace/WorkspaceAccessPolicy.cpp
|
|
src/workspace/WorkspaceTool.h
|
|
src/workspace/WorkspaceToolRegistry.h
|
|
src/workspace/WorkspaceToolRegistry.cpp
|
|
src/workspace/WorkspaceAgent.h
|
|
src/workspace/WorkspaceAgent.cpp
|
|
src/workspace/WorkspaceController.h
|
|
src/workspace/WorkspaceController.cpp
|
|
src/workspace/WorkspaceHistory.h
|
|
src/workspace/WorkspaceHistory.cpp
|
|
src/workspace/tools/ListFilesTool.h
|
|
src/workspace/tools/ListFilesTool.cpp
|
|
src/workspace/tools/ReadFileTool.h
|
|
src/workspace/tools/ReadFileTool.cpp
|
|
src/workspace/tools/SearchFilesTool.h
|
|
src/workspace/tools/SearchFilesTool.cpp
|
|
src/workspace/tools/SearchTextTool.h
|
|
src/workspace/tools/SearchTextTool.cpp
|
|
src/workspace/tools/OpenFileTool.h
|
|
src/workspace/tools/OpenFileTool.cpp
|
|
src/workspace/tools/CreateFileTool.h
|
|
src/workspace/tools/CreateFileTool.cpp
|
|
src/workspace/tools/CreateDirectoryTool.h
|
|
src/workspace/tools/CreateDirectoryTool.cpp
|
|
src/workspace/tools/WriteFileTool.h
|
|
src/workspace/tools/WriteFileTool.cpp
|
|
src/workspace/tools/CopyFileTool.h
|
|
src/workspace/tools/CopyFileTool.cpp
|
|
src/workspace/tools/MoveFileTool.h
|
|
src/workspace/tools/MoveFileTool.cpp
|
|
src/workspace/tools/RenameFileTool.h
|
|
src/workspace/tools/RenameFileTool.cpp
|
|
src/workspace/tools/DeleteToTrashTool.h
|
|
src/workspace/tools/DeleteToTrashTool.cpp
|
|
```
|
|
|
|
注意:
|
|
|
|
当前项目 `CMAKE_AUTOMOC` 是关闭的。如果新增类不使用 `Q_OBJECT`,可以继续保持现状。如果新增 QWidget 并需要 signals / slots,则需要重新考虑 `CMAKE_AUTOMOC`。
|
|
|
|
第一阶段建议 workspace 业务类都不要使用 `Q_OBJECT`,避免牵连构建配置。
|
|
|
|
------
|
|
|
|
# 15. 日志要求
|
|
|
|
不要记录敏感内容。
|
|
|
|
允许记录:
|
|
|
|
```text
|
|
打开工作区路径
|
|
扫描文件数量
|
|
执行的工具名称
|
|
操作是否成功
|
|
错误摘要
|
|
```
|
|
|
|
禁止记录:
|
|
|
|
```text
|
|
API Key
|
|
Authorization header
|
|
完整敏感文件内容
|
|
.env 内容
|
|
密钥文件内容
|
|
用户完整隐私文本
|
|
```
|
|
|
|
使用项目已有 Logger,不要使用 `OutputDebugStringA`。
|
|
|
|
------
|
|
|
|
# 16. 错误处理
|
|
|
|
所有工具错误都必须返回 `WorkspaceToolResult`,不要直接弹窗。
|
|
|
|
错误示例:
|
|
|
|
```text
|
|
路径不在当前工作区内。
|
|
目标文件已存在。
|
|
该文件类型不允许写入。
|
|
该文件可能包含敏感信息,已拒绝读取。
|
|
删除操作已取消。
|
|
无法移动到回收站。
|
|
```
|
|
|
|
UI 层负责展示错误。
|
|
|
|
------
|
|
|
|
# 17. 测试清单
|
|
|
|
## 17.1 工作区选择
|
|
|
|
测试:
|
|
|
|
```text
|
|
选择普通项目目录
|
|
选择空目录
|
|
选择不存在目录
|
|
选择 C:/Windows,应该拒绝
|
|
选择 Program Files,应该拒绝
|
|
选择包含中文路径的目录
|
|
选择包含空格路径的目录
|
|
```
|
|
|
|
------
|
|
|
|
## 17.2 扫描
|
|
|
|
测试:
|
|
|
|
```text
|
|
扫描普通 Qt 项目
|
|
扫描包含 build 目录的项目
|
|
扫描包含 .git 的项目
|
|
扫描大量文件目录
|
|
扫描中文文件名
|
|
扫描深层目录
|
|
```
|
|
|
|
要求:
|
|
|
|
```text
|
|
不崩溃
|
|
不扫系统目录
|
|
不进入跳过目录
|
|
结果数量受限制
|
|
```
|
|
|
|
------
|
|
|
|
## 17.3 搜索文件
|
|
|
|
测试:
|
|
|
|
```text
|
|
搜索 main
|
|
搜索 .cpp
|
|
搜索 README
|
|
搜索不存在文件
|
|
搜索中文文件名
|
|
```
|
|
|
|
要求:
|
|
|
|
```text
|
|
最多返回 30 条
|
|
显示相对路径
|
|
结果可用于后续“打开第几个”
|
|
```
|
|
|
|
------
|
|
|
|
## 17.4 搜索文本
|
|
|
|
测试:
|
|
|
|
```text
|
|
搜索 class
|
|
搜索 include
|
|
搜索中文关键词
|
|
搜索不存在关键词
|
|
搜索超大文件
|
|
```
|
|
|
|
要求:
|
|
|
|
```text
|
|
显示路径、行号、片段
|
|
跳过二进制文件
|
|
跳过超大文件
|
|
不读取敏感文件
|
|
```
|
|
|
|
------
|
|
|
|
## 17.5 读取文件
|
|
|
|
测试:
|
|
|
|
```text
|
|
读取 .cpp
|
|
读取 .md
|
|
读取 .json
|
|
读取图片,应该拒绝
|
|
读取 exe,应该拒绝
|
|
读取 .env,应该拒绝或强确认
|
|
读取工作区外文件,应该拒绝
|
|
```
|
|
|
|
------
|
|
|
|
## 17.6 创建文件
|
|
|
|
测试:
|
|
|
|
```text
|
|
在工作区创建 test.txt
|
|
创建已存在文件,应该拒绝
|
|
创建非法文件名,应该拒绝
|
|
创建 .bat,应该拒绝
|
|
创建到工作区外,应该拒绝
|
|
```
|
|
|
|
------
|
|
|
|
## 17.7 修改文件
|
|
|
|
测试:
|
|
|
|
```text
|
|
修改普通 txt
|
|
修改 cpp
|
|
修改已存在文件前生成备份
|
|
修改二进制文件,应该拒绝
|
|
修改敏感文件,应该拒绝
|
|
```
|
|
|
|
要求:
|
|
|
|
```text
|
|
必须确认
|
|
必须备份
|
|
失败不能破坏原文件
|
|
```
|
|
|
|
------
|
|
|
|
## 17.8 移动和重命名
|
|
|
|
测试:
|
|
|
|
```text
|
|
移动普通文件
|
|
移动到已存在目标,应该拒绝
|
|
重命名普通文件
|
|
重命名为非法文件名,应该拒绝
|
|
移动到工作区外,应该拒绝
|
|
```
|
|
|
|
------
|
|
|
|
## 17.9 删除到回收站
|
|
|
|
测试:
|
|
|
|
```text
|
|
删除普通文件到回收站
|
|
删除文件夹到回收站
|
|
删除工作区外文件,应该拒绝
|
|
永久删除请求,应该拒绝
|
|
批量删除请求,第一阶段应该拒绝
|
|
```
|
|
|
|
------
|
|
|
|
## 17.10 对话上下文
|
|
|
|
测试:
|
|
|
|
```text
|
|
用户:搜索 README
|
|
用户:打开第一个
|
|
|
|
用户:搜索 fileops
|
|
用户:读取第二个
|
|
|
|
用户:找一下包含 FileOperationManager 的文件
|
|
用户:总结这些文件的作用
|
|
```
|
|
|
|
要求:
|
|
|
|
```text
|
|
系统能记住上一轮搜索结果
|
|
“第一个”“第二个”能正确解析
|
|
上下文过期后要求用户重新选择
|
|
```
|
|
|
|
------
|
|
|
|
# 18. 推荐开发任务拆分
|
|
|
|
## 任务 1:新增类型和安全策略
|
|
|
|
目标:
|
|
|
|
```text
|
|
新增 WorkspaceTypes.h
|
|
新增 WorkspaceAccessPolicy
|
|
不接 UI
|
|
保证项目可编译
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
能判断路径是否在工作区内
|
|
能拒绝系统目录
|
|
能拒绝符号链接
|
|
能拒绝危险后缀
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 2:新增扫描和索引
|
|
|
|
目标:
|
|
|
|
```text
|
|
实现 WorkspaceScanner
|
|
实现 WorkspaceIndex
|
|
支持扫描工作区文件树
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
可以扫描普通项目
|
|
可以跳过 build/.git/node_modules
|
|
可以按文件名搜索
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 3:新增只读工具
|
|
|
|
目标:
|
|
|
|
```text
|
|
ListFilesTool
|
|
ReadFileTool
|
|
SearchFilesTool
|
|
SearchTextTool
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
能列目录
|
|
能读文本文件
|
|
能搜索文件名
|
|
能搜索文本内容
|
|
不读取二进制和敏感文件
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 4:新增打开工具
|
|
|
|
目标:
|
|
|
|
```text
|
|
OpenFileTool
|
|
OpenDirectory
|
|
RevealInExplorer
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
能打开普通文件
|
|
能打开文件夹
|
|
危险后缀拒绝
|
|
工作区外路径拒绝
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 5:新增写入工具
|
|
|
|
目标:
|
|
|
|
```text
|
|
CreateFileTool
|
|
CreateDirectoryTool
|
|
WriteFileTool
|
|
CopyFileTool
|
|
MoveFileTool
|
|
RenameFileTool
|
|
DeleteToTrashTool
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
所有写操作必须要求 confirmed
|
|
未确认时拒绝执行
|
|
目标已存在时拒绝覆盖
|
|
删除只进回收站
|
|
写入前备份
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 6:新增 WorkspaceController
|
|
|
|
目标:
|
|
|
|
```text
|
|
统一管理工作区、索引、工具、待确认计划
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
能 openWorkspace
|
|
能 scanWorkspace
|
|
能 handleMessage
|
|
能保存 pendingPlan
|
|
能确认执行 pendingPlan
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 7:接入 PetWindow
|
|
|
|
目标:
|
|
|
|
```text
|
|
PetWindow 增加 WorkspaceController
|
|
聊天消息中的工作区相关请求转发给 WorkspaceController
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
用户可以选择工作区
|
|
可以搜索文件
|
|
可以读取文件
|
|
写操作会弹确认
|
|
确认后执行
|
|
```
|
|
|
|
------
|
|
|
|
## 任务 8:替换旧 fileops
|
|
|
|
目标:
|
|
|
|
```text
|
|
旧 handleFileOperationChatMessage 改为调用 workspace
|
|
删除旧 FileOperationManager 依赖
|
|
更新 CMake
|
|
```
|
|
|
|
验收:
|
|
|
|
```text
|
|
项目无旧 FileOperationManager 引用
|
|
项目能编译
|
|
README 更新为“本地工作区助手”
|
|
```
|
|
|
|
------
|
|
|
|
# 19. README 更新要求
|
|
|
|
README 中文件操作部分应改为:
|
|
|
|
```text
|
|
本地工作区助手:
|
|
|
|
- 用户选择一个工作区目录后,桌宠可以读取、搜索和分析其中的文本文件。
|
|
- 支持文件名搜索、文本搜索、文件读取、项目结构分析。
|
|
- 支持创建、修改、移动、重命名和删除到回收站,但所有写操作都需要用户确认。
|
|
- 不支持永久删除。
|
|
- 不支持执行脚本或系统命令。
|
|
- 不允许访问工作区外路径。
|
|
- 敏感文件和危险后缀会被拦截或要求强确认。
|
|
```
|
|
|
|
------
|
|
|
|
# 20. 最终验收标准
|
|
|
|
本轮重构完成后,至少应达到:
|
|
|
|
```text
|
|
1. 用户可以选择一个本地项目目录作为工作区。
|
|
2. 程序可以扫描工作区并建立文件索引。
|
|
3. 用户可以通过对话搜索文件。
|
|
4. 用户可以通过对话读取和分析文本文件。
|
|
5. 用户可以要求分析项目结构。
|
|
6. 用户可以创建文本文件和文件夹。
|
|
7. 用户可以移动、重命名、删除到回收站。
|
|
8. 所有写操作必须展示计划并等待确认。
|
|
9. 所有路径必须限制在工作区内。
|
|
10. 不允许永久删除。
|
|
11. 不允许执行脚本或命令。
|
|
12. 不允许默认读取敏感文件。
|
|
13. 旧文件操作功能被新 Workspace 系统替代。
|
|
14. 项目可以正常编译。
|
|
```
|
|
|
|
------
|
|
|
|
# 21. 特别注意
|
|
|
|
这是一次架构升级,不是简单加几个文件函数。
|
|
|
|
不要把功能写成:
|
|
|
|
```text
|
|
AI 说删就删
|
|
AI 说改就改
|
|
AI 说运行就运行
|
|
```
|
|
|
|
必须写成:
|
|
|
|
```text
|
|
AI 提出计划
|
|
程序校验路径和风险
|
|
用户确认
|
|
程序执行白名单工具
|
|
```
|
|
|
|
这个边界必须守住。
|
|
|
|
最终目标是:
|
|
|
|
> 让 DesktopPet 具备“读工作区、理解工作区、规划修改、确认后执行”的能力,形成桌宠形态的本地工作区 Agent。 |