diff --git a/.project-docs/30-worklog/tasks/20260914-yuxi-embedding-ml-a174ed62.md b/.project-docs/30-worklog/tasks/20260914-yuxi-embedding-ml-a174ed62.md index 09b952f..abbda50 100644 --- a/.project-docs/30-worklog/tasks/20260914-yuxi-embedding-ml-a174ed62.md +++ b/.project-docs/30-worklog/tasks/20260914-yuxi-embedding-ml-a174ed62.md @@ -20,12 +20,15 @@ - Concurrent Task Gate passed through the official project-docs check/start/status flow. This feature worktree is isolated from the MakeLore main checkout and other active tasks; the UX integration base is already present at the recorded base commit. - The user decided that Yuxi maintains embedding providers, endpoint/API key, enabled embedding models, and dimensions. one-api does not configure embeddings; Works Square remains the creator Token Point ledger only. +- The user subsequently clarified that embedding vectorization is paid by the platform: it must not enter user usage, Token Point deductions, or Agent ceilings. Knowledge processing that triggers dialogue-model calls remains subject to the original model billing rules. - The client should tell administrators to configure the provider and model in Yuxi, then refresh the knowledge/model directory. Remove the old Works Square activation, one-api vector-interface, and cross-end model-ID matching instructions. - Scope is limited to the client knowledge configuration copy, shared client typing where needed to retain `dimension`, focused test fixtures/assertions, and synchronized README wording. No Yuxi, Works Square, AgentBus, authentication, payment, installation, or deployment changes. ## Outcome - The knowledge panel and README now describe Yuxi-owned embedding configuration. The old Works Square activation, one-api vector-interface, and cross-end model-ID matching instructions were removed. The client catalog state now uses the shared model contract, including `dimension`; no embedding-specific Works/one-api filtering was present or added. +- This continuation updates the knowledge upload/indexing explanation, the empty-model guidance, the cost-ceiling explanation, and the cost-source label so platform-funded embedding is separated from billable dialogue-model calls. +- The final wording correction removes the unsupported billable OCR implication: knowledge processing is described as billing only dialogue-model calls under the original rules, while embedding remains platform-funded and outside user usage, Token Points, and Agent ceilings. ## Verification @@ -34,12 +37,14 @@ - `pnpm run typecheck` passed; scoped ESLint for the changed client and test files passed; `git diff --check` passed. - `pnpm run build:vite` passed Renderer, Main, Preload, and utility targets with the repository's existing Browserslist, chunk-size, and mixed-import warnings. - `pnpm exec playwright test tests/e2e/cloud-agents.spec.ts` passed 1/1 scenario, including the updated Yuxi-only empty-catalog guidance. -- The fresh independent Reviewer completed the shared three-service review with Standards PASS and Spec PASS. The MakeLore client, README, and focused test changes had no blocking findings and require no further product changes; the review record is `D:\\Datas\\OthersProjects\\.codex-worktrees\\makelore\\20260914-embedding-review-ml-4e8b\\.project-docs\\30-worklog\\tasks\\20260914-embedding-review-ml-4e8b.md`. +- Follow-up correction verification: the focused knowledge/workflows unit run passed 22/22; the rebuilt Vite bundle passed; the cloud-agent Electron E2E passed 1/1 with the platform-funded embedding and billable dialogue-model assertions; typecheck and scoped ESLint passed (one existing CloudCosts hooks warning remains). +- The replacement fresh independent Reviewer completed the shared three-service review with Standards PASS and Spec PASS. The MakeLore client, README, and focused test changes had no blocking findings and require no further product changes; the review record is `D:\\Datas\\OthersProjects\\.codex-worktrees\\makelore\\20260915-embedding-final-review-ml-c58f10\\.project-docs\\30-worklog\\tasks\\20260915-embedding-final-review-ml-c58f10.md`. +- The user authorized this batch to be committed and merged into the repository main branch. The integration task and main checkout remain owned by the parent agent; this feature task only hands off the reviewed source commit. - No live Yuxi/Works request, production configuration, packaging, deployment, or remote push was performed. ## Follow-ups -- Integration must include the resulting source commit. A rebuilt client is required before users see the updated guidance. +- Integration must include the resulting source commit, and a rebuilt client is required before users see the updated guidance. ## Promotion Candidates diff --git a/README.md b/README.md index 9648f04..86d4661 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,11 @@ Makelore 是一个面向软件、视觉创作、智能机器人与个人云智能体的 AI 桌面工作台。当前版本为 `2.0.0`,源码提供四个模块入口;云智能体需配套配置 WS/Yuxi 服务。模块入口页按 Agents、Code、Canvas、Robot 排列,统一采用横向插画卡片;Agents 标语为“打造你想象中的AI助手”。工作区左上角入口点击后返回模块入口页: - `Makelore Code|AI 编程`:管理本地项目、项目智能体、对话、文件上下文、代码变更和运行时。 -- `Makelore Agents|AI 智能体`:配置个人云智能体并试聊,发布后正式对话、按账号分享或创建应用 API Key。支持流式回复、审批、排队请求、附件与产物、自动任务和活动历史;重新进入时恢复最近智能体与对话,未确认操作可按原输入重试。聊天可提出日程建议,由创建者核对能力、时间和费用后启用。知识库支持上传、索引、替换、删除及导入本人会话附件;个人 MCP 凭据、Skills、子智能体可自助管理。支持智能体和会话归档、发布版本比较及恢复为草稿。所有模型调用由创建者个人词元点数支付,可按智能体设置每次任务和每日上限,费用按时间、来源、应用分页统计;分享/API 调用者保有自己的内容空间。Main 管理云会话和本机文件,Renderer 通过 Host API 操作。配套服务接入见 [Yuxi MakeLore 说明](https://xerrors.github.io/Yuxi/advanced/makelore-agents.html)。 编辑采用全高桌面分栏,支持拖动调整与展开、独立滚动、小窗口配置/试用切换。首次创建按选用途、说要求、试一试引导,提供科学问答、故事、英语和笔记整理起点;回答方式可多选,特别要求直接编辑,仍以草稿的 system_prompt 保存。新助手预选云端目录的第一个可用模型并明确显示,可自行更换;已有助手不自动换模型。能力、知识与限制折叠到高级设置。草稿明确保存(Ctrl/⌘+S),保存与切换页面保留当前试用及未发送文字;“保存并重新试用”使用最新保存的要求,保留上次试用供对比,并可复用上次问题,不自动发送。示例问题仅填入输入框;有运行、排队、审批或未确认操作时先处理当前试用。工具确认先展示实际操作说明与参数,完整技术详情可展开。确认“开始使用”会创建仅自己可用的发布版本并进入独立对话,分享与应用仍单独开启。费用上限在限制中独立保存。Enter 发送、Shift+Enter 换行,F6 切换面板焦点、Esc 恢复分栏。 +- `Makelore Agents|AI 智能体`:配置个人云智能体并试聊,发布后正式对话、按账号分享或创建应用 API Key。支持流式回复、审批、排队请求、附件与产物、自动任务和活动历史;重新进入时恢复最近智能体与对话,未确认操作可按原输入重试。聊天可提出日程建议,由创建者核对能力、时间和费用后启用。知识库支持上传、索引、替换、删除及导入本人会话附件;个人 MCP 凭据、Skills、子智能体可自助管理。支持智能体和会话归档、发布版本比较及恢复为草稿。除知识库 embedding 向量化外,模型调用(包括知识处理触发的对话模型调用)仍按原规则由创建者个人词元点数支付,可按智能体设置每次任务和每日上限,费用按时间、来源、应用分页统计;embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限;分享/API 调用者保有自己的内容空间。Main 管理云会话和本机文件,Renderer 通过 Host API 操作。配套服务接入见 [Yuxi MakeLore 说明](https://xerrors.github.io/Yuxi/advanced/makelore-agents.html)。 编辑采用全高桌面分栏,支持拖动调整与展开、独立滚动、小窗口配置/试用切换。首次创建按选用途、说要求、试一试引导,提供科学问答、故事、英语和笔记整理起点;回答方式可多选,特别要求直接编辑,仍以草稿的 system_prompt 保存。新助手预选云端目录的第一个可用模型并明确显示,可自行更换;已有助手不自动换模型。能力、知识与限制折叠到高级设置。草稿明确保存(Ctrl/⌘+S),保存与切换页面保留当前试用及未发送文字;“保存并重新试用”使用最新保存的要求,保留上次试用供对比,并可复用上次问题,不自动发送。示例问题仅填入输入框;有运行、排队、审批或未确认操作时先处理当前试用。工具确认先展示实际操作说明与参数,完整技术详情可展开。确认“开始使用”会创建仅自己可用的发布版本并进入独立对话,分享与应用仍单独开启。费用上限在限制中独立保存。Enter 发送、Shift+Enter 换行,F6 切换面板焦点、Esc 恢复分栏。 - 云知识库的向量模型由平台管理员在 Yuxi 后台维护:在「智能体管理 → 模型供应商」启用供应商,按供应商要求填写有效的服务地址和 API Key,添加并启用 embedding 模型并填写实际向量维度;one-api 不参与向量模型配置,Works Square 只负责创建者词元点数账本。客户端区分目录加载中、加载失败与无可用模型,空状态提供管理员配置说明;「刷新知识库与模型」保留未提交名称,未确认的创建请求沿用原操作身份。 + 云知识库的 embedding 模型只由平台管理员在 Yuxi 后台维护:在「智能体管理 → 模型供应商」启用供应商,按供应商要求填写有效的服务地址和 API Key,添加并启用 embedding 模型并填写实际向量维度;embedding 向量化费用由平台承担,不计入用户用量、词元点数或智能体费用上限;one-api 不参与 embedding 配置,Works Square 只负责其他应计费模型调用的创建者词元点数账本。客户端区分目录加载中、加载失败与无可用模型,空状态提供管理员配置说明;「刷新知识库与模型」保留未提交名称,未确认的创建请求沿用原操作身份。 - Agents 侧栏的「渠道」统一管理个人微信账号。每个账号由唯一扫码微信身份连接,可以在发布智能体前先扫码,之后选择或更换目标智能体;多个微信账号可以使用同一个已发布智能体,切换目标不需要重新扫码。账号可单独启用、暂停、重新连接或断开,不提供联系人邀请或授权调用者管理。Agent 的「使用与分享」只展示已关联渠道并提供定位入口。选中账号的二级详情保留运行/投递活动、失败文件补发和微信对话;对话可审批、停止、新开一段并保存实际产物,不同账号的会话相互隔离。自动任务可明确选择把结果发送到已经开始对话的微信账号,暂停保留目标;所有模型调用仍由智能体创建者支付,费用统计包含微信渠道。渠道需要配套版本的 AgentBus Core/微信 Adapter、Yuxi 和 Works Square,桌面用户无需填写服务凭据。Main 保管操作恢复记录,重开界面不会自动重发绑定或执行请求;验证码不写入恢复记录,已移除的联系人权限操作记录只能丢弃。用户与应用分享不属于微信渠道账号管理范围。 + Agents 侧栏的「渠道」统一管理个人微信账号。每个账号由唯一扫码微信身份连接,可以在发布智能体前先扫码,之后选择或更换目标智能体;多个微信账号可以使用同一个已发布智能体,切换目标不需要重新扫码。账号可单独启用、暂停、重新连接或断开,不提供联系人邀请或授权调用者管理。Agent 的「使用与分享」只展示已关联渠道并提供定位入口。选中账号的二级详情保留运行/投递活动、失败文件补发和微信对话;对话可审批、停止、新开一段并保存实际产物,不同账号的会话相互隔离。自动任务可明确选择把结果发送到已经开始对话的微信账号,暂停保留目标;渠道触发的聊天等应计费模型调用仍由智能体创建者支付,费用统计包含微信渠道。渠道需要配套版本的 AgentBus Core/微信 Adapter、Yuxi 和 Works Square,桌面用户无需填写服务凭据。Main 保管操作恢复记录,重开界面不会自动重发绑定或执行请求;验证码不写入恢复记录,已移除的联系人权限操作记录只能丢弃。用户与应用分享不属于微信渠道账号管理范围。 - `Makelore Canvas|AI 绘画`:每个设计项目(Workspace)维护一份从创建起就存在的 Living Form。左侧项目栏负责新建、切换和管理 Workspace,并在桌面设计模式下以 256px 宽度常驻展开;中央沿用 AI 编程的安静对话画布、自然消息流和底部悬浮输入器,AI 整理出的制作方案作为对话内的轻量可编辑稿持续更新;桌面端右侧同为 256px 的全高历史作品栏集中展示当前项目的制作记录与生成结果。紧凑窗口通过左侧抽屉访问项目列表,历史记录保留在时间线中。参考图从本地上传后以 `@图片N` 绑定,具体用法只写在创作提示词中。 - `Makelore Robot|AI 机器`:管理机器人智能体、设备激活绑定、智能体配置与设备分配;机器人工作台的智能体位于 Robot 全局侧栏,选中后在内容区先查看绑定设备、再查看基础设置,当前智能体通过 URL 参数保持可分享选择;绑定设备时默认先选择“引导配网”或“已有激活码”。在 Windows 与 macOS 的引导路径中,Makelore 可在弹窗内扫描并连接附近开放的 `Xiaozhi-*` 配网热点,失败时仍可通过系统 Wi-Fi 手动连接;后续继续复用机器人现有热点配网页面,不修改固件,也不由 Makelore 接收 Wi-Fi 密码。 diff --git a/src/pages/CloudAgents/CloudCosts.tsx b/src/pages/CloudAgents/CloudCosts.tsx index 340da2f..17761d2 100644 --- a/src/pages/CloudAgents/CloudCosts.tsx +++ b/src/pages/CloudAgents/CloudCosts.tsx @@ -6,7 +6,7 @@ import type { CloudApplication, CloudBudget, CloudCostPage, CloudCostSource } fr import { usePendingCloudInput } from './CloudPending'; const message = (e: unknown) => e instanceof Error ? e.message : '费用服务暂不可用'; -const sources: Record = { self: '自己使用', shared: '分享', api: 'API', scheduled: '自动任务', preview: '草稿预览', knowledge: '知识库处理', channel: '微信渠道' }; +const sources: Record = { self: '自己使用', shared: '分享', api: 'API', scheduled: '自动任务', preview: '草稿预览', knowledge: '知识库模型调用', channel: '微信渠道' }; export function CloudBudgetEditor({ slug }: { slug: string }) { const [budget, setBudget] = useState(null); @@ -24,7 +24,7 @@ export function CloudBudgetEditor({ slug }: { slug: string }) { }, [slug, accept]); return

