ai-helper-agent 1.17.7 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/README.zh-CN.md +8 -4
- package/dist/assets/{agent-store-BFaBECYz.js → agent-store-C4hZkQT5.js} +2 -2
- package/dist/assets/{agent-store-BFaBECYz.js.map → agent-store-C4hZkQT5.js.map} +1 -1
- package/dist/assets/background.js +54 -54
- package/dist/assets/background.js.map +1 -1
- package/dist/assets/content.js +13 -11
- package/dist/assets/{i18n-CohqPkkN.js → i18n-CAh-vB_T.js} +7 -5
- package/dist/assets/i18n-CAh-vB_T.js.map +1 -0
- package/dist/assets/model-profiles-CGxULM3O.js +25 -0
- package/dist/assets/model-profiles-CGxULM3O.js.map +1 -0
- package/dist/assets/options-Df_1Dtn8.css +1 -0
- package/dist/assets/options.js +78 -63
- package/dist/assets/options.js.map +1 -1
- package/dist/assets/session-store-uZ_LNasH.js +77 -0
- package/dist/assets/session-store-uZ_LNasH.js.map +1 -0
- package/dist/assets/side_panel.css +1 -1
- package/dist/assets/side_panel.js +462 -429
- package/dist/assets/side_panel.js.map +1 -1
- package/dist/icons/badges/version.svg +4 -4
- package/dist/manifest.json +1 -1
- package/dist/offscreen/offscreen.js +7 -5
- package/dist/options.html +3 -3
- package/dist/side_panel.html +118 -30
- package/package.json +1 -1
- package/dist/assets/i18n-CohqPkkN.js.map +0 -1
- package/dist/assets/model-profiles-BS2LIjxf.js +0 -2
- package/dist/assets/model-profiles-BS2LIjxf.js.map +0 -1
- package/dist/assets/options-CE9-fjJV.css +0 -1
- package/dist/assets/session-store-DwXNnVF5.js +0 -100
- package/dist/assets/session-store-DwXNnVF5.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# AI Helper Agent
|
|
4
4
|
|
|
5
|
-
AI Helper Agent — a local proxy service that provides the [AI Helper Chrome Extension](https://github.com/xiweicheng/ai-helper) ([Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/ai-helper-%E7%BD%91%E9%A1%B5%E6%99%BA%E8%83%BD%E5%8A%A9%E6%89%8B/kabhmgfbkhpbfhhnokaafhkdbckeipcl)) with local file read/write, system command execution, Skill system,
|
|
5
|
+
AI Helper Agent — a local proxy service that provides the [AI Helper Chrome Extension](https://github.com/xiweicheng/ai-helper) ([Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/ai-helper-%E7%BD%91%E9%A1%B5%E6%99%BA%E8%83%BD%E5%8A%A9%E6%89%8B/kabhmgfbkhpbfhhnokaafhkdbckeipcl)) with local file read/write, system command execution, Skill system, MCP protocol extension, and an optional local knowledge base (RAG) capability.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -39,6 +39,7 @@ After startup, the terminal will display a 6-digit pairing code. Enter it in the
|
|
|
39
39
|
| `status` | Check running status |
|
|
40
40
|
| `paircode` | Show pairing code |
|
|
41
41
|
| `config` | View current configuration |
|
|
42
|
+
| `rag status` / `rag install` | Check RAG dependency availability / one-click install |
|
|
42
43
|
| `help` | Show help information |
|
|
43
44
|
| `--version` / `-v` | Show version number |
|
|
44
45
|
|
|
@@ -75,6 +76,8 @@ The agent manages process lifecycle via a PID file (`~/.ai-helper-agent/agent.pi
|
|
|
75
76
|
- `stop` command prefers graceful shutdown via API, falls back to killing process via PID file
|
|
76
77
|
- Automatically cleans up PID file on normal shutdown
|
|
77
78
|
|
|
79
|
+
Command termination targets the **entire process tree** — grandchild processes spawned by `npm` etc. (download / build subtasks) are cleaned up together, so stopping a command (`/api/exec/stop`) or timing out never leaves orphan processes writing to disk; POSIX signals the process group, Windows uses `taskkill /T`.
|
|
80
|
+
|
|
78
81
|
## Security
|
|
79
82
|
|
|
80
83
|
### File Sandbox
|
|
@@ -361,12 +364,12 @@ Configuration file path: `~/.ai-helper-agent/config.json`
|
|
|
361
364
|
|
|
362
365
|
## Knowledge Base (RAG)
|
|
363
366
|
|
|
364
|
-
Optional local retrieval-augmented generation. Turn documents into searchable knowledge bases so the extension can answer with cited sources. The RAG stack ships as optional dependencies — the agent detects availability at startup and reports it via `/api/rag/status`; when dependencies are missing, RAG requests return `503` and the extension offers one-click installation (whitelisted packages, progress polled from `/api/rag/install/status`).
|
|
367
|
+
Optional local retrieval-augmented generation. Turn documents into searchable knowledge bases so the extension can answer with cited sources. The RAG stack ships as optional dependencies — the agent detects availability at startup and reports it via `/api/rag/status`; when dependencies are missing, RAG requests return `503` and the extension offers one-click installation (whitelisted packages, progress polled from `/api/rag/install/status`). Installation is also available from the CLI: `ai-helper-agent rag status` / `ai-helper-agent rag install`. Users who have installed the dependencies successfully before get **automatic recovery on startup**: `npm -g` upgrades prune manually-installed packages inside the package directory, so the agent re-installs them automatically (marked `trigger=auto`) — no manual action needed; users who never installed successfully are not prompted.
|
|
365
368
|
|
|
366
369
|
- **Data location** — knowledge bases are stored under `~/.ai-helper-agent/rag/` (override with the `AI_HELPER_RAG_ROOT` environment variable)
|
|
367
|
-
- **Multiple knowledge bases** — create / update / delete collections, each keeping its own embedding config and statistics
|
|
370
|
+
- **Multiple knowledge bases** — create / update / delete / enable / disable collections, each keeping its own embedding config and statistics
|
|
368
371
|
- **Multi-format ingestion** — `.txt` `.md` `.json` `.csv` `.html` / PDF / Word (`mammoth`) / PPT (`officeparser`) / Excel; ingest by raw text, file (base64), or URL, with staged parsing → chunking → embedding → storage progress
|
|
369
|
-
- **Hybrid retrieval** — vector similarity with keyword-hit boosting; searching multiple bases splits the `topK` quota across them
|
|
372
|
+
- **Hybrid retrieval** — vector similarity with keyword-hit boosting (mixed Chinese/English keyword extraction); searching multiple bases splits the `topK` quota across them
|
|
370
373
|
- **Pluggable embeddings** — local model (`Xenova/bge-small-zh-v1.5`, 512-dim, runs locally via `@huggingface/transformers`) by default, or any OpenAI-compatible embedding endpoint (with a connectivity test returning actual dimensions)
|
|
371
374
|
- **Index rebuild** — changing a collection's embedding space rebuilds its index in the background (temporary-directory replay → atomic swap)
|
|
372
375
|
|
|
@@ -385,6 +388,7 @@ Endpoints are registered inside the authenticated region (Bearer token required)
|
|
|
385
388
|
| POST | `/api/rag/collections` | Create a knowledge base |
|
|
386
389
|
| PUT | `/api/rag/collections/{id}` | Update name / description / embedding config (rebuilds index on embedding-space change) |
|
|
387
390
|
| DELETE | `/api/rag/collections/{id}` | Delete a knowledge base |
|
|
391
|
+
| POST | `/api/rag/collections/{id}/toggle` | Enable / disable a knowledge base |
|
|
388
392
|
| GET | `/api/rag/collections/{id}/stats` | Document / chunk statistics |
|
|
389
393
|
| POST | `/api/rag/collections/{id}/ingest` | Ingest text / file / URL (synchronous) |
|
|
390
394
|
| GET | `/api/rag/collections/{id}/ingest/status` | Ingestion progress snapshot (for polling) |
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# AI Helper Agent
|
|
4
4
|
|
|
5
|
-
AI Helper 代理服务,为 [AI Helper Chrome 扩展](https://github.com/xiweicheng/ai-helper)([Edge 扩展商店](https://microsoftedge.microsoft.com/addons/detail/ai-helper-%E7%BD%91%E9%A1%B5%E6%99%BA%E8%83%BD%E5%8A%A9%E6%89%8B/kabhmgfbkhpbfhhnokaafhkdbckeipcl))提供本地文件读写、系统命令执行、Skill
|
|
5
|
+
AI Helper 代理服务,为 [AI Helper Chrome 扩展](https://github.com/xiweicheng/ai-helper)([Edge 扩展商店](https://microsoftedge.microsoft.com/addons/detail/ai-helper-%E7%BD%91%E9%A1%B5%E6%99%BA%E8%83%BD%E5%8A%A9%E6%89%8B/kabhmgfbkhpbfhhnokaafhkdbckeipcl))提供本地文件读写、系统命令执行、Skill 技能系统、MCP 协议扩展与可选本地知识库(RAG)能力。
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
@@ -39,6 +39,7 @@ ai-helper-agent start --workdir /path/to/your/project --port 18911
|
|
|
39
39
|
| `status` | 查看运行状态 |
|
|
40
40
|
| `paircode` | 查看配对码提示 |
|
|
41
41
|
| `config` | 查看当前配置 |
|
|
42
|
+
| `rag status` / `rag install` | 检测 RAG 依赖可用性 / 一键安装 RAG 依赖 |
|
|
42
43
|
| `help` | 显示帮助信息 |
|
|
43
44
|
| `--version` / `-v` | 显示版本号 |
|
|
44
45
|
|
|
@@ -75,6 +76,8 @@ Agent 通过 PID 文件(`~/.ai-helper-agent/agent.pid`)管理进程生命周
|
|
|
75
76
|
- `stop` 命令优先通过 API 优雅关闭,失败则通过 PID 文件 kill 进程
|
|
76
77
|
- 正常关闭时自动清理 PID 文件
|
|
77
78
|
|
|
79
|
+
命令终止按**整棵进程树**清理 —— `npm` 等派生出的孙进程(下载 / 编译子任务)一并终止,停止命令(`/api/exec/stop`)或超时终止后不会留下孤儿进程继续写磁盘;POSIX 对进程组发信号,Windows 使用 `taskkill /T`。
|
|
80
|
+
|
|
78
81
|
## 安全机制
|
|
79
82
|
|
|
80
83
|
### 文件沙箱
|
|
@@ -361,12 +364,12 @@ enabled: true
|
|
|
361
364
|
|
|
362
365
|
## 知识库(RAG)
|
|
363
366
|
|
|
364
|
-
可选的本地检索增强生成(RAG)能力:将文档索引为可检索的知识库,让插件回答时附带引用来源。RAG 依赖为可选安装 —— Agent 启动时自动检测可用性,并通过 `/api/rag/status` 对外暴露;依赖缺失时 RAG 请求返回 `503`,插件端提供一键安装(白名单依赖,进度可经 `/api/rag/install/status`
|
|
367
|
+
可选的本地检索增强生成(RAG)能力:将文档索引为可检索的知识库,让插件回答时附带引用来源。RAG 依赖为可选安装 —— Agent 启动时自动检测可用性,并通过 `/api/rag/status` 对外暴露;依赖缺失时 RAG 请求返回 `503`,插件端提供一键安装(白名单依赖,进度可经 `/api/rag/install/status` 轮询)。也可通过 CLI 安装:`ai-helper-agent rag status` / `ai-helper-agent rag install`。曾成功安装过依赖的用户享受**启动自动恢复**:`npm -g` 更新代理会清理包目录内手动安装的依赖,Agent 启动检测到缺失时自动重新安装(标记 `trigger=auto`),用户零操作;从未安装成功过的用户不触发。
|
|
365
368
|
|
|
366
369
|
- **数据位置** —— 知识库存储于 `~/.ai-helper-agent/rag/`(可用环境变量 `AI_HELPER_RAG_ROOT` 覆盖)
|
|
367
|
-
- **多知识库管理** —— 创建 / 更新 /
|
|
370
|
+
- **多知识库管理** —— 创建 / 更新 / 删除 / 启用 / 停用知识库,各自维护向量配置与统计信息
|
|
368
371
|
- **多格式导入** —— `.txt` `.md` `.json` `.csv` `.html` / PDF / Word(`mammoth`)/ PPT(`officeparser`)/ Excel;支持文本、文件(base64)、URL 三种导入方式,解析 → 分块 → 向量化 → 存储分阶段进度可查
|
|
369
|
-
- **混合检索** —— 向量相似度 +
|
|
372
|
+
- **混合检索** —— 向量相似度 + 关键词命中抬分(中英文混合关键词提取);跨库检索时 `topK` 配额按库均分
|
|
370
373
|
- **可插拔向量化** —— 默认本地模型(`Xenova/bge-small-zh-v1.5`,512 维,经 `@huggingface/transformers` 本地运行),也可接入任意 OpenAI 兼容向量服务(支持连通性测试并返回实际维度)
|
|
371
374
|
- **索引重建** —— 知识库向量空间变更时后台自动重建(临时目录重放 → 原子换入)
|
|
372
375
|
|
|
@@ -385,6 +388,7 @@ enabled: true
|
|
|
385
388
|
| POST | `/api/rag/collections` | 创建知识库 |
|
|
386
389
|
| PUT | `/api/rag/collections/{id}` | 更新名称 / 描述 / 向量配置(向量空间变更自动重建索引) |
|
|
387
390
|
| DELETE | `/api/rag/collections/{id}` | 删除知识库 |
|
|
391
|
+
| POST | `/api/rag/collections/{id}/toggle` | 启用 / 停用知识库 |
|
|
388
392
|
| GET | `/api/rag/collections/{id}/stats` | 文档数 / 分块数统计 |
|
|
389
393
|
| POST | `/api/rag/collections/{id}/ingest` | 导入文本 / 文件 / URL(同步执行) |
|
|
390
394
|
| GET | `/api/rag/collections/{id}/ingest/status` | 导入进度快照(供轮询) |
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-C0FnF6B9.js";import{a as t,c as n}from"./i18n-
|
|
2
|
-
//# sourceMappingURL=agent-store-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-C0FnF6B9.js";import{a as t,c as n}from"./i18n-CAh-vB_T.js";import{_ as r,g as i}from"./session-store-uZ_LNasH.js";var a=e({createAgent:()=>m,deleteAgent:()=>g,getActiveAgentId:()=>_,getAgent:()=>p,getAllAgents:()=>d,getCustomAgents:()=>f,setActiveAgentId:()=>v,updateAgent:()=>h});t(`zh`,{agentStore:{unnamedAgent:`未命名Agent`}}),t(`en`,{agentStore:{unnamedAgent:`Unnamed Agent`}});var o=`customAgents`,s=`activeAssistantId`,c=`activeAgentId`,l=!1;async function u(){if(l)return;l=!0;let e=await chrome.storage.local.get([c,s]),t=e[c],n=e[s];t&&!n&&!t.startsWith(`pa_`)&&(await chrome.storage.local.set({[s]:t}),await chrome.storage.local.remove(c))}async function d(){let e=(await chrome.storage.local.get([o]))[o]||[];return[...i,...e]}async function f(){return(await chrome.storage.local.get([o]))[o]||[]}async function p(e){return e&&(await d()).find(t=>t.id===e)||null}async function m(e){let t=await f(),i={id:r(),name:e.name||n(`agentStore.unnamedAgent`),description:e.description||``,icon:e.icon||`🤖`,systemPrompt:e.systemPrompt||``,toolIds:e.toolIds||null,skillIds:e.skillIds||null,mcpExcludedServerIds:e.mcpExcludedServerIds??null,isBuiltin:!1,allowSubDispatch:e.allowSubDispatch!==void 0&&e.allowSubDispatch,model:e.model||null,temperature:e.temperature===void 0?null:e.temperature,topP:e.topP===void 0?null:e.topP,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};return t.push(i),await chrome.storage.local.set({[o]:t}),i}async function h(e,t){let n=await f(),r=n.findIndex(t=>t.id===e);return r===-1?null:(n[r]={...n[r],...t,id:e,isBuiltin:!1,updatedAt:new Date().toISOString()},await chrome.storage.local.set({[o]:n}),n[r])}async function g(e){let t=await f(),n=t.findIndex(t=>t.id===e);return n!==-1&&(t.splice(n,1),await chrome.storage.local.set({[o]:t}),(await chrome.storage.local.get([s]))[s]===e&&await chrome.storage.local.remove(s),!0)}async function _(){return await u(),(await chrome.storage.local.get([s]))[s]||null}async function v(e){e?await chrome.storage.local.set({[s]:e}):await chrome.storage.local.remove(s)}export{p as a,h as c,_ as i,m as n,d as o,g as r,v as s,a as t};
|
|
2
|
+
//# sourceMappingURL=agent-store-C4hZkQT5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-store-
|
|
1
|
+
{"version":3,"file":"agent-store-C4hZkQT5.js","names":[],"sources":["../../src/side_panel/agent-store.js"],"sourcesContent":["// side_panel/agent-store.js - Agent 数据持久化\nimport { BUILTIN_AGENTS, generateAgentId } from '../shared/agent-defaults.js';\nimport { t, registerTranslations } from '../shared/i18n.js';\n\nregisterTranslations('zh', {\n agentStore: {\n unnamedAgent: '未命名Agent',\n },\n});\nregisterTranslations('en', {\n agentStore: {\n unnamedAgent: 'Unnamed Agent',\n },\n});\n\nconst STORAGE_KEY = 'customAgents';\nconst ACTIVE_KEY = 'activeAssistantId';\nconst LEGACY_ACTIVE_KEY = 'activeAgentId';\n\nlet migratedActiveKey = false;\n\nasync function migrateLegacyActiveKey() {\n if (migratedActiveKey) return;\n migratedActiveKey = true;\n\n const result = await chrome.storage.local.get([LEGACY_ACTIVE_KEY, ACTIVE_KEY]);\n const legacyValue = result[LEGACY_ACTIVE_KEY];\n const newValue = result[ACTIVE_KEY];\n\n if (legacyValue && !newValue && !legacyValue.startsWith('pa_')) {\n await chrome.storage.local.set({ [ACTIVE_KEY]: legacyValue });\n await chrome.storage.local.remove(LEGACY_ACTIVE_KEY);\n }\n}\n\n/**\n * 获取所有 Agent(内置 + 用户自定义)\n * @returns {Promise<Array>}\n */\nexport async function getAllAgents() {\n const result = await chrome.storage.local.get([STORAGE_KEY]);\n const customAgents = result[STORAGE_KEY] || [];\n return [...BUILTIN_AGENTS, ...customAgents];\n}\n\n/**\n * 仅获取用户自定义的 Agent\n * @returns {Promise<Array>}\n */\nexport async function getCustomAgents() {\n const result = await chrome.storage.local.get([STORAGE_KEY]);\n return result[STORAGE_KEY] || [];\n}\n\n/**\n * 根据 ID 获取单个 Agent\n * @param {string} agentId\n * @returns {Promise<Object|null>}\n */\nexport async function getAgent(agentId) {\n if (!agentId) return null;\n const all = await getAllAgents();\n return all.find(a => a.id === agentId) || null;\n}\n\n/**\n * 创建新的自定义 Agent\n * @param {Object} agentData - 不含 id 的 Agent 数据\n * @returns {Promise<Object>}\n */\nexport async function createAgent(agentData) {\n const agents = await getCustomAgents();\n const newAgent = {\n id: generateAgentId(),\n name: agentData.name || t('agentStore.unnamedAgent'),\n description: agentData.description || '',\n icon: agentData.icon || '🤖',\n systemPrompt: agentData.systemPrompt || '',\n toolIds: agentData.toolIds || null, // null = 继承全局\n skillIds: agentData.skillIds || null, // null = 继承全部启用技能\n mcpExcludedServerIds: agentData.mcpExcludedServerIds ?? null, // MCP 服务排除列表(服务级 deny-list)\n isBuiltin: false,\n allowSubDispatch: agentData.allowSubDispatch !== undefined ? agentData.allowSubDispatch : false,\n model: agentData.model || null,\n temperature: agentData.temperature !== undefined ? agentData.temperature : null,\n topP: agentData.topP !== undefined ? agentData.topP : null,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n agents.push(newAgent);\n await chrome.storage.local.set({ [STORAGE_KEY]: agents });\n return newAgent;\n}\n\n/**\n * 更新已有的自定义 Agent\n * @param {string} agentId\n * @param {Object} updates\n * @returns {Promise<Object|null>}\n */\nexport async function updateAgent(agentId, updates) {\n const agents = await getCustomAgents();\n const idx = agents.findIndex(a => a.id === agentId);\n if (idx === -1) return null;\n \n agents[idx] = {\n ...agents[idx],\n ...updates,\n id: agentId, // id 不可变\n isBuiltin: false, // 不可变\n updatedAt: new Date().toISOString(),\n };\n await chrome.storage.local.set({ [STORAGE_KEY]: agents });\n return agents[idx];\n}\n\n/**\n * 删除自定义 Agent\n * @param {string} agentId\n * @returns {Promise<boolean>}\n */\nexport async function deleteAgent(agentId) {\n const agents = await getCustomAgents();\n const idx = agents.findIndex(a => a.id === agentId);\n if (idx === -1) return false;\n \n agents.splice(idx, 1);\n await chrome.storage.local.set({ [STORAGE_KEY]: agents });\n\n // 如果删除的 Agent 是当前选中的,重置为默认\n const result = await chrome.storage.local.get([ACTIVE_KEY]);\n if (result[ACTIVE_KEY] === agentId) {\n await chrome.storage.local.remove(ACTIVE_KEY);\n }\n \n return true;\n}\n\n/**\n * 获取当前选中的 Agent ID\n * @returns {Promise<string|null>}\n */\nexport async function getActiveAgentId() {\n await migrateLegacyActiveKey();\n const result = await chrome.storage.local.get([ACTIVE_KEY]);\n return result[ACTIVE_KEY] || null;\n}\n\n/**\n * 设置当前选中的 Agent ID\n * @param {string|null} agentId\n */\nexport async function setActiveAgentId(agentId) {\n if (agentId) {\n await chrome.storage.local.set({ [ACTIVE_KEY]: agentId });\n } else {\n await chrome.storage.local.remove(ACTIVE_KEY);\n }\n}\n\n/**\n * 从模板创建 Agent\n * @param {Object} template\n * @returns {Promise<Object>}\n */\nexport async function createAgentFromTemplate(template) {\n return createAgent({\n name: template.name,\n icon: template.icon,\n description: template.description,\n systemPrompt: template.systemPrompt,\n toolIds: template.toolIds ? [...template.toolIds] : null,\n allowSubDispatch: template.allowSubDispatch || false,\n });\n}\n"],"mappings":"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"}
|