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 new file mode 100644 index 0000000..09b952f --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260914-yuxi-embedding-ml-a174ed62.md @@ -0,0 +1,46 @@ +# Task: 知识库向量配置改由Yuxi维护 + +## Identity + +- Task ID: 20260914-yuxi-embedding-ml-a174ed62 +- Mode: Feature +- Branch: codex/20260914-yuxi-embedding-ml-a174ed62-yuxi-embedding +- Worktree: D:\Datas\OthersProjects\.codex-worktrees\makelore\20260914-yuxi-embedding-ml-a174ed62 +- Base commit: f92753329c511d60f61c156172fdf81eab2790d5 +- Owner: codex +- Status: Ready for Integration + +## Scope + +- Update the MakeLore cloud Agent knowledge-base empty state and README configuration guidance so Yuxi is the sole embedding-model owner. +- Keep the existing `knowledge` Host API response shape (`databases` plus embedding models with `id`, `name`, and `dimension`) and make the client state use that shared contract. +- Verify that the client has no embedding-specific dependency on the Works Square or one-api model catalogs; do not change chat-model routing, account, billing, or server behavior. + +## Intent And Constraints + +- 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 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. + +## Verification + +- `pnpm install --frozen-lockfile --offline` completed with the pinned `pnpm@10.33.4`; the install did not change manifests or the lockfile. +- `pnpm exec vitest run tests/unit/cloud-knowledge-catalog.test.tsx --maxWorkers=1` passed 5/5 tests. +- `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`. +- 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. + +## Promotion Candidates + +- The README and in-product empty-state wording are the product-facing record of the accepted Yuxi embedding ownership decision; no separate canonical ADR or architecture change is proposed by this feature task. diff --git a/README.md b/README.md index 13692e5..9648f04 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Makelore 是一个面向软件、视觉创作、智能机器人与个人云智 - `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 恢复分栏。 - 云知识库的向量模型由平台管理员配置:Yuxi 后台「智能体管理 → 模型供应商」启用 embedding 模型并填写实际维度;Works Square 运营后台「模型管理」从 one-api 刷新并激活相同模型 ID。one-api 必须支持该模型的向量接口。客户端区分目录加载中、加载失败与无可用模型,空状态提供管理员配置说明;「刷新知识库与模型」保留未提交名称,未确认的创建请求沿用原操作身份。 + 云知识库的向量模型由平台管理员在 Yuxi 后台维护:在「智能体管理 → 模型供应商」启用供应商,按供应商要求填写有效的服务地址和 API Key,添加并启用 embedding 模型并填写实际向量维度;one-api 不参与向量模型配置,Works Square 只负责创建者词元点数账本。客户端区分目录加载中、加载失败与无可用模型,空状态提供管理员配置说明;「刷新知识库与模型」保留未提交名称,未确认的创建请求沿用原操作身份。 Agents 侧栏的「渠道」统一管理个人微信账号。每个账号由唯一扫码微信身份连接,可以在发布智能体前先扫码,之后选择或更换目标智能体;多个微信账号可以使用同一个已发布智能体,切换目标不需要重新扫码。账号可单独启用、暂停、重新连接或断开,不提供联系人邀请或授权调用者管理。Agent 的「使用与分享」只展示已关联渠道并提供定位入口。选中账号的二级详情保留运行/投递活动、失败文件补发和微信对话;对话可审批、停止、新开一段并保存实际产物,不同账号的会话相互隔离。自动任务可明确选择把结果发送到已经开始对话的微信账号,暂停保留目标;所有模型调用仍由智能体创建者支付,费用统计包含微信渠道。渠道需要配套版本的 AgentBus Core/微信 Adapter、Yuxi 和 Works Square,桌面用户无需填写服务凭据。Main 保管操作恢复记录,重开界面不会自动重发绑定或执行请求;验证码不写入恢复记录,已移除的联系人权限操作记录只能丢弃。用户与应用分享不属于微信渠道账号管理范围。 diff --git a/src/pages/CloudAgents/CloudKnowledge.tsx b/src/pages/CloudAgents/CloudKnowledge.tsx index 435b12d..09c21af 100644 --- a/src/pages/CloudAgents/CloudKnowledge.tsx +++ b/src/pages/CloudAgents/CloudKnowledge.tsx @@ -3,14 +3,15 @@ import { cloudAgentsApi } from '@/lib/cloud-agents-api'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { usePendingCloudInput } from './CloudPending'; -import type { CloudKnowledge, CloudKnowledgeFile, CloudThread, CloudAttachment } from '../../../shared/cloud-agents'; +import type { CloudAgentOperations, CloudKnowledge, CloudKnowledgeFile, CloudThread, CloudAttachment } from '../../../shared/cloud-agents'; const statusName: Record = { uploaded: '待解析', parsing: '解析中', parsed: '待索引', indexing: '索引中', indexed: '可检索', error_parsing: '解析失败', error_indexing: '索引失败', }; export function CloudKnowledgePanel({ slug, onCreated, onDeleted }: { slug: string; onCreated: (kb: CloudKnowledge) => void; onDeleted?: (id: string) => void }) { - const [catalog, setCatalog] = useState<{ databases: CloudKnowledge[]; models: { id: string; name: string }[] } | null>(null); + type CloudEmbeddingModel = CloudAgentOperations['knowledge']['output']['models'][number]; + const [catalog, setCatalog] = useState<{ databases: CloudKnowledge[]; models: CloudEmbeddingModel[] } | null>(null); const [kbId, setKbId] = useState(''); const [files, setFiles] = useState([]); const [next, setNext] = useState(null); @@ -84,13 +85,13 @@ export function CloudKnowledgePanel({ slug, onCreated, onDeleted }: { slug: stri {catalog?.models.map(m => )} {!catalogLoading && !catalogError && catalog && !catalog.models.length &&
-

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