费用上限

-

这个智能体的自用、分享、API、微信渠道和自动任务共同计入。单次任务包含多轮模型调用及子智能体;知识库处理也计入费用。留空表示不设额外上限,填写 0 可暂停新增模型调用。

+

这个智能体的自用、分享、API、微信渠道和自动任务共同计入。单次任务包含多轮模型调用及子智能体;知识处理触发的对话模型调用仍按实际用量计入费用,embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限。留空表示不设额外上限,填写 0 可暂停新增模型调用。

{ e.preventDefault(); setBusy(true); setError(''); try { accept(await cloudAgentsApi.call('saveBudget', { slug, request_limit_points: requestLimit.trim() || null, daily_limit_points: dailyLimit.trim() || null })); } diff --git a/src/pages/CloudAgents/CloudKnowledge.tsx b/src/pages/CloudAgents/CloudKnowledge.tsx index 09c21af..9a8e81c 100644 --- a/src/pages/CloudAgents/CloudKnowledge.tsx +++ b/src/pages/CloudAgents/CloudKnowledge.tsx @@ -65,7 +65,7 @@ export function CloudKnowledgePanel({ slug, onCreated, onDeleted }: { slug: stri return
管理我的知识文档
-

上传到知识库的文档可供获准使用此智能体的人检索。解析后建立索引才会生效,向量调用扣除你的词元点数。

+

上传到知识库的文档可供获准使用此智能体的人检索。解析并建立索引后才会生效;embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限。知识处理如触发对话模型调用,仍按原模型实际用量计费。

{error &&

{error}

} {catalogError &&

知识库与模型目录加载失败:{catalogError}。请刷新重试。

}
@@ -85,7 +85,7 @@ export function CloudKnowledgePanel({ slug, onCreated, onDeleted }: { slug: stri {catalog?.models.map(m => )} {!catalogLoading && !catalogError && catalog && !catalog.models.length &&
-

暂时没有可用的向量模型。请联系平台管理员在 Yuxi 完成配置,然后刷新。

+

暂时没有可用的向量模型。Embedding 只在 Yuxi 配置,请联系平台管理员启用后刷新;向量化费用由平台承担,不计入用户用量或智能体费用上限。

管理员配置说明
    diff --git a/tests/e2e/cloud-agents.spec.ts b/tests/e2e/cloud-agents.spec.ts index e3dbdba..16e778c 100644 --- a/tests/e2e/cloud-agents.spec.ts +++ b/tests/e2e/cloud-agents.spec.ts @@ -100,9 +100,13 @@ test('personal cloud Agent creation, draft save and leave protection in Electron await page.getByRole('button', { name: '高级设置', exact: true }).click(); await page.getByRole('button', { name: '知识', exact: true }).click(); await page.getByText('管理我的知识文档', { exact: true }).click(); + const knowledgeDescription = page.getByText(/上传到知识库的文档可供/); + await expect(knowledgeDescription).toContainText('embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限'); + await expect(knowledgeDescription).toContainText('知识处理如触发对话模型调用,仍按原模型实际用量计费'); await page.getByRole('button', { name: '新建知识库', exact: true }).click(); await expect(page.getByLabel('向量模型', { exact: true })).toBeDisabled(); await page.getByText('管理员配置说明', { exact: true }).click(); + await expect(page.getByText(/Embedding 只在 Yuxi 配置/)).toBeVisible(); await expect(page.getByText(/Yuxi 后台/)).toContainText('智能体管理 → 模型供应商'); await expect(page.getByText(/Yuxi 后台/)).toContainText('服务地址和 API Key'); await expect(page.getByText(/Works Square 运营后台|one-api/)).toHaveCount(0); diff --git a/tests/unit/cloud-agents-workflows.test.tsx b/tests/unit/cloud-agents-workflows.test.tsx index 0419c64..23691da 100644 --- a/tests/unit/cloud-agents-workflows.test.tsx +++ b/tests/unit/cloud-agents-workflows.test.tsx @@ -118,6 +118,8 @@ it('saves independent Agent ceilings and pages cost results under the active sou render(<>); const request = await screen.findByLabelText('每次任务上限(词元点数)'); await waitFor(() => expect(request).toBeEnabled()); + expect(screen.getByRole('option', { name: '知识库模型调用' })).toBeInTheDocument(); + expect(screen.getByText(/知识处理触发的对话模型调用仍按实际用量计入费用/)).toHaveTextContent('embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限'); fireEvent.change(request, { target: { value: '20.50' } }); fireEvent.change(screen.getByLabelText('每日上限(词元点数)'), { target: { value: '100' } }); fireEvent.click(screen.getByRole('button', { name: '保存费用上限' })); diff --git a/tests/unit/cloud-knowledge-catalog.test.tsx b/tests/unit/cloud-knowledge-catalog.test.tsx index 6bf0965..2f40fb8 100644 --- a/tests/unit/cloud-knowledge-catalog.test.tsx +++ b/tests/unit/cloud-knowledge-catalog.test.tsx @@ -20,8 +20,10 @@ function openCreation() { it('explains who configures an empty embedding catalog and refreshes without losing the name', async () => { api.call.mockResolvedValueOnce(empty).mockResolvedValueOnce(available); openCreation(); - expect(await screen.findByText('暂时没有可用的向量模型。请联系平台管理员在 Yuxi 完成配置,然后刷新。')).toBeVisible(); + expect(await screen.findByText('暂时没有可用的向量模型。Embedding 只在 Yuxi 配置,请联系平台管理员启用后刷新;向量化费用由平台承担,不计入用户用量或智能体费用上限。')).toBeVisible(); expect(screen.getByRole('combobox', { name: '向量模型' })).toBeDisabled(); + expect(screen.getByText(/上传到知识库的文档可供/)).toHaveTextContent('embedding 向量化由平台承担,不计入用户用量、词元点数或智能体费用上限'); + expect(screen.getByText(/上传到知识库的文档可供/)).toHaveTextContent('知识处理如触发对话模型调用,仍按原模型实际用量计费'); fireEvent.click(screen.getByText('管理员配置说明')); expect(screen.getByText(/Yuxi 后台/)).toHaveTextContent('智能体管理 → 模型供应商'); expect(screen.getByText(/Yuxi 后台/)).toHaveTextContent('服务地址和 API Key');