+

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

管理员配置说明
    -
  1. Yuxi 后台「智能体管理 → 模型供应商」:启用供应商,添加并启用 embedding 模型,填写模型实际向量维度。
  2. -
  3. Works Square 运营后台「模型管理」:从 one-api 刷新,激活同一模型并保存。
  4. -
  5. 两端模型 ID 必须完全一致,one-api 需支持该模型的向量接口。配置完成后点击「刷新知识库与模型」。
  6. +
  7. Yuxi 后台「智能体管理 → 模型供应商」:启用供应商,按供应商要求填写有效的服务地址和 API Key。
  8. +
  9. 在同一后台添加并启用 embedding 模型,填写该模型的实际向量维度。
  10. +
  11. 配置完成后回到这里点击「刷新知识库与模型」。
} diff --git a/tests/e2e/cloud-agents.spec.ts b/tests/e2e/cloud-agents.spec.ts index 1ce20c5..e3dbdba 100644 --- a/tests/e2e/cloud-agents.spec.ts +++ b/tests/e2e/cloud-agents.spec.ts @@ -38,7 +38,7 @@ test('personal cloud Agent creation, draft save and leave protection in Electron if (path.endsWith('/actions')) { const input = body.input ?? {}; if (body.operation === 'catalog') return result({ models: [{ id: 'test-model', name: '创作模型' }], resources: {}, pricing: null }); - if (body.operation === 'knowledge') return result({ databases: [], models: ++knowledgeCatalogLoads === 1 ? [] : [{ id: 'fixture:test-embedding', name: '资料向量模型' }] }); + if (body.operation === 'knowledge') return result({ databases: [], models: ++knowledgeCatalogLoads === 1 ? [] : [{ id: 'fixture:test-embedding', name: '资料向量模型', dimension: 1024 }] }); if (body.operation === 'resources') return result({ mcps: [], skills: [], subagents: [] }); if (body.operation === 'budget' || body.operation === 'saveBudget') { if (body.operation === 'saveBudget') limits = input; @@ -104,7 +104,8 @@ test('personal cloud Agent creation, draft save and leave protection in Electron await expect(page.getByLabel('向量模型', { exact: true })).toBeDisabled(); await page.getByText('管理员配置说明', { exact: true }).click(); await expect(page.getByText(/Yuxi 后台/)).toContainText('智能体管理 → 模型供应商'); - await expect(page.getByText(/Works Square 运营后台/)).toBeVisible(); + await expect(page.getByText(/Yuxi 后台/)).toContainText('服务地址和 API Key'); + await expect(page.getByText(/Works Square 运营后台|one-api/)).toHaveCount(0); await page.getByLabel('知识库名称', { exact: true }).fill('我的创作资料'); await page.screenshot({ path: testInfo.outputPath('knowledge-empty.png') }); await page.getByRole('button', { name: '刷新知识库与模型', exact: true }).click(); diff --git a/tests/unit/cloud-knowledge-catalog.test.tsx b/tests/unit/cloud-knowledge-catalog.test.tsx index ebc26f3..6bf0965 100644 --- a/tests/unit/cloud-knowledge-catalog.test.tsx +++ b/tests/unit/cloud-knowledge-catalog.test.tsx @@ -6,7 +6,7 @@ const api = vi.hoisted(() => ({ call: vi.fn() })); vi.mock('@/lib/cloud-agents-api', () => ({ cloudAgentsApi: api })); const slug = 'ml-' + 'a'.repeat(32); const empty = { databases: [], models: [] }; -const available = { ...empty, models: [{ id: 'relay:fixture-embedding', name: '资料向量模型' }] }; +const available = { ...empty, models: [{ id: 'relay:fixture-embedding', name: '资料向量模型', dimension: 1024 }] }; beforeEach(() => vi.resetAllMocks()); afterEach(cleanup); @@ -20,11 +20,12 @@ 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('暂时没有可用的向量模型。请联系平台管理员完成云端配置,然后刷新。')).toBeVisible(); + expect(await screen.findByText('暂时没有可用的向量模型。请联系平台管理员在 Yuxi 完成配置,然后刷新。')).toBeVisible(); expect(screen.getByRole('combobox', { name: '向量模型' })).toBeDisabled(); fireEvent.click(screen.getByText('管理员配置说明')); expect(screen.getByText(/Yuxi 后台/)).toHaveTextContent('智能体管理 → 模型供应商'); - expect(screen.getByText(/Works Square 运营后台/)).toHaveTextContent('模型管理'); + expect(screen.getByText(/Yuxi 后台/)).toHaveTextContent('服务地址和 API Key'); + expect(screen.queryByText(/Works Square 运营后台|one-api/)).not.toBeInTheDocument(); fireEvent.change(screen.getByRole('textbox', { name: '知识库名称' }), { target: { value: '创作资料' } }); fireEvent.click(screen.getByRole('button', { name: '刷新知识库与模型' })); expect(await screen.findByRole('option', { name: '资料向量模型' })).toBeInTheDocument();