mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-01 15:30:52 +08:00
Release v1.62.0
This commit is contained in:
@@ -57,6 +57,8 @@ internal/exec-plans/*
|
||||
!internal/exec-plans/agent-tools-test-batches/*.md
|
||||
!internal/exec-plans/devlime-codex-claude-alignment-gap-list.md
|
||||
!internal/exec-plans/app-server-implementation-plan.md
|
||||
!internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md
|
||||
!internal/exec-plans/tauri-wrapper-command-inventory.md
|
||||
internal/roadmap/**
|
||||
!internal/roadmap/
|
||||
!internal/roadmap/appserver/
|
||||
|
||||
@@ -32,10 +32,11 @@
|
||||
8. **新增命名禁止品牌前缀** - 新程序、目录、crate/package、Electron IPC channel、App Server 方法、API 网关、类型、模块和脚本默认不得添加 `Lime` / `lime_` / `lime-` 品牌前缀;直接使用领域名,如 `app_server_*`、`app-server`。只有对外发布品牌标识、历史兼容或第三方生态已固定命名时才允许保留,并在执行计划说明原因
|
||||
9. **`scripts/` 根目录冻结** - `scripts/` 根目录是历史入口区,不再作为新增脚本默认落点;新增可执行脚本默认放到 `scripts/<domain>/`、`scripts/lib/` 或所属 package,并通过 `npm run governance:scripts` 守住根目录基线。只有公开稳定入口且无法归入领域子目录时才允许例外,必须同步 `scripts/README.md`、`scripts/script-root-governance-baseline.json` 和执行计划退出条件
|
||||
10. **新增 Agent 逻辑默认走 App Server** - 新 AI Agent、runtime、host integration、跨 App 复用能力默认落到 `app-server` crates、JSON-RPC 协议、client 与 RuntimeCore;Electron 只作为 Desktop Host bridge,负责 IPC、窗口、托盘、Dock、updater 和 sidecar 生命周期,不是第二套后端或业务 adapter;`agent_runtime_*` / Aster 旧命令只作为 Desktop 兼容 facade,不再直接承接新业务逻辑,除非执行计划明确说明过渡原因和退出条件
|
||||
11. **Electron 打包事实源统一 Forge** - Electron packaging / installer / signing / notarization / updater metadata 的 current 配置只允许走 `forge.config.mjs`、`electron-forge package`、`electron-forge make` 与 Forge 官方 maker;运行时更新只允许走 `electron/updateHost.ts` + Electron 内置 `autoUpdater`。旧 builder 配置 / CLI、自定义 Windows installer maker、旧 YAML / blockmap updater metadata 均按 `dead` 处理,不得新增引用或写回文档、CI、守卫、i18n evidence;Windows current installer 为 Forge Squirrel,macOS current updater metadata 为 `RELEASES.json`,Windows current updater metadata 为 `RELEASES`。
|
||||
12. **不要继续扩展 compat / deprecated 路径** - 新 API、新命令、新前端入口默认落在当前 `current` 主路径
|
||||
13. **规划改了且明确无需兼容时,优先删旧实现** - 如果用户已明确“上一版无人使用 / 不用兼容 / 旧实现阻碍主线”,旧实现默认按 `dead` 或带退出条件的 `deprecated` 处理,不要继续修补、包裹或平移
|
||||
14. **`legacy current reference` 不是续命许可** - 旧路线图、旧实现锚点只用于理解现状与迁移,不等于允许继续往旧页面、旧命令、旧协议上加功能
|
||||
11. **`lime-rs/src/commands/**` 只做旧 Tauri wrapper 删除清理** - 该目录不再承接新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub;允许触碰的场景只剩删除旧 wrapper、撤 runner / dispatcher / catalog / mock 注册后的机械编译修复,或记录无法删除的 blocker。新增 Rust 后端能力必须落到 App Server crates / RuntimeCore / services 等 current 事实源;桌面壳能力落到 Electron Desktop Host
|
||||
12. **Electron 打包事实源统一 Forge** - Electron packaging / installer / signing / notarization / updater metadata 的 current 配置只允许走 `forge.config.mjs`、`electron-forge package`、`electron-forge make` 与 Forge 官方 maker;运行时更新只允许走 `electron/updateHost.ts` + Electron 内置 `autoUpdater`。旧 builder 配置 / CLI、自定义 Windows installer maker、旧 YAML / blockmap updater metadata 均按 `dead` 处理,不得新增引用或写回文档、CI、守卫、i18n evidence;Windows current installer 为 Forge Squirrel,macOS current updater metadata 为 `RELEASES.json`,Windows current updater metadata 为 `RELEASES`。
|
||||
13. **不要继续扩展 compat / deprecated 路径** - 新 API、新命令、新前端入口默认落在当前 `current` 主路径
|
||||
14. **规划改了且明确无需兼容时,优先删旧实现** - 如果用户已明确“上一版无人使用 / 不用兼容 / 旧实现阻碍主线”,旧实现默认按 `dead` 或带退出条件的 `deprecated` 处理,不要继续修补、包裹或平移
|
||||
15. **`legacy current reference` 不是续命许可** - 旧路线图、旧实现锚点只用于理解现状与迁移,不等于允许继续往旧页面、旧命令、旧协议上加功能
|
||||
|
||||
## 工程硬规则
|
||||
|
||||
|
||||
+30
-29
@@ -1,50 +1,51 @@
|
||||
## Lime v1.61.0
|
||||
## Lime v1.62.0
|
||||
|
||||
<sub>The Simplified Chinese release notes are the primary version. This English page is a companion for international readers.</sub>
|
||||
|
||||
### New Features
|
||||
|
||||
- Added App Server JSON-RPC current protocols for automation jobs, covering scheduler config, scheduler status, job list/read/create/update/delete, run now, health, run history, schedule preview, and schedule validation.
|
||||
- Moved model Provider management onto the App Server current path, covering Provider list, catalog, read, create, update, delete, sort order, config import/export, connection tests, chat tests, model fetching, API key management, key rotation, usage/error records, and UI state persistence.
|
||||
- Expanded both the TypeScript and Rust App Server clients with typed automation and model Provider methods backed by shared protocol constants and schemas.
|
||||
- Added an Electron runtime wrapper and continued routing Electron Desktop Host commands into App Server current data surfaces.
|
||||
- Expanded the App Server JSON-RPC file-system mutation protocol with create-directory, create-file, delete-file, rename-file, and a shared mutation response shape.
|
||||
- Added the usage statistics current data surface, including summary reads, daily trends, model rankings, and range parameters backed by protocol schemas.
|
||||
- Moved knowledge pack detail reads onto the App Server `knowledgePack/read` current path.
|
||||
- Expanded Agent Runtime typed clients across sessions, threads, artifacts, export, media, objectives, sites, subagents, and inventory.
|
||||
- Improved Agent App cloud bootstrap, install-state projections, and app logo/icon display for clearer runtime state and visual identity.
|
||||
- Added a built-in Lime logo fallback on the startup screen when external icon assets are unavailable.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fixed automation settings and job APIs so missing required App Server results fail closed instead of falling back to legacy commands.
|
||||
- Fixed API Key Provider and model Provider flows so reads, writes, tests, imports, and exports no longer depend on legacy `safeInvoke` paths.
|
||||
- Fixed unregistered desktop-host mock commands silently succeeding; explicit test mocks now fail closed unless a command is registered.
|
||||
- Fixed diagnostic-only APIs being mixed with production API behavior by introducing a dedicated diagnostic facade.
|
||||
- Fixed the risk of automation `runNow` falling back to the old Tauri executor before the App Server automation executor is fully migrated.
|
||||
- Fixed several frontend APIs that could still fall back to renderer mocks or legacy paths when App Server or Electron current routes were unavailable.
|
||||
- Fixed stale MCP errors remaining after successful server-list refreshes and stopped automatic external-app imports on the first empty MCP list.
|
||||
- Fixed shape mismatches in MCP server/tool reads, Agent Runtime session reads, and App Server artifact reads that could lead to incorrect UI state.
|
||||
- Tightened official Skill marketplace response validation for envelopes, lists, bundles, and visual assets.
|
||||
- Fixed Electron main-window options, IPC channels, and host-command boundaries that were missing current allowlist or test coverage.
|
||||
- Tightened browser, model, skill, session-file, config-system, and related desktop-host mocks so tests cannot accidentally simulate production capabilities.
|
||||
- Removed a duplicate Agent App install-success toast from the install review flow.
|
||||
|
||||
### Improvements And Refactors
|
||||
|
||||
- Continued consolidating frontend API gateways for automation, model Providers, file browsing, session files, knowledge, memory, MCP, voice, updates, and workspaces around App Server and Electron current boundaries.
|
||||
- Removed old automation Rust command and DevBridge dispatcher paths, classifying the legacy automation command family as dead surface.
|
||||
- Reduced the default `src/lib/desktop-host/*Mocks` surface so production paths cannot fake App Server capabilities through default mocks.
|
||||
- Removed obsolete `webview-api` exposure and types to reduce overlap between browser runtime helpers and the desktop current path.
|
||||
- Moved more automation, Provider, and file-browser responsibilities into the App Server local data source, reducing old compatibility wrappers in the services crate.
|
||||
- Updated command-boundary governance with current automation and Provider method lists plus legacy-command regression guards.
|
||||
- Continued consolidating DevBridge dispatchers around the App Server and Desktop Host current paths, removing or shrinking old agent-session export, files, models, voice, and workspace branches.
|
||||
- Significantly reduced the default `src/lib/desktop-host/*Mocks` surface so unregistered mock commands fail by default.
|
||||
- Kept App Server protocol schema export, Rust clients, TypeScript clients, and contract guards synchronized as new protocol methods are added.
|
||||
- Continued moving file browsing, connect, memory, project resources, gallery materials, provider, server runtime, voice, update, and related frontend gateways onto current boundaries.
|
||||
- Added a dedicated Rust usage statistics service and routed App Server processor/runtime/local data source responsibilities through it.
|
||||
- Changed old Connect Tauri commands to explicit retired-command errors; production now routes through Electron deep-link bridge and App Server JSON-RPC.
|
||||
|
||||
### Tests And Quality
|
||||
|
||||
- Expanded App Server client contracts for automation and model Provider protocols, schemas, TypeScript client methods, and Rust client methods.
|
||||
- Added command-contract guards that block legacy automation and Provider commands from returning through Tauri commands, DevBridge dispatchers, mock priority commands, or runtime surfaces.
|
||||
- Added targeted regressions for automation APIs, API Key Provider, model Providers, execution runs, session files, hint routes, document export, image search, video generation, and voice models.
|
||||
- Added desktop-host mock-boundary tests to ensure unregistered mocks fail closed and test fixtures explicitly register commands.
|
||||
- Expanded Electron host command, IPC channel, update host, App Server host, and current entrypoint coverage.
|
||||
- Improved Vitest smart-runner and test-file filtering coverage for more stable focused validation.
|
||||
- Updated the root app, Rust workspace, CLI npm package, Agent App runtime package, App Server client package, and lockfiles to `1.61.0`.
|
||||
- Expanded App Server client contracts for file-system mutations, usage statistics, Agent Runtime clients, schema export, and Rust/TypeScript client synchronization.
|
||||
- Added targeted regressions for MCP hooks, MCP fail-closed behavior, manual import behavior, Agent Runtime agent/media/objective/site/subagent/thread/export clients, App Server read models, file-system APIs, and usage stats.
|
||||
- Expanded Agent Apps page, ViewModel, cloud bootstrap, official Skill marketplace, desktop-host mock-boundary, and `webview-api` coverage.
|
||||
- Added production UI command current-boundary, Knowledge current-boundary, and Rust command current-boundary guards.
|
||||
- Continued guarding command contracts against legacy, mock priority, and old DevBridge paths returning into current production routes.
|
||||
- Updated the root app, Rust workspace, CLI npm package, Agent App runtime package, App Server client package, and lockfiles to `1.62.0`.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Updated Desktop Host / App Server command-boundary documentation for automation, model Providers, file browsing, mocks, DevBridge, and legacy surface classification.
|
||||
- Updated the App Server frontend integration matrix and implementation plan with automation and Provider migration progress.
|
||||
- Updated quality workflow and Playwright/E2E guidance to keep GUI validation centered on real Electron Desktop Host plus App Server paths.
|
||||
- Updated Agent App, Agent UI, Managed Objective, and Skill Forge roadmap notes where current command boundaries changed.
|
||||
- Updated App Server protocol schemas and manifest with machine-readable definitions for usage statistics, file-system mutations, and knowledge pack reads.
|
||||
- Kept five-locale i18n resources in sync for official Skill marketplace invalid-response errors and removed the unused install-success copy.
|
||||
|
||||
### Other
|
||||
|
||||
- Continued reducing old Tauri, legacy desktop facade, and renderer mock influence on production paths so release facts, command boundaries, and GUI validation stay on the current single path.
|
||||
- Continued reducing old Tauri, legacy desktop facade, and renderer mock influence on GUI production paths so release facts center on App Server JSON-RPC, Electron Desktop Host, and current clients.
|
||||
|
||||
**Full changes**: `v1.60.0` -> `v1.61.0`
|
||||
**Full changes**: `v1.61.0` -> `v1.62.0`
|
||||
|
||||
+30
-29
@@ -1,42 +1,43 @@
|
||||
## Lime v1.61.0
|
||||
## Lime v1.62.0
|
||||
|
||||
### 新功能
|
||||
- App Server JSON-RPC 新增自动化任务 current 协议,覆盖调度器配置、状态读取、任务列表 / 详情 / 创建 / 更新 / 删除、立即运行、健康检查、运行历史、计划预览与计划校验。
|
||||
- 模型 Provider 管理迁移到 App Server current 主链,覆盖 Provider 列表、目录、详情、新建、更新、删除、排序、配置导入导出、连接测试、聊天测试、模型拉取、API Key 管理、Key 轮转、使用 / 错误记录与 UI state 持久化。
|
||||
- TypeScript 与 Rust App Server client 补齐自动化和模型 Provider 的类型化客户端方法,前端、Electron 与 Rust 侧共享同一组协议常量和 schema。
|
||||
- Electron Desktop Host 新增 Electron runtime 封装,并继续把 host command 收敛到 App Server current 数据面。
|
||||
- App Server JSON-RPC 扩展文件系统写入协议,覆盖创建目录、创建文件、删除文件和重命名文件,并补齐统一 mutation response。
|
||||
- App Server 新增使用统计 current 数据面,支持摘要读取、日期趋势、模型排行与区间参数,前端 `usageStats` 网关迁移到同一组协议 schema。
|
||||
- 知识包详情读取迁移到 App Server `knowledgePack/read` 主链,知识库详情页不再依赖前端 legacy command gate。
|
||||
- Agent Runtime typed client 扩展会话、线程、产物、导出、媒体、目标、站点、子代理和 inventory 能力,前端与 App Server client 共用更完整的 current 方法面。
|
||||
- Agent App 页面补充 cloud bootstrap、安装状态投影和应用 Logo / icon 展示,应用卡片和安装确认弹窗可以呈现更明确的运行时状态与视觉识别。
|
||||
- 启动页在缺少外部图标资源时使用内置 Lime 图形 Logo 兜底,避免退回纯文字块。
|
||||
|
||||
### 修复
|
||||
- 修复自动化设置和任务 API 缺少 App Server 必需返回值时可能被旧路径伪装成功的问题,现在会 fail closed,不再回退 legacy 命令。
|
||||
- 修复 API Key Provider / 模型 Provider 读取、写入、测试、导入导出等路径对 legacy `safeInvoke` 的依赖,App Server 不可用时明确暴露错误。
|
||||
- 修复未注册 desktop-host mock 命令可静默通过的风险,测试 mock 遇到未知命令会直接失败。
|
||||
- 修复诊断类 API 与生产 API 混用的问题,新增 diagnostic facade,避免把诊断降级误认为真实业务链路。
|
||||
- 修复自动化 `runNow` 在 App Server 执行器迁移未完成时回退旧 Tauri 执行器的风险,current 协议会拒绝旧执行器回流。
|
||||
- 修复多组前端 API 在 App Server 或 Electron current 路径不可用时可能继续走 renderer mock / legacy fallback 的问题,改为 fail closed 并暴露真实错误。
|
||||
- 修复 MCP 服务器列表刷新成功后旧错误状态残留的问题,并取消首次空列表时自动导入外部应用配置的副作用,改为用户手动触发。
|
||||
- 修复 MCP server / tool 读取、Agent Runtime session 读取、App Server artifact 读取等路径中返回形状不一致导致的 UI 状态误判。
|
||||
- 修复官方技能市场对异常响应包容过宽的问题,新增 envelope、列表、bundle 和视觉资源返回结构校验。
|
||||
- 修复 Electron 主窗口配置、IPC channel 与 host command 边界中部分命令未纳入 current 白名单或测试覆盖的缺口。
|
||||
- 修复 browser、model、skill、session file、config system 等 desktop-host mock 默认值过宽的问题,避免测试夹具误模拟生产能力。
|
||||
- 移除 Agent App 安装成功的重复 toast,避免确认弹窗关闭时产生噪声提示。
|
||||
|
||||
### 优化与重构
|
||||
- 自动化、模型 Provider、文件浏览、会话文件、知识、记忆、MCP、语音、更新、工作区等前端 API 网关继续收敛到 App Server / Electron current 边界。
|
||||
- 删除旧自动化 Rust command 与 DevBridge dispatcher,旧自动化命令族进入治理层 dead surface。
|
||||
- 大幅收缩 `src/lib/desktop-host/*Mocks` 默认 mock 面,生产路径不再通过 default mock 伪造 App Server 能力。
|
||||
- 移除旧 `webview-api` 暴露面中的过时类型和入口,减少浏览器运行时与桌面 current 主链的重叠。
|
||||
- App Server 本地数据源吸收自动化、Provider 与文件浏览相关能力,降低 services crate 中旧兼容包装的职责。
|
||||
- 命令边界文档和治理目录补充自动化 / Provider current 方法清单及旧命令禁回流规则。
|
||||
- DevBridge dispatcher 继续收敛到 App Server / Desktop Host current 主链,删除或收缩旧 agent session export、files、models、voice、workspace 等 dispatcher 分支。
|
||||
- `src/lib/desktop-host/*Mocks` 大幅瘦身,未显式注册的 mock 命令默认失败,减少生产路径被测试默认值掩盖的风险。
|
||||
- App Server protocol schema export、Rust client、TypeScript client 与 contract guard 同步扩展,降低协议新增时的手工同步成本。
|
||||
- 文件浏览、连接、记忆、项目资源、gallery materials、provider、server runtime、voice、update 等前端 API 网关继续向 current 边界收敛。
|
||||
- Rust services 新增独立使用统计服务,App Server processor / runtime / local data source 统一承接 usage statistics 读取职责。
|
||||
- Connect 旧 Tauri 命令改为明确退场错误,生产路径统一到 Electron deep link bridge 与 App Server JSON-RPC。
|
||||
|
||||
### 测试与质量
|
||||
- App Server client contract 扩展自动化与模型 Provider 覆盖,校验新协议、schema、TypeScript 客户端和 Rust 客户端保持同步。
|
||||
- 命令契约守卫新增自动化 / Provider 旧命令禁回流检查,阻止 legacy Tauri command、DevBridge dispatcher、mock priority 与 runtime surface 重新接入。
|
||||
- 新增自动化 API、API Key Provider、模型 Provider、执行运行、会话文件、提示路由、文档导出、图片搜索、视频生成、语音模型等定向回归。
|
||||
- 新增 desktop-host mock 边界测试,确认未注册 mock fail closed,测试夹具必须显式注册命令。
|
||||
- 扩展 Electron host command、IPC channel、update host、App Server host 与 current entrypoint 测试。
|
||||
- Vitest smart runner 与测试文件过滤逻辑补充回归,提升局部测试选择和守卫稳定性。
|
||||
- 根应用、Rust workspace、CLI npm package、Agent App runtime package、App Server client package 与锁文件版本统一更新到 `1.61.0`。
|
||||
- 新增和扩展 App Server client contract,覆盖文件系统 mutation、使用统计、Agent Runtime 多客户端、schema export 与 Rust/TypeScript client 同步。
|
||||
- 新增 MCP hooks、MCP fail-closed、手动导入行为、Agent Runtime agent/media/objective/site/subagent/thread/export、App Server read model、file system、usage stats 等定向回归。
|
||||
- 扩展 Agent Apps 页面、ViewModel、cloud bootstrap、官方 Skill marketplace、desktop-host mock 边界和 `webview-api` 测试。
|
||||
- 新增生产 UI command current boundary、Knowledge current boundary 与 Rust command current boundary 守卫,覆盖 App Server current 方法和 legacy 命令退出边界。
|
||||
- 命令契约守卫继续阻止 legacy / mock priority / DevBridge 旧入口回流到 current 生产路径。
|
||||
- 根应用、Rust workspace、CLI npm package、Agent App runtime package、App Server client package 与锁文件版本统一更新到 `1.62.0`。
|
||||
|
||||
### 文档
|
||||
- 更新 Desktop Host / App Server 命令边界,明确自动化、模型 Provider、文件浏览、mock、DevBridge 与 legacy surface 的 current / dead 分类。
|
||||
- 更新 App Server 前端集成矩阵和实施计划,记录自动化与 Provider 迁移到 App Server current 主链的进度。
|
||||
- 更新质量工作流与 Playwright / E2E 指南,继续强调 GUI 桌面产品必须通过真实 Electron Desktop Host + App Server 路径验证。
|
||||
- 更新 Agent App、Agent UI、Managed Objective、Skill Forge 等路线图中与 current 命令边界相关的说明。
|
||||
- 更新 App Server 协议 schema 与 manifest,新增机器可读协议定义,覆盖使用统计、文件系统写操作、知识包读取等能力。
|
||||
- 五语言 i18n 资源同步新增官方技能市场非法响应错误文案,并移除不再使用的安装成功文案。
|
||||
|
||||
### 其他
|
||||
- 继续减少旧 Tauri / legacy desktop facade / renderer mock 对生产路径的影响,让发版事实源、命令边界和 GUI 验证保持 current 单主链。
|
||||
- 继续减少旧 Tauri / legacy desktop facade / renderer mock 对 GUI 主路径的影响,让发布版本以 App Server JSON-RPC、Electron Desktop Host 与 current client 为单一事实源。
|
||||
|
||||
**完整变更**: `v1.60.0` -> `v1.61.0`
|
||||
**完整变更**: `v1.61.0` -> `v1.62.0`
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
- 测试与质量资料:`../internal/test/`、`../internal/tests/`、`../internal/testing/`
|
||||
- 研究、PRD、技术专题:`../internal/research/`、`../internal/prd/`、`../internal/tech/`
|
||||
- Electron 打包 / 发布 / updater 规则:`../AGENTS.md`、`../internal/aiprompts/quality-workflow.md`、`../internal/roadmap/appserver/release-updater.md`;current 打包事实源是 `forge.config.mjs` 与 Electron Forge。
|
||||
- Rust command 清理规则:`../AGENTS.md`、`../internal/aiprompts/commands.md`、`../internal/roadmap/appserver/README.md`;`lime-rs/src/commands/**` 是旧 Tauri wrapper 清理区,不再承接新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub。
|
||||
|
||||
## 维护规则
|
||||
|
||||
|
||||
@@ -399,6 +399,33 @@ describe("ElectronHostCommands MCP current source", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("ElectronHostCommands retired Knowledge legacy facade", () => {
|
||||
it.each([
|
||||
"knowledge_list_packs",
|
||||
"knowledge_get_pack",
|
||||
"knowledge_import_source",
|
||||
"knowledge_compile_pack",
|
||||
"knowledge_set_default_pack",
|
||||
"knowledge_update_pack_status",
|
||||
"knowledge_resolve_context",
|
||||
"knowledge_validate_context_run",
|
||||
])("%s 已从 Electron Host 退场,生产只能走 App Server JSONL current", async (command) => {
|
||||
const userDataDir = await createTempUserDataDir();
|
||||
const request = vi.fn();
|
||||
const host = createHost(userDataDir, () => undefined, request);
|
||||
|
||||
await expect(
|
||||
host.invoke(command, {
|
||||
request: {
|
||||
workingDir: "/workspace/project",
|
||||
name: "sample-product",
|
||||
},
|
||||
}),
|
||||
).rejects.toThrow(`Electron host command is not implemented: ${command}`);
|
||||
expect(request).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("ElectronHostCommands model provider current source", () => {
|
||||
it("get_default_provider 应忽略旧配置值并返回 App Server 当前已配置 Provider", async () => {
|
||||
const userDataDir = await createTempUserDataDir();
|
||||
|
||||
+84
-83
@@ -1,3 +1,4 @@
|
||||
/* global Buffer, process */
|
||||
import { app, shell } from "./electronRuntime";
|
||||
import {
|
||||
AppServerRequestError,
|
||||
@@ -15,7 +16,6 @@ import {
|
||||
METHOD_AGENT_SESSION_UPDATE,
|
||||
METHOD_CAPABILITY_LIST,
|
||||
METHOD_EVIDENCE_EXPORT,
|
||||
METHOD_KNOWLEDGE_PACK_LIST,
|
||||
METHOD_MODEL_LIST,
|
||||
METHOD_MODEL_PREFERENCES_LIST,
|
||||
METHOD_MODEL_PROVIDER_ALIAS_LIST,
|
||||
@@ -30,7 +30,9 @@ import {
|
||||
METHOD_MCP_TOOL_LIST,
|
||||
METHOD_PROJECT_MEMORY_READ,
|
||||
METHOD_SKILL_LIST,
|
||||
METHOD_SKILL_READ,
|
||||
METHOD_USAGE_STATS_DAILY_TRENDS_LIST,
|
||||
METHOD_USAGE_STATS_MODEL_RANKING_LIST,
|
||||
METHOD_USAGE_STATS_READ,
|
||||
METHOD_WORKSPACE_BY_PATH_READ,
|
||||
METHOD_WORKSPACE_DEFAULT_ENSURE,
|
||||
METHOD_WORKSPACE_DEFAULT_READ,
|
||||
@@ -58,7 +60,6 @@ import {
|
||||
type CapabilityDescriptor,
|
||||
type CapabilityListResponse,
|
||||
type EvidenceExportResponse,
|
||||
type KnowledgeListPacksResponse,
|
||||
type ModelListResponse,
|
||||
type ModelPreferencesListResponse,
|
||||
type ModelProviderAliasListResponse,
|
||||
@@ -73,7 +74,10 @@ import {
|
||||
type McpToolListResponse,
|
||||
type ProjectMemoryReadResponse,
|
||||
type SkillListResponse,
|
||||
type SkillReadResponse,
|
||||
type UsageStatsDailyTrendsListResponse,
|
||||
type UsageStatsModelRankingListResponse,
|
||||
type UsageStatsRangeParams,
|
||||
type UsageStatsReadResponse,
|
||||
type WorkspaceEnsureReadyResponse,
|
||||
type WorkspaceListResponse,
|
||||
type WorkspaceProjectPathResolveResponse,
|
||||
@@ -99,6 +103,9 @@ type FileManagerLocationCandidate = Omit<FileManagerLocation, "path"> & {
|
||||
path: string | null;
|
||||
};
|
||||
type ElectronKnownPathName = "home" | "desktop" | "documents" | "downloads";
|
||||
type UsageStatsSummaryWire = UsageStatsReadResponse["stats"];
|
||||
type UsageStatsModelUsageWire = UsageStatsModelRankingListResponse["ranking"][number];
|
||||
type UsageStatsDailyUsageWire = UsageStatsDailyTrendsListResponse["trends"][number];
|
||||
|
||||
const CONFIG_FILE = "config.json";
|
||||
const OEM_CLOUD_OAUTH_CALLBACK_BRIDGE_EVENT = "oem-cloud-oauth-callback";
|
||||
@@ -233,18 +240,14 @@ export class ElectronHostCommands {
|
||||
return await this.#ensureDefaultWorkspaceReady();
|
||||
case "workspace_ensure_ready":
|
||||
return await this.#ensureWorkspaceReady(args);
|
||||
case "list_executable_skills":
|
||||
return await this.#listExecutableSkills();
|
||||
case "get_local_skills_for_app":
|
||||
return await this.#listLocalSkillsForApp(args);
|
||||
case "get_skill_detail":
|
||||
return await this.#readSkillDetail(args);
|
||||
case "get_usage_stats":
|
||||
return this.#getUsageStats();
|
||||
return await this.#getUsageStats(args);
|
||||
case "get_model_usage_ranking":
|
||||
return this.#emptyDiagnosticList("get_model_usage_ranking");
|
||||
return await this.#getModelUsageRanking(args);
|
||||
case "get_daily_usage_trends":
|
||||
return this.#emptyDiagnosticList("get_daily_usage_trends");
|
||||
return await this.#getDailyUsageTrends(args);
|
||||
case "get_voice_input_config":
|
||||
return this.#getVoiceInputConfig();
|
||||
case "get_voice_shortcut_runtime_status":
|
||||
@@ -313,8 +316,6 @@ export class ElectronHostCommands {
|
||||
return await this.#cancelAgentAppRuntimeTask(args);
|
||||
case "agent_app_runtime_submit_host_response":
|
||||
return await this.#submitAgentAppRuntimeHostResponse(args);
|
||||
case "knowledge_list_packs":
|
||||
return await this.#listKnowledgePacks(args);
|
||||
case "report_frontend_debug_log":
|
||||
this.#reportFrontendDebugLog(args);
|
||||
return null;
|
||||
@@ -1221,14 +1222,6 @@ export class ElectronHostCommands {
|
||||
return response.providers;
|
||||
}
|
||||
|
||||
async #listModelProviderCatalog(): Promise<unknown[]> {
|
||||
const response =
|
||||
await this.#appServerRequest<ModelProviderCatalogListResponse>(
|
||||
METHOD_MODEL_PROVIDER_CATALOG_LIST,
|
||||
);
|
||||
return response.providers;
|
||||
}
|
||||
|
||||
async #listModels(params: AppServerParams = {}): Promise<unknown[]> {
|
||||
const response = await this.#appServerRequest<ModelListResponse>(
|
||||
METHOD_MODEL_LIST,
|
||||
@@ -1468,12 +1461,6 @@ export class ElectronHostCommands {
|
||||
return response.result;
|
||||
}
|
||||
|
||||
async #listExecutableSkills(): Promise<unknown[]> {
|
||||
const response =
|
||||
await this.#appServerRequest<SkillListResponse>(METHOD_SKILL_LIST);
|
||||
return response.skills;
|
||||
}
|
||||
|
||||
async #listLocalSkillsForApp(args: HostArgs): Promise<unknown[]> {
|
||||
const request = readRequest(args);
|
||||
const appName = readString(request, "app") ?? "lime";
|
||||
@@ -1485,23 +1472,6 @@ export class ElectronHostCommands {
|
||||
return response.skills.map(skillToLocalSkill);
|
||||
}
|
||||
|
||||
async #readSkillDetail(args: HostArgs): Promise<unknown> {
|
||||
const request = readRequest(args);
|
||||
const skillName =
|
||||
readString(request, "skillName") ??
|
||||
readString(request, "skill_name") ??
|
||||
readString(args, "skillName") ??
|
||||
readString(args, "skill_name");
|
||||
if (!skillName) {
|
||||
throw new Error("get_skill_detail requires skillName");
|
||||
}
|
||||
const response = await this.#appServerRequest<SkillReadResponse>(
|
||||
METHOD_SKILL_READ,
|
||||
{ skillName },
|
||||
);
|
||||
return response.skill;
|
||||
}
|
||||
|
||||
async #listWorkspaceSkillBindings(args: HostArgs): Promise<unknown> {
|
||||
const request = readRequest(args);
|
||||
const workspaceRoot =
|
||||
@@ -1534,42 +1504,30 @@ export class ElectronHostCommands {
|
||||
);
|
||||
}
|
||||
|
||||
async #listKnowledgePacks(args: HostArgs): Promise<unknown> {
|
||||
const request = readRequest(args);
|
||||
const workingDir =
|
||||
readString(request, "workingDir") ??
|
||||
readString(request, "working_dir") ??
|
||||
readString(args, "workingDir") ??
|
||||
readString(args, "working_dir");
|
||||
if (!workingDir) {
|
||||
throw new Error("knowledge_list_packs requires workingDir");
|
||||
}
|
||||
return await this.#appServerRequest<KnowledgeListPacksResponse>(
|
||||
METHOD_KNOWLEDGE_PACK_LIST,
|
||||
{
|
||||
workingDir,
|
||||
includeArchived:
|
||||
readBoolean(request, "includeArchived") ??
|
||||
readBoolean(request, "include_archived") ??
|
||||
false,
|
||||
},
|
||||
async #getUsageStats(args: HostArgs): Promise<Record<string, unknown>> {
|
||||
const response = await this.#appServerRequest<UsageStatsReadResponse>(
|
||||
METHOD_USAGE_STATS_READ,
|
||||
readUsageStatsParams(args),
|
||||
);
|
||||
return toLegacyUsageStats(response.stats);
|
||||
}
|
||||
|
||||
#getUsageStats(): Record<string, unknown> {
|
||||
return {
|
||||
total_conversations: 0,
|
||||
total_messages: 0,
|
||||
total_tokens: 0,
|
||||
total_time_minutes: 0,
|
||||
monthly_conversations: 0,
|
||||
monthly_messages: 0,
|
||||
monthly_tokens: 0,
|
||||
today_conversations: 0,
|
||||
today_messages: 0,
|
||||
today_tokens: 0,
|
||||
diagnostic: this.#diagnosticMeta("get_usage_stats"),
|
||||
};
|
||||
async #getModelUsageRanking(args: HostArgs): Promise<unknown[]> {
|
||||
const response =
|
||||
await this.#appServerRequest<UsageStatsModelRankingListResponse>(
|
||||
METHOD_USAGE_STATS_MODEL_RANKING_LIST,
|
||||
readUsageStatsParams(args),
|
||||
);
|
||||
return response.ranking.map(toLegacyModelUsage);
|
||||
}
|
||||
|
||||
async #getDailyUsageTrends(args: HostArgs): Promise<unknown[]> {
|
||||
const response =
|
||||
await this.#appServerRequest<UsageStatsDailyTrendsListResponse>(
|
||||
METHOD_USAGE_STATS_DAILY_TRENDS_LIST,
|
||||
readUsageStatsParams(args),
|
||||
);
|
||||
return response.trends.map(toLegacyDailyUsage);
|
||||
}
|
||||
|
||||
#getVoiceInputConfig(): Record<string, unknown> {
|
||||
@@ -1892,12 +1850,6 @@ export class ElectronHostCommands {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
#throwMissingAppServerMethod(command: string): never {
|
||||
throw new Error(
|
||||
`${command} has no Electron current adapter because no App Server JSON-RPC method is defined for it yet. Electron Host must not return synthetic empty data.`,
|
||||
);
|
||||
}
|
||||
|
||||
#reportFrontendDebugLog(args: HostArgs): void {
|
||||
const report = readRecord(args, "report");
|
||||
const level = readString(report, "level") ?? "info";
|
||||
@@ -1934,6 +1886,55 @@ function readRequest(value: unknown): Record<string, unknown> {
|
||||
return readRecord(value, "request") ?? toRecord(value) ?? {};
|
||||
}
|
||||
|
||||
function readUsageStatsParams(args: HostArgs): UsageStatsRangeParams {
|
||||
const request = readRequest(args);
|
||||
const timeRange =
|
||||
readString(request, "timeRange") ??
|
||||
readString(request, "time_range") ??
|
||||
readString(args, "timeRange") ??
|
||||
readString(args, "time_range") ??
|
||||
"month";
|
||||
return { timeRange };
|
||||
}
|
||||
|
||||
function toLegacyUsageStats(
|
||||
stats: UsageStatsSummaryWire,
|
||||
): Record<string, unknown> {
|
||||
return {
|
||||
total_conversations: stats.totalConversations,
|
||||
total_messages: stats.totalMessages,
|
||||
total_tokens: stats.totalTokens,
|
||||
total_time_minutes: stats.totalTimeMinutes,
|
||||
monthly_conversations: stats.monthlyConversations,
|
||||
monthly_messages: stats.monthlyMessages,
|
||||
monthly_tokens: stats.monthlyTokens,
|
||||
today_conversations: stats.todayConversations,
|
||||
today_messages: stats.todayMessages,
|
||||
today_tokens: stats.todayTokens,
|
||||
};
|
||||
}
|
||||
|
||||
function toLegacyModelUsage(
|
||||
item: UsageStatsModelUsageWire,
|
||||
): Record<string, unknown> {
|
||||
return {
|
||||
model: item.model,
|
||||
conversations: item.conversations,
|
||||
tokens: item.tokens,
|
||||
percentage: item.percentage,
|
||||
};
|
||||
}
|
||||
|
||||
function toLegacyDailyUsage(
|
||||
item: UsageStatsDailyUsageWire,
|
||||
): Record<string, unknown> {
|
||||
return {
|
||||
date: item.date,
|
||||
conversations: item.conversations,
|
||||
tokens: item.tokens,
|
||||
};
|
||||
}
|
||||
|
||||
function readArray(value: unknown, key: string): unknown[] | undefined {
|
||||
const record = toRecord(value);
|
||||
const next = record?.[key];
|
||||
|
||||
@@ -49,7 +49,7 @@ describe("electron/ipcChannels", () => {
|
||||
expect(isElectronHostCommand("get_api_key_providers")).toBe(false);
|
||||
expect(isElectronHostCommand("list_dir")).toBe(false);
|
||||
expect(isElectronHostCommand("read_file_preview_cmd")).toBe(false);
|
||||
expect(isElectronHostCommand("list_executable_skills")).toBe(true);
|
||||
expect(isElectronHostCommand("list_executable_skills")).toBe(false);
|
||||
expect(isElectronHostCommand("workspace_list")).toBe(true);
|
||||
expect(isElectronHostCommand("workspace_get_by_path")).toBe(true);
|
||||
expect(isElectronHostCommand("get_config")).toBe(true);
|
||||
@@ -87,6 +87,18 @@ describe("electron/ipcChannels", () => {
|
||||
expect(isElectronHostCommand("unified_memory_stats")).toBe(true);
|
||||
expect(isElectronHostCommand("get_mcp_servers")).toBe(true);
|
||||
expect(isElectronHostCommand("mcp_list_servers_with_status")).toBe(true);
|
||||
for (const command of [
|
||||
"knowledge_list_packs",
|
||||
"knowledge_get_pack",
|
||||
"knowledge_import_source",
|
||||
"knowledge_compile_pack",
|
||||
"knowledge_set_default_pack",
|
||||
"knowledge_update_pack_status",
|
||||
"knowledge_resolve_context",
|
||||
"knowledge_validate_context_run",
|
||||
]) {
|
||||
expect(isElectronHostCommand(command)).toBe(false);
|
||||
}
|
||||
expect(isElectronHostCommand("site_get_adapter_catalog_status")).toBe(true);
|
||||
expect(isElectronHostCommand("open_external_url")).toBe(true);
|
||||
expect(isElectronHostCommand("open_with_default_app")).toBe(true);
|
||||
@@ -158,9 +170,6 @@ describe("electron/ipcChannels", () => {
|
||||
"get_models_by_tier",
|
||||
"get_models_for_provider",
|
||||
"get_provider_alias_config",
|
||||
"get_skill_detail",
|
||||
"knowledge_list_packs",
|
||||
"list_executable_skills",
|
||||
"mcp_list_prompts",
|
||||
"mcp_list_resources",
|
||||
"mcp_list_servers_with_status",
|
||||
|
||||
@@ -68,9 +68,6 @@ export const ELECTRON_HOST_COMMANDS = [
|
||||
"get_voice_instructions",
|
||||
"get_voice_shortcut_runtime_status",
|
||||
"list_audio_devices",
|
||||
"get_skill_detail",
|
||||
"knowledge_list_packs",
|
||||
"list_executable_skills",
|
||||
"mcp_list_prompts",
|
||||
"mcp_list_resources",
|
||||
"mcp_list_servers_with_status",
|
||||
@@ -157,9 +154,6 @@ export const ELECTRON_APP_SERVER_TRUTH_BRIDGE_COMMANDS = [
|
||||
"get_models_by_tier",
|
||||
"get_models_for_provider",
|
||||
"get_provider_alias_config",
|
||||
"get_skill_detail",
|
||||
"knowledge_list_packs",
|
||||
"list_executable_skills",
|
||||
"mcp_list_prompts",
|
||||
"mcp_list_resources",
|
||||
"mcp_list_servers_with_status",
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
buildMainWindowStartupDataUrl,
|
||||
buildMainWindowStartupHtml,
|
||||
buildMainWindowStartupOptions,
|
||||
resolveStartupLogoDataUrl,
|
||||
} from "./mainWindowOptions";
|
||||
|
||||
describe("main window chrome options", () => {
|
||||
@@ -39,11 +40,25 @@ describe("main window chrome options", () => {
|
||||
|
||||
expect(html).toContain("Lime <Dev> "Fast"");
|
||||
expect(html).not.toContain('Lime <Dev> "Fast"');
|
||||
expect(html).toContain("startup-logo-fallback");
|
||||
expect(html).toContain('class="startup-logo"');
|
||||
expect(html).toContain("data:image/svg+xml;charset=utf-8");
|
||||
expect(html).not.toContain("startup-logo-fallback");
|
||||
expect(dataUrl.startsWith("data:text/html;charset=utf-8,")).toBe(true);
|
||||
expect(decodeURIComponent(dataUrl.split(",", 2)[1] ?? "")).toBe(html);
|
||||
});
|
||||
|
||||
it("启动页缺少外部图标资源时应保留 Lime 图形 Logo 兜底", () => {
|
||||
const fallbackLogo = resolveStartupLogoDataUrl(null);
|
||||
|
||||
expect(fallbackLogo).toMatch(/^data:image\/svg\+xml;charset=utf-8,/);
|
||||
expect(decodeURIComponent(fallbackLogo.split(",", 2)[1] ?? "")).toContain(
|
||||
"ringGrad",
|
||||
);
|
||||
expect(resolveStartupLogoDataUrl(" data:image/png;base64,abc ")).toBe(
|
||||
"data:image/png;base64,abc",
|
||||
);
|
||||
});
|
||||
|
||||
it("启动页文案应支持 Electron 侧五语言选择", () => {
|
||||
const html = buildMainWindowStartupHtml({
|
||||
appName: "Lime",
|
||||
|
||||
@@ -18,6 +18,12 @@ interface MainWindowStartupHtmlOptions {
|
||||
subtitle?: string;
|
||||
}
|
||||
|
||||
const FALLBACK_STARTUP_LOGO_SVG = `<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="ringGrad" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#064E3B"/><stop offset="35%" stop-color="#10B981"/><stop offset="70%" stop-color="#84CC16"/><stop offset="100%" stop-color="#D9F99D"/></linearGradient><linearGradient id="starGrad" x1="0%" y1="100%" x2="100%" y2="0%"><stop offset="0%" stop-color="#22C55E"/><stop offset="100%" stop-color="#ECFCCB"/></linearGradient><filter id="macOSVolume" x="-15%" y="-15%" width="130%" height="130%"><feOffset dx="2" dy="2" in="SourceAlpha" result="lightOffset"/><feComposite operator="out" in="SourceAlpha" in2="lightOffset" result="lightEdge"/><feFlood flood-color="#ffffff" flood-opacity="0.6" result="lightColor"/><feComposite operator="in" in="lightColor" in2="lightEdge" result="lightRim"/><feOffset dx="-3" dy="-3" in="SourceAlpha" result="darkOffset"/><feComposite operator="out" in="SourceAlpha" in2="darkOffset" result="darkEdge"/><feFlood flood-color="#022C22" flood-opacity="0.5" result="darkColor"/><feComposite operator="in" in="darkColor" in2="darkEdge" result="darkRim"/><feDropShadow dx="0" dy="16" stdDeviation="20" flood-color="#022C22" flood-opacity="0.15" in="SourceGraphic" result="shadowedGraphic"/><feMerge><feMergeNode in="shadowedGraphic"/><feMergeNode in="lightRim"/><feMergeNode in="darkRim"/></feMerge></filter><mask id="ringMask"><rect width="512" height="512" fill="white"/><line x1="256" y1="256" x2="-20" y2="256" stroke="black" stroke-width="14"/><line x1="256" y1="256" x2="-20" y2="532" stroke="black" stroke-width="14"/><line x1="256" y1="256" x2="256" y2="532" stroke="black" stroke-width="14"/></mask></defs><g filter="url(#macOSVolume)"><g mask="url(#ringMask)"><path d="M 256 56 A 200 200 0 0 0 56 256 A 200 200 0 0 0 256 456 A 200 200 0 0 0 456 256 L 336 256 A 80 80 0 0 1 256 336 A 80 80 0 0 1 176 256 A 80 80 0 0 1 256 176 Z" fill="url(#ringGrad)"/></g><path d="M 256 220 Q 256 256 292 256 Q 256 256 256 292 Q 256 256 220 256 Q 256 256 256 220 Z" fill="#10B981"/><path d="M 356 92 Q 356 156 420 156 Q 356 156 356 220 Q 356 156 292 156 Q 356 156 356 92 Z" fill="url(#starGrad)"/><circle cx="436" cy="62" r="10" fill="#D9F99D"/><circle cx="456" cy="100" r="5" fill="#84CC16"/></g></svg>`;
|
||||
|
||||
const FALLBACK_STARTUP_LOGO_DATA_URL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
|
||||
FALLBACK_STARTUP_LOGO_SVG,
|
||||
)}`;
|
||||
|
||||
const MAIN_WINDOW_STARTUP_COPY = {
|
||||
"zh-CN": {
|
||||
slogan: "青柠一下,灵感即来",
|
||||
@@ -60,9 +66,8 @@ export function buildMainWindowStartupHtml({
|
||||
const escapedAppName = escapeHtml(appName);
|
||||
const escapedSlogan = escapeHtml(slogan ?? copy.slogan);
|
||||
const escapedSubtitle = escapeHtml(subtitle ?? copy.subtitle);
|
||||
const logoMarkup = iconDataUrl
|
||||
? `<img class="startup-logo" src="${escapeHtml(iconDataUrl)}" alt="${escapedAppName}" data-lime-startup-logo />`
|
||||
: `<div class="startup-logo startup-logo-fallback" aria-label="${escapedAppName}" data-lime-startup-logo>${escapedAppName.slice(0, 1)}</div>`;
|
||||
const startupLogoSrc = resolveStartupLogoDataUrl(iconDataUrl);
|
||||
const logoMarkup = `<img class="startup-logo" src="${escapeHtml(startupLogoSrc)}" alt="${escapedAppName}" data-lime-startup-logo />`;
|
||||
|
||||
return `<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
@@ -177,16 +182,6 @@ export function buildMainWindowStartupHtml({
|
||||
filter: drop-shadow(0 28px 44px rgba(15, 23, 42, 0.16));
|
||||
}
|
||||
|
||||
.startup-logo-fallback {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #13bf73;
|
||||
color: #ffffff;
|
||||
font-size: 96px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.startup-copy {
|
||||
position: relative;
|
||||
margin-top: 12px;
|
||||
@@ -423,6 +418,11 @@ export function buildMainWindowStartupDataUrl(html: string): string {
|
||||
return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
|
||||
}
|
||||
|
||||
export function resolveStartupLogoDataUrl(iconDataUrl?: string | null): string {
|
||||
const normalizedIconDataUrl = iconDataUrl?.trim();
|
||||
return normalizedIconDataUrl || FALLBACK_STARTUP_LOGO_DATA_URL;
|
||||
}
|
||||
|
||||
export function buildMainWindowChromeOptions(
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
): MainWindowChromeOptions {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
4. **新旧并存问题先看治理文档** - 避免在 compat / deprecated 路径上继续长新表面
|
||||
5. **新增命名不要加品牌前缀** - 新程序、目录、crate/package、Electron IPC channel、App Server 方法、API 网关、类型、模块和脚本默认使用领域名,不要加 `Lime` / `lime_` / `lime-`;只有对外品牌、历史兼容或生态固定命名才例外,并在计划里说明
|
||||
6. **新增 Agent 逻辑默认走 App Server** - 新 AI Agent、runtime、host integration、跨 App 复用能力先落到 `app-server` crates、JSON-RPC 协议、client 与 RuntimeCore;Electron 只作为 Desktop Host bridge,负责 IPC 和桌面壳能力,不是第二套后端或业务 adapter;`agent_runtime_*` / Aster 旧命令只作为 Lime Desktop 兼容 facade
|
||||
7. **`lime-rs/src/commands/**` 只做旧 wrapper 清理** - 该目录不再承接新的业务逻辑、API adapter、runtime 分支或领域服务实现;新增后端能力进 App Server crates / RuntimeCore / services,桌面壳能力进 Electron Desktop Host
|
||||
|
||||
## 按场景导航
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
这条路径是 current 事实源。Electron 只负责 Desktop Host bridge:preload / IPC 白名单、窗口、托盘、Dock、菜单、updater、签名发布、sidecar 生命周期和少量 renderer-safe projection。Electron 不是第二套后端,也不要把它命名成后端适配层;App Server JSON-RPC 才是 backend 事实入口。
|
||||
|
||||
Updater 是明确的 Desktop Host 壳能力,不进入 App Server,也不得回流 Rust Tauri command facade。旧 updater command 面已删除:`lime-rs/src/commands/update_cmd.rs` 不再存在,`lime-rs/src/commands/mod.rs` 不再声明 `update_cmd`,`runner.rs` 不再注册旧 updater handler 或后台检查任务。后续若调整更新体验,只能改 Electron Desktop Host updater current 链路、前端 `src/lib/api/appUpdate.ts` 网关和 release / Forge 文档,不得在 `lime-rs/src/commands/` 新增 updater stub、compat wrapper 或业务实现。
|
||||
|
||||
生产路径不能 mock。`safeInvoke` / `invoke`、Electron Host、App Server sidecar、GUI smoke 和业务 E2E 必须进入真实 Electron Desktop Host IPC / App Server JSON-RPC;无真实通道时 fail-closed。`mockPriorityCommands`、`defaultMocks`、`invokeMockOnly`、`explicitMockFallback`、内存事件 / 窗口 / 快捷键夹具和 mock backend 只允许测试文件或显式测试夹具使用,不能作为产品降级、浏览器模式兜底或交付证据。
|
||||
|
||||
macOS 真实 Electron E2E / GUI smoke 可以使用 Chromium `--use-mock-keychain` 隔离系统钥匙串。这只隔离测试进程的 Keychain backend,不等于业务 mock;目的是避免隔离 `HOME / ELECTRON_E2E_USER_DATA_DIR` 时触发“找不到用于储存 `Lime Key` 的钥匙串”系统弹窗或污染用户真实钥匙串。生产 App 和普通开发预览不得依赖该参数。
|
||||
@@ -31,6 +33,8 @@ macOS 真实 Electron E2E / GUI smoke 可以使用 Chromium `--use-mock-keychain
|
||||
|
||||
新增 AI Agent / runtime / host integration / 跨 App 复用能力默认走 App Server JSON-RPC current 主链。Electron main / preload 只作为 Desktop Host bridge,负责桌面壳能力、sidecar 生命周期与白名单 IPC;只有为旧 GUI 做兼容适配时,才继续触碰 `agent_runtime_*` / Aster legacy command facade;这类改动不能承接新业务逻辑,必须写清退出条件。
|
||||
|
||||
`lime-rs/src/commands/**` 是旧 Tauri command wrapper 删除清理区,不再承接新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub。允许触碰它的场景只剩:删除旧 wrapper;撤 runner / DevBridge dispatcher / catalog / mock 注册后的机械编译修复;或记录无法删除的 blocker。新增 Rust 后端能力必须落到 App Server crates / RuntimeCore / services 等 current 事实源;桌面壳能力落到 Electron Desktop Host。
|
||||
|
||||
这样做的目的不是“多包一层”,而是为了保证:
|
||||
|
||||
- 前端只有一个可治理的调用出口
|
||||
@@ -688,6 +692,7 @@ npm run verify:local
|
||||
|
||||
- 在页面、组件、普通 Hook 中直接散落 `invoke`
|
||||
- 给 `compat` 路径继续长新业务逻辑
|
||||
- 在 `lime-rs/src/commands/**` 新增业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub;该目录只允许删除旧 Tauri wrapper、撤注册后的机械编译修复,或登记 blocker
|
||||
- 把已经进入 `deprecated` / `dead-candidate` / `dead` 的命令重新接回主链
|
||||
- 只改前端或只改 Rust,一侧通过就宣布完成
|
||||
- 用“先兼容一下”作为长期保留第二套入口的理由
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
生产路径不能 mock。mock 只允许作为测试夹具、契约守卫或已标明测试场景的本地 fixture;如果生产入口需要靠 `defaultMocks`、`mockPriorityCommands`、`invokeMockOnly`、renderer mock fallback 或 App Server mock backend 才能跑通,该入口应判为阻塞缺口,而不是可交付降级。
|
||||
|
||||
`lime-rs/src/commands/**` 是旧 Tauri command wrapper 删除清理区,不再承接新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub。新增 Rust 后端能力必须进入 App Server crates / RuntimeCore / services 等 current 事实源;桌面壳能力进入 Electron Desktop Host。该目录只允许删除旧 wrapper、撤 runner / DevBridge dispatcher / catalog / mock 注册后的机械编译修复,或登记无法删除的 blocker。
|
||||
|
||||
## 无历史包袱原则
|
||||
|
||||
如果用户已经明确下面任一前提:
|
||||
@@ -243,8 +245,10 @@ Electron packaging / installer / signing / notarization / updater metadata 只
|
||||
- `current`:`electron/updateHost.ts` + Electron 内置 `autoUpdater`,只负责运行时更新检查、下载和安装会话
|
||||
- `current`:macOS `MakerDMG` / `MakerZIP` 产物与 `RELEASES.json`,Windows `MakerSquirrel` 产物与 `RELEASES` / `.nupkg` / Setup
|
||||
- `dead`:旧 builder 配置 / CLI、自定义 Windows installer maker、旧 YAML / blockmap updater metadata、把旧打包链当 current 的文档或 i18n evidence
|
||||
- `dead / deleted`:旧 Rust / Tauri updater command 面,包括 `lime-rs/src/commands/update_cmd.rs`、`commands::update_cmd::*` runner 注册、`UpdateInstallSessionState` 管理和 Rust 后台更新检查任务;不得以 stub 或 compat wrapper 形式恢复到 `lime-rs/src/commands/`
|
||||
|
||||
发现新引用旧 builder 配置 / CLI、自定义 Windows installer maker、旧 YAML / blockmap updater metadata 时,默认先判为旧路回流,而不是新增 compat。
|
||||
发现新引用旧 Rust / Tauri updater command、`update_cmd.rs` 或 Rust 后台更新检查任务时,也按 updater 旧路回流处理;current 修复必须回到 Electron Desktop Host updater 链路。
|
||||
|
||||
### 2. 命令边界
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
|
||||
生产不能 mock,只有测试才 mock。`src/lib/desktop-host/` 中的 mock、`mockPriorityCommands`、`defaultMocks`、`invokeMockOnly`、`explicitMockFallback` 和 App Server mock backend 只允许用于 `*.test.*`、测试夹具、契约守卫或专门声明为测试的 smoke 场景;GUI smoke、业务 E2E、Electron Host 和 App Server sidecar 生产路径必须真实连通,失败时直接暴露错误。
|
||||
|
||||
`lime-rs/src/commands/**` 是旧 Tauri command wrapper 删除清理区,不再承接新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub。质量检查不能把该目录当成新增 Rust 后端能力或桌面壳能力的落点;新增后端能力必须进入 App Server crates / RuntimeCore / services,桌面壳能力进入 Electron Desktop Host。涉及该目录的测试只允许作为 cleanup guard,证明旧 wrapper 已删除、已迁出或没有回流,不能作为 GUI current 可交付证据。
|
||||
|
||||
新增或迁移测试时按下面顺序处理:
|
||||
|
||||
1. 新 Agent / runtime / host integration / 跨 App 复用能力,优先补 App Server protocol / server / npm client / Electron host 测试。
|
||||
@@ -230,6 +232,8 @@ Electron 打包 / 发布 / updater metadata 的 current 事实源固定为 `forg
|
||||
|
||||
旧 builder 配置 / CLI、自定义 Windows installer maker 与旧 YAML / blockmap updater metadata 属于 `dead`,不得继续作为 current 文档、CI、质量任务、i18n app metadata evidence 或守卫输入。运行时更新链路以 `electron/updateHost.ts` + Electron 内置 `autoUpdater` 为 current;Windows installer 以 Forge Squirrel 为 current,必须产出 `RELEASES` / `.nupkg` / Setup,macOS updater metadata 以 Forge ZIP maker 的 `RELEASES.json` 为 current。
|
||||
|
||||
旧 Rust / Tauri updater command 面已经删除,质量检查不能再把 `lime-rs/src/commands/update_cmd.rs`、`commands::update_cmd::*` runner 注册、`UpdateInstallSessionState` 或 Rust 后台更新检查任务当作 fallback 或可修补对象。若 updater 行为失败,按 Electron Desktop Host / Forge / feed current 链路补实现和验证;不要在 `lime-rs/src/commands/` 新增 updater stub 或 compat wrapper。
|
||||
|
||||
`scripts/` 根目录是冻结的历史入口区。新增可执行脚本默认必须放到 `scripts/<domain>/`、`scripts/lib/` 或所属 package;只有公开稳定入口且无法归入领域子目录时才允许新增根目录例外。涉及脚本目录、脚本入口或新增脚本时,必须同步检查:
|
||||
|
||||
- `scripts/README.md`
|
||||
|
||||
@@ -1664,3 +1664,4 @@ git diff --check
|
||||
648. P3.302 验证 / 边界:`npm run test:contracts` 通过,App Server client contract 仍为 `210 checks`,frontend commands `388`,Electron host commands `107`,mock priority commands `0`,DevBridge truth commands `148`,并通过 scripts governance、Electron release workflow guard、Harness cleanup 与 docs boundary。`npm run verify:gui-smoke` 通过,覆盖版本一致性 `1.60.0`、renderer smoke build、`packages/app-server-client` build、Electron host typecheck / main / preload build、desktop assets、App Server sidecar asset prepare 与真实 Electron smoke,输出确认 `renderer loaded`、`app-server initialized protocol=appserver.v0 version=1.60.0`、`claw workbench shell ready`。`npm run smoke:agent-runtime-current-fixture` 通过,覆盖 history/cache 66 项、stream terminal 18 项、Claw MessageList 3 项、Electron/App Server fixture guard 17 项,并实际运行 `Claw 停止后同会话继续输出 Electron fixture`;本轮最新 session 为 `claw-chat-current-1780877737248-88730`,`liveProviderUsed=false`。该刀证明当前非 live current 主链在并行脏工作树下仍可用;仍不调用正式模型、不联网、不使用 App Server mock backend、renderer mock fallback、`mockPriorityCommands`、`defaultMocks` 或 `invokeMockOnly`,也不替代用户明确授权后的 live Provider streaming / WebSearch-WebFetch 联网 E2E。
|
||||
649. P3.303 live Provider 未授权 gate 复验:继续沿完整目标中最后的 live Provider / WebSearch-WebFetch 缺口推进,但本轮没有用户明确授权调用正式模型或联网工具,因此只复验 fail-closed 安全边界。`npm run smoke:claw-chat-ready-streaming -- --timeout-ms 30000` 按预期以退出码 1 停在授权检查,提示必须显式传入 `--allow-live-provider`,或设置 `LIME_ALLOW_LIVE_PROVIDER_SMOKE=1 / LIME_REAL_API_TEST=1`;该运行没有进入 DevBridge、Provider、`agentSession/turn/start`、WebSearch 或 WebFetch 阶段。该证据证明未授权时不会把真实 Provider / 联网工具当作默认回归门槛偷偷运行;它不是 live E2E 通过证据,完整目标仍缺用户明确授权后的 `npm run smoke:claw-chat-ready-streaming -- --allow-live-provider --timeout-ms 180000` 实跑。
|
||||
650. P3.304 Electron Forge release / updater metadata 收口复核:按用户要求“旧 builder / updater metadata 要清理”,本轮只认领 release/updater/i18n 事实源复核与文档口径修正,不修改 Agent Runtime、Electron Host 运行时逻辑或 App Server 数据主链。当前发布事实源固定为 `forge.config.mjs`、`electron-forge package`、`electron-forge make` 与 Forge 官方 maker;Windows current installer 是 Forge Squirrel 的 Setup / `.nupkg` / `RELEASES`,macOS current updater metadata 是 Forge ZIP 的 `RELEASES.json`,运行时更新仍是 `electron/updateHost.ts` + Electron 内置 `autoUpdater`。旧 Tauri builder / NSIS / electron-builder / electron-updater / `latest*.yml` / `latest.json` / blockmap / `.app.tar.gz` / `.sig` 均保持 `dead`,只允许出现在 fail-fast 守卫或负向测试 fixture。i18n app metadata 进度记录已改为 Forge scope 当前计数:`10` 个审计字段、`translatable=1`、`stable=3`、`sourceOnly=6`;`hasInstallerLocalizationWorkflow=true` 只表示 build-time manifest workflow ready,不表示真实平台 installer metadata 会按 locale 生成。两份 app metadata evidence 已用本地命令刷新,但 `internal/roadmap/i18n/**` 当前被 `.gitignore` 忽略,未形成 tracked diff。
|
||||
651. P3.305 `app-server-agent-backend` dead crate 删除收口:按用户明确确认,本轮完成旧独立 backend crate 删除。`lime-rs/crates/app-server-agent-backend/Cargo.toml` 与 `src/main.rs` 已删除,空目录已移除;`lime-rs/Cargo.lock` 删除 `name = "app-server-agent-backend"` package block。当前 `current` 事实源保持 `lime-rs/crates/app-server/src/runtime_backend.rs` 的 `RuntimeBackend`、`AppServerBackendMode::Runtime`、`AppServerRuntimeFactory::runtime_backend_core(...)` 与 `app-server --backend runtime`;旧独立 crate 归类为 `dead`,显式 external backend 模式只作为通用 fixture / override 协议能力保留,不再绑定长命名独立 crate。`scripts/check-app-server-client-contract.mjs` 新增守卫:禁止 `lime-rs/crates/app-server-agent-backend` 目录回流,并禁止 `Cargo.lock` 再出现 `app-server-agent-backend` package;原 dev sidecar 守卫继续禁止自动解析、构建或注入旧 backend。
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# Tauri wrapper command inventory
|
||||
|
||||
生成时间:2026-06-08 CST
|
||||
状态:`snapshot_current_dirty_worktree`
|
||||
关联队列:`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
|
||||
## 口径
|
||||
|
||||
- 本报告是机械扫描快照,用于多进程拆分清理,不是最终删除裁决。
|
||||
- `low-reference` / `devbridge-only` 只能作为候选信号;删除前仍需核对前端网关、Electron Host / App Server、legacy runner、`agentCommandCatalog`、mock 与契约测试。
|
||||
- 当前工作树存在大量并行脏写集,本报告避免触碰 `runner.rs`、`commandPolicy.ts`、`agentCommandCatalog.json` 和 App Server protocol。
|
||||
- `lime-rs/src/commands/**` 是旧 Tauri command wrapper 删除清理区,不再承接新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub;下表中的文件只代表待删除 surface,不是新增落点,也不是退场包装落点。
|
||||
|
||||
## 总量
|
||||
|
||||
| Surface | Count | 说明 |
|
||||
| --- | ---: | --- |
|
||||
| Rust `#[tauri::command]` | 490 | 74 个文件 |
|
||||
| `tauri::generate_handler!` 注册 | 513 | 仅统计 handler 列表最后一级函数名 |
|
||||
| DevBridge dispatcher 字符串命令 | 147 | 17 个 dispatcher 文件 |
|
||||
| 前端直接 `safeInvoke/invoke` 字符串 | 27 | 9 个前端文件;动态常量另见 API token |
|
||||
| `src/lib/api` 命令名 token | 1062 | 用于补足动态 `safeInvoke(command)` |
|
||||
| App Server JSON-RPC method | 93 | protocol 源码字符串扫描 |
|
||||
|
||||
## 高密度旧 wrapper 文件
|
||||
|
||||
| Count | File | 推荐拆分 |
|
||||
| ---: | --- | --- |
|
||||
| 29 | `lime-rs/src/commands/webview_cmd.rs` | Desktop Host / Browser Runtime |
|
||||
| 28 | `lime-rs/src/commands/skill_cmd.rs` | Skills / marketplace / execution 分拆 |
|
||||
| 21 | `lime-rs/src/commands/aster_agent_cmd/command_api/runtime_api.rs` | Agent Runtime 主链,最后处理 |
|
||||
| 19 | `lime-rs/src/commands/mcp_cmd.rs` | App Server MCP current |
|
||||
| 16 | `lime-rs/src/commands/config_cmd.rs` | Config / Desktop Host shell split |
|
||||
| 16 | `lime-rs/src/commands/machine_id_cmd.rs` | Machine identity / diagnostics split |
|
||||
| 15 | `lime-rs/src/commands/memory_management_cmd.rs` | Memory App Server current |
|
||||
| 15 | `lime-rs/src/commands/workspace_cmd.rs` | Workspace App Server current |
|
||||
| 14 | `lime-rs/src/commands/model_registry_cmd.rs` | Model Provider current |
|
||||
| 14 | `lime-rs/src/commands/session_files_cmd.rs` | Session files App Server current |
|
||||
| 13 | `lime-rs/src/commands/memory_cmd.rs` | Memory App Server current |
|
||||
| 12 | `lime-rs/src/commands/agent_app_cmd.rs` | Agent App current / Desktop Host shell split |
|
||||
| 12 | `lime-rs/src/commands/site_capability_cmd.rs` | Site capability current |
|
||||
| 10 | `lime-rs/src/commands/browser_connector_cmd.rs` | Desktop Host / Browser Runtime |
|
||||
| 10 | `lime-rs/src/commands/telemetry_cmd.rs` | Telemetry / App Server split |
|
||||
| 9 | `lime-rs/src/commands/gateway_tunnel_cmd.rs` | Gateway channel / tunnel split |
|
||||
| 9 | `lime-rs/src/commands/material_cmd.rs` | Materials / project resources |
|
||||
| 9 | `lime-rs/src/commands/models_cmd.rs` | Model Provider current |
|
||||
| 9 | `lime-rs/src/commands/persona_cmd.rs` | Persona / project memory split |
|
||||
| 9 | `lime-rs/src/commands/prompt_cmd.rs` | Prompt service split |
|
||||
|
||||
## DevBridge 热点
|
||||
|
||||
| Count | File | 清理口径 |
|
||||
| ---: | --- | --- |
|
||||
| 31 | `lime-rs/src/dev_bridge/dispatcher/agent_sessions.rs` | Agent Runtime 高风险,最后处理 |
|
||||
| 22 | `lime-rs/src/dev_bridge/dispatcher/skills.rs` | Skills 高风险,单进程处理 |
|
||||
| 22 | `lime-rs/src/dev_bridge/dispatcher/voice.rs` | Voice split |
|
||||
| 14 | `lime-rs/src/dev_bridge/dispatcher/browser/runtime.rs` | Browser Runtime current gateway |
|
||||
| 8 | `lime-rs/src/dev_bridge/dispatcher/agent_apps.rs` | Agent App current gateway |
|
||||
| 7 | `lime-rs/src/dev_bridge/dispatcher/browser/sessions.rs` | Browser Runtime current gateway |
|
||||
| 7 | `lime-rs/src/dev_bridge/dispatcher/capability_drafts.rs` | Capability Draft current gateway |
|
||||
| 7 | `lime-rs/src/dev_bridge/dispatcher/files.rs` | File / layered design gateway |
|
||||
| 7 | `lime-rs/src/dev_bridge/dispatcher/knowledge.rs` | Knowledge App Server current |
|
||||
| 4 | `lime-rs/src/dev_bridge/dispatcher/browser/bridge.rs` | Browser Runtime current gateway |
|
||||
| 4 | `lime-rs/src/dev_bridge/dispatcher/providers.rs` | Provider current gateway |
|
||||
| 3 | `lime-rs/src/dev_bridge/dispatcher/app_runtime.rs` | Config / diagnostics split |
|
||||
| 3 | `lime-rs/src/dev_bridge/dispatcher/browser/cdp.rs` | Browser Runtime current gateway |
|
||||
| 3 | `lime-rs/src/dev_bridge/dispatcher/models.rs` | 已在 Q3A 处理中 |
|
||||
| 3 | `lime-rs/src/dev_bridge/dispatcher/project_resources.rs` | 已在 Q3B blocked |
|
||||
| 1 | `lime-rs/src/dev_bridge/dispatcher/memory.rs` | Memory current gateway |
|
||||
| 1 | `lime-rs/src/dev_bridge/dispatcher/runtime_queries.rs` | Runtime query current gateway |
|
||||
|
||||
## 低引用候选
|
||||
|
||||
这些命令当前在扫描范围内只出现在少量 Rust 文件,且没有命中前端直接调用、`src/lib/api` 命令 token 或 DevBridge dispatcher。它们适合作为后续 `TW-Q2-DEAD-NAMES` 子任务,但必须等共享写集释放后再删 runner / catalog。
|
||||
|
||||
| Command | Occurrence files | 下一步 |
|
||||
| --- | --- | --- |
|
||||
| `add_model_to_provider` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/models_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `add_provider` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/models_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `check_codex_cli_status` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/external_tools_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `create_a2ui_form` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/a2ui_form_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `create_persona` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/persona_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `create_webview_panel` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/webview_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `delete_a2ui_form` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/a2ui_form_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `delete_avatar` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/file_upload_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `delete_persona` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/persona_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `execute_ecommerce_review_reply` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/ecommerce_review_reply_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `export_bundle` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `export_config` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `export_config_yaml` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `fetch_provider_models_from_api` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/model_registry_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `focus_webview_panel` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/webview_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_a2ui_form` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/a2ui_form_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_a2ui_forms_by_message` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/a2ui_form_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_a2ui_forms_by_session` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/a2ui_form_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_all_provider_models` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/models_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_auto_launch_status` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_available_voices` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/voice_test_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_config_dir_path` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_config_paths` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_config_status` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_default_persona` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/persona_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_external_tools` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/external_tools_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_material` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/material_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_materials_content` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/material_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_memory_feedback_stats` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/memory_feedback_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_models_config` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/models_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_persona` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/persona_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_project_context` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/workspace_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_provider_models` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/models_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_relay_info` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/connect_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_sysinfo` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/services/sysinfo_service.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_telegram_remote_status` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/telegram_remote_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_tool_versions` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/config_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_websocket_connections` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/websocket_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_websocket_status` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/websocket_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
| `get_webview_panels` | `lime-rs/src/app/runner.rs`<br>`lime-rs/src/commands/webview_cmd.rs` | 核对产品入口后拆独立删除任务 |
|
||||
|
||||
## 需要优先解释的漂移
|
||||
|
||||
| Signal | Command / group | 说明 |
|
||||
| --- | --- | --- |
|
||||
| tauri-command-not-registered | `knowledge_compile_pack` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_get_pack` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_import_source` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_list_packs` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_resolve_context` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_set_default_pack` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_update_pack_status` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| tauri-command-not-registered | `knowledge_validate_context_run` | Rust 命令定义未进入当前 runner 注册;确认是否测试专用、遗漏注册或可删。 |
|
||||
| devbridge-only | `get_models` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_compile_pack` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_get_pack` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_import_source` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_resolve_context` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_set_default_pack` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_update_pack_status` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
| devbridge-only | `knowledge_validate_context_run` | 只在 DevBridge 字符串分发出现;若 App Server method 已覆盖,可删 dispatcher 分支。 |
|
||||
|
||||
## 前端仍可见的 legacy Rust 命令名
|
||||
|
||||
这些命令仍出现在前端直接调用或 API 网关 token 中,不应快删;要按 current 主链迁完后再撤 Rust wrapper。
|
||||
|
||||
| Source | Commands |
|
||||
| --- | --- |
|
||||
| direct safeInvoke/invoke | `agent_app_launch_shell`, `agent_runtime_get_tool_inventory`, `agent_runtime_list_sessions`, `agent_runtime_save_review_decision`, `companion_get_pet_status`, `complete_audio_generation_task_artifact`, `create_audio_generation_task_artifact`, `execution_run_get_general_workbench_state`, `get_config`, `get_media_task_artifact`, `get_or_create_default_project`, `list_media_task_artifacts`, `open_external_url`, `report_frontend_debug_log`, `save_config`, `update_provider_env_vars`, `workspace_get_projects_root`, `workspace_list` |
|
||||
| src/lib/api token | `add_mcp_server`, `add_skill_repo`, `agent_app_fetch_cloud_package`, `agent_app_get_ui_runtime_status`, `agent_app_inspect_local_package`, `agent_app_launch_shell`, `agent_app_list_installed`, `agent_app_runtime_cancel_task`, `agent_app_runtime_get_task`, `agent_app_runtime_start_task`, `agent_app_runtime_submit_host_response`, `agent_app_save_installed_state`, `agent_app_select_directory`, `agent_app_set_disabled`, `agent_app_start_ui_runtime`, `agent_app_stop_ui_runtime`, `agent_app_uninstall`, `agent_app_uninstall_rehearsal`, `agent_get_process_status`, `agent_runtime_audit_objective`, `agent_runtime_clear_objective`, `agent_runtime_close_subagent`, `agent_runtime_compact_session`, `agent_runtime_continue_objective`, `agent_runtime_create_session`, `agent_runtime_delete_session`, `agent_runtime_diff_file_checkpoint`, `agent_runtime_export_analysis_handoff`, `agent_runtime_export_evidence_pack`, `agent_runtime_export_handoff_bundle`, `agent_runtime_export_replay_case`, `agent_runtime_export_review_decision_template`, `agent_runtime_get_file_checkpoint`, `agent_runtime_get_objective`, `agent_runtime_get_session`, `agent_runtime_get_thread_read`, `agent_runtime_get_tool_inventory`, `agent_runtime_interrupt_turn`, `agent_runtime_list_file_checkpoints`, `agent_runtime_list_sessions`, `agent_runtime_list_workspace_skill_bindings`, `agent_runtime_promote_queued_turn`, `agent_runtime_remove_queued_turn`, `agent_runtime_replay_request`, `agent_runtime_respond_action`, `agent_runtime_restore_file_checkpoint`, `agent_runtime_resume_subagent`, `agent_runtime_resume_thread`, `agent_runtime_save_review_decision`, `agent_runtime_send_subagent_input`, `agent_runtime_set_objective`, `agent_runtime_spawn_subagent`, `agent_runtime_submit_turn`, `agent_runtime_update_objective_status`, `agent_runtime_update_session`, `agent_runtime_wait_subagents`, `agent_start_process`, `agent_stop_process`, `analyze_layered_design_flat_image`, `aster_agent_configure_provider`, `aster_agent_init`, `aster_agent_status`, `cancel_media_task_artifact`, `cancel_video_generation_task`, `capability_draft_create`, `capability_draft_execute_controlled_get`, `capability_draft_get`, `capability_draft_list`, `capability_draft_register`, `capability_draft_submit_approval_session_inputs`, `capability_draft_verify`, `character_create`, `character_delete`, `character_get`, `character_list`, `character_update`, `clear_diagnostic_log_history`, `clear_logs`, `companion_get_pet_status`, `companion_launch_pet` |
|
||||
|
||||
## 推荐并行切片
|
||||
|
||||
1. `TW-Q2-LOW-REFERENCE`:从低引用候选里每次认领 1-3 个命令;写集必须包含 runner / Rust wrapper / catalog / mock,当前共享热区未释放前只读。
|
||||
2. `TW-Q3-DEVBRIDGE-ONLY`:优先删 `devbridge-only` 且 App Server method 已覆盖的 dispatcher 分支;不要动 Agent Runtime。
|
||||
3. `TW-Q4-DESKTOP-HOST-SHELL`:`open_external_url`、窗口、更新、系统打开等纯壳能力只迁 Electron Host,不进 App Server。
|
||||
4. `TW-Q5-APP-SERVER-READS`:Workspace / Knowledge / Model / Session files 读链按 App Server method 逐条撤 Tauri wrapper。
|
||||
@@ -0,0 +1,838 @@
|
||||
# Tauri wrapper 快速清理队列
|
||||
|
||||
创建时间:2026-06-08 CST
|
||||
状态:`parallel_dispatch_ready`
|
||||
关联计划:
|
||||
|
||||
- `internal/exec-plans/production-command-current-migration-plan.md`
|
||||
- `internal/exec-plans/rust-commands-current-migration-cleanup-plan.md`
|
||||
- `internal/roadmap/appserver/frontend-electron-migration.md`
|
||||
|
||||
## 目标
|
||||
|
||||
把 Tauri -> Electron / App Server 迁移里的低价值旧面先收掉,减少后续主链迁移时的噪音和误判。
|
||||
|
||||
排序原则:
|
||||
|
||||
1. 从易到难:先清零引用、文档 / smoke 旧词、纯测试夹具、已 current 覆盖的 dispatcher 分支;再动跨四侧协议和运行时主链。
|
||||
2. 从不重要到重要:先处理不影响 Agent 主链的旧产品面、诊断面、低频壳能力;最后处理 MCP、Workspace、Knowledge、Agent Runtime。
|
||||
3. 不把所有旧命令一比一迁到 App Server。业务事实源进 App Server;窗口、shell、录音设备、CDP、系统打开等进 Electron Desktop Host;无产品入口的旧面直接判 `dead`。
|
||||
|
||||
当前基线:
|
||||
|
||||
- Rust `#[tauri::command]`:当前快照约 490 个,分布在 74 个文件。
|
||||
- `lime-rs/src/app/runner.rs` `generate_handler!`:当前快照约 513 个注册。
|
||||
- Rust `DevBridge dispatcher`:约 147 个字符串命令,分布在 17 个 dispatcher 文件。
|
||||
- 工作树已有大量共享脏写集;执行本队列前必须先重新做只读基线并认领窄写集。
|
||||
|
||||
硬边界:
|
||||
|
||||
- `lime-rs/src/commands/**` 是旧 Tauri command wrapper 删除清理区,不再落新的业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub。
|
||||
- 该目录只允许做旧 wrapper 删除、撤 runner / DevBridge dispatcher / catalog / mock 注册后的机械编译修复,或记录无法删除的 blocker。
|
||||
- 新 Rust 后端能力必须落到 App Server crates / RuntimeCore / services 等 current 事实源;桌面壳能力落到 Electron Desktop Host。
|
||||
- 任一子任务若发现必须在 `lime-rs/src/commands/**` 新增逻辑、保留 stub 或新增薄委托,默认判定为任务拆分错误,应改为迁 App Server / Electron Host、直接撤旧注册,或只登记 blocker。
|
||||
|
||||
## 多进程分配规则
|
||||
|
||||
本文件用于多个进程并行认领清理任务。每个进程启动后只做一件事:选一个未认领 Task ID,追加认领记录,然后只修改自己声明的写集。
|
||||
|
||||
启动协议:
|
||||
|
||||
```bash
|
||||
git status --short --untracked-files=all
|
||||
git diff --name-only
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
认领规则:
|
||||
|
||||
- 一个进程一次只认领一个 Task ID。
|
||||
- 没有在本文件追加认领记录的进程,只能只读调研,不能写代码。
|
||||
- 认领记录只能追加,不能改写别的进程已有记录。
|
||||
- 发现目标文件已被其它进程修改,立即放弃该 Task ID,改选其它未冲突任务。
|
||||
- 触碰 `runner.rs`、`dev_bridge/dispatcher.rs`、`commandPolicy.ts`、`agentCommandCatalog.json`、`scripts/check-*-contract.mjs` 时,默认视为共享写集,不能和其它任务夹写。
|
||||
- 删除文件、批量迁移或大范围格式化必须单独确认;本队列优先做小额清理。
|
||||
|
||||
认领记录模板:
|
||||
|
||||
```text
|
||||
- 2026-06-08 <进程名> <Task ID> 认领
|
||||
- 写集:<精确文件列表>
|
||||
- 只读参考:<文件或目录>
|
||||
- 避让:<当前不得触碰的共享文件>
|
||||
- 目标:<本轮最小闭环>
|
||||
- 验证:<命令列表>
|
||||
- 启动基线:<git status 摘要>
|
||||
- 状态:claimed | in_progress | blocked_conflict | ready_for_review | done | abandoned
|
||||
```
|
||||
|
||||
完成记录模板:
|
||||
|
||||
```text
|
||||
- 2026-06-08 <进程名> <Task ID> 完成
|
||||
- 清理结果:<deleted | removed-from-runner | removed-from-devbridge | guard-added | compat-delegates-only>
|
||||
- 旧入口搜索:<rg 命令与结论>
|
||||
- 验证结果:<命令与结果>
|
||||
- 剩余阻塞:<无 / 具体文件与原因>
|
||||
```
|
||||
|
||||
## 快速分配表
|
||||
|
||||
| Task ID | 优先级 | 可并行性 | 难度 | 重要性 | 推荐写集 | 避让写集 | 目标 |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| TW-Q0-INVENTORY | 1 | 可单独并行 | 低 | 低 | 新增 inventory 报告或治理测试 | `runner.rs`、App Server protocol 热区 | 输出机械 command 对照,给后续进程减少重复扫描 |
|
||||
| TW-Q1-DOCS-SMOKE | 2 | 可并行 | 低 | 低 | `internal/**`、`scripts/electron/current-docs-guard.test.mjs`、相关 smoke fixture | App Server protocol、Rust commands | 清 current 文档 / smoke 里的旧 Tauri 证据 |
|
||||
| TW-Q2-DEAD-NAMES | 3 | 可并行调研,写入需拆子任务 | 低到中 | 低 | 旧命令所在前端 / mock / runner / dispatcher 精确文件 | 当前已脏共享文件 | 清零引用或已下线旧命令族 |
|
||||
| TW-Q3A-DEVBRIDGE-MODELS | 4 | 可并行 | 中 | 低 | `lime-rs/src/dev_bridge/dispatcher/models.rs`、必要 guard | `commandPolicy.ts` 若已被占用 | 清 models dispatcher 已 current 分支 |
|
||||
| TW-Q3B-DEVBRIDGE-PROJECT-RESOURCES | 4 | 可并行 | 中 | 低 | `lime-rs/src/dev_bridge/dispatcher/project_resources.rs`、必要 guard | `commandPolicy.ts` 若已被占用 | 清 materials / project resources dispatcher 已 current 分支 |
|
||||
| TW-Q3C-DEVBRIDGE-APP-RUNTIME | 4 | 可并行 | 中 | 低到中 | `lime-rs/src/dev_bridge/dispatcher/app_runtime.rs`、必要 guard | config / logs 共享写集 | 清 config / diagnostics 旧 dispatcher 分支 |
|
||||
| TW-Q4A-WINDOW-SHELL | 5 | 需避开 Electron host 热区 | 中 | 低到中 | `window_cmd.rs`、Electron window API / tests | `electron/hostCommands.ts` 若已被占用 | 把窗口壳能力收回 Electron Host |
|
||||
| TW-Q4B-EXTERNAL-TOOLS-SHELL | 5 | 可并行 | 中 | 低到中 | `external_tools_cmd.rs`、`src/lib/api/externalUrl.ts`、Electron shell tests | App Server protocol | 清外部打开 / CLI login shell wrapper |
|
||||
| TW-Q5A-KNOWLEDGE-READ | 6 | 当前易冲突 | 中 | 中 | `knowledge_cmd.rs`、knowledge API / tests / mocks | `local_data_source.rs`、protocol 热区若未释放 | 清已 current 的 knowledge 读链旧入口 |
|
||||
| TW-Q5B-MODEL-READ | 6 | 可并行 | 中 | 中 | `model_registry_cmd.rs`、models API / mocks / dispatcher | `commandPolicy.ts` 若已被占用 | 清 model registry 读链旧入口 |
|
||||
| TW-Q5C-AGENT-APP-READ | 6 | 当前易冲突 | 中 | 中 | `agent_app_cmd.rs`、Agent Apps API / UI tests | Agent Apps 页面热区若未释放 | 清 Agent App installed / UI runtime 读链残留 |
|
||||
| TW-Q6-SESSION-FILES | 7 | 可并行但需 App Server 判断 | 中 | 中 | `session_files_cmd.rs`、session files API / mocks | App Server protocol 热区 | 清 session file 读写残留 |
|
||||
| TW-Q7-CONFIG-LOGS-DIAG | 8 | 可并行拆分 | 中 | 中 | config / logs / diagnostics API 与 Rust wrapper | `app/commands/config.rs` 若被占用 | 拆分配置、日志、诊断 current owner |
|
||||
| TW-Q8-BROWSER-WEBVIEW | 9 | 建议单进程 | 中到高 | 中 | `webview_cmd.rs`、browser dispatcher、`src/lib/webview-api.ts` | Electron host 热区 | 清 Browser / Webview / CDP / Profile wrapper |
|
||||
| TW-Q9-VOICE-ASR | 10 | 可并行 | 中到高 | 中到高 | voice / ASR API、dispatcher voice、desktop-host voice mocks | 录音设备 / Electron host 热区 | 拆分录音设备与 ASR service current owner |
|
||||
| TW-Q10-SKILLS | 11 | 建议单进程 | 高 | 中到高 | `skill_cmd.rs`、`dispatcher/skills.rs`、skills API / mocks | Agent Runtime tool runtime | 清 Skill catalog / package / marketplace wrapper |
|
||||
| TW-Q11-MCP | 12 | 当前易冲突 | 高 | 高 | `mcp_cmd.rs`、MCP API / App Server protocol / tests | App Server protocol 热区 | 完成 MCP current 化并撤旧 wrapper |
|
||||
| TW-Q12-KNOWLEDGE-WORKSPACE-CONTENT-WRITE | 13 | 建议单进程 | 高 | 高 | knowledge / workspace / content API、Rust wrappers、App Server protocol | App Server protocol 热区 | 迁写链并清旧入口 |
|
||||
| TW-Q13-MEMORY | 14 | 建议单进程 | 高 | 高 | memory / unifiedMemory / memoryRuntime API 与 Rust wrappers | RuntimeCore / workspace 文件系统热区 | 迁 Memory / Unified Memory / Project Memory |
|
||||
| TW-Q14-AGENT-APP-RUNTIME | 15 | 当前易冲突 | 高 | 高 | agent app runtime API、Rust wrappers、Agent Apps UI | Agent Apps 页面热区 | 迁 Agent App task / UI runtime 旧 facade |
|
||||
| TW-Q15-AGENT-RUNTIME | 16 | 不建议作为快速清理并行项 | 最高 | 最高 | App Server runtime、agentRuntime clients、Aster runtime core | `runtime_turn/**`、tool runtime、protocol 热区 | 逐条迁 Agent Runtime residual |
|
||||
|
||||
推荐并行启动方式:
|
||||
|
||||
- 第一批:`TW-Q1-DOCS-SMOKE`、`TW-Q2-DEAD-NAMES`、`TW-Q3A-DEVBRIDGE-MODELS`、`TW-Q3B-DEVBRIDGE-PROJECT-RESOURCES`。
|
||||
- 第二批:`TW-Q4B-EXTERNAL-TOOLS-SHELL`、`TW-Q5B-MODEL-READ`、`TW-Q6-SESSION-FILES`、`TW-Q9-VOICE-ASR`。
|
||||
- 第三批:`TW-Q8-BROWSER-WEBVIEW`、`TW-Q10-SKILLS`、`TW-Q11-MCP`、`TW-Q12-KNOWLEDGE-WORKSPACE-CONTENT-WRITE`。
|
||||
- 最后处理:`TW-Q15-AGENT-RUNTIME`,它是主线迁移,不是快速清理。
|
||||
|
||||
## 认领记录
|
||||
|
||||
- 2026-06-08 Codex TW-Q2-FILE-UPLOAD-WRAPPER 认领
|
||||
- 写集:`lime-rs/src/app/runner.rs`、`lime-rs/src/commands/mod.rs`、`lime-rs/src/commands/file_upload_cmd.rs`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`src`、`electron`、`packages`、`scripts`、`internal/exec-plans/production-command-current-migration-plan.md`
|
||||
- 避让:Knowledge 写集、Electron host / ipc 共享热区、App Server protocol、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:删除已无正向入口的 `upload_avatar` / `delete_avatar` 旧 Tauri wrapper,减少 `lime-rs/src/commands/**` 清理区存量。
|
||||
- 验证:`rg` 引用搜索、`rustfmt --edition 2021 --check --config skip_children=true "lime-rs/src/app/runner.rs" "lime-rs/src/commands/mod.rs"`、`cargo check --manifest-path "lime-rs/Cargo.toml" -p lime-agent`、`node scripts/check-command-contracts.mjs`
|
||||
- 启动基线:工作树已有大量并行脏写集;`runner.rs` / `mod.rs` 为共享脏文件,本轮只删除目标命令注册和模块声明。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 Codex TW-Q2-FILE-UPLOAD-WRAPPER 完成
|
||||
- 清理结果:`deleted`;`lime-rs/src/commands/file_upload_cmd.rs` 已删除,`commands::file_upload_cmd::{upload_avatar, delete_avatar}` 已从 `runner.rs` 注册撤掉,`commands/mod.rs` 已移除模块声明。
|
||||
- 旧入口搜索:`rg -n "upload_avatar|delete_avatar|file_upload_cmd|commands::file_upload_cmd|pub mod file_upload_cmd" "lime-rs/src" "src" "electron" "packages" "scripts" --glob "!lime-rs/target/**"` 无命中。
|
||||
- 验证结果:`rustfmt --edition 2021 --check --config skip_children=true "lime-rs/src/app/runner.rs" "lime-rs/src/commands/mod.rs"` 通过;`cargo check --manifest-path "lime-rs/Cargo.toml" -p lime-agent` 通过;`node scripts/check-command-contracts.mjs` 通过,frontend commands `121`、Electron host commands `100`、mock priority commands `0`、DevBridge truth commands `120`。
|
||||
- 剩余阻塞:无;完整 `npm run test:contracts` 可在本轮其它共享写集稳定后复跑。
|
||||
|
||||
- 2026-06-08 Codex TW-Q2-PERSONA-WRAPPER 认领
|
||||
- 写集:`lime-rs/src/app/runner.rs`、`lime-rs/src/commands/mod.rs`、`lime-rs/src/commands/persona_cmd.rs`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`lime-rs/src/services/runtime_auxiliary_projection_service.rs`、`lime-rs/src/services/runtime_evidence_auxiliary_runtime_service.rs`、`src`、`electron`、`packages`、`scripts`
|
||||
- 避让:Knowledge 写集、Electron host / ipc 共享热区、App Server protocol、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:删除已退场的项目人设 Tauri command 旧实现,保留 Runtime auxiliary persona projection current 业务语义。
|
||||
- 验证:`rg` 引用搜索、`rustfmt --edition 2021 --check --config skip_children=true "lime-rs/src/app/runner.rs" "lime-rs/src/commands/mod.rs"`、`cargo check --manifest-path "lime-rs/Cargo.toml" -p lime-agent`、`node scripts/check-command-contracts.mjs`
|
||||
- 启动基线:`persona_cmd.rs` 仍为完整旧 DB / Agent 生成 wrapper;前端 / Electron / packages / scripts 无同名正向调用,业务 persona projection 只通过 `auxiliary.generate_persona` route 留在 runtime services。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 Codex TW-Q2-PERSONA-WRAPPER 完成
|
||||
- 清理结果:`deleted`;`lime-rs/src/commands/persona_cmd.rs` 已删除,9 条 `commands::persona_cmd::*` runner 注册已撤掉,`commands/mod.rs` 已移除模块声明。
|
||||
- 旧入口搜索:`rg -n "commands::persona_cmd|pub mod persona_cmd|\\b(create_persona|list_personas|get_persona|update_persona|delete_persona|set_default_persona|list_persona_templates|get_default_persona|generate_persona)\\b" "lime-rs/src" "src" "electron" "packages" "scripts" --glob "!lime-rs/target/**"` 只剩 runtime services 中的 `auxiliary.generate_persona` route / tests,不再有 Tauri command 或前端调用。
|
||||
- 验证结果:`rustfmt --edition 2021 --check --config skip_children=true "lime-rs/src/app/runner.rs" "lime-rs/src/commands/mod.rs"` 通过;`cargo check --manifest-path "lime-rs/Cargo.toml" -p lime-agent` 通过;`node scripts/check-command-contracts.mjs` 通过,frontend commands `121`、Electron host commands `100`、mock priority commands `0`、DevBridge truth commands `120`。
|
||||
- 剩余阻塞:无;`auxiliary.generate_persona` 是 Runtime evidence / projection current 语义,不属于旧 Tauri command 残留。
|
||||
|
||||
- 2026-06-08 Codex TW-Q1-DOCS-SMOKE 认领
|
||||
- 写集:`internal/roadmap/agentui/README.md`、`internal/roadmap/agentui/lime-agentui-target-architecture.md`、`internal/roadmap/agentui/lime-agentui-code-map.md`、`internal/roadmap/agentui/lime-agentui-backend-coordination.md`、`internal/roadmap/agentui/lime-agentui-implementation-roadmap.md`、`internal/roadmap/agentui/conversation-projection-implementation-plan.md`、`scripts/electron/current-docs-guard.test.mjs`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`internal/roadmap/appserver/frontend-electron-migration.md`、`internal/aiprompts/commands.md`
|
||||
- 避让:App Server protocol、Rust commands、`electron/hostCommands.ts`、`electron/ipcChannels.ts`、`lime-rs/src/app/runner.rs`、`lime-rs/src/dev_bridge/dispatcher/**`
|
||||
- 目标:清掉 AgentUI current 文档里把旧 Tauri command 当主链证据的表述,并补 current docs guard 防回流。
|
||||
- 验证:`node --check "scripts/electron/current-docs-guard.test.mjs"`、`npm test -- "scripts/electron/current-docs-guard.test.mjs"`、定向 `rg`
|
||||
- 启动基线:工作树已有大量并行脏写集;本轮目标写集启动时均未被修改。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 Codex TW-Q1-DOCS-SMOKE 完成
|
||||
- 清理结果:`guard-added`;AgentUI current 文档不再把旧 Tauri command / bridge 表述为 current command gateway。
|
||||
- 旧入口搜索:`rg -n "Tauri Commands|Tauri Command 层|Tauri command 主入口|RuntimeApi --> Tauri|Api --> Tauri|Tauri --> AgentCrate|Tauri --> Services|任何新增或修改 Tauri command 必须同步四侧|runtime command \\+ DAO|Tauri command / bridge|协议、Tauri command" "internal/roadmap/agentui"` 无命中。
|
||||
- 验证结果:`node --check "scripts/electron/current-docs-guard.test.mjs"` 通过;`npm test -- "scripts/electron/current-docs-guard.test.mjs"` 通过,12 tests passed;定向 `git diff --check` 通过。
|
||||
- 剩余阻塞:无;`.gitignore` 已补 `!internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`,本文件可被 Git 追踪。
|
||||
|
||||
- 2026-06-08 main TW-Q3D-DEVBRIDGE-EMPTY-MODULES 认领
|
||||
- 写集:`lime-rs/src/dev_bridge/dispatcher.rs`、`lime-rs/src/dev_bridge/dispatcher/channels.rs`、`lime-rs/src/dev_bridge/dispatcher/companion.rs`、`lime-rs/src/dev_bridge/dispatcher/external_tools.rs`、`lime-rs/src/dev_bridge/dispatcher/tray.rs`
|
||||
- 只读参考:`lime-rs/src/dev_bridge/dispatcher/**`
|
||||
- 避让:`runner.rs`、App Server protocol、Electron host、Agent Runtime、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:删除只返回 `Ok(None)` 的空 dispatcher 模块,减少 DevBridge 分发噪音。
|
||||
- 验证:`rg` 引用搜索、`rustfmt --edition 2021 --check "lime-rs/src/dev_bridge/dispatcher.rs"`、`git diff --check -- "lime-rs/src/dev_bridge/dispatcher.rs"`
|
||||
- 启动基线:目标空模块未出现在 `git status --short`,`dispatcher.rs` 已有共享脏写集,本轮只移除空模块声明和空调用。
|
||||
- 状态:ready_for_review
|
||||
|
||||
- 2026-06-08 main TW-Q3D-DEVBRIDGE-EMPTY-MODULES 完成
|
||||
- 清理结果:deleted empty dispatcher files;removed-from-devbridge empty route calls。
|
||||
- 旧入口搜索:`rg -n "mod (channels|companion|external_tools|tray)|channels::try_handle|companion::try_handle|external_tools::try_handle|tray::try_handle" "lime-rs/src/dev_bridge"` 无命中。
|
||||
- 验证结果:`rustfmt --edition 2021 --check "lime-rs/src/dev_bridge/dispatcher.rs"` 通过;`git diff --check -- "lime-rs/src/dev_bridge/dispatcher.rs"` 通过。
|
||||
- 剩余阻塞:`lime-rs/src/dev_bridge/dispatcher.rs` 是共享脏文件,后续真实 command 分支清理需要继续按窄写集认领。
|
||||
|
||||
- 2026-06-08 subagent-models TW-Q3A-DEVBRIDGE-MODELS blocked_conflict
|
||||
- 写集:未写入。
|
||||
- 只读结论:`lime-rs/src/dev_bridge/dispatcher/models.rs` 已有 staged 修改,当前只剩 `get_models`、`refresh_model_registry`、`get_model_registry_provider_ids`;`get_model_registry`、`get_model_preferences`、`get_model_sync_state`、`get_all_alias_configs`、`get_provider_alias_config` 已从该 dispatcher 分支移除。
|
||||
- 阻塞:`src/lib/dev-bridge/commandPolicy.ts` 和 `src/lib/governance/agentCommandCatalog.json` 均为 `MM`,不能夹写同步 truth / catalog。
|
||||
- 验证结果:`git diff --cached --check -- "lime-rs/src/dev_bridge/dispatcher/models.rs"` 通过;`npm run governance:legacy-report` 通过;`npm run test:contracts` 失败于既有 Knowledge / desktop-host guard,不属于本任务写集。
|
||||
|
||||
- 2026-06-08 subagent-project-resources TW-Q3B-DEVBRIDGE-PROJECT-RESOURCES blocked_conflict
|
||||
- 写集:未写入。
|
||||
- 只读结论:`lime-rs/src/dev_bridge/dispatcher/project_resources.rs` 仍有 `list_materials`、`get_material_count`、`upload_material`;`src/lib/api/materials.ts` 仍通过 `safeInvoke(...)` 调这些命令。
|
||||
- 阻塞:`project_resources.rs` 已脏,且 `commandPolicy.ts` / `agentCommandCatalog.json` 均为 `MM`,不能夹写。
|
||||
- 验证结果:`git diff --check -- "lime-rs/src/dev_bridge/dispatcher/project_resources.rs"` 通过。
|
||||
|
||||
- 2026-06-08 main TW-Q0-SHARED-HEATMAP 只读复核
|
||||
- 写集:`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读结论:当前 `runner.rs`、`commandPolicy.ts`、`agentCommandCatalog.json`、`scripts/check-command-contracts.mjs` 仍是共享脏写集;多数可疑 Rust command 删除都需要同步这些事实源,不适合作为无人协调的快删项。
|
||||
- 低引用候选:`fetch_provider_models_from_api`、`start_telegram_remote`、`stop_telegram_remote`、`get_telegram_remote_status`、`update_last_check_timestamp`、`get_sysinfo` 仅被 `runner.rs` 直接引用,但因 `runner.rs` 当前为 `MM`,本轮不夹写。
|
||||
- 结论:后续进程若要继续快清,应优先选新的未脏守卫 / 文档切片,或等待共享写集释放后再处理低引用 command。
|
||||
- 状态:ready_for_review
|
||||
|
||||
- 2026-06-08 main TW-Q0-INVENTORY 认领
|
||||
- 写集:`internal/exec-plans/tauri-wrapper-command-inventory.md`、`.gitignore`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`lime-rs/src/app/runner.rs`、`lime-rs/src/dev_bridge/**`、`lime-rs/src/commands/**`、`src/lib/api/**`、`electron/**`、`packages/app-server-client/**`
|
||||
- 避让:`runner.rs`、App Server protocol、Electron host、Agent Runtime、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:落一份机械 inventory 快照,帮助后续进程按命令族拆分清理,不重复扫描。
|
||||
- 验证:`rg` 计数复核、`git diff --check`
|
||||
- 启动基线:工作树已有大量并行脏写集;本轮只新增 inventory 文档并补 `.gitignore` 白名单。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q0-INVENTORY 完成
|
||||
- 清理结果:`guard-added` / `inventory-added`;新增 `internal/exec-plans/tauri-wrapper-command-inventory.md`,记录 Tauri command、runner、DevBridge、前端 invoke 与 App Server method 的机械对照。
|
||||
- 旧入口搜索:`rg -n "#\\[tauri::command" "lime-rs/src" -g "*.rs" | wc -l` 当前为 `490`;inventory 明确 `low-reference` / `devbridge-only` 只是辅助信号,不直接等于 `dead`。
|
||||
- 验证结果:`git diff --check -- ".gitignore" ".codex/skills/lime-command-boundary/references/commands.md" "internal/aiprompts/commands.md" "internal/exec-plans/tauri-wrapper-command-inventory.md" "internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md" "internal/roadmap/agentapp/p17-formal-entry-contract.md" "internal/roadmap/agentapp/p17-lifecycle-cleanup-contract-hardening.md" "internal/roadmap/agentapp/p18-typed-capability-sdk-gate.md" "internal/roadmap/agentapp/p18-7-full-lime-capability-surface.md" "internal/roadmap/agentapp/p17-4-host-bridge-runtime.md" "internal/roadmap/agentui/html-preview-provider-readiness-20260526.md" "internal/roadmap/agentui/lime-agentui-standard-alignment.md"` 通过。
|
||||
- 剩余阻塞:真正删除低引用命令仍需等待 `runner.rs`、`commandPolicy.ts`、`agentCommandCatalog.json` 等共享写集释放。
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMANDS-DIR-FREEZE 认领
|
||||
- 写集:`AGENTS.md`、`internal/aiprompts/commands.md`、`.codex/skills/lime-command-boundary/references/commands.md`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`、`internal/exec-plans/tauri-wrapper-command-inventory.md`
|
||||
- 只读参考:`AGENTS.md`、`internal/aiprompts/governance.md`
|
||||
- 避让:`lime-rs/src/commands/**`、`runner.rs`、App Server protocol、Electron host、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:明确 `lime-rs/src/commands/**` 只作为旧 Tauri wrapper 清理区,不再落新业务逻辑。
|
||||
- 验证:`rg` 规则命中、`git diff --check`
|
||||
- 启动基线:目标规则文件未出现在 `git status --short`;队列与 inventory 为本轮新增未跟踪文件。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMANDS-DIR-FREEZE 完成
|
||||
- 清理结果:`guard-added`;根 `AGENTS.md`、命令边界文档、skill 参考、清理队列和 inventory 均写明 `lime-rs/src/commands/**` 不再承接新逻辑。
|
||||
- 旧入口搜索:`rg -n "lime-rs/src/commands/\\*\\*.*清理区|不再承接新的业务逻辑|不再落新的业务逻辑|新增业务逻辑、API adapter" "AGENTS.md" "internal/aiprompts/commands.md" ".codex/skills/lime-command-boundary/references/commands.md" "internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md" "internal/exec-plans/tauri-wrapper-command-inventory.md"` 命中 9 处。
|
||||
- 验证结果:定向 `git diff --check` 通过。
|
||||
- 剩余阻塞:仍需后续把现有 wrapper 按领域迁出或删除;本条只封新增方向。
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMANDS-DIR-HARD-FREEZE 完成
|
||||
- 写集:`AGENTS.md`、`internal/aiprompts/commands.md`、`.codex/skills/lime-command-boundary/references/commands.md`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`、`internal/exec-plans/tauri-wrapper-command-inventory.md`
|
||||
- 清理结果:`guard-hardened`;`lime-rs/src/commands/**` 规则从“可保留薄委托 / 退场包装”收紧为“只删旧 wrapper、撤注册、做机械编译修复,删不动就登记 blocker”。
|
||||
- 旧入口搜索:`rg -n "只允许.*薄|只允许.*stub|只允许.*兼容委托|保留带退出条件|收窄带退出条件|收窄为委托" ...` 无命中;`rg -n "deprecated_.*command|DEPRECATED_.*COMMAND|已退场|legacy Tauri command|退场" "lime-rs/src/commands"` 命中现有 command stub 化 diff,作为后续撤注册 / 删除 blocker,不在本轮夹写。
|
||||
- 验证结果:`git diff --check -- "AGENTS.md" "internal/aiprompts/commands.md" ".codex/skills/lime-command-boundary/references/commands.md" "internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md" "internal/exec-plans/tauri-wrapper-command-inventory.md"` 通过。
|
||||
- 剩余阻塞:当前 `lime-rs/src/commands/**` 已有大量并行脏 diff,部分文件被改成 deprecated stub;本轮不夹写这些共享文件,后续应按命令族直接撤 runner / dispatcher / catalog / mock 后删除,而不是继续补 stub。
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMANDS-DIR-STUB-GUARD 认领
|
||||
- 写集:`src/lib/governance/rustCommandsCurrentBoundary.test.ts`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`lime-rs/src/commands/**`、`internal/aiprompts/commands.md`、`.codex/skills/lime-command-boundary/references/commands.md`
|
||||
- 避让:`lime-rs/src/commands/**`、`lime-rs/src/app/runner.rs`、App Server protocol、Electron host、`src/lib/governance/agentCommandCatalog.json`、`src/lib/dev-bridge/commandPolicy.ts`、`internal/roadmap/appserver/**`
|
||||
- 目标:补一个不碰共享热区的 guard,把当前已存在的 deprecated/fail-closed command stub 文件登记成待删基线,禁止继续在 `lime-rs/src/commands/**` 新增同类 stub 文件。
|
||||
- 验证:`npx vitest run "src/lib/governance/rustCommandsCurrentBoundary.test.ts" --silent=passed-only --disableConsoleIntercept`、`npx eslint --max-warnings 0 "src/lib/governance/rustCommandsCurrentBoundary.test.ts"`、`git diff --check`
|
||||
- 启动基线:`runner.rs`、`agentCommandCatalog.json`、`commandPolicy.ts`、App Server protocol、Electron host 与 App Server roadmap 文档均为并行脏写集;本轮不夹写。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMANDS-DIR-STUB-GUARD 完成
|
||||
- 清理结果:`guard-added`;`rustCommandsCurrentBoundary.test.ts` 现在把当前已出现的 deprecated/fail-closed command stub 文件当作待删上限,允许后续减少,但禁止在 `lime-rs/src/commands/**` 新增同类 stub 文件。
|
||||
- 旧入口搜索:`node` 脚本扫描 `lime-rs/src/commands/**/*.rs` 的 `DEPRECATED_*COMMAND` / `deprecated_*command` / `fail-closed 退场面` / `legacy Tauri command` 命中 19 个现有 stub 文件;这些文件仍是后续撤 runner / dispatcher / catalog / mock 后删除的 blocker,不是完成态。
|
||||
- 验证结果:`npx vitest run "src/lib/governance/rustCommandsCurrentBoundary.test.ts" --silent=passed-only --disableConsoleIntercept` 通过,4 tests;`npx eslint --max-warnings 0 "src/lib/governance/rustCommandsCurrentBoundary.test.ts"` 通过;`git diff --check` 通过。
|
||||
- 剩余阻塞:`runner.rs`、`agentCommandCatalog.json`、`commandPolicy.ts`、App Server protocol、Electron host 与 App Server roadmap 文档仍为并行共享脏写集;本轮未物理删除 command wrapper。
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMAND-SKILL-STUB-RULE 认领
|
||||
- 写集:`.codex/skills/lime-command-boundary/references/commands.md`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`internal/aiprompts/commands.md`
|
||||
- 避让:`lime-rs/src/commands/**`、`runner.rs`、App Server protocol、Electron host、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:同步命令边界 skill 参考文件的明确禁止项,避免后续 Agent 从 skill 读取到“只禁止业务逻辑但未禁止 compat wrapper / 退场 stub”的旧口径。
|
||||
- 验证:定向 `rg`、`git diff --check`
|
||||
- 启动基线:目标 skill 参考文件未出现在 `git status --short`;共享热区仍为并行脏写集。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMAND-SKILL-STUB-RULE 完成
|
||||
- 清理结果:`guard-hardened`;`.codex/skills/lime-command-boundary/references/commands.md` 的“明确禁止”段已同步禁止在 `lime-rs/src/commands/**` 新增 compat wrapper / 退场 stub。
|
||||
- 旧入口搜索:`rg -n '在 `lime-rs/src/commands/\*\*` 新增业务逻辑' "internal/aiprompts/commands.md" ".codex/skills/lime-command-boundary/references/commands.md"` 两处一致命中。
|
||||
- 验证结果:`git diff --check -- ".codex/skills/lime-command-boundary/references/commands.md" "internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md"` 通过。
|
||||
- 剩余阻塞:skill 本体仍需同步 `lime-rs/src/commands/**` 硬禁区,避免只读 `SKILL.md` 的 Agent 漏读 references 后沿旧 compat 口径行动。
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMAND-SKILL-BODY-RULE 认领
|
||||
- 写集:`.codex/skills/lime-command-boundary/SKILL.md`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`.codex/skills/lime-command-boundary/references/commands.md`、`internal/aiprompts/commands.md`
|
||||
- 避让:`lime-rs/src/commands/**`、`runner.rs`、App Server protocol、Electron host、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:让 skill 本体直接携带 `lime-rs/src/commands/**` 删除清理区规则,减少后续 Agent 漏读 reference 时继续补 compat wrapper / stub 的风险。
|
||||
- 验证:定向 `rg`、`git diff --check`
|
||||
- 启动基线:目标 skill 本体未出现在 `git status --short`;共享热区仍为并行脏写集。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q0-COMMAND-SKILL-BODY-RULE 完成
|
||||
- 清理结果:`guard-hardened`;`.codex/skills/lime-command-boundary/SKILL.md` 本体已直接写明 `lime-rs/src/commands/**` 是旧 Tauri wrapper 删除清理区,禁止新增业务逻辑、API adapter、runtime 分支、领域服务实现、compat wrapper 或退场 stub。
|
||||
- 旧入口搜索:`rg` 命中 skill 本体、skill reference 和仓库 `internal/aiprompts/commands.md` 的同一硬边界;后续 Agent 即使只读 skill 本体也会看到 `commands/**` 禁区。
|
||||
- 验证结果:`git diff --check -- ".codex/skills/lime-command-boundary/SKILL.md" ".codex/skills/lime-command-boundary/references/commands.md" "internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md"` 通过。
|
||||
- 剩余阻塞:这仍是守卫收口,不替代物理删除;当前 `runner.rs` / catalog / commandPolicy / Electron-App Server protocol 热区未释放。
|
||||
|
||||
- 2026-06-08 main TW-Q1-AGENTAPP-AGENTUI-DOC-TERMS 认领
|
||||
- 写集:`internal/roadmap/agentapp/p17-formal-entry-contract.md`、`internal/roadmap/agentapp/p17-lifecycle-cleanup-contract-hardening.md`、`internal/roadmap/agentapp/p18-typed-capability-sdk-gate.md`、`internal/roadmap/agentapp/p18-7-full-lime-capability-surface.md`、`internal/roadmap/agentapp/p17-4-host-bridge-runtime.md`、`internal/roadmap/agentui/html-preview-provider-readiness-20260526.md`、`internal/roadmap/agentui/lime-agentui-standard-alignment.md`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`internal/aiprompts/commands.md`、子代理只读文档残留报告
|
||||
- 避让:`lime-rs/src/commands/**`、`runner.rs`、App Server protocol、Electron host、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:清掉 Agent App / AgentUI current 计划中把新增能力表述为 Tauri command / Rust registration 的误导,改为 Electron Desktop Host / App Server / legacy facade 边界。
|
||||
- 验证:定向 `rg`、`git diff --check`
|
||||
- 启动基线:目标 roadmap 文件启动时未出现在 `git status --short`;仅队列和 inventory 为本轮新增未跟踪文件。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q1-AGENTAPP-AGENTUI-DOC-TERMS 完成
|
||||
- 清理结果:`deprecated docs evidence`;P17 / P18 / AgentUI current 语境不再要求新增或修改 Tauri command / Rust registration,统一改成 Electron Desktop Host IPC / App Server JSON-RPC / legacy desktop facade 命令边界;HTML 预览文档把旧 Tauri asset protocol 降级为 deprecated reference。
|
||||
- 旧入口搜索:`rg -n "修改 Tauri command|改动 Tauri command|引入或修改 Tauri command|新增 Tauri command|专用 Tauri command|平行 Tauri command|Tauri bridge command|直接 Tauri|Tauri / raw Worker|允许集中调用 Tauri command|在 Tauri 中|Tauri 本地文件预览|Rust 注册" ...` 无命中;剩余 `assetProtocol` / `WebviewWindow` / `convertFileSrc` 仅在 `deprecated reference` 外部依据段落。
|
||||
- 验证结果:`node --check "scripts/electron/current-docs-guard.test.mjs"` 通过;`npm test -- "scripts/electron/current-docs-guard.test.mjs"` 通过,12 tests;`npm run governance:legacy-report` 通过,边界违规 0;定向 `git diff --check` 通过。
|
||||
- 剩余阻塞:历史实施记录里“未新增 Tauri command”的过去事实仍保留;不作为 current 迁移指引。
|
||||
|
||||
- 2026-06-08 main TW-Q1-KNOWLEDGE-RUNTIME-DOC-TERMS 认领
|
||||
- 写集:`internal/roadmap/knowledge/prd.md`、`internal/roadmap/agentruntime/test-cases.md`、`internal/roadmap/agentruntime/architecture.md`、`internal/roadmap/agentruntime/implementation-plan.md`、`internal/roadmap/memory/acceptance.md`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`internal/aiprompts/commands.md`、`internal/aiprompts/governance.md`
|
||||
- 避让:`lime-rs/src/commands/**`、`runner.rs`、App Server protocol、Electron host、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:清掉 Knowledge / AgentRuntime / Memory current 计划中把命令边界写成 Tauri command / Rust generate_handler / tauri-mock 的误导。
|
||||
- 验证:定向 `rg`、`git diff --check`
|
||||
- 启动基线:目标 roadmap 文件启动时未出现在 `git status --short`;共享热区仍为 `MM`,本轮不夹写。
|
||||
- 状态:done
|
||||
|
||||
- 2026-06-08 main TW-Q1-KNOWLEDGE-RUNTIME-DOC-TERMS 完成
|
||||
- 清理结果:`deprecated docs evidence`;Knowledge / AgentRuntime / Memory current 规划不再把命令边界描述为新增或验证 Tauri command / Rust `generate_handler` / tauri-mock,而是收敛到 App Server / Electron Host / legacy facade 边界。
|
||||
- 旧入口搜索:`rg -n 'Tauri command|Tauri commands|tauri::generate_handler|src/lib/tauri-mock|新增 Tauri command|修改 Tauri|若新增 Tauri|如果新增 Tauri|必须同步.*Tauri|Tauri 壳|Rust `generate_handler`|Rust handler|Rust 注册' "internal/roadmap/knowledge/prd.md" "internal/roadmap/agentruntime/test-cases.md" "internal/roadmap/agentruntime/architecture.md" "internal/roadmap/agentruntime/implementation-plan.md" "internal/roadmap/memory/acceptance.md"` 无命中。
|
||||
- 验证结果:定向 `git diff --check` 通过;后续补 `current-docs-guard` / `governance:legacy-report` 结果。
|
||||
- 剩余阻塞:其他历史 roadmap 中仍有“未新增 Tauri command”等过去事实记录;本条只清 current 规划 / 测试口径。
|
||||
|
||||
## 快速清理通用退出条件
|
||||
|
||||
每个条目只有同时满足下列条件,才能从队列中移除:
|
||||
|
||||
- `rg` 证明生产入口不再引用旧命令名。
|
||||
- 对应 `runner.rs` 注册已删除,或有明确 compat 退出条件。
|
||||
- 对应 `lime-rs/src/dev_bridge/dispatcher/**` 分支已删除,或只剩 test-only / compat delegate。
|
||||
- `src/lib/dev-bridge/commandPolicy.ts`、`agentCommandCatalog.json`、desktop-host mock / legacy mock 没有把旧命令重新当 current。
|
||||
- 至少跑最近的 contract / lint / doc check;涉及命令边界时跑 `npm run test:contracts`。
|
||||
|
||||
## 队列
|
||||
|
||||
### Q0:只读 inventory 与守卫补齐
|
||||
|
||||
难度:低
|
||||
重要性:低
|
||||
分类:`current guard`
|
||||
|
||||
可先做:
|
||||
|
||||
- 生成并提交一份机械 inventory:`#[tauri::command]`、`runner.rs` 注册、DevBridge dispatcher、前端 `safeInvoke`、Electron Host 白名单、App Server methods 对照。
|
||||
- 给 `scripts/check-command-contracts.mjs` 或独立治理测试补统计阈值,防止已清命令回流。
|
||||
|
||||
为什么先做:
|
||||
|
||||
- 不改业务逻辑。
|
||||
- 能把后续每一刀的删除范围变成可验证事实。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
node scripts/check-command-contracts.mjs
|
||||
npm run test:contracts
|
||||
```
|
||||
|
||||
### Q1:文档 / smoke / 测试 fixture 里的旧 Tauri 证据
|
||||
|
||||
难度:低
|
||||
重要性:低
|
||||
分类:`dead / deprecated docs evidence`
|
||||
|
||||
候选:
|
||||
|
||||
- current 文档中仍把 `tauri dev`、`headless Tauri`、`Tauri GUI smoke` 当可交付证据的残留。
|
||||
- smoke summary / process owner 里只用于旁路观测的旧 Tauri runtime 字段。
|
||||
- standalone artifact adapter、旧 package materializer、旧 `src-tauri` 命名 fixture。
|
||||
|
||||
执行口径:
|
||||
|
||||
- current 文档和 current smoke 只允许写 Electron Desktop Host / App Server。
|
||||
- 旧 Tauri 只允许出现在 `deprecated` / `dead guard` 语境。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
node --check "scripts/electron/current-docs-guard.test.mjs"
|
||||
npm test -- "scripts/electron/current-docs-guard.test.mjs" "scripts/electron/current-entrypoints.test.mjs"
|
||||
rg -n "tauri dev|headless Tauri|Tauri GUI smoke|src-tauri" "internal" "scripts"
|
||||
```
|
||||
|
||||
### Q2:零引用或已下线产品线的旧命令名
|
||||
|
||||
难度:低到中
|
||||
重要性:低
|
||||
分类:`dead`
|
||||
|
||||
优先候选:
|
||||
|
||||
- 旧 Plugin / SceneApp 命令族:`plugin_*`、`sceneapp_*`。
|
||||
- 旧设置页安全 / 性能命令:`get_retry_config`、`update_retry_config`、`get_failover_config`。
|
||||
- 旧 provider helper:`fetch_provider_models_auto` 等无 current 入口的 helper。
|
||||
- 已经不在前端 current 入口出现的 demo / diagnostic / one-off command。
|
||||
|
||||
执行口径:
|
||||
|
||||
- 不迁成 compat。
|
||||
- 直接删前端入口、runner 注册、DevBridge dispatcher、mock / catalog 残留。
|
||||
- 如果只剩文档历史记录,不改历史计划正文,只补 current guard。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
rg -n "<旧命令名>" "src" "electron" "lime-rs/src" "packages" "scripts"
|
||||
npm run test:contracts
|
||||
```
|
||||
|
||||
### Q3:已 current 覆盖的 DevBridge dispatcher 分支
|
||||
|
||||
难度:中
|
||||
重要性:低到中
|
||||
分类:`deprecated -> dead`
|
||||
|
||||
优先候选:
|
||||
|
||||
- `lime-rs/src/dev_bridge/dispatcher/models.rs`
|
||||
- `get_models`
|
||||
- `get_model_registry_provider_ids`
|
||||
- `refresh_model_registry`
|
||||
- `lime-rs/src/dev_bridge/dispatcher/project_resources.rs`
|
||||
- `list_materials`
|
||||
- `get_material_count`
|
||||
- `upload_material`
|
||||
- `lime-rs/src/dev_bridge/dispatcher/memory.rs`
|
||||
- `unified_memory_list`
|
||||
- `lime-rs/src/dev_bridge/dispatcher/app_runtime.rs`
|
||||
- `get_config`
|
||||
- `save_config`
|
||||
- `get_server_diagnostics`
|
||||
|
||||
为什么靠前:
|
||||
|
||||
- dispatcher 分支本身不是 current transport。
|
||||
- 很多分支只是旧 HTTP debug bridge 的命令分发,不应再作为生产事实源。
|
||||
|
||||
注意:
|
||||
|
||||
- 删除前必须确认 Electron Host / App Server / frontend gateway 已可真实工作。
|
||||
- 如果命令仍在 `commandPolicy.ts` 的 DevBridge truth 里,要同步移除或改为 deprecated guard。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
rg -n "<命令名>" "src" "electron" "lime-rs/src/dev_bridge" "lime-rs/src/app/runner.rs" "scripts"
|
||||
npm run test:contracts
|
||||
```
|
||||
|
||||
### Q4:纯壳能力的旧 Tauri wrapper
|
||||
|
||||
难度:中
|
||||
重要性:低到中
|
||||
分类:`Desktop Host current`
|
||||
|
||||
候选:
|
||||
|
||||
- `window_cmd.rs`
|
||||
- `get_window_size`
|
||||
- `set_window_size`
|
||||
- `center_window`
|
||||
- `toggle_fullscreen`
|
||||
- `is_fullscreen`
|
||||
- `tray_cmd.rs`
|
||||
- `sync_tray_model_shortcuts`
|
||||
- `external_tools_cmd.rs`
|
||||
- `open_external_url`
|
||||
- `open_codex_cli_login`
|
||||
- `open_codex_cli_logout`
|
||||
- `config_cmd.rs`
|
||||
- `open_config_folder`
|
||||
- `open_auth_dir`
|
||||
- `expand_path`
|
||||
|
||||
执行口径:
|
||||
|
||||
- 迁到 Electron Desktop Host,不进 App Server。
|
||||
- 前端入口放在 `src/lib/desktop-host/*` 或对应 `src/lib/api/*`。
|
||||
- 清理同名 Tauri command、runner 注册和 DevBridge dispatcher。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npx vitest run "electron/hostCommands.test.ts" "electron/ipcChannels.test.ts"
|
||||
npm run test:contracts
|
||||
```
|
||||
|
||||
### Q5:已 current 的读链残留
|
||||
|
||||
难度:中
|
||||
重要性:中
|
||||
分类:`compat / deprecated -> dead`
|
||||
|
||||
候选:
|
||||
|
||||
- Knowledge 读链:
|
||||
- `knowledge_list_packs`
|
||||
- `knowledge_get_pack`
|
||||
- Workspace 读链:
|
||||
- `workspace_list`
|
||||
- `workspace_get`
|
||||
- `workspace_get_default`
|
||||
- `workspace_get_projects_root`
|
||||
- Model registry 读链:
|
||||
- `get_model_registry`
|
||||
- `get_model_registry_provider_ids`
|
||||
- `search_models`
|
||||
- `get_models_for_provider`
|
||||
- Agent App installed / UI runtime 读链:
|
||||
- `agent_app_list_installed`
|
||||
- `agent_app_get_ui_runtime_status`
|
||||
|
||||
为什么排在 Q5:
|
||||
|
||||
- 对用户可见,但多为读链,迁移风险低于写链和 runtime 主链。
|
||||
- 需要同步前端 API、Electron projection、App Server client / protocol、mock 和 runner,不能只删 Rust。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/knowledge.test.ts" "src/lib/api/modelRegistry.test.ts" "src/lib/api/agentApps.test.ts"
|
||||
```
|
||||
|
||||
### Q6:本地文件和 session file 残留
|
||||
|
||||
难度:中
|
||||
重要性:中
|
||||
分类:`current App Server service / Desktop Host shell split`
|
||||
|
||||
候选:
|
||||
|
||||
- `file_browser_service.rs`
|
||||
- `get_file_name`
|
||||
- `session_files_cmd.rs`
|
||||
- `session_files_resolve_file_path`
|
||||
- `session_files_save_file`
|
||||
- `session_files_read_file`
|
||||
- `session_files_list_files`
|
||||
- DevBridge `dispatcher/files.rs`
|
||||
- layered design export / read / OCR 相关旧分支
|
||||
|
||||
执行口径:
|
||||
|
||||
- 文件 CRUD / session file metadata 进 App Server / services。
|
||||
- 打开目录、系统 reveal、默认 App 打开归 Electron Host。
|
||||
- layered design 文件读写若已有 current gateway,应同轮撤 DevBridge 分支。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/session-files.test.ts" "src/lib/api/fileBrowser.test.ts"
|
||||
```
|
||||
|
||||
### Q7:Config / Logs / Diagnostics 残留
|
||||
|
||||
难度:中
|
||||
重要性:中
|
||||
分类:`split: App Server config service / Electron diagnostics`
|
||||
|
||||
候选:
|
||||
|
||||
- `app/commands/config.rs`
|
||||
- `get_config`
|
||||
- `save_config`
|
||||
- `get_environment_preview`
|
||||
- `get_default_provider`
|
||||
- `set_default_provider`
|
||||
- `app/commands/logs.rs`
|
||||
- `get_logs`
|
||||
- `clear_logs`
|
||||
- `report_frontend_crash`
|
||||
- `report_frontend_debug_log`
|
||||
- `export_support_bundle`
|
||||
- `app/commands/server.rs`
|
||||
- `get_server_diagnostics`
|
||||
|
||||
执行口径:
|
||||
|
||||
- 配置事实源若属于 runtime / provider,应收进 App Server 或 services。
|
||||
- 前端 crash/debug/support bundle 更偏 Electron Desktop Host / diagnostic bridge。
|
||||
- 不允许 DevBridge health / diagnostic 假装 current Electron-host 证据。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/appConfig.test.ts" "src/lib/api/logs.test.ts" "src/lib/api/frontendCrash.test.ts" "src/lib/api/frontendDebug.test.ts"
|
||||
```
|
||||
|
||||
### Q8:Browser / Webview / CDP / Profile
|
||||
|
||||
难度:中到高
|
||||
重要性:中
|
||||
分类:`Desktop Host / Browser Runtime current`
|
||||
|
||||
候选大户:
|
||||
|
||||
- `webview_cmd.rs`:约 29 个 Tauri command。
|
||||
- `browser_connector_cmd.rs`:约 10 个。
|
||||
- `browser_profile_cmd.rs`:约 5 个。
|
||||
- `browser_environment_cmd.rs`:约 4 个。
|
||||
- DevBridge browser dispatcher:`browser/runtime.rs`、`browser/sessions.rs`、`browser/cdp.rs`、`browser/bridge.rs`。
|
||||
|
||||
执行口径:
|
||||
|
||||
- CDP / browser window / profile launch 属于 Electron Desktop Host 或 Browser Runtime,不进 App Server runtime。
|
||||
- 先清已 current 的 debug / smoke 分支,再迁真实用户入口。
|
||||
- 浏览器动作审计、session state、event buffer 需要明确 Browser Runtime 事实源,不能用 DevBridge fallback。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/webview-api.test.ts" "src/lib/desktop-host/browserMocks.test.ts"
|
||||
```
|
||||
|
||||
### Q9:Voice / ASR / Recording / Voice Models
|
||||
|
||||
难度:中到高
|
||||
重要性:中到高
|
||||
分类:`split: Desktop Host device / App Server service`
|
||||
|
||||
候选:
|
||||
|
||||
- DevBridge `dispatcher/voice.rs`:约 22 个命令。
|
||||
- `voice_model_cmd.rs`
|
||||
- `voice_test_cmd.rs`
|
||||
- `asr_cmd.rs`
|
||||
- recording start / stop / snapshot / segment / status。
|
||||
|
||||
执行口径:
|
||||
|
||||
- 录音设备、快捷键、系统麦克风权限归 Electron Desktop Host。
|
||||
- ASR 凭证、模型目录、转写任务可进入 App Server / services。
|
||||
- 不允许测试 mock 当生产录音通路。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/asrProvider.test.ts" "src/lib/api/voiceModels.test.ts" "src/lib/desktop-host/voiceMocks.test.ts"
|
||||
```
|
||||
|
||||
### Q10:Skills / Skill Package / Marketplace
|
||||
|
||||
难度:高
|
||||
重要性:中到高
|
||||
分类:`App Server service / Desktop Host shell split`
|
||||
|
||||
候选大户:
|
||||
|
||||
- `skill_cmd.rs`:约 28 个 command。
|
||||
- DevBridge `dispatcher/skills.rs`:约 22 个 command。
|
||||
- `skill_exec_cmd.rs`
|
||||
- `officialSkillMarketplace` 前端 gateway / desktop-host mocks。
|
||||
|
||||
执行口径:
|
||||
|
||||
- skill catalog / install / package metadata 进 App Server / services。
|
||||
- reveal、file association、打开本地包归 Electron Desktop Host。
|
||||
- `execute_skill` 与 Agent Runtime tool chain 相关,不能和 marketplace 管理混在一刀。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/skills.test.ts" "src/lib/api/skill-execution.test.ts" "src/lib/api/officialSkillMarketplace.test.ts"
|
||||
```
|
||||
|
||||
### Q11:MCP 管理与运行命令
|
||||
|
||||
难度:高
|
||||
重要性:高
|
||||
分类:`App Server current`
|
||||
|
||||
候选:
|
||||
|
||||
- `mcp_cmd.rs`:约 19 个 command。
|
||||
- CRUD / import / sync / start-stop / tool-call / prompt-get / resource-read。
|
||||
|
||||
执行口径:
|
||||
|
||||
- 不修回旧 Tauri in-process bridge。
|
||||
- MCP server config、tool call、prompt/resource 读写都应走 App Server JSON-RPC。
|
||||
- list/status 已 current 的部分,迁完后同轮撤 Tauri wrapper 和 runner 注册。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
cargo test --manifest-path "lime-rs/Cargo.toml" -p app-server mcp
|
||||
npx vitest run "src/lib/api/mcp.test.ts" "src/lib/api/mcp.failClosed.test.ts" "src/hooks/useMcp.test.tsx" "src/hooks/useMcpServers.test.tsx"
|
||||
```
|
||||
|
||||
### Q12:Knowledge / Workspace / Content 写链
|
||||
|
||||
难度:高
|
||||
重要性:高
|
||||
分类:`App Server current`
|
||||
|
||||
候选:
|
||||
|
||||
- `knowledge_import_source`
|
||||
- `knowledge_compile_pack`
|
||||
- `knowledge_set_default_pack`
|
||||
- `knowledge_update_pack_status`
|
||||
- `knowledge_resolve_context`
|
||||
- `workspace_create`
|
||||
- `workspace_update`
|
||||
- `workspace_delete`
|
||||
- `workspace_set_default`
|
||||
- `content_create`
|
||||
- `content_update`
|
||||
- `content_delete`
|
||||
- `content_reorder`
|
||||
|
||||
执行口径:
|
||||
|
||||
- 写链必须有真实 App Server method、schema、TS client、front gateway 和 fail-closed 测试。
|
||||
- 迁完后撤同名 DevBridge dispatcher、runner 注册、Tauri wrapper。
|
||||
- 不保留新旧两个 service / projection。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
cargo test --manifest-path "lime-rs/Cargo.toml" -p app-server knowledge
|
||||
npx vitest run "src/lib/api/knowledge.test.ts" "src/lib/api/project.test.ts"
|
||||
```
|
||||
|
||||
### Q13:Memory / Unified Memory / Project Memory
|
||||
|
||||
难度:高
|
||||
重要性:高
|
||||
分类:`App Server current / RuntimeCore support`
|
||||
|
||||
候选:
|
||||
|
||||
- `memory_cmd.rs`:character / world_building / outline / project memory。
|
||||
- `memory_management_cmd.rs`:runtime stats / cleanup / scaffold / prefetch。
|
||||
- `unified_memory_cmd.rs`:CRUD / search / stats / analyze。
|
||||
- `memory_search_cmd.rs`、`memory_feedback_cmd.rs`。
|
||||
|
||||
执行口径:
|
||||
|
||||
- runtime memory 与 Agent turn 上下文绑定,不能只迁 UI API。
|
||||
- CRUD 和 search 可先按 service 分层进 App Server。
|
||||
- scaffold runtime agents template 涉及 workspace 文件系统,需确认 Desktop Host / App Server 边界。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/memory.test.ts" "src/lib/api/memoryRuntime.test.ts" "src/lib/api/unifiedMemory.test.ts"
|
||||
```
|
||||
|
||||
### Q14:Agent App Runtime / Agent App install
|
||||
|
||||
难度:高
|
||||
重要性:高
|
||||
分类:`App Server current / compat facade`
|
||||
|
||||
候选:
|
||||
|
||||
- `agent_app_runtime_start_task`
|
||||
- `agent_app_runtime_get_task`
|
||||
- `agent_app_runtime_cancel_task`
|
||||
- `agent_app_runtime_submit_host_response`
|
||||
- `agent_app_start_ui_runtime`
|
||||
- `agent_app_stop_ui_runtime`
|
||||
- `agent_app_launch_shell`
|
||||
- `agent_app_select_directory`
|
||||
- install / uninstall / package inspection。
|
||||
|
||||
执行口径:
|
||||
|
||||
- task lifecycle 进入 App Server runtime / agent app runtime client。
|
||||
- shell launch / directory picker 归 Electron Desktop Host。
|
||||
- install/package cloud bootstrap 需要同步前端、App Server client、mock 和 governance catalog。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
npx vitest run "src/lib/api/agentAppRuntime.test.ts" "src/lib/api/agentApps.test.ts" "src/features/agent-app/ui/AgentAppsPage.test.tsx"
|
||||
```
|
||||
|
||||
### Q15:Agent Runtime residual
|
||||
|
||||
难度:最高
|
||||
重要性:最高
|
||||
分类:`App Server RuntimeCore current`
|
||||
|
||||
候选大户:
|
||||
|
||||
- `agent_runtime_create_session`
|
||||
- `agent_runtime_list_sessions`
|
||||
- `agent_runtime_get_session`
|
||||
- `agent_runtime_update_session`
|
||||
- `agent_runtime_submit_turn`
|
||||
- `agent_runtime_get_thread_read`
|
||||
- `agent_runtime_respond_action`
|
||||
- `agent_runtime_export_evidence_pack`
|
||||
- `agent_runtime_get_tool_inventory`
|
||||
- `agent_runtime_spawn_subagent`
|
||||
- checkpoint / handoff / replay / review / queued turn。
|
||||
|
||||
执行口径:
|
||||
|
||||
- 不能简单删除;必须逐条迁到 App Server JSON-RPC current。
|
||||
- `runtime_turn/**`、`tool_runtime/**`、DTO、event projection、evidence projection 里的可复用核心先抽到 RuntimeCore / services。
|
||||
- legacy `agent_runtime_*` 最多保留 thin compat delegate,并写退出条件;不得再承接新业务逻辑。
|
||||
|
||||
验证:
|
||||
|
||||
```bash
|
||||
npm run check:agent-runtime-clients
|
||||
npm run test:contracts
|
||||
npm run smoke:agent-session-history-electron-fixture -- --timeout-ms 180000
|
||||
```
|
||||
|
||||
## 推荐执行顺序
|
||||
|
||||
如果目标是快速减少 Tauri 痕迹,建议按下面顺序开刀:
|
||||
|
||||
1. Q0:inventory 和守卫。
|
||||
2. Q1:文档 / smoke / fixture 旧 Tauri 证据。
|
||||
3. Q2:零引用 / 已下线旧命令族。
|
||||
4. Q3:已 current 覆盖的 DevBridge dispatcher 分支。
|
||||
5. Q4:纯壳能力旧 Tauri wrapper。
|
||||
6. Q5:已 current 的读链残留。
|
||||
7. Q6-Q10:按领域分批清中等风险旧面。
|
||||
8. Q11-Q15:回到 App Server 主链,逐条迁 MCP、Workspace / Knowledge / Memory、Agent Runtime。
|
||||
|
||||
不要为了“看起来清得多”优先碰 Q15。Agent Runtime 是主链事实源迁移,不是快速垃圾回收。
|
||||
|
||||
## 文档 / 守卫补强记录
|
||||
|
||||
- 2026-06-08 Codex TW-Q2-USAGE-STATS-WRAPPER 认领
|
||||
- 写集:`lime-rs/src/app/runner.rs`、`lime-rs/src/commands/mod.rs`、`lime-rs/src/commands/usage_stats_cmd.rs`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`src/lib/api/usageStats.ts`、`src/lib/api/usageStats.test.ts`、`packages/app-server-client/src/protocol.ts`、`lime-rs/crates/app-server-protocol/src/protocol/v0.rs`
|
||||
- 避让:Knowledge 写集、Electron host / ipc 共享热区、App Server protocol、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 目标:删除已由 App Server `usageStats/*` current 主链覆盖的旧 Tauri 使用统计 wrapper,减少 `lime-rs/src/commands/**` 清理区存量。
|
||||
- 验证:`rg` 引用搜索、`rustfmt --edition 2021 --check --config skip_children=true "lime-rs/src/app/runner.rs" "lime-rs/src/commands/mod.rs"`、`cargo check --manifest-path "lime-rs/Cargo.toml" -p lime-agent`、`npx vitest run "src/lib/api/usageStats.test.ts"`、`node scripts/check-command-contracts.mjs`
|
||||
- 启动基线:`usage_stats_cmd.rs` 已是 fail-closed 退场占位;前端 `usageStats.ts` 已通过 App Server client 调用 `usageStats/read`、`usageStats/modelRanking/list`、`usageStats/dailyTrends/list`;`runner.rs` / `mod.rs` 为共享脏文件,本轮只删除 usage stats 注册和模块声明。
|
||||
- 状态:in_progress
|
||||
|
||||
- 2026-06-08 Codex TW-Q0-COMMANDS-DIR-DOCS-BROADCAST 完成
|
||||
- 写集:`docs/README.md`、`internal/aiprompts/governance.md`、`internal/aiprompts/quality-workflow.md`、`scripts/electron/current-rules-guard.test.mjs`、`internal/exec-plans/tauri-wrapper-quick-cleanup-queue.md`
|
||||
- 只读参考:`AGENTS.md`、`internal/aiprompts/README.md`、`internal/aiprompts/commands.md`、`internal/roadmap/appserver/**`
|
||||
- 避让:Knowledge 写集、`lime-rs/src/commands/**`、`lime-rs/src/app/runner.rs`、App Server protocol、Electron host、`commandPolicy.ts`、`agentCommandCatalog.json`
|
||||
- 清理结果:`guard-hardened`;`docs/README.md`、治理文档、质量文档和 `current-rules-guard.test.mjs` 已同步知道 `lime-rs/src/commands/**` 是旧 Tauri wrapper 删除清理区,不再承接业务逻辑、API adapter、runtime 分支、领域 service、compat wrapper 或退场 stub。
|
||||
- 旧入口搜索:`rg -n "lime-rs/src/commands/\\*\\*" "docs/README.md" "internal/aiprompts/governance.md" "internal/aiprompts/quality-workflow.md" "scripts/electron/current-rules-guard.test.mjs"` 命中 4 处。
|
||||
- 验证结果:`node --check "scripts/electron/current-rules-guard.test.mjs"` 通过;`npm test -- "scripts/electron/current-rules-guard.test.mjs"` 通过;`npm run docs:boundary` 通过;`npm run test:contracts` 通过;定向 `git diff --check` 通过。
|
||||
- 剩余阻塞:`.codex/skills/.../references` 是本地忽略文件,已同步当前工作流参考,但不作为版本化事实源;后续长期规则仍以 `AGENTS.md`、`internal/aiprompts/*`、`internal/roadmap/appserver/*`、`docs/README.md` 和守卫测试为准。
|
||||
@@ -135,7 +135,7 @@ Host Bridge 是 P17.4 Runtime surface production hardening 的前置子项。没
|
||||
| P17.4.2 | 已完成:Agent task stream contract hardening。 | `lime.agent.startTask / streamTask / getTask / cancelTask / retryTask` 与 Host Bridge response 证据。 | App 内可 start / stream / get / cancel / retry,不回跳通用 Chat。 |
|
||||
| P17.4.3 | 已完成:Structured write-back guard。 | storage namespace / artifact kind / evidence subject 写回声明校验。 | 未声明 storage / artifact / evidence 写回被拒绝;声明项写回保留 provenance。 |
|
||||
| P17.4.4 | App bootstrap sample。 | content factory runtime package / host-bridge.js 样板。 | 示例 App 通过标准 bridge 取 snapshot、发 task、写回结果。 |
|
||||
| P17.4.5 | 已完成:Security and smoke。 | hostBridge 安全、RuntimePage UI、schema / contract 回归。 | feature island 无直接 Tauri / raw Worker,完整 GUI smoke 已通过。 |
|
||||
| P17.4.5 | 已完成:Security and smoke。 | hostBridge 安全、RuntimePage UI、schema / contract 回归。 | feature island 无直接 legacy desktop host API / raw Worker,完整 GUI smoke 已通过。 |
|
||||
|
||||
## 当前下一刀
|
||||
|
||||
@@ -146,7 +146,7 @@ P17.4 已完成当前 production hardening 闭环:`AgentAppHostBridge`、`capa
|
||||
协作分工:
|
||||
|
||||
1. 本轮只触碰客户端 runtime surface、对应 UI 回归和本 P17.4 roadmap。
|
||||
2. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不改变 Cloud / LimeCore control-plane 边界。
|
||||
2. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不改变 Cloud / LimeCore control-plane 边界。
|
||||
3. 不触碰 agentknowledge、上游 `agentapp` 标准仓库或真实 delete-data。
|
||||
|
||||
本轮完成内容:
|
||||
@@ -176,7 +176,7 @@ P17.4 已完成当前 production hardening 闭环:`AgentAppHostBridge`、`capa
|
||||
协作分工:
|
||||
|
||||
1. 本轮只认领客户端 Host Bridge runtime 任务流回归,不触碰 `agentknowledge`、Lime Cloud / LimeCore、上游标准仓库或 AgentApp 其他 roadmap 资料。
|
||||
2. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不改变桌面端 Agent 本地运行边界。
|
||||
2. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不改变桌面端 Agent 本地运行边界。
|
||||
3. P17.4.2 暂不声明完整完成;本轮只证明 App UI 内 start / stream / cancel 可以通过标准 `capability:invoke` 闭环。
|
||||
|
||||
本轮完成内容:
|
||||
@@ -202,7 +202,7 @@ P17.4 已完成当前 production hardening 闭环:`AgentAppHostBridge`、`capa
|
||||
协作分工:
|
||||
|
||||
1. 本轮只认领 P17.4.2 Host Bridge task contract,不触碰 AgentApp 其他 roadmap 总纲资料、`agentknowledge`、Lime Cloud / LimeCore 或上游标准仓库。
|
||||
2. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不绕过 `src/features/agent-app` feature island。
|
||||
2. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不绕过 `src/features/agent-app` feature island。
|
||||
3. retry 语义先做 SDK / adapter / mock / dispatcher / Host Bridge response 的最小闭环,不提前做真实模型重试、成本策略或后台队列。
|
||||
|
||||
本轮完成内容:
|
||||
@@ -234,7 +234,7 @@ P17.4 已完成当前 production hardening 闭环:`AgentAppHostBridge`、`capa
|
||||
|
||||
1. 本轮只认领内容工厂 App bootstrap 和 Host Bridge request / response 样板,不触碰 SceneApp 清理、安装生命周期和 Cloud / LimeCore 控制面。
|
||||
2. 内容工厂继续保持非技术用户界面;Host 同步发生在用户确认链后,不把业务主链回跳到通用 Chat。
|
||||
3. 不新增私有 postMessage 协议,不新增 Tauri command,不绕过 Host capability readiness。
|
||||
3. 不新增私有 postMessage 协议,不新增 legacy desktop facade,不绕过 Host capability readiness。
|
||||
|
||||
本轮完成内容:
|
||||
|
||||
@@ -264,7 +264,7 @@ P17.4 已完成当前 production hardening 闭环:`AgentAppHostBridge`、`capa
|
||||
协作分工:
|
||||
|
||||
1. 本轮只认领客户端 Host 侧 structured write-back guard,不触碰上游 `content-factory-app`、Lime Cloud / LimeCore 或其他 AgentApp roadmap 总纲资料。
|
||||
2. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,App UI 仍只能通过 `capability:invoke` 进入 Host Capability SDK。
|
||||
2. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,App UI 仍只能通过 `capability:invoke` 进入 Host Capability SDK。
|
||||
3. storage 暂按 manifest storage namespace 约束,不扩展到表级 schema 校验;artifact / evidence 做声明级强制校验。
|
||||
|
||||
本轮完成内容:
|
||||
|
||||
@@ -25,7 +25,7 @@ P16-H 已完成多 App repository、selected launcher、持久化 lifecycle、cl
|
||||
| 固定正式入口 | `agent-apps` 成为用户可见 App 管理和启动入口,不再依赖 Lab 心智解释核心流程。 |
|
||||
| 固定研发入口 | `agent-app-lab` 继续用于 fixture、smoke、cleanup rehearsal、flag-off 和实验断言。 |
|
||||
| 复用 current 主链 | P17 不新增第二套 installer、store、scanner、guard、runtime loader 或 cleanup 机制。 |
|
||||
| 明确能力边界 | App 只能通过 Capability SDK 使用 Lime 能力,不能 import Lime 内部模块或直接调用 Tauri command。 |
|
||||
| 明确能力边界 | App 只能通过 Capability SDK 使用 Lime 能力,不能 import Lime 内部模块或直接调用 legacy desktop facade。 |
|
||||
| 保持失败可清理 | disable、uninstall rehearsal、cleanup evidence、residual audit 和 flag-off 仍是正式入口前硬门槛。 |
|
||||
| 分离后续 gate | 真实 delete-data、public catalog、企业控制台和完整内容工厂业务系统分别另立计划。 |
|
||||
|
||||
@@ -175,7 +175,7 @@ flowchart TD
|
||||
| P17-US5 | 作为用户,我可以 disable / enable App。 | 状态持久化到 repository,刷新后不丢,disabled App 不可启动。 |
|
||||
| P17-US6 | 作为用户,我可以预览卸载和删除数据影响。 | P17 只输出 rehearsal evidence / residual audit,不执行真实 delete-data。 |
|
||||
| P17-US7 | 作为开发者,我仍能在 Lab 里跑 fixture 和 smoke。 | `agent-app-lab` 保留但不承担正式入口职责。 |
|
||||
| P17-US8 | 作为维护者,我能证明 App 没有绕过 SDK。 | `src/features/agent-app` 无直接 `safeInvoke` / `invoke` / raw Worker / Tauri command 扩散。 |
|
||||
| P17-US8 | 作为维护者,我能证明 App 没有绕过 SDK。 | `src/features/agent-app` 无直接 `safeInvoke` / `invoke` / raw Worker / legacy desktop facade 扩散。 |
|
||||
|
||||
## 分阶段计划
|
||||
|
||||
@@ -222,7 +222,7 @@ flowchart TD
|
||||
3. `agent-apps` 可在 Lab flag-off 后保持可见,`agent-app-lab` 在 flag-off 后不可见。
|
||||
4. 所有用户可见文案覆盖 `zh-CN / zh-TW / en-US / ja-JP / ko-KR`。
|
||||
5. `src/features/agent-app` 不直接出现 `safeInvoke`、`invoke(`、`tauri::`、`generate_handler`、`new Worker`。
|
||||
6. 如修改 Tauri command / bridge,必须同步 frontend gateway、Rust registration、command catalog、mock priority / default mocks,并执行 `npm run test:contracts`。
|
||||
6. 如触碰 Electron Desktop Host IPC / App Server JSON-RPC / legacy desktop facade 命令边界,必须同步前端 gateway、治理目录册、mock priority / default mocks,并执行 `npm run test:contracts`;不得在 `lime-rs/src/commands/**` 新增业务逻辑。
|
||||
7. GUI 证据必须区分 Agent Apps formal smoke 与 Agent App Lab smoke;不能用 Lab 证据冒充正式入口可交付。
|
||||
|
||||
## 最小验证
|
||||
|
||||
@@ -36,7 +36,7 @@ P17.2 已完成以下主链:
|
||||
- 不做真实 delete-data。
|
||||
- 不做完整行业内容系统。
|
||||
- 不把 `agent-app-lab` 的 smoke 当正式入口证据。
|
||||
- 不让 App 直接调用 Lime internal store、Tauri command 或 raw Worker。
|
||||
- 不让 App 直接调用 Lime internal store、legacy desktop facade 或 raw Worker。
|
||||
- 不解决 P17.4 runtime production hardening;P17.4 只在 P17.3 状态契约稳定后继续。
|
||||
|
||||
## 客户端 / 服务端边界
|
||||
@@ -55,7 +55,7 @@ P17.2 已完成以下主链:
|
||||
| 分类 | 对象 | P17.3 规则 |
|
||||
|---|---|---|
|
||||
| current | `src/features/agent-app/install/*` | installed state、setup state、cleanup preview、package cache、install review 的客户端事实源。 |
|
||||
| current | `src/lib/api/agentApps.ts` | 允许集中调用 Tauri command 的 API gateway;feature island 不直接 `safeInvoke` / `invoke`。 |
|
||||
| current | `src/lib/api/agentApps.ts` | Agent Apps 前端命令网关;feature island 不直接 `safeInvoke` / `invoke`。 |
|
||||
| current | `src/features/agent-app/ui/AgentAppsPage.tsx` | 正式用户入口,展示 lifecycle / cleanup review / residual audit。 |
|
||||
| current | `src/features/agent-app/runtime/entryRuntimeGuard.ts` | 启动前唯一 guard;P17.3 要让它消费 disabled / cleanup-blocked 状态。 |
|
||||
| current | `internal/roadmap/agentapp/p17-lifecycle-cleanup-contract-hardening.md` | P17.3 当前执行计划。 |
|
||||
@@ -75,7 +75,7 @@ P17.2 已完成以下主链:
|
||||
| P17.3-US4 | 作为用户,我能选择保留数据卸载演练。 | keep-data rehearsal 只标记 package / lifecycle action;storage / artifact / evidence 保留原因清晰。 |
|
||||
| P17.3-US5 | 作为维护者,我能导出 cleanup evidence。 | evidence 不含 secret value;包含 appId、version、namespace、action、blocked reason、timestamp。 |
|
||||
| P17.3-US6 | 作为维护者,我能看到 residual audit。 | audit 只检查 Agent App namespace;残留按 blocking / warning / informational 分类。 |
|
||||
| P17.3-US7 | 作为开发者,我能证明 App 无法绕过 lifecycle。 | `src/features/agent-app` 无直接 Tauri / raw Worker;launch 必经 P14 guard 和 P17.3 lifecycle gate。 |
|
||||
| P17.3-US7 | 作为开发者,我能证明 App 无法绕过 lifecycle。 | `src/features/agent-app` 无直接 legacy desktop facade / raw Worker;launch 必经 P14 guard 和 P17.3 lifecycle gate。 |
|
||||
|
||||
## 状态模型
|
||||
|
||||
@@ -221,7 +221,7 @@ flowchart TD
|
||||
| P17.3.3 | 已完成最小实现:Cleanup namespace classifier。 | 复用 cleanup plan,补 package / setup / overlay / secret / storage / artifact / evidence 分类。 | 单测覆盖 keep-data 与 delete-data rehearsal 差异。 |
|
||||
| P17.3.4 | 已完成最小实现:Evidence export / residual audit formalize。 | 复用 P16-H evidence / audit,正式入口展示 JSON preview。 | evidence 不含 secret value;audit 只查 Agent App namespace。 |
|
||||
| P17.3.5 | 已完成最小实现:Guard integration。 | P14 guard 消费 lifecycle disabled / cleanup-blocked。 | disabled / cleanup-blocked 都不能启动;enabled 仍走 readiness。 |
|
||||
| P17.3.6 | 已完成:Boundary and regression。 | feature island boundary rg、UI tests、schema cross-check 回归。 | 不新增 Tauri command;不直接 `safeInvoke`;P17.2.5 cross-check 继续通过。 |
|
||||
| P17.3.6 | 已完成:Boundary and regression。 | feature island boundary rg、UI tests、schema cross-check 回归。 | 不新增 legacy desktop facade;不直接 `safeInvoke`;P17.2.5 cross-check 继续通过。 |
|
||||
|
||||
## 验收标准
|
||||
|
||||
@@ -233,7 +233,7 @@ flowchart TD
|
||||
6. residual audit 只检查 Agent App namespace,不扫描全局用户目录。
|
||||
7. keep-data 与 delete-data rehearsal 的数据影响可解释。
|
||||
8. `agent-app-lab` 仍只是研发验证入口,不能替代正式入口证据。
|
||||
9. `src/features/agent-app` 不直接 `safeInvoke` / `invoke` / Tauri command / raw Worker。
|
||||
9. `src/features/agent-app` 不直接 `safeInvoke` / `invoke` / legacy desktop facade / raw Worker。
|
||||
10. Cloud / LimeCore 不运行 Agent、不渲染 UI、不接管本地 storage 或 delete-data。
|
||||
|
||||
## 最小验证
|
||||
@@ -255,7 +255,7 @@ rg -n "safeInvoke|invoke\(|tauri::|generate_handler|mockPriorityCommands|default
|
||||
git diff --check -- internal/roadmap/agentapp src/features/agent-app src/lib/api/agentApps.ts
|
||||
```
|
||||
|
||||
如改动 Tauri command / bridge,必须追加:
|
||||
如触碰 Electron Desktop Host IPC / App Server JSON-RPC / legacy desktop facade 命令边界,必须追加:
|
||||
|
||||
```bash
|
||||
npm run test:contracts
|
||||
@@ -296,7 +296,7 @@ P17.3.0 到 P17.3.6 已完成阶段闭环:lifecycle descriptor、正式页面
|
||||
|
||||
1. 本轮只触碰客户端正式入口 `AgentAppsPage`、对应 UI 回归和本 P17.3 roadmap 记录。
|
||||
2. 不触碰 `/Users/coso/Documents/dev/ai/limecloud/limecore`、`agentknowledge`、Cloud control-plane 文档和上游 `agentapp` 标准仓库。
|
||||
3. 不继续改 Tauri command / mock / API gateway;P17.3.1 已完成的 rehearsal-only 命令边界保持原样。
|
||||
3. 不继续改 legacy desktop facade / mock / API gateway;P17.3.1 已完成的 rehearsal-only 命令边界保持原样。
|
||||
|
||||
本轮完成内容:
|
||||
|
||||
@@ -327,7 +327,7 @@ P17.3.0 到 P17.3.6 已完成阶段闭环:lifecycle descriptor、正式页面
|
||||
|
||||
1. 本轮只触碰客户端 cleanup contract、Agent App feature island 内部 adapter/mock uninstall projection、对应测试和本 P17.3 roadmap。
|
||||
2. 不触碰 `/Users/coso/Documents/dev/ai/limecloud/limecore`、`agentknowledge`、Cloud control-plane 文档和上游 `agentapp` 标准仓库。
|
||||
3. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
3. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
|
||||
本轮完成内容:
|
||||
|
||||
@@ -362,7 +362,7 @@ P17.3.0 到 P17.3.6 已完成阶段闭环:lifecycle descriptor、正式页面
|
||||
|
||||
1. 本轮只触碰正式客户端入口 `AgentAppsPage`、对应 UI 回归和本 P17.3 roadmap。
|
||||
2. 不新增 i18n key;正式入口复用已覆盖五语言的 cleanup evidence / residual audit 展示 key,避免新增未本地化文案。
|
||||
3. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
3. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
|
||||
本轮完成内容:
|
||||
|
||||
@@ -390,7 +390,7 @@ P17.3.0 到 P17.3.6 已完成阶段闭环:lifecycle descriptor、正式页面
|
||||
协作分工:
|
||||
|
||||
1. 本轮只触碰 P14 runtime guard、正式入口 guard 调用、Lab guard 调用、对应 guard / UI 回归和本 P17.3 roadmap。
|
||||
2. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
2. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
3. 不触碰 Cloud / LimeCore / agentknowledge / 上游 `agentapp` 标准仓库。
|
||||
|
||||
本轮完成内容:
|
||||
@@ -424,14 +424,14 @@ P17.3.0 到 P17.3.6 已完成阶段闭环:lifecycle descriptor、正式页面
|
||||
协作分工:
|
||||
|
||||
1. 本轮只做 P17.3 阶段回归与边界验证,不继续扩大实现范围。
|
||||
2. 不新增 Tauri command,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
2. 不新增 legacy desktop facade,不改 `src/lib/api/agentApps.ts`,不改变 P17.3 rehearsal-only 卸载边界。
|
||||
3. 不触碰 Cloud / LimeCore / agentknowledge / 上游 `agentapp` 标准仓库。
|
||||
|
||||
本轮验证内容:
|
||||
|
||||
1. reference CLI / public schema cross-check 继续通过,证明 P17.2.5 标准对齐未被 P17.3 lifecycle / cleanup 改动破坏。
|
||||
2. 正式入口 `AgentAppsPage`、runtime surface `AgentAppRuntimePage`、P14 guard、cleanup classifier / evidence / audit、Lab manager、adapter/mock uninstall projection 均完成定向回归。
|
||||
3. feature island boundary 扫描无命中:`src/features/agent-app` 仍不直接 `safeInvoke` / `invoke` / Tauri command / raw Worker。
|
||||
3. feature island boundary 扫描无命中:`src/features/agent-app` 仍不直接 `safeInvoke` / `invoke` / legacy desktop facade / raw Worker。
|
||||
4. touched-file whitespace check 通过。
|
||||
5. `nice -n 10 npm run typecheck` 通过;上轮外部 experts test 类型错误已不再出现。
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
| 要求 | 证据 |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| 全量能力名只有一份事实源。 | catalog 测试断言 `LIME_CAPABILITY_NAMES`、profile keys、adapter keys 一致。 |
|
||||
| App 不再自建底层 Agent 能力。 | 内容工厂只调用 SDK facade;无裸模型 API / 私有 bridge / 专用 Tauri command。 |
|
||||
| App 不再自建底层 Agent 能力。 | 内容工厂只调用 SDK facade;无裸模型 API / 私有 bridge / 专用 legacy desktop command。 |
|
||||
| Lime 主 App 封装运行过程。 | `runtimeProcess` 包含 thinking、text、execution、tools、skills、model、usage、cost、artifacts、evidence。 |
|
||||
| 过程不消失。 | 终态默认折叠但 timeline 保留。 |
|
||||
| 使用 Skills。 | `lime.agent` task 的 capability hints / skill bindings 可被 Host 投影,调用证据可见。 |
|
||||
|
||||
@@ -65,7 +65,7 @@ P18 的问题不是继续扩大页面能力,而是把已经出现的 `lime.age
|
||||
- 不执行任意 raw worker bundle;P18 只允许 typed workflow / capability invoke。
|
||||
- 不把通用 Chat 作为 Agent App 核心流程容器;Expert Chat 只是 entry 或嵌入式协作者。
|
||||
- 不新增第二套 repository、installer、cleanup scanner 或 Agent Runtime。
|
||||
- 不为了 P18 增加新的 Tauri command;除非现有 host service 无法表达且先完成命令边界审计。
|
||||
- 不为了 P18 增加新的 legacy desktop facade;新增后端能力必须进 App Server current 主链,桌面壳能力进 Electron Desktop Host。
|
||||
|
||||
## 核心原则
|
||||
|
||||
@@ -257,7 +257,7 @@ flowchart TD
|
||||
| App 开发者 | 我只依赖 `@lime/app-sdk` 类型和 mock host,就能本地测试 App 工作流。 | 不 import Lime internal path;mock / real host 的错误码一致。 |
|
||||
| 平台维护者 | 我升级 storage、AgentRuntime 或 Tool Broker 时,不需要修改每个 App。 | SDK contract tests 通过;App 只感知兼容版本和稳定错误码。 |
|
||||
| 企业管理员 | 我可以用 policy / tenant overlay 控制工具、secret、成本和 network。 | Bridge 层强制策略;UI 只展示结果,不承担最终授权。 |
|
||||
| QA / 智能体 | 我能用 contract tests 和 GUI smoke 证明正式入口与 SDK 边界没有漂移。 | `src/features/agent-app` 无直接 `safeInvoke` / `invoke` / Tauri / raw Worker 越界。 |
|
||||
| QA / 智能体 | 我能用 contract tests 和 GUI smoke 证明正式入口与 SDK 边界没有漂移。 | `src/features/agent-app` 无直接 `safeInvoke` / `invoke` / legacy desktop facade / raw Worker 越界。 |
|
||||
|
||||
## 用例
|
||||
|
||||
@@ -435,7 +435,7 @@ nice -n 10 npm test -- src/features/agent-app/runtime/workflowRuntimeHost.test.t
|
||||
rg -n "SceneApp|contentEngineering|sceneapp_|safeInvoke|invoke\\(|new Worker|Worker\\(" src/features/agent-app || true
|
||||
```
|
||||
|
||||
边界:P18.6 未新增 worker runtime、未执行 raw worker、未新增 network / filesystem / secret 通道,也未修改 Cloud / LimeCore / Tauri command。
|
||||
边界:P18.6 未新增 worker runtime、未执行 raw worker、未新增 network / filesystem / secret 通道,也未修改 Cloud / LimeCore / legacy desktop facade。
|
||||
|
||||
## 验收标准
|
||||
|
||||
@@ -465,7 +465,7 @@ npm run smoke:agent-apps -- --timeout-ms 300000 --interval-ms 1000
|
||||
npm run verify:gui-smoke -- --reuse-running --timeout-ms 300000
|
||||
```
|
||||
|
||||
如果 P18 引入或修改 Tauri command,必须同步前端 gateway、Rust handler、治理目录册和 mock priority,并执行 `npm run test:contracts`。
|
||||
P18 不得在 `lime-rs/src/commands/**` 新增业务逻辑。若触碰 Electron Desktop Host IPC / App Server JSON-RPC / legacy desktop facade 命令边界,必须同步前端 gateway、治理目录册和 mock priority,并执行 `npm run test:contracts`。
|
||||
|
||||
## 风险与应对
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
| 层 | 角色 | 输入 | 输出 | Owner |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Product Surface | 收集用户意图与业务状态 | Chat 输入、Claw `@` 命令、Agent App 表单、Automation job | surface request | Chat / Claw / Agent App / Automation |
|
||||
| Runtime Surface Adapter | 把 surface intent 适配为统一 runtime request | taskKind、capabilityId、app provenance、request metadata | AgentRuntime submit request | frontend gateway / Rust surface facade |
|
||||
| Runtime Control Plane | 接收、排队、中断、恢复 | submit/interrupt/resume/respond/export | accepted turn、queued turn、actions | Rust runtime command |
|
||||
| Runtime Surface Adapter | 把 surface intent 适配为统一 runtime request | taskKind、capabilityId、app provenance、request metadata | AgentRuntime submit request | frontend gateway / App Server surface |
|
||||
| Runtime Control Plane | 接收、排队、中断、恢复 | submit/interrupt/resume/respond/export | accepted turn、queued turn、actions | App Server RuntimeCore |
|
||||
| Execution Loop | 执行 agent turn | input snapshot、model config、tool inventory | model/tool/action events | Query Loop / runtime_turn |
|
||||
| Orchestration Facts | 记录 task、routing、permission、sandbox、process、subagent | execution loop 内部状态 | RuntimeEvent stream | AgentRuntime Profile |
|
||||
| Durable Read Models | 支撑恢复和 GUI 投影 | event log、runtime state | ThreadReadModel、TaskSnapshot | runtime store / repository |
|
||||
@@ -187,7 +187,7 @@ GUI 与恢复入口。必须表达:
|
||||
| context owner refs | `turn_context`、`context_trace`、memory / compaction runtime metadata,后续收敛为 `context.*` facts |
|
||||
| policy owner refs | runtime permission/action/sandbox metadata,后续收敛为 `permission.*` / `action.*` facts |
|
||||
| GUI projection | Workspace / Harness current read model |
|
||||
| command contract | frontend gateway、Rust `generate_handler!`、catalog、mock |
|
||||
| command contract | frontend gateway、App Server / Electron Host / legacy facade boundary、catalog、mock |
|
||||
|
||||
`agent_app_cmd.rs` 当前属于 Agent App 生命周期 owner,不是完整 AgentRuntime owner。`LIME_GATEWAY_*` / `OPENAI_BASE_URL` 注入只能视为低阶模型 executor 或开发期 fallback;完整 `lime.agent` / `lime.workflow` 必须进入 AgentRuntime Surface。
|
||||
|
||||
@@ -257,7 +257,7 @@ legacy state -> new parallel truth -> UI/evidence
|
||||
## 9. 验证策略
|
||||
|
||||
1. Schema fixture 校验:验证 Lime Profile fixtures。
|
||||
2. Command mapping 测试:验证 Tauri command / frontend gateway / mock / catalog 与 profile control plane 一致。
|
||||
2. Command mapping 测试:验证 Electron Desktop Host / App Server / legacy facade、frontend gateway、mock / catalog 与 profile control plane 一致。
|
||||
3. Event replay 测试:用 event stream 重建 ThreadReadModel。
|
||||
4. Evidence consistency 测试:确认 evidence/replay/review 读同一事实源。
|
||||
5. GUI smoke:确认 Workspace/Harness 展示 read model,而不是 UI-only truth。
|
||||
|
||||
@@ -213,8 +213,8 @@
|
||||
|
||||
### 9.2 Contract 测试
|
||||
|
||||
- Tauri command、frontend gateway、catalog、mock 与 profile control plane 映射一致。
|
||||
- `safeInvoke(...)` / Rust handler / command catalog / mocks 同步。
|
||||
- Electron Desktop Host / App Server / legacy facade、frontend gateway、catalog、mock 与 profile control plane 映射一致。
|
||||
- frontend gateway / App Server method / legacy facade handler / command catalog / mocks 同步。
|
||||
|
||||
### 9.3 Replay 测试
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
|
||||
- Rust 定向测试覆盖 Evidence / Replay / Analysis / Review Markdown locale。
|
||||
- `cargo check -p lime --lib` 不出现 presentation copy unused warning。
|
||||
- 未新增 Tauri command、前端 gateway、mock 或 request shape。
|
||||
- 未新增 legacy desktop facade、前端 gateway、mock 或 request shape;不得在 `lime-rs/src/commands/**` 新增业务逻辑。
|
||||
|
||||
## 12. 实施后的下一刀
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ agent_runtime_submit_turn
|
||||
| --- | --- | --- | --- |
|
||||
| Schema / Fixture | 验证 Lime Profile 事件和 snapshot 形状 | AgentRuntime profile fixtures | 改 schema、事件字段、snapshot 字段时 |
|
||||
| Runtime Unit | 验证 ids、事件 envelope、状态转换 | `runtime_turn`、runtime queue、read model builder | 改 submit turn、事件构造、状态机时 |
|
||||
| Contract | 验证 Tauri command、frontend gateway、catalog、mock 同步 | `agent_runtime_*` commands | 改命令或 bridge 时 |
|
||||
| Contract | 验证 Electron Desktop Host / App Server / legacy facade、frontend gateway、catalog、mock 同步 | `agent_runtime_*` current / compat command boundary | 改命令边界或 bridge 时 |
|
||||
| Replay / Projection | 验证 event stream 可重建 read model | `ThreadReadModel`、`TaskSnapshot` | 改 projection 或恢复逻辑时 |
|
||||
| Evidence Consistency | 验证 evidence/replay/review 同源 | `agent_runtime_export_evidence_pack` | 改 evidence、review、analysis 时 |
|
||||
| GUI Smoke | 验证用户真实看到 runtime facts | Workspace、Harness、Dashboard | 改 GUI 主路径时 |
|
||||
@@ -179,9 +179,9 @@ Owner 侧对应测试文档:
|
||||
|
||||
| ID | 用例 | 检查对象 | 期望结果 |
|
||||
| --- | --- | --- | --- |
|
||||
| AR-CONTRACT-001 | submit command 同步 | frontend `safeInvoke`、Rust handler、catalog、mock | `agent_runtime_submit_turn` 四侧一致 |
|
||||
| AR-CONTRACT-002 | evidence command 同步 | frontend gateway、Rust handler、catalog、mock | `agent_runtime_export_evidence_pack` 四侧一致 |
|
||||
| AR-CONTRACT-003 | action response command 同步 | permission/action gateway、Rust handler、catalog、mock | `respond_action` 或现有等价 command 不漂移 |
|
||||
| AR-CONTRACT-001 | submit command 同步 | frontend gateway、App Server method / legacy facade handler、catalog、mock | `agent_runtime_submit_turn` 兼容面委托 current 主链且不漂移 |
|
||||
| AR-CONTRACT-002 | evidence command 同步 | frontend gateway、App Server method / legacy facade handler、catalog、mock | `agent_runtime_export_evidence_pack` 兼容面委托 current 主链且不漂移 |
|
||||
| AR-CONTRACT-003 | action response command 同步 | permission/action gateway、App Server method / legacy facade handler、catalog、mock | `respond_action` 或现有等价 command 不漂移 |
|
||||
| AR-CONTRACT-004 | compat 命令只委托 current | 旧 evidence/replay command | 只调用 `agent_runtime_export_*`,不重建第二套导出逻辑 |
|
||||
| AR-CONTRACT-005 | mock 与真实 contract 同形 | `mockPriorityCommands` / `defaultMocks` | mock 返回字段不缺 current read model required fields |
|
||||
|
||||
@@ -247,7 +247,7 @@ npm run governance:legacy-report
|
||||
| 改 AgentContext / AgentPolicy / AgentEvidence linkage | 对应 AR-CTX / AR-POL / AR-EVID-LINK 用例 + 定向 owner ref 测试 |
|
||||
| 改 AgentUI profile event 兼容 / presentation mapper | `agentStreamUnknownEventController` / `agentStreamListenerReadinessController` / `agentUiTeamWorkbenchViewModel` / `AgentUiTeamWorkbenchSurfaceView` / `TeamWorkbenchSummaryPanel` / `HarnessStatusPanel` / `AgentThreadReliabilityPanel` / `AgentThreadTimelineArtifactCard` 定向单测 |
|
||||
| 改 deprecated/compat 路径 | Governance guard + 相关 contract 用例 |
|
||||
| 改 Rust runtime 主链 | 定向 Rust 测试 + Runtime identity / Event 用例 + 必要时 `npm run verify:local` |
|
||||
| 改 Rust runtime 主链 | App Server / RuntimeCore 定向 Rust 测试 + Runtime identity / Event 用例 + 必要时 `npm run verify:local` |
|
||||
|
||||
## 17. 不通过判定
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ AgentUI 不是再做一个聊天页面,而是把 Lime 已有的 runtime、time
|
||||
本目录回答四类问题:
|
||||
|
||||
1. **产品结构**:Lime 的 AgentUI 应该由哪些层组成,哪些信息应该出现在首屏,哪些应该进入展开详情。
|
||||
2. **代码结构**:现有前端、协议、Tauri command、Rust runtime、service、持久化层分别负责什么。
|
||||
2. **代码结构**:现有前端、协议、Electron Desktop Host / App Server command gateway、Rust runtime、service、持久化层分别负责什么。
|
||||
3. **运行流程**:发送消息、打开旧会话、排队输入、权限确认、产物生成、证据导出如何流动。
|
||||
4. **落地顺序**:哪些改动先解决体感慢、卡顿、重复吐字和多任务管理,哪些进入中长期演进。
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
暂不改:
|
||||
|
||||
1. Tauri command。
|
||||
1. Electron Desktop Host / App Server command gateway。
|
||||
2. agent runtime event protocol。
|
||||
3. Warp governance JSON。
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
1. 普通用户打开 `.html / .htm` 文件时,默认看到网页预览,而不是源码。
|
||||
2. 用户需要看代码时,可以在同一画布切换到源码。
|
||||
3. 真实本地 HTML 文件在 Tauri 中应通过受控 asset protocol 预览,并可打开独立预览窗口。
|
||||
3. 真实本地 HTML 文件应通过 Electron Desktop Host 受控本地文件预览能力展示,并可打开独立预览窗口。
|
||||
4. 用户在 AI 服务商设置页点测试时,文本模型应做真实聊天试跑,不能只用极轻量探活显示“连接成功”。
|
||||
5. 聊天页真实调用遇到 `402 Payment Required / Insufficient Balance / 余额不足` 时,应展示余额或额度不足的可操作提示。
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
| HTML 文件识别 | `workspaceFilePreview.ts` 将 `.html / .htm` 解析为 `contentType: "html"`、`language: "html"` | 已实现 |
|
||||
| 默认网页预览 | `CanvasPanel` 对 HTML 默认渲染 iframe;无真实路径用 `srcDoc` | 已实现 |
|
||||
| 源码切换 | HTML 工具栏提供“预览 / 源码”切换,源码走 `CodePreview` | 已实现 |
|
||||
| Tauri 本地文件预览 | 有 `sourcePath` 或绝对 `baseFilePath` 时使用 `convertFileSrc` 生成 iframe `src` | 已实现 |
|
||||
| 浏览器 / DevBridge 回退预览 | `convertFileSrc` 不可用且返回原始绝对路径时,不再把 `/Users/...html` 当成 Vite 站内 iframe `src`;改用 `srcDoc` 展示真实 HTML 内容 | 已实现 |
|
||||
| 独立预览窗口 | `openHtmlPreviewWindow` 使用 Tauri `WebviewWindow` 创建 `html-preview-*`,失败回退系统默认应用 | 已实现 |
|
||||
| 本地文件预览 | 有 `sourcePath` 或绝对 `baseFilePath` 时通过 Electron Desktop Host / renderer-safe file URL resolver 生成 iframe `src` | 已实现 |
|
||||
| 浏览器 / DevBridge 回退预览 | 本地文件 resolver 不可用且返回原始绝对路径时,不再把 `/Users/...html` 当成 Vite 站内 iframe `src`;改用 `srcDoc` 展示真实 HTML 内容 | 已实现 |
|
||||
| 独立预览窗口 | `openHtmlPreviewWindow` 通过 Electron Desktop Host 打开 `html-preview-*` 独立预览窗口,失败回退系统默认应用 | 已实现 |
|
||||
| HTML artifact 流式阶段预览 | `resolveDefaultArtifactViewMode` 对 `html` 与 `code + language: html` 始终返回 `preview`,不再因 `writePhase: streaming` 默认源码 | 已实现 |
|
||||
| HTML artifact 工具栏切换 | `HtmlRenderer` 接入外部 `viewMode / previewSize` 受控状态;工作区已有外部工具栏时隐藏内部重复工具栏,源码切换会真实移除 iframe 并渲染源码 | 已实现 |
|
||||
| `.htm` 产物识别 | `buildArtifactFromWrite` 将 `.htm` 构建为 `html` artifact,并标记 `language: "html"` | 已实现 |
|
||||
| Tauri 权限与 CSP | `tauri.conf*.json` 启用 `assetProtocol`,CSP 覆盖 `asset:` / `http://asset.localhost` / `frame-src`;capability 覆盖 `html-preview-*` 与 `core:webview:allow-create-webview-window` | 已实现 |
|
||||
| Electron 权限与 CSP | current 预览能力应由 Electron Desktop Host / App Server 文件边界提供受控 URL,CSP 覆盖本地预览 iframe 来源;旧 Tauri `assetProtocol` / `WebviewWindow` 证据仅作为 deprecated reference | 待复核 |
|
||||
| Provider 设置页不再误导 | 文本模型按钮显示“试跑当前模型”,并通过 App Server current `modelProvider/testChat` 做真实聊天试跑;旧 `test_api_key_provider_chat` 已判为 `dead`,不得作为正向证据恢复 | 已实现 |
|
||||
| 402 额度错误友好化 | `agentRuntimeErrorPresentation` 将 `402 / Payment Required / Insufficient Balance / 余额不足 / 额度不足` 归一为额度不足提示;聊天时间线、折叠摘要、流式失败 assistant patch 与会话概览均在 presentation 层显示友好提示,不再向普通用户暴露 raw Provider error | 已实现 |
|
||||
| 失败态不过度重复 | 失败详情只保留在时间线错误卡等主解释位置;assistant 正文若只是同一失败详情的重复文案会被隐藏,底部运行状态行只保留“失败 + 耗时”等短状态 | 已实现 |
|
||||
@@ -34,12 +34,12 @@
|
||||
|
||||
## 外部依据
|
||||
|
||||
Context7 查询 Tauri v2 官方文档后确认:
|
||||
迁移前 Tauri v2 官方文档曾用于确认旧实现:
|
||||
|
||||
- `convertFileSrc()` 用于把设备文件路径转换为 WebView 可加载 URL;需要在 `tauri.conf.json` 配置 `assetProtocol`、scope 与 CSP。
|
||||
- 前端创建新 WebView window 需要 `core:webview:allow-create-webview-window` capability;动态窗口 label 需要 capability `windows` 覆盖。
|
||||
|
||||
当前实现与上述方向一致。
|
||||
当前 Tauri -> Electron 迁移下,上述内容只能作为 deprecated reference;current 证据应回到 Electron Desktop Host / App Server 文件边界。
|
||||
|
||||
## 已执行验证
|
||||
|
||||
@@ -57,7 +57,7 @@ npx vitest run \
|
||||
"src/components/agent/chat/workspace/useWorkspaceArtifactPreviewActions.test.tsx"
|
||||
```
|
||||
|
||||
结果:4 个文件、26 个用例通过。最新复跑时与 HTML artifact、Provider 试跑和 402 错误展示相关用例合并执行,12 个文件、98 个用例通过。覆盖 Tauri asset URL 预览、浏览器 / DevBridge 回退 `srcDoc` 预览、源码切换、真实路径保留、HTML artifact 默认预览、Provider 文本模型真实试跑入口和额度不足提示。
|
||||
结果:4 个文件、26 个用例通过。最新复跑时与 HTML artifact、Provider 试跑和 402 错误展示相关用例合并执行,12 个文件、98 个用例通过。覆盖本地 HTML 预览、浏览器 / DevBridge 回退 `srcDoc` 预览、源码切换、真实路径保留、HTML artifact 默认预览、Provider 文本模型真实试跑入口和额度不足提示。
|
||||
|
||||
```bash
|
||||
npx vitest run \
|
||||
|
||||
@@ -329,7 +329,7 @@ session detail + thread_read + timeline + artifacts + verification
|
||||
| P0 | session summary snapshot | `session_runtime.rs` / DTO | 打开 tab 不拉全量 detail |
|
||||
| P0 | first event / first text tracing | `runtime_turn.rs` / event converter | 首字慢可分段定位 |
|
||||
| P0 | getSession 可关闭 timeline detail | `runtime_api.rs` / `session_store.rs` | 旧会话 messages 先渲染 |
|
||||
| P1 | timeline page API | runtime command + DAO | 展开过程时分页加载 |
|
||||
| P1 | timeline page API | App Server JSON-RPC method + DAO | 展开过程时分页加载 |
|
||||
| P1 | batch session patch | session update command | access mode/provider/strategy 回填合并 |
|
||||
| P1 | queue/capsule summary in list | session list DTO | sidebar/tab 不抢 detail |
|
||||
| P1 | tool detail on-demand | tool IO offload + command | 大工具输出不进正文 |
|
||||
@@ -339,10 +339,10 @@ session detail + thread_read + timeline + artifacts + verification
|
||||
|
||||
## 10. 命令边界注意事项
|
||||
|
||||
任何新增或修改 Tauri command 必须同步四侧:
|
||||
任何新增或修改 AgentUI command surface 必须走 Electron Desktop Host / App Server current 主链,并同步四侧:
|
||||
|
||||
1. 前端 API client。
|
||||
2. Rust command 注册。
|
||||
2. Electron Desktop Host bridge / App Server JSON-RPC method。
|
||||
3. command catalog。
|
||||
4. mock / browser fallback。
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> 状态:代码事实地图
|
||||
> 更新时间:2026-04-30
|
||||
> 目标:把 AgentUI 相关前端、协议、Tauri command、Rust runtime、service、持久化入口分层,作为后续拆分和性能优化的定位图。
|
||||
> 目标:把 AgentUI 相关前端、协议、Electron Desktop Host / App Server command gateway、Rust runtime、service、持久化入口分层,作为后续拆分和性能优化的定位图。
|
||||
|
||||
## 1. 总览
|
||||
|
||||
@@ -11,16 +11,16 @@ flowchart TB
|
||||
UI[src/components/agent/chat UI]
|
||||
Hooks[src/components/agent/chat/hooks state + stream]
|
||||
Api[src/lib/api/agentRuntime + agentProtocol]
|
||||
Tauri[lime-rs commands/aster_agent_cmd]
|
||||
CommandGateway[Electron Desktop Host bridge / App Server JSON-RPC]
|
||||
AgentCrate[lime-rs/crates/agent runtime crate]
|
||||
Services[lime-rs/src/services]
|
||||
Store[(SQLite + .lime files)]
|
||||
|
||||
UI --> Hooks
|
||||
Hooks --> Api
|
||||
Api --> Tauri
|
||||
Tauri --> AgentCrate
|
||||
Tauri --> Services
|
||||
Api --> CommandGateway
|
||||
CommandGateway --> AgentCrate
|
||||
CommandGateway --> Services
|
||||
AgentCrate --> Services
|
||||
Services --> Store
|
||||
AgentCrate --> Store
|
||||
@@ -76,11 +76,12 @@ flowchart TB
|
||||
- `parseAgentEvent` 是兼容边界,不是鼓励继续新增 legacy 事件。
|
||||
- `historyLimit/historyOffset/historyBeforeMessageId` 是旧会话性能主接口,后续 pagination/virtualization 要继续沿用。
|
||||
|
||||
## 5. Tauri Command 层
|
||||
## 5. Command Gateway 层
|
||||
|
||||
| 文件 | 当前职责 | AgentUI 相关能力 |
|
||||
| --- | --- | --- |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/command_api/runtime_api.rs` | runtime Tauri command 主入口 | submit、interrupt、compact、resume、get session、thread read、file checkpoint、evidence/review export |
|
||||
| `src/lib/api/agentRuntime/*` + Electron Desktop Host / App Server JSON-RPC | AgentUI current command gateway | submit、interrupt、compact、resume、get session、thread read、file checkpoint、evidence/review export |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/command_api/runtime_api.rs` | legacy `agent_runtime_*` Rust command facade | 迁移期兼容入口,只允许委托 current runtime / service 事实源,不作为新增能力入口 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/runtime_turn.rs` | turn 执行主链 | 提前发 `runtime_status`、执行 provider/runtime/tool/hook/memory/artifact/auto compact |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/session_runtime.rs` | session create/list/update/recent runtime context | sidebar/session summary 和 tab 管理基础 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/subagent_runtime.rs` | subagent runtime | team/capsule 子代理状态基础 |
|
||||
|
||||
@@ -304,7 +304,7 @@ useAgentSession
|
||||
| 文档变更 | markdown 格式检查、`git status --short` |
|
||||
| 前端 UI/Hook | 受影响 `*.test.tsx` / `*.test.ts`,默认 `npm run verify:local` |
|
||||
| 流式事件逻辑 | `agentStreamRuntimeHandler.test.ts`、`agentStreamTurnEventBinding.test.ts` |
|
||||
| Tauri command / bridge | `npm run verify:local` + `npm run test:contracts` |
|
||||
| Electron Desktop Host / App Server command boundary | `npm run verify:local` + `npm run test:contracts` |
|
||||
| GUI 主路径 | `npm run verify:local` + `npm run verify:gui-smoke` |
|
||||
| 真实交互 | Playwright E2E:新建对话、打开两个历史会话、发送消息、queue/steer、pending action |
|
||||
|
||||
|
||||
@@ -234,14 +234,14 @@ AgentRuntimeProfileEvent / ThreadReadModel / EvidenceSummary
|
||||
|
||||
## 8.2 2026-05-10 Board/team 直接写回命令边界审计
|
||||
|
||||
- 已审计 current 命令边界:`src/lib/api`、`lime-rs/src/app/runner.rs`、`agentCommandCatalog.json`、`mockPriorityCommands.ts` 与 `defaultMocks` 均没有可复用的 board/team 直接写回命令;`TaskCreate/TaskList/TaskGet/TaskUpdate` 当前是 aster runtime tool / inventory,不是 Tauri bridge command。
|
||||
- 已审计 current 命令边界:`src/lib/api`、App Server / Electron Desktop Host 命令边界、`agentCommandCatalog.json`、`mockPriorityCommands.ts` 与 `defaultMocks` 均没有可复用的 board/team 直接写回命令;`TaskCreate/TaskList/TaskGet/TaskUpdate` 当前是 aster runtime tool / inventory,不是 legacy desktop facade command。
|
||||
- 已确认真实可写事实源仍是 `TaskUpdateTool`:它通过 `resolve_task_board_state` / `persist_task_board_state` 读写 session task board,并在 owner 变化时输出 `ownerChange` / `owner_change` metadata;Agent UI 只消费该结构化 metadata 派生 `work_board` assign/reassign。
|
||||
- 已明确不新增临时 UI 本地写回或平行 Tauri command。若未来要做无 prompt direct board/team write-back,必须先新增 current command 或 shared task board service,并同步前端网关、Rust 注册、治理目录册、DevBridge priority mock 与 default mock,同时解决 runtime `shared_task_list_storage` 与 session `extension_data` 的一致性。
|
||||
- 已明确不新增临时 UI 本地写回或平行 legacy desktop command。若未来要做无 prompt direct board/team write-back,必须先新增 App Server current method 或 shared task board service,并同步前端网关、Electron / App Server 命令边界、治理目录册与测试 mock,同时解决 runtime `shared_task_list_storage` 与 session `extension_data` 的一致性。
|
||||
- 因此 v0.6 标准对齐口径调整为:`work_board` / reassignment 的合规 baseline 是 `Team Workbench selector -> TaskUpdate prompt/runtime turn -> TaskUpdateTool owner_change source -> Agent UI projection`;无 prompt 直接写回归入 future product command boundary,不再作为本轮 projection 对齐阻塞项。
|
||||
|
||||
## 8.3 2026-05-10 Playwright E2E 与真实 child context 复验
|
||||
|
||||
- 已补浏览器 DevBridge subagent control 命令族:`agent_runtime_spawn_subagent`、`agent_runtime_send_subagent_input`、`agent_runtime_wait_subagents`、`agent_runtime_resume_subagent`、`agent_runtime_close_subagent` 已接入 dispatcher 与 HTTP cooldown bypass,契约仍落在现有 `agent_runtime_*` current 主链,不新增 Tauri command。
|
||||
- 已补浏览器 DevBridge subagent control 命令族:`agent_runtime_spawn_subagent`、`agent_runtime_send_subagent_input`、`agent_runtime_wait_subagents`、`agent_runtime_resume_subagent`、`agent_runtime_close_subagent` 已接入 dispatcher 与 HTTP cooldown bypass,契约仍落在现有 `agent_runtime_*` current 主链;后续不得在 `lime-rs/src/commands/**` 追加新业务逻辑。
|
||||
- 已补 session store limited history 空会话探测:`get_runtime_session_detail_with_history_page` 不再因为 persisted empty fast path 跳过 runtime overlay / subagent context;`agent_runtime_get_session(parent, { historyLimit })` 能返回 `child_subagent_sessions`,空 child detail 也能返回 `subagent_parent_context`。
|
||||
- Playwright E2E 复验已覆盖:普通会话 tab 不显示 `AgentUI N` 内部 badge;Team Workbench `Agent UI v0.6 / 10 events`、10 个 surface、三类 lane、`工作台操作视图`、`Surface 专门视图`、Harness AgentUI 投影、真实 child context 与 console `0 error / 0 warning` 均有证据。
|
||||
- 证据索引:`internal/exec-plans/agentui-playwright-e2e-2026-05-10.md`;截图与 JSON 位于 `internal/exec-plans/evidence/agentui-e2e-2026-05-10/09-session-store-subagent-context.json`、`09-team-workbench-real-child-context-after-session-store-fix.png`、`10-transcript-open-detail-real-child-focus-context.png`、`10-console-errors-final-real-child-focus.txt`。
|
||||
|
||||
@@ -39,13 +39,13 @@ flowchart TB
|
||||
|
||||
Composer --> RuntimeApi[agentRuntime API clients]
|
||||
RuntimeApi --> Protocol[AgentEvent / Session DTO / ThreadRead]
|
||||
RuntimeApi --> Tauri[Tauri Commands agent_runtime_*]
|
||||
RuntimeApi --> CommandGateway[Electron Desktop Host bridge / App Server JSON-RPC]
|
||||
|
||||
Tauri --> RuntimeQueue[Runtime Queue]
|
||||
Tauri --> SessionStore[Session Store]
|
||||
Tauri --> TimelineRecorder[AgentTimelineRecorder]
|
||||
Tauri --> ArtifactServices[Artifact Services]
|
||||
Tauri --> EvidenceServices[Evidence / Review Services]
|
||||
CommandGateway --> RuntimeQueue[Runtime Queue]
|
||||
CommandGateway --> SessionStore[Session Store]
|
||||
CommandGateway --> TimelineRecorder[AgentTimelineRecorder]
|
||||
CommandGateway --> ArtifactServices[Artifact Services]
|
||||
CommandGateway --> EvidenceServices[Evidence / Review Services]
|
||||
|
||||
RuntimeQueue --> Aster[Aster Agent Runtime]
|
||||
Aster --> Events[AgentEvent stream]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# App Server 路线图
|
||||
|
||||
> 状态:current planning source
|
||||
> 更新时间:2026-06-06
|
||||
> 更新时间:2026-06-08
|
||||
> Owner:Lime Runtime / App Server / 独立 App 集成
|
||||
|
||||
## 1. 定位
|
||||
@@ -41,12 +41,14 @@ App Server + JSON-RPC Protocol + RuntimeCore + ExecutionBackend Adapters
|
||||
| `current target` | `RuntimeCore` | 跨 App、跨执行后端复用的公共 runtime service 层。 |
|
||||
| `current target` | `ExecutionBackend` | Aster 和未来更多执行后端的适配接口。 |
|
||||
| `current reference` | `lime-rs/crates/agent` | 当前最接近 runtime core 的 crate,后续继续拆公共模型与服务。 |
|
||||
| `current reference` | `lime-rs/src/commands/aster_agent_cmd/runtime_turn.rs` 及相邻 service 逻辑 | Aster backend 的现有实现参考;不能继续被当作公共 runtime core。 |
|
||||
| `current client` | Lime Desktop / content-studio / 更多独立 App 的 app-server client | 独立 App 只通过协议消费 runtime,不直接 import Lime 内部实现。 |
|
||||
| `compat` | legacy desktop facade | 迁移期继续服务 Lime Desktop,但只能委托 App Server service,不继续拥有独立 runtime 事实。 |
|
||||
| `compat cleanup` | `lime-rs/src/commands/**` | 旧 Tauri command wrapper 清理区;只能删除、迁出或收窄为带退出条件的薄委托,不再承接新实现。 |
|
||||
| `compat` | legacy desktop facade | 迁移期继续服务 Lime Desktop,但只能委托 App Server / Electron Desktop Host current 主链,不继续拥有独立 runtime 事实。 |
|
||||
| `deprecated` | 壳层内直接拼接 runtime 业务逻辑 | 只允许迁移和下线,不允许新增能力。 |
|
||||
| `dead` | 新独立 App 自建完整 Agent runtime | 不再作为 Lime 生态扩展方向。 |
|
||||
|
||||
`lime-rs/src/commands/**` 的历史实现只能作为迁移参考,不能再作为新业务逻辑、API adapter、runtime 分支或领域服务的落点。新增 Rust 后端能力必须进入 App Server crates / RuntimeCore / services 等 current 事实源;窗口、托盘、Dock、updater、shell、deep link 等桌面壳能力进入 Electron Desktop Host。若某个能力仍只能通过 `commands/` wrapper 才能跑通,应把它判为 current 主链缺口,而不是继续补旧 wrapper。
|
||||
|
||||
## 3. 文档索引
|
||||
|
||||
| 文档 | 作用 |
|
||||
@@ -81,7 +83,7 @@ App Server + JSON-RPC Protocol + RuntimeCore + ExecutionBackend Adapters
|
||||
3. 不让独立 App 直接调用 Lime 内部 Rust 模块。
|
||||
4. 不新增第二套 tool runtime、skill runtime、workspace runtime。
|
||||
5. 不在 App 侧用 UI-only state 模拟 Agent 执行成功。
|
||||
6. 不一次性迁完所有 legacy desktop commands;先迁 Agent runtime 主链。
|
||||
6. 不一次性迁完所有 legacy desktop commands;但 `lime-rs/src/commands/**` 只允许作为清理区处理,不再新增实现。
|
||||
7. 不把 `Aster`、`runtime_turn.rs` 或 legacy desktop command DTO 直接定义成公共协议。
|
||||
|
||||
## 6. 当前执行顺序
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# App Server 架构蓝图
|
||||
|
||||
> 状态:current planning source
|
||||
> 更新时间:2026-06-06
|
||||
> 更新时间:2026-06-08
|
||||
> 作用:定义 App Server 的分层、进程边界、服务抽象、事实源和替换路线。
|
||||
|
||||
## 1. 架构目标
|
||||
@@ -28,7 +28,7 @@ flowchart TB
|
||||
subgraph HostBridge["Desktop Host Bridge / Clients"]
|
||||
LimeElectronBridge["Lime Electron Desktop Host Bridge<br/>current"]
|
||||
ContentStudioBridge["content-studio Desktop Host bridge<br/>App Server client"]
|
||||
LegacyFacade["Legacy Desktop Facade<br/>compat / deprecated"]
|
||||
LegacyFacade["Legacy Desktop Facade<br/>compat cleanup"]
|
||||
GenericClient["Generic TS / Rust Client"]
|
||||
end
|
||||
|
||||
@@ -109,6 +109,8 @@ flowchart TB
|
||||
| ExecutionBackend | Aster / 未来执行引擎的 runtime 下游适配 | 公共 facts、App 生命周期、Desktop Host bridge |
|
||||
| Runtime Services | Tool、Skill、Workspace、Memory、Policy、Artifact、Evidence | App UI 投影 |
|
||||
|
||||
Rust 实现落点必须跟随这张分层表。`lime-rs/src/commands/**` 是旧 Tauri command wrapper 清理区,不属于 RuntimeCore、ExecutionBackend 或 Runtime Services 的新实现目录;它只允许删除旧 wrapper、迁出逻辑、或把迁移期 legacy desktop facade 收窄成带退出条件的薄委托。新增后端能力进入 App Server crates / RuntimeCore / services;桌面壳能力进入 Electron Desktop Host。
|
||||
|
||||
## 4. 事实流
|
||||
|
||||
```text
|
||||
@@ -216,11 +218,12 @@ target:
|
||||
迁移原则:
|
||||
|
||||
1. 先抽 service,后改 legacy facade。
|
||||
2. legacy command 保留原命令名和兼容合同,内部只委托。
|
||||
2. legacy command 如仍保留原命令名和兼容合同,内部只能委托 current 主链,并写清退出条件。
|
||||
3. App Server 与 legacy facade 共享 RuntimeCore,不共享壳层对象。
|
||||
4. Aster 逻辑先收进 `AsterBackend`,不要上浮成公共协议。
|
||||
5. 新能力只加到 core / backend / protocol,不再加到 legacy command glue。
|
||||
6. backend mode 由 runtime factory 声明;standalone binary 默认 `mock`,legacy desktop facade 如保留只负责注入 `AsterBackendHost`。
|
||||
7. 新实现不得落到 `lime-rs/src/commands/**`;发现旧 wrapper 阻碍 current 主链时,优先迁出或删除,而不是新增 compat 包装。
|
||||
|
||||
## 8. 独立 App 集成边界
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Electron Desktop Host Current 方案
|
||||
|
||||
> 状态:current implementation source
|
||||
> 更新时间:2026-06-06
|
||||
> 更新时间:2026-06-08
|
||||
> 作用:固定 Lime Desktop 前端宿主由 Electron 全面接管后的 renderer、Desktop Host bridge、App Server sidecar、桌面壳能力和验收口径。
|
||||
> 关联:[architecture.md](./architecture.md)、[frontend-integration-matrix.md](./frontend-integration-matrix.md)、[release-updater.md](./release-updater.md)、[consumer-integration.md](./consumer-integration.md)。
|
||||
|
||||
@@ -37,6 +37,7 @@ Electron 只负责 Desktop Host bridge、preload / IPC 白名单、窗口、托
|
||||
| `current` | `src/lib/desktop-host/*` | renderer-safe 桌面能力 API,生产走 Electron bridge,测试夹具显式注入 |
|
||||
| `current` | `src/lib/api/appServer.ts`、`packages/app-server-client/src/protocol.ts` | renderer 侧 App Server JSON-RPC gateway 与协议事实源 |
|
||||
| `current` | `electron/updateHost.ts`、`forge.config.mjs`、`.github/workflows/release.yml` | updater、签名、公证和发布包事实源 |
|
||||
| `compat cleanup` | `lime-rs/src/commands/**` | 旧 Tauri command wrapper 清理区;只允许删除、迁出或带退出条件的薄委托,不再承接新业务逻辑 |
|
||||
| `compat` | legacy desktop facade | 只允许迁移期委托和投影,不继续承接新业务逻辑 |
|
||||
| `deprecated` | `lime-rs/` 下仍被 git 跟踪的旧宿主配置文件 | 仅作为物理清理候选保留;不得作为 package scripts、Electron Forge、updater、CI 或版本同步输入 |
|
||||
| `dead` | 旧 builder 配置 / CLI、自定义 Windows installer maker、旧 YAML / blockmap updater metadata | 不得作为 release、updater、签名、公证、CI、i18n app metadata 或版本同步输入 |
|
||||
@@ -50,6 +51,8 @@ Electron 只负责 Desktop Host bridge、preload / IPC 白名单、窗口、托
|
||||
4. 当前仍被 git 跟踪的旧宿主配置文件后续应单独删除或迁移;在删除前只能标记为 `deprecated cleanup candidate`,不能作为 current release、updater、签名、公证或开发入口证据。
|
||||
5. 旧 builder 配置 / CLI、自定义 Windows installer maker 与旧 updater metadata 已进入 `dead`,不能作为 Electron current 打包、发布或 metadata 事实源。
|
||||
|
||||
`lime-rs/src/commands/**` 不再是 Electron current 后端实现目录。若 renderer 需要新增 Agent runtime、workspace、artifact、evidence、Knowledge、MCP 等后端能力,应进入 App Server JSON-RPC / RuntimeCore / services;若需要新增窗口、shell、托盘、Dock、updater、deep link 等桌面壳能力,应进入 Electron Desktop Host bridge。旧 wrapper 缺能力时必须 fail closed 并登记 current 缺口,不能在 `commands/` 里补 stub、compat wrapper 或平行实现。
|
||||
|
||||
## 3. Renderer 契约
|
||||
|
||||
业务组件、页面、hook 和 View Model 不直接碰桌面 IPC。推荐路径是:
|
||||
@@ -133,6 +136,7 @@ Electron Desktop Host bridge
|
||||
3. Agent session create / list / read、thread read model、turn start / cancel、action respond 已经迁到 App Server JSON-RPC 前端 gateway。
|
||||
4. `src/lib/desktop-host/*` 生产路径已按 Electron bridge 优先、无 bridge fail-closed、测试显式 mock 的规则收口。
|
||||
5. release / updater / signing / notarization 已由 Electron Forge 和 Electron updater 文档锁定。
|
||||
6. `lime-rs/src/commands/**` 已固定为旧 Tauri wrapper 清理区;新实现不得继续落入该目录。
|
||||
|
||||
仍需继续推进:
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ Electron main 是 Desktop Host bridge,不是后端适配层,也不是第二
|
||||
19. Agent App mock SDK 只允许测试环境显式使用;`mockSdkEnabled` 在生产构建中硬关闭,`buildMockCapabilityProfile`、`MockCapabilityHost`、`createMockLimeCapabilityTransport` 都必须通过 test-only 断言,且 mock transport 只允许测试夹具显式导入。public SDK / production runtime 不再导出或导入 mock transport、mock host、mock capability profile 或 mock handler 类型;生产 Agent App runtime 缺真实 App Server / Electron current method 时必须 fail closed,不能用 mock capability profile、mock host 或 mock transport 作为产品闭环。
|
||||
20. `src/lib/api/project.ts` 的 workspace/project 读与目录就绪链路已通过 `AppServerClient.request(...)` 进入 App Server current 主链,并直接复用 `packages/app-server-client/src/protocol.ts` 的 `METHOD_WORKSPACE_*` 常量;`workspace/list`、`workspace/read`、`workspace/byPath/read`、`workspace/default/read`、`workspace/default/ensure`、`workspace/projectsRoot/read`、`workspace/projectPath/resolve`、`workspace/ensureReady` 缺少必需 result 时 fail closed,不再把 `workspace_get*`、`workspace_list`、`workspace_ensure_*` 或 `get_or_create_default_project` 当作前端事实源。`workspace_create/update/delete/set_default` 与 content 相关命令仍暂保 compat,因为 App Server 目前没有完整等价写 method。
|
||||
21. `src/lib/api/modelRegistry.ts` 的模型 registry / preference / sync 读链,以及 provider / tier / alias scoped 读链的前端 gateway,已通过 `AppServerClient.request(...)` 进入 App Server current 主链,并直接复用 `packages/app-server-client/src/protocol.ts` 的 `METHOD_MODEL_*` / `METHOD_MODEL_PROVIDER_*` 常量;`model/list`、`modelPreferences/list`、`modelSyncState/read`、`modelProvider/fetchModels`、`modelProviderAlias/read`、`modelProviderAlias/list` 缺少必需 result 时 fail closed,不再把 `get_model_registry`、`get_model_preferences`、`get_model_sync_state`、`get_models_for_provider`、`get_models_by_tier`、`get_provider_alias_config`、`get_all_alias_configs` 或 `fetch_provider_models_auto` 当作前端事实源。`scripts/model-registry-current-smoke.mjs` 已通过真实设置页“添加模型”面板证明 `model/list`、`modelPreferences/list`、`modelSyncState/read` 经 `app_server_handle_json_lines` 到达 App Server,且未观察到旧 `get_model_*` 命令、模型写入 / refresh side-effect 或 `agentSession/turn/start`。本 GUI 证据不覆盖 `modelProviderAlias/read` / `modelProviderAlias/list` 的 alias GUI 触发,不覆盖 provider / tier scoped 查询或 provider ids 兼容查询。`refresh_model_registry`、`search_models`、`toggle_model_favorite`、`hide_model`、`record_model_usage` 与 provider ids 兼容查询仍暂保 compat,因为 App Server 目前没有完整等价写 / refresh method。
|
||||
22. `src/lib/api/knowledge.ts` 的 `listKnowledgePacks(...)` 已通过 `AppServerClient.request("knowledgePack/list", ...)` 进入 App Server current 主链;空 `workingDir`、缺少 `workingDir/rootPath` 或 `packs` 非数组时 fail closed,不再把 `knowledge_list_packs`、renderer mock 或 Electron legacy facade 当作前端事实源。`scripts/knowledge-current-smoke.mjs` 已通过真实 GUI 点击路径证明项目资料页面列表读取经 `app_server_handle_json_lines` 观察到 `knowledgePack/list`,且未观察到旧 `knowledge_list_packs` 命令。`knowledge_get_pack`、`knowledge_import_source`、`knowledge_compile_pack`、`knowledge_set_default_pack`、`knowledge_update_pack_status`、`knowledge_resolve_context`、`knowledge_validate_context_run` 仍暂保 compat,因为 App Server 当前只覆盖知识包列表读链。
|
||||
22. `src/lib/api/knowledge.ts` 的 Knowledge 生命周期网关已全量改走 App Server current method:`knowledgePack/list`、`knowledgePack/read`、`knowledgePack/source/import`、`knowledgePack/compile`、`knowledgePack/default/set`、`knowledgePack/status/update`、`knowledgeContext/resolve`、`knowledgeContextRun/validate`。空 `workingDir`、缺少必需 result 或 DTO 形状不对时 fail closed,不再把 `knowledge_*`、renderer mock、desktop-host mock 或 Electron legacy facade 当作前端事实源。App Server protocol / schema / TS client / Rust client / processor / RuntimeCore / `LocalAppDataSource -> lime_knowledge` 已覆盖同一组 method;`electron/hostCommands.ts` 与 `electron/ipcChannels.ts` 中的 `knowledge_*` compat facade 已退场,只保留通用 `app_server_handle_json_lines` / `app_server_drain_events` current bridge。`scripts/knowledge-current-smoke.mjs` 已证明项目资料页面列表读取经 `app_server_handle_json_lines` 观察到 `knowledgePack/list` 且无旧 `knowledge_list_packs`;Knowledge product / GUI / provider smoke 也已改为调用 `knowledgePack/*` current method。剩余缺口只限 live Builder Skill runtime binding:`knowledgePack/compile` 遇到 `builderRuntime.enabled=true` 时在 App Server current 路径 fail closed,后续必须把 Builder runtime binding 迁入 App Server current,不得回落到 `lime-rs/src/commands/knowledge_cmd.rs`。
|
||||
23. `src/lib/api/skill-execution.ts` 的 `listExecutableSkills()` 与 `getSkillDetail(...)` 已通过 `AppServerClient.request(...)` 进入 App Server current 主链,并直接复用 `packages/app-server-client/src/protocol.ts` 的 `METHOD_SKILL_LIST` / `METHOD_SKILL_READ`;`skill/list` 或 `skill/read` 缺少必需 result 时 fail closed,不再把 `list_executable_skills`、`get_skill_detail`、renderer mock 或 Electron legacy facade 当作前端读事实源。`scripts/skills-current-smoke.mjs` 已通过真实 GUI slash skill preflight 证明 `skill/list` 经 `app_server_handle_json_lines` 返回 `result.skills` 数组,且未观察到旧 Skill 命令、`execute_skill` 或 `agentSession/turn/start`。`skill/read` 真实 GUI 触发与 `execute_skill` 仍暂保 compat side-effect,因为 App Server 当前没有完整等价执行 method。
|
||||
24. `src/lib/api/agentApps.ts` 的 `listInstalledAgentApps(...)` 已通过 `AppServerClient.request("agentAppInstalled/list", {})` 进入 App Server current 主链;缺少 `states` 或 `issues` 时 fail closed,不再把 `agent_app_list_installed`、renderer mock 或 Electron legacy facade 当作前端事实源。`scripts/agent-app/installed-current-smoke.mjs` 已通过真实 GUI 点击路径证明 Agent Apps 管理页已安装列表读取经 `app_server_handle_json_lines` 观察到 `agentAppInstalled/list`,且未观察到旧 `agent_app_list_installed` 命令。`agent_app_save_installed_state`、install / uninstall / shell 等写入或 desktop side-effect 命令仍暂保 compat,因为 App Server 当前只覆盖已安装列表读链;UI runtime start / status / stop 已拆到 `agentAppUiRuntime/*` current method。`scripts/agent-app/ui-runtime-current-smoke.mjs` 已通过真实前端 gateway 证明 UI runtime `status` / `stop` / `start` 均经 `app_server_handle_json_lines -> agentAppUiRuntime/*` 到达 App Server,未观察到旧 `agent_app_*_ui_runtime` 命令,并用一次性不存在的 appId 验证 `start` fail closed、不写 installed state、不启动子进程;`scripts/agent-app/ui-runtime-stdio-fixture-smoke.mjs` 已进一步证明 App Server stdio / RuntimeCore 可用 fixture installed state 启动真实 npm dev 子进程,完成 `/api/bootstrap` ready、`entryUrl` 可达、status running 与 stop stopped 生命周期;`scripts/agent-app/ui-runtime-electron-fixture-smoke.mjs` 已证明真实 Electron-host GUI 能从正式侧栏进入 fixture Agent App runtime 页面,发出 `agentAppUiRuntime/start`,并让 iframe surface 打开 App Server 返回的 `entryUrl`。该证据只覆盖 Agent App UI runtime 生命周期,不覆盖 Agent 对话 turn、tool runtime、evidence 或 Claw/Aster 完整执行链。
|
||||
25. `src/lib/api/automation.ts` 的 scheduler / job / schedule 网关已通过 `AppServerClient.request(...)` 进入 App Server current 主链,覆盖 `automationScheduler/config/read|update|status`、`automationJob/list|read|create|update|delete|runNow|health|runHistory` 与 `automationSchedule/preview|validate`;缺少必需 result 时 fail closed,不再把旧 `get_automation_*`、`*_automation_job`、renderer mock 或 Electron legacy facade 当作前端事实源。`scripts/automation-current-smoke.mjs` 已通过真实 GUI 点击路径证明持续流程任务列表读取经 `app_server_handle_json_lines` 观察到 `automationJob/list`,且未观察到旧 automation 命令族。旧 Tauri / Electron / DevBridge automation command surface 已判为 `dead` 并从 runner、dispatcher、Electron host 白名单和 mock priority 中移除;`automationJob/runNow` 已进入 current 协议,但 App Server 自动化执行器尚未迁完,当前实现 fail closed,不回退旧 Tauri 执行器。
|
||||
@@ -53,7 +53,7 @@ Electron main 是 Desktop Host bridge,不是后端适配层,也不是第二
|
||||
33. `AppSidebar` 与 `AgentChatWorkspace` 的 workspace 过滤投影已收口:本地记忆项目只保留导航上下文,不能在未验证前成为 App Server `agentSession/list.workspaceId` 过滤条件;Agent 工作台仅在 `projectSelectionSource=remembered` 且项目尚未加载为同一 ID 时暂缓 runtime workspace,显式外部项目、初始会话、话题绑定项目、默认项目和手动选择继续按 current 主路径进入 `useAgentChatUnified`。
|
||||
34. Connect deep link 已切到 Electron Desktop Host URL bridge 与 App Server JSON-RPC current 主链。`electron/main.ts` 同时收集 macOS `open-url`、首启 `process.argv` 与 `second-instance` argv 中的 `lime://` URL,preload 只暴露 renderer-safe `deepLink.getCurrent/onOpenUrl`;业务解析、Relay registry 校验、API Key 保存和 callback 发送只允许经 `src/lib/api/connect.ts -> connectDeepLink/resolve`、`connectOpenDeepLink/resolve`、`connectRelayApiKey/save`、`connectCallback/send` 进入 App Server。`scripts/connect-deep-link-current-smoke.mjs` 已用真实 Electron 首启参数证明 `lime://connect` 触发确认弹窗,并观察到 `app_server_handle_json_lines -> connectDeepLink/resolve`;`scripts/connect-open-deep-link-current-smoke.mjs` 已用真实 Electron 首启参数证明 `lime://open` 官网入口经 `connectOpenDeepLink/resolve` 解析后进入 Agent 官网入口页面状态。旧 `deep-link://new-url`、`deep-link-connect`、`deep-link-error`、`handle_deep_link`、`handle_open_deep_link`、`save_relay_api_key`、`send_connect_callback`、`list_relay_providers`、`refresh_relay_registry` 不得回流。仍未覆盖可信 HTTPS webhook 网络投递或真实 Relay registry 网络刷新。
|
||||
35. renderer 侧 App Server JSON-RPC result envelope 已统一收口到 `src/lib/api/appServer.ts`:`handleAppServerJsonLines(...)` 与 `drainAppServerEvents(...)` 同时兼容 Electron `safeInvoke` 返回的 `{ result: { lines } }` 和旧 `{ lines }`,避免设置页把真实 App Server response 误判成 `agentAppInstalled/list did not return states`、`modelProvider/list did not return providers`、`model/list did not return models`、`modelProviderAlias/list did not return configs`。`src/lib/dev-bridge/commandPolicy.ts` 也把 `workspace/default/read`、`workspace/default/ensure`、`workspace/list`、`workspace/read`、`workspace/byPath/read`、`workspace/projectsRoot/read`、`workspace/projectPath/resolve`、`workspace/ensureReady` 这组 App Server workspace 启动真相 method 归到 `startup-truth` 30 秒 profile,防止设置页 / 默认工作区准备态被 5 秒 `truth` 超时误杀。Claw 发送前的本地恢复 session 现在必须先经 `runtime.getSession(..., { historyLimit: 40 })` 被 App Server 确认;`session not found` 或 workspace mismatch 会丢弃本地恢复快照并新建 App Server session,普通桥接错误继续 fail closed。该修复不新增 App Server method,不把 `agentRuntime` 扩成业务 runtime,只修前端 thin gateway 和 session 恢复保护。
|
||||
36. App Server `RuntimeBackend` 已成为 Claw/Aster 执行链 current backend。对照 Codex `app-server` 后,Lime 不再把长命名 `lime-rs/crates/app-server-agent-backend` 当默认事实源;旧 external 二进制已迁入 `lime-rs/crates/app-server/src/runtime_backend.rs` 的 `ExecutionBackend` implementation,并通过 `initialize_aster_runtime(db.clone()) -> AsterAgentState::new() -> configure_provider_from_pool(...) / configure_provider(...) -> stream_reply_with_policy(...)` 复用 Claw/Aster 流式执行链。`app-server --backend runtime`、`AppServerBackendMode::Runtime`、`AppServerRuntimeFactory::runtime_backend_core(...)`、Electron dev 默认 `APP_SERVER_BACKEND_MODE=runtime` 是 current;`app-server-agent-backend` 只能作为 `deprecated/compat` external command / fixture 过渡对象,删除前必须先证明引用清零并按危险操作规则确认。RuntimeBackend 读取 App Server `ExecutionRequest.session / turn`、扁平 `hostOptions.asterChatRequest` 与 `turn_config` 镜像,恢复 provider/model/system prompt/reasoning/sandbox/web search 等请求合同;runtime event 投影为 App Server current event type,最终输出 `turn.final_done`。provider/model 选择已按 Claw session default 语义收口:显式 runtime preference -> host provider_config / preference -> session `businessObjectRef.metadata` 中完整 provider/model default;不再扫描全局 enabled Provider `custom_models`,不再读取 `ModelRegistryService` cached models,避免 GUI 无显式偏好时误选无关 Provider。`useAgentSession.createFreshSession(...)` 在 `agentSession/start` 时同步写入 `providerSelector`、`modelName`、`executionRuntime` 与 `extensionData["lime_provider_routing.v0"]`,消除首回合等待异步 `agentSession/update` 的 race。显式 `web_search=false` 仍优先禁用,显式 `search_mode` 优先保留;无显式配置时默认 `RequestToolPolicyMode::Allowed`,把 WebSearch / WebFetch 作为模型可见工具交给模型按 tool choice auto 判断,禁止按“今天 / 新闻 / 最新”等自然语言关键词提升为 `Required`。该事实证明默认主链不再依赖 external glue,也不等同于 live provider 授权后的完整 Claw streaming GUI E2E。
|
||||
36. App Server `RuntimeBackend` 已成为 Claw/Aster 执行链 current backend。对照 Codex `app-server` 后,Lime 不再把长命名 `lime-rs/crates/app-server-agent-backend` 当默认事实源;旧 external 二进制已迁入 `lime-rs/crates/app-server/src/runtime_backend.rs` 的 `ExecutionBackend` implementation,并通过 `initialize_aster_runtime(db.clone()) -> AsterAgentState::new() -> configure_provider_from_pool(...) / configure_provider(...) -> stream_reply_with_policy(...)` 复用 Claw/Aster 流式执行链。`app-server --backend runtime`、`AppServerBackendMode::Runtime`、`AppServerRuntimeFactory::runtime_backend_core(...)`、Electron dev 默认 `APP_SERVER_BACKEND_MODE=runtime` 是 current;`lime-rs/crates/app-server-agent-backend` 已按 `dead` 删除,`Cargo.lock` 不再包含 `app-server-agent-backend` package,contract guard 同步禁止该目录或 lockfile package 回流。RuntimeBackend 读取 App Server `ExecutionRequest.session / turn`、扁平 `hostOptions.asterChatRequest` 与 `turn_config` 镜像,恢复 provider/model/system prompt/reasoning/sandbox/web search 等请求合同;runtime event 投影为 App Server current event type,最终输出 `turn.final_done`。provider/model 选择已按 Claw session default 语义收口:显式 runtime preference -> host provider_config / preference -> session `businessObjectRef.metadata` 中完整 provider/model default;不再扫描全局 enabled Provider `custom_models`,不再读取 `ModelRegistryService` cached models,避免 GUI 无显式偏好时误选无关 Provider。`useAgentSession.createFreshSession(...)` 在 `agentSession/start` 时同步写入 `providerSelector`、`modelName`、`executionRuntime` 与 `extensionData["lime_provider_routing.v0"]`,消除首回合等待异步 `agentSession/update` 的 race。显式 `web_search=false` 仍优先禁用,显式 `search_mode` 优先保留;无显式配置时默认 `RequestToolPolicyMode::Allowed`,把 WebSearch / WebFetch 作为模型可见工具交给模型按 tool choice auto 判断,禁止按“今天 / 新闻 / 最新”等自然语言关键词提升为 `Required`。该事实证明默认主链不再依赖独立 external glue crate,也不等同于 live provider 授权后的完整 Claw streaming GUI E2E。
|
||||
37. Agent session messages Electron fixture 已把 `agentSession/turn/start -> agentSession/read.detail.messages` 证据收紧到 read model 收敛后再断言。`scripts/smoke/agent-session-messages-electron-fixture-smoke.mjs` 仍使用真实 Electron preload `app_server_handle_json_lines` 与一次性 `APP_SERVER_BACKEND_MODE=external` fixture backend,但 turn accepted 后会通过 `waitForReadModel()` 轮询同一 App Server JSON-RPC `agentSession/read`,直到 `detail.messages_count=2`、`detail.messages` 同时包含用户消息和 `message.delta` 投影的 assistant 消息。最新 summary 位于 `.lime/qc/gui-evidence/agent-session-messages-electron-fixture/agent-session-messages-electron-fixture-summary.json`,显示 `ok=true`、`electronPreloadBridge=true`、`backendKinds=["turnStart"]`、`detailMessagesCount=2`、`detailMessagesLength=2`、`consoleErrors=[]`。该证据用于区分真实后端缺口与异步收敛竞态;它不使用 legacy `agent_runtime_*`、renderer mock、default mock 或 App Server mock backend,也不等同 live provider 完整 Claw streaming GUI E2E。
|
||||
38. 更新提醒窗口属于 Electron Desktop Host updater 壳能力,不进入 App Server JSON-RPC 或 RuntimeCore。`src/components/app-sidebar/AppUpdateEntry.tsx -> src/lib/api/appUpdate.ts -> safeInvoke("open_update_window", { anchorRect }) -> electron/updateHost.ts -> electron/main.ts` 已把侧边栏更新按钮锚点投影到 Electron 通知窗口定位;Electron Host 只管理窗口生命周期与位置,不新增后端业务 adapter,也不引入 mock fallback。最新 GUI evidence 位于 `.lime/qc/gui-evidence/update-notification-ui/update-notification-ui-summary.json` 与 `.lime/qc/gui-evidence/update-notification-ui/update-notification-ui.png`,summary 显示 `ok=true`、窗口 `232x128`、根背景透明、外层容器 `padding=0px`、toast 为唯一白色表面且内容未裁切;该证据证明更新弹层不再居中、不再露出双重背景,但不代表 release feed / signing / install session 全链路完成。
|
||||
|
||||
@@ -97,7 +97,7 @@ Electron main 是 Desktop Host bridge,不是后端适配层,也不是第二
|
||||
| project memory aggregate read | `projectMemory/read` | `app_server_handle_json_lines -> projectMemory/read` | `getProjectMemory` | `partial` | 聚合读已直连 App Server method;`scripts/project-memory-current-smoke.mjs` 已补真实 GUI / bridge 证据,确认 Agent 首页默认工作区记忆读取 `projectMemory/read` 且无旧 `project_memory_get` 命令;角色 / 世界观 / 大纲 CRUD 仍是 compat。 |
|
||||
| model registry/preferences/sync read | `model/list` / `modelPreferences/list` / `modelSyncState/read` / `modelProvider/fetchModels` / `modelProviderAlias/*` | 通用 JSONL 可达;legacy `get_model_*` / `fetch_provider_models_auto` facade 仅允许停留在负向守卫和历史记录 | `src/lib/api/modelRegistry.ts -> AppServerClient.request` | `partial` | `scripts/model-registry-current-smoke.mjs` 已补设置页“添加模型”真实 GUI / bridge 证据,确认 `model/list`、`modelPreferences/list`、`modelSyncState/read` 均返回有效 result 且无旧 model 命令、模型写入 / refresh side-effect 或 Agent turn;alias/provider/tier scoped gateway 与 provider live fetch 已 current 化但 GUI 逐项证据仍缺,provider ids、favorite / refresh 等仍是 compat 或待补 App Server method。 |
|
||||
| API key provider list/catalog | `modelProvider/*` / `modelProviderKey/*` / `modelProviderUiState/*` / `modelProviderConfig/*` | 通用 JSONL 可达;legacy `get_api_key_providers` / `get_system_provider_catalog` / `get_provider_ui_state` / `set_provider_ui_state` facade 已判为 `dead`,不得回流 | `src/lib/api/apiKeyProvider.ts -> AppServerClient.request` | `partial` | Provider list/catalog/read/write、API Key 写入 / 启停、UI state、导入导出、连接测试与 chat test gateway 已直连 App Server;`scripts/provider-settings-current-smoke.mjs` 已补真实 GUI / bridge 证据,确认设置页读取 `modelProvider/list`、添加模型 catalog 读取 `modelProvider/catalog/list` 且无旧 Provider 命令;单 Provider、secret 写入、UI state、导入导出和连接测试的 GUI 逐项证据仍缺。 |
|
||||
| knowledge pack list | `knowledgePack/list` | 通用 JSONL 可达;legacy `knowledge_list_packs` facade 仅兼容投影 | `src/lib/api/knowledge.ts -> AppServerClient.request` | `partial` | 知识包列表读链已直连 App Server;`scripts/knowledge-current-smoke.mjs` 已补真实 GUI / bridge 证据,确认项目资料页面读取 `knowledgePack/list` 且无旧 `knowledge_list_packs` 命令;get/import/compile/default/status/resolve/validate 仍是 compat。 |
|
||||
| knowledge lifecycle / context | `knowledgePack/list` / `knowledgePack/read` / `knowledgePack/source/import` / `knowledgePack/compile` / `knowledgePack/default/set` / `knowledgePack/status/update` / `knowledgeContext/resolve` / `knowledgeContextRun/validate` | `app_server_handle_json_lines -> knowledgePack/* / knowledgeContext*`;旧 `knowledge_*` Electron facade 已退场,Rust Tauri wrapper / DevBridge dispatcher 只剩 dead file candidate | `src/lib/api/knowledge.ts -> AppServerClient.request` | `wired-current-except-live-builderRuntime` | 前端网关、App Server protocol / schema / TS client / Rust client / processor / RuntimeCore / `LocalAppDataSource -> lime_knowledge` 已覆盖全量 Knowledge current method,desktop-host Knowledge 默认 mock 已清空,Electron `knowledge_*` 白名单与 facade 已撤。`scripts/knowledge-current-smoke.mjs` 已覆盖列表 GUI / bridge 证据;`scripts/knowledge-product-e2e.mjs`、`scripts/knowledge-gui-smoke.mjs`、`scripts/knowledge-provider-e2e.mjs` 已改为 current JSON-RPC method。`knowledgePack/compile` 的普通离线编译走 current;live Builder Skill runtime binding 尚未迁入 App Server,`builderRuntime.enabled=true` 当前 fail closed,不得复活 `lime-rs/src/commands/knowledge_cmd.rs`。 |
|
||||
| Agent App installed list | `agentAppInstalled/list` | 通用 JSONL 可达;legacy `agent_app_list_installed` facade 仅兼容投影 | `src/lib/api/agentApps.ts -> AppServerClient.request` | `partial` | 已安装列表读链已直连 App Server;`scripts/agent-app/installed-current-smoke.mjs` 已补真实 GUI / bridge 证据,确认 Agent Apps 页面读取 `agentAppInstalled/list` 且无旧 `agent_app_list_installed` 命令;保存、安装、卸载和 shell side-effect 仍是 compat。 |
|
||||
| automation scheduler/job/schedule | `automationScheduler/config/read` / `automationScheduler/config/update` / `automationScheduler/status` / `automationJob/list` / `automationJob/read` / `automationJob/create` / `automationJob/update` / `automationJob/delete` / `automationJob/runNow` / `automationJob/health` / `automationJob/runHistory` / `automationSchedule/preview` / `automationSchedule/validate` | `app_server_handle_json_lines -> automation*`;旧 `get_automation_*` / `*_automation_job` Tauri、Electron facade、DevBridge dispatcher 和 mock surface 已判为 `dead`,不得回流 | `src/lib/api/automation.ts -> AppServerClient.request` | `partial` | 自动化 scheduler/job/schedule 网关已直连 App Server method,并有前端 no legacy fallback 测试;`scripts/automation-current-smoke.mjs` 已补真实 GUI / bridge 证据,确认持续流程任务列表读取 `automationJob/list` 且无旧 automation 命令族。`automationJob/runNow` 仍是 current 缺口:协议、client、前端和 processor 已接入,但 App Server 自动化执行器尚未迁完,当前 fail closed,不回退旧 Tauri 执行器;`scripts/managed-objective-automation-smoke.mjs` 也改为只走 `automationJob/create/runNow/runHistory`,遇到该执行器缺口时失败而不是调用旧命令。 |
|
||||
| Connect deep link resolve/open | `connectDeepLink/resolve` / `connectOpenDeepLink/resolve` | Electron protocol/open-url / 首启参数 / `second-instance` -> preload `deepLink.getCurrent/onOpenUrl` -> `app_server_handle_json_lines` | `useDeepLink -> src/lib/api/connect.ts` | `wired` | `scripts/connect-deep-link-current-smoke.mjs` 已用真实 Electron 首启参数证明 `lime://connect` 经 preload bridge 到达 `connectDeepLink/resolve` 并出现确认弹窗;`scripts/connect-open-deep-link-current-smoke.mjs` 已用真实 Electron 首启参数证明 `lime://open?kind=prompt&slug=gemini-longform-master...` 经 `connectOpenDeepLink/resolve` 到达 Agent 官网入口 banner / prompt 状态。两条证据均未观察到旧 Tauri deep-link 事件或旧 Connect 命令。 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# App Server 分阶段实施计划
|
||||
|
||||
> 状态:current planning source
|
||||
> 更新时间:2026-06-06
|
||||
> 更新时间:2026-06-08
|
||||
> 作用:把 App Server 从路线图推进到可执行的工程阶段,支持渐进式替换和多独立 App 复用。
|
||||
|
||||
## 1. 实施原则
|
||||
@@ -12,6 +12,7 @@
|
||||
4. App Server 和 legacy desktop facade 必须共享 RuntimeCore。
|
||||
5. 旧 command glue 只能作为 compat facade,不继续长业务逻辑。
|
||||
6. 新 App 只能走 App Server Client,不直接链接 Lime 内部实现。
|
||||
7. `lime-rs/src/commands/**` 是旧 Tauri command wrapper 清理区,不再承接新的业务逻辑、API adapter、runtime 分支或领域服务实现。
|
||||
|
||||
## 2. 阶段总览
|
||||
|
||||
@@ -28,6 +29,8 @@
|
||||
| P8 | 多 App 复用 | capability discovery、client isolation、本地 socket 评估 | 第二个独立 App 不新增 runtime 实现即可接入。 |
|
||||
| P9 | 退场审计 | legacy desktop glue 分类、守卫、删除计划 | 旧 runtime glue 有退出条件和扫描守卫。 |
|
||||
|
||||
阶段推进时不得把 `lime-rs/src/commands/**` 当成新阶段产物目录。P3 / P4 / P7 的后端能力进入 App Server crates、RuntimeCore、ExecutionBackend 和 services;P5 的桌面壳能力进入 Electron Desktop Host bridge。legacy desktop command 只允许作为迁移期委托,且每条保留项必须有退出条件。
|
||||
|
||||
## 3. P0:文档和协议冻结
|
||||
|
||||
已完成目标:
|
||||
@@ -139,6 +142,7 @@
|
||||
6. fixture 覆盖 request / response / notification。
|
||||
7. standalone `app-server` 只能启动 host-independent backend。
|
||||
8. legacy desktop Aster host 只能通过 host bridge 注入,不进入 protocol / router / standalone CLI。
|
||||
9. 不新增或恢复 `lime-rs/src/commands/**` 中的 App Server JSON-RPC command wrapper。
|
||||
|
||||
## 7. P6:content-studio 试点
|
||||
|
||||
@@ -216,6 +220,7 @@
|
||||
2. 给 compat / deprecated 路径写退出条件。
|
||||
3. 补治理扫描,禁止新 runtime 逻辑落回 command glue。
|
||||
4. 删除无入口 adapter。
|
||||
5. 按命令族删除或迁出 `lime-rs/src/commands/**` 剩余 wrapper;不得新增 stub 或平行 compat 实现。
|
||||
|
||||
退出条件:
|
||||
|
||||
@@ -223,6 +228,7 @@
|
||||
2. 新 App 只通过 App Server Client。
|
||||
3. App Server 协议成为新增 Agent 能力的默认入口。
|
||||
4. 治理报告能发现回流。
|
||||
5. `lime-rs/src/commands/**` 只剩明确带退出条件的薄委托,或已经按领域迁出 / 删除。
|
||||
|
||||
## 11. 验证计划
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Electron Release / Updater 边界
|
||||
|
||||
> 状态:current planning source
|
||||
> 更新时间:2026-06-07
|
||||
> 更新时间:2026-06-08
|
||||
> 作用:固定 Lime Desktop 下线上一代前端宿主后的 release、签名、公证、updater feed 与平稳迁移口径。
|
||||
|
||||
## 1. 事实源
|
||||
@@ -23,6 +23,8 @@ Codex CLI / `codex-rs` 只作为 App Server protocol / daemon lifecycle / client
|
||||
|
||||
旧 builder 配置 / CLI、自定义 Windows installer maker 与旧 YAML / blockmap updater metadata 已按 `dead` 处理,不再作为 release、updater、签名、公证、CI、i18n app metadata 或版本同步输入。
|
||||
|
||||
旧 Rust / Tauri updater command 面同样已按 `dead / deleted` 处理:`lime-rs/src/commands/update_cmd.rs` 已物理删除,`lime-rs/src/commands/mod.rs` 不再声明 `update_cmd`,`lime-rs/src/app/runner.rs` 不再管理 `UpdateInstallSessionState`、不再启动 Rust 后台更新检查,也不再注册旧 updater `generate_handler!`。后续不得用 stub、compat wrapper 或新实现把 updater 放回 `lime-rs/src/commands/`;只允许经 Electron Desktop Host updater current 链路演进。
|
||||
|
||||
官方依据:
|
||||
|
||||
- Electron Forge Makers:`https://www.electronforge.io/config/makers`
|
||||
@@ -149,6 +151,8 @@ Renderer 仍通过既有命令名进入更新体验,但实现 owner 已切到
|
||||
| `get_update_check_settings` | Electron updater 设置投影 |
|
||||
| `open_update_window` | Electron 通知窗口生命周期与定位 |
|
||||
|
||||
这些命令名只是前端体验的稳定入口,不代表可以恢复 Tauri command。`check_update`、`check_for_updates`、`download_update`、`start_update_install_session`、`get_update_install_session`、`get_update_check_settings`、`set_update_check_settings`、`get_update_notification_metrics`、`record_update_notification_action`、`skip_update_version`、`remind_update_later`、`dismiss_update_notification`、`update_last_check_timestamp`、`close_update_window`、`test_update_window` 的旧 Rust 注册和实现已经删除;如果 Electron Host 缺少真实能力,前端必须 fail closed,而不是回落到 Rust `commands/`。
|
||||
|
||||
开发态默认不启用真实 updater。只有显式设置 `LIME_ELECTRON_ENABLE_DEV_UPDATER=1` 时才允许在开发包里调用 Electron 内置 `autoUpdater`,避免开发环境误连生产 feed。
|
||||
|
||||
`open_update_window` 允许 renderer 通过前端 gateway 传入侧边栏更新按钮的锚点矩形;Electron Host 只做参数投影和窗口定位,不承接后端业务事实。更新提醒窗口必须贴近侧栏更新入口上方,并保持透明独立窗口内只有一层实体 toast 表面,避免居中弹出或外层背景露出造成双层弹窗观感。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# App Server 服务抽取计划
|
||||
|
||||
> 状态:current planning source
|
||||
> 更新时间:2026-06-06
|
||||
> 更新时间:2026-06-08
|
||||
> 作用:定义如何从现有 Lime runtime 中抽出可被 App Server 和 legacy desktop facade 共用的服务层。
|
||||
|
||||
## 1. 抽取原则
|
||||
@@ -13,6 +13,7 @@
|
||||
5. App Server 和 legacy desktop facade 必须调用同一个 RuntimeCore。
|
||||
6. 服务层不能依赖 retired desktop host app handle、event emitter 或 state container。
|
||||
7. 事件 sink、路径、凭证、workspace、policy 都通过 trait / context 注入。
|
||||
8. `lime-rs/src/commands/**` 是旧 Tauri command wrapper 清理区,不再承接新的业务逻辑、API adapter、runtime 分支或领域服务实现。
|
||||
|
||||
## 2. 当前候选事实源
|
||||
|
||||
@@ -22,9 +23,10 @@
|
||||
| `ExecutionBackend` | `current target` | 后端适配接口,Aster 和未来后端都走这里。 |
|
||||
| `AsterBackend` | `current target` | 对现有 Aster runtime_turn/tool_runtime 的适配封装。 |
|
||||
| `lime-rs/crates/agent` | `current reference` | 当前最接近 core 的 crate,后续继续拆公共模型与服务。 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/runtime_turn.rs` | `current reference` | Aster backend 实现参考,不直接成为公共 core。 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/tool_runtime/*` | `current reference` | Aster tool execution 参考,事件需转换为公共 tool facts。 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/command_api/*` | `compat` | 保留 legacy desktop command DTO / facade,逐步委托 service。 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/runtime_turn.rs` | `compat cleanup reference` | Aster backend 历史实现参考,只能用于迁出逻辑;不再作为公共 core 或新 runtime 落点。 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/tool_runtime/*` | `compat cleanup reference` | Aster tool execution 历史参考,事件需迁到公共 tool facts;不再新增 tool 业务逻辑。 |
|
||||
| `lime-rs/src/commands/aster_agent_cmd/command_api/*` | `compat cleanup` | legacy desktop command DTO / facade;只允许委托 service 并逐步删除。 |
|
||||
| `lime-rs/src/commands/**` | `compat cleanup` | 旧 Tauri wrapper 清理区;新增后端能力进入 App Server crates / RuntimeCore / services,桌面壳能力进入 Electron Desktop Host。 |
|
||||
| 前端 `safeInvoke` / `invoke` agent runtime API | `compat client` | Lime Desktop 迁移期继续保留,但可改为 app-server client。 |
|
||||
| `app-server-protocol` | `current target` | 定义 wire DTO 和 schema。 |
|
||||
| `app-server` crate 家族 | `current target` | 参考 codex-rs 分层命名,提供 protocol / transport / server / client / daemon / test-client。 |
|
||||
@@ -140,11 +142,11 @@ RuntimeEventSink
|
||||
| session/thread/turn/task/run/action ids | RuntimeCore |
|
||||
| JSON-RPC wire DTO | app-server-protocol |
|
||||
| backend 选择、取消、事件序列 | RuntimeCore |
|
||||
| Aster prompt / tool orchestration 细节 | AsterBackend |
|
||||
| Aster prompt / tool orchestration 细节 | AsterBackend;迁移完成前可参考旧 `aster_agent_cmd`,但不得在 `lime-rs/src/commands/**` 新增逻辑 |
|
||||
| 未来其他执行引擎细节 | 对应 ExecutionBackend |
|
||||
| 旧 Lime Agent event payload 解析 | Desktop compat facade |
|
||||
| legacy desktop host handle / window event | DesktopHostBridge |
|
||||
| Electron sidecar 管理 | app-server-client / app-server-daemon |
|
||||
| Electron sidecar 管理 | Electron Desktop Host / app-server-client / app-server-daemon |
|
||||
| content-studio 业务对象 | content-studio App surface |
|
||||
|
||||
## 6. 分阶段抽取
|
||||
@@ -233,6 +235,8 @@ RuntimeEventSink
|
||||
2. legacy desktop event sink。
|
||||
3. Lime Desktop frontend gateway。
|
||||
|
||||
这些允许位置只表示迁移期可读 / 可委托,不表示可以继续写新实现。`lime-rs/src/commands/**` 中的旧 facade 必须随 RuntimeCore / App Server / Electron Host 覆盖逐步删除。
|
||||
|
||||
退出条件:
|
||||
|
||||
1. service crate 编译不依赖 retired desktop host crates。
|
||||
@@ -244,7 +248,7 @@ RuntimeEventSink
|
||||
后续实现应补:
|
||||
|
||||
1. 结构测试:service crate 不得依赖 retired desktop host crates。
|
||||
2. 文本扫描:新 runtime 业务逻辑不得落回 command glue。
|
||||
2. 文本扫描:新 runtime 业务逻辑、API adapter、领域 service 不得落回 `lime-rs/src/commands/**`。
|
||||
3. contract test:legacy desktop facade 和 App Server 对同一 fixture 产出一致事件。
|
||||
4. protocol test:JSON-RPC request / response / notification schema 稳定。
|
||||
5. 边界测试:`app-server` 公共后端 contract 不得重新出现 Lime/Aster 私有事件类型。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# App Server / Electron 测试迁移口径
|
||||
|
||||
> 状态:current testing source
|
||||
> 更新时间:2026-06-06
|
||||
> 更新时间:2026-06-08
|
||||
> 作用:定义 Tauri GUI 退场后,测试用例如何迁到 Electron Desktop Host + App Server JSON-RPC current。
|
||||
|
||||
## 1. 结论
|
||||
@@ -19,6 +19,7 @@
|
||||
1. 用 Tauri GUI smoke 证明 Desktop current 可交付。
|
||||
2. 新增测试继续把 production artifact build 称为 `Tauri build`。
|
||||
3. 新 Agent / runtime 测试绕过 App Server JSON-RPC,直接压到 legacy command glue。
|
||||
4. 为了让旧测试通过,在 `lime-rs/src/commands/**` 新增 stub、compat wrapper、mock fallback 或业务逻辑。
|
||||
|
||||
## 2. 当前测试事实源
|
||||
|
||||
@@ -36,6 +37,7 @@
|
||||
| `current` | `scripts/lib/agent-qc-report-core.test.ts` | 验证 Agent QC package script fixture 中的 `verify:gui-smoke` 指向 `smoke:electron`,不再把旧 `scripts/verify-gui-smoke.mjs` 当 current 证据。 |
|
||||
| `current` | `scripts/lib/gui-smoke-run-lock.test.mjs` | 验证 GUI smoke run lock owner fixture 使用 `npm run smoke:electron`,不再把旧脚本路径写进 current owner metadata。 |
|
||||
| `current` | `scripts/verify-gui-smoke.mjs` | 保留旧文件名作为兼容入口,但直接委托 `npm run smoke:electron`,直接执行也只验证 Electron Desktop Host。 |
|
||||
| `compat cleanup guard` | `src/lib/governance/rustCommandsCurrentBoundary.test.ts` | 锁定 `lime-rs/src/commands/**` 只能作为旧 wrapper 清理区,防止 in-process bridge / runtime 新实现回流到 Tauri command。 |
|
||||
| `deprecated guard` | `scripts/standalone-deprecated-artifact-adapter-guard.test.mjs` | 验证旧 standalone artifact adapter 默认 blocked,且不回流 current release evidence / GUI 证据。 |
|
||||
| `deprecated artifact adapter` | `scripts/lib/agent-app-standalone-native-*.test.mjs` | 只允许证明 standalone artifact adapter fail-closed,不作为 current 发布链证据。 |
|
||||
| `dead guard` | `scripts/electron/current-entrypoints.test.mjs` | 验证 root Tauri GUI app entry files 已删除,不能重新作为 Desktop current 或 deprecated runner 入口回流。 |
|
||||
@@ -78,6 +80,8 @@ npm run test:contracts
|
||||
|
||||
旧 `agent_runtime_*` 测试只证明 Desktop compat adapter 委托,不再作为新增业务逻辑的主要证据。
|
||||
|
||||
`lime-rs/src/commands/**` 相关测试只允许作为 cleanup guard:证明旧 wrapper 已删除、已迁出、只做薄委托或没有回流。新增 Agent / runtime / workspace / artifact / evidence / Knowledge / MCP 能力的正向测试必须覆盖 App Server protocol / RuntimeCore / client / Electron Host current 链路;新增桌面壳能力的正向测试必须覆盖 Electron main / preload / desktop-host API。不能把 legacy Rust command 注册测试当作 GUI current 可交付证据。
|
||||
|
||||
## 4. 下一批迁移
|
||||
|
||||
优先处理:
|
||||
@@ -91,6 +95,7 @@ npm run test:contracts
|
||||
1. `src/lib/governance/legacySurfaceCatalog.json` 当前也在并行进程 staged 写集,本轮不覆盖;后续需要补脚本级 surface,覆盖 legacy smoke / artifact adapter,并限制 allowed paths 只允许 dead guard、deprecated guard 与历史说明。
|
||||
2. 只剩历史命名的 package materializer 只能作为 deprecated adapter 依赖,不得重新进入 current release 证据。
|
||||
3. Rust crate 内依赖 host state 的 Aster backend 测试,等 RuntimeCore / ExecutionBackend 解耦后再迁。
|
||||
4. `lime-rs/src/commands/**` 的剩余 wrapper 清理按命令族分批推进;等待 App Server / Electron Host current 覆盖后删除,不再为它们补新正向用例。
|
||||
|
||||
## 5. 当前验证证据
|
||||
|
||||
|
||||
@@ -445,20 +445,23 @@ interface KnowledgeContextResolutionRun {
|
||||
|
||||
### 7.4 模块边界
|
||||
|
||||
后端知识域必须独立于 Tauri 壳:
|
||||
后端知识域必须独立于桌面壳与 legacy command facade:
|
||||
|
||||
```text
|
||||
lime-rs/crates/knowledge/
|
||||
src/lib.rs # KnowledgePack 文件事实源、编译、解析、测试
|
||||
|
||||
lime-rs/crates/app-server/
|
||||
# 暴露 knowledgePack/*、knowledgeContext/* current JSON-RPC method,不承载重复领域逻辑
|
||||
|
||||
lime-rs/src/commands/knowledge_cmd.rs
|
||||
# 只做 Tauri command 薄适配,不承载领域逻辑
|
||||
# 仅作为待清理 legacy desktop facade;不得新增业务逻辑
|
||||
```
|
||||
|
||||
前端知识域也必须独立于 Memory,同时通过现有 Agent 主链组合:
|
||||
|
||||
```text
|
||||
src/lib/api/knowledge.ts # safeInvoke 网关和命令类型
|
||||
src/lib/api/knowledge.ts # App Server current 网关和类型
|
||||
src/features/knowledge/domain/ # 资料类型、状态、用户可见文案、名称归一化
|
||||
src/features/knowledge/import/ # 文件读取、清洗、导入编排、错误提示
|
||||
src/features/knowledge/use/ # 资料选择、启用、请求 metadata
|
||||
@@ -472,7 +475,7 @@ src/components/agent/chat/workspace/knowledge/ # Workspace 与现有 Agent 发
|
||||
固定规则:
|
||||
|
||||
1. `lime-knowledge` 是后端领域事实源。
|
||||
2. `knowledge_cmd.rs` 只做参数透传、错误返回和 Tauri 注册。
|
||||
2. `knowledge_cmd.rs` 只作为待清理 legacy desktop facade,不承载领域逻辑;新能力不得继续落到 `lime-rs/src/commands/**`。
|
||||
3. 前端页面不得直接裸 `invoke`,只能经 `src/lib/api/knowledge.ts`。
|
||||
4. File Manager、首页、输入框资料图标、`@` 兼容入口和消息工具栏只发起资料动作,不承载知识领域逻辑。
|
||||
5. 项目资料使用必须回到现有 Agent,不新增独立 Agent。
|
||||
@@ -498,8 +501,8 @@ flowchart TB
|
||||
|
||||
EntryOrchestrator --> Import["导入与清洗<br/>文件正文 / 粘贴文本 / 对话片段"]
|
||||
Import --> Api["src/lib/api/knowledge.ts"]
|
||||
Api --> Commands["knowledge_* Tauri commands"]
|
||||
Commands --> Domain["lime-knowledge crate"]
|
||||
Api --> AppServer["App Server JSON-RPC<br/>knowledgePack/* / knowledgeContext/*"]
|
||||
AppServer --> Domain["lime-knowledge crate"]
|
||||
|
||||
Domain --> Sources["sources/<br/>原始来源"]
|
||||
Domain --> Wiki["wiki/<br/>维护后的主知识"]
|
||||
@@ -849,17 +852,17 @@ knowledge_validate_context_run
|
||||
| `knowledge_resolve_context` | 按任务、状态、信任、预算解析 fenced context。 |
|
||||
| `knowledge_validate_context_run` | 校验 `runs/context-*.json` 是否符合 Agent Knowledge context-resolution schema;用于开发、CI 和诊断面板,不进入普通用户主路径。 |
|
||||
|
||||
命令实现时必须同步:
|
||||
命令边界变更时必须同步:
|
||||
|
||||
1. 前端 `safeInvoke(...)` / `invoke(...)`。
|
||||
2. Rust `tauri::generate_handler!`。
|
||||
3. `src/lib/governance/agentCommandCatalog.json`。
|
||||
4. `src/lib/dev-bridge/mockPriorityCommands.ts`。
|
||||
5. `src/lib/tauri-mock/core.ts`。
|
||||
1. 前端 `src/lib/api/knowledge.ts` App Server 网关。
|
||||
2. App Server JSON-RPC protocol / client / runtime 处理器。
|
||||
3. Electron Desktop Host bridge / preload 白名单。
|
||||
4. `src/lib/governance/agentCommandCatalog.json`。
|
||||
5. `src/lib/dev-bridge/mockPriorityCommands.ts` 与 `src/lib/desktop-host/knowledgeMocks.ts` 等测试 mock。
|
||||
|
||||
固定事实源声明:
|
||||
|
||||
**后续知识包能力只允许向 `KnowledgePack + knowledge_* + Knowledge Context Resolver` 收敛;`project_memory_get` 只保留项目资料附属层职责,不能继续定义知识包主链。**
|
||||
**后续知识包能力只允许向 `KnowledgePack + App Server knowledgePack/* / knowledgeContext/* + Knowledge Context Resolver` 收敛;`project_memory_get` 只保留项目资料附属层职责,不能继续定义知识包主链。旧 `knowledge_*` desktop facade 只作为待清理兼容面,不得新增逻辑。**
|
||||
|
||||
命令契约补充:
|
||||
|
||||
|
||||
@@ -162,15 +162,16 @@
|
||||
5. 新前台 projection 不反向定义 runtime prompt。
|
||||
6. 开发者开关只控制展示 / 实验,不改变事实源地位。
|
||||
|
||||
### 4.2 命令和 mock 同步
|
||||
### 4.2 命令边界和 mock 同步
|
||||
|
||||
如果新增或修改 Tauri 命令,必须满足:
|
||||
如果新增或修改 Electron Desktop Host IPC / App Server JSON-RPC / legacy desktop facade 命令边界,必须满足:
|
||||
|
||||
1. 前端 API 网关同步。
|
||||
2. Rust `generate_handler!` 同步。
|
||||
2. App Server protocol / runtime 或 Electron Host bridge 同步。
|
||||
3. `agentCommandCatalog` 同步。
|
||||
4. DevBridge mock / browser mock 同步。
|
||||
4. DevBridge mock / desktop-host mock 同步。
|
||||
5. `npm run test:contracts` 通过。
|
||||
6. 不得在 `lime-rs/src/commands/**` 新增业务逻辑;该目录只允许清理旧 wrapper 或保留带退出条件的薄兼容委托。
|
||||
|
||||
### 4.3 测试覆盖
|
||||
|
||||
|
||||
Generated
+28
-52
@@ -161,7 +161,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "app-server"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-server-protocol",
|
||||
@@ -178,33 +178,22 @@ dependencies = [
|
||||
"lime-skills",
|
||||
"reqwest 0.12.28",
|
||||
"rusqlite",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "app-server-agent-backend"
|
||||
version = "1.61.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aster-core",
|
||||
"lime-agent",
|
||||
"lime-core",
|
||||
"lime-services",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "app-server-client"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"app-server-protocol",
|
||||
"app-server-transport",
|
||||
@@ -215,7 +204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "app-server-daemon"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"app-server-protocol",
|
||||
"app-server-transport",
|
||||
@@ -227,7 +216,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "app-server-protocol"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -236,7 +225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "app-server-test-client"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"app-server-client",
|
||||
@@ -247,7 +236,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "app-server-transport"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"app-server-protocol",
|
||||
"serde_json",
|
||||
@@ -3906,7 +3895,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-agent"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aster-core",
|
||||
@@ -3935,7 +3924,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-browser-runtime"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"futures",
|
||||
@@ -3952,7 +3941,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-cli"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lime-core",
|
||||
@@ -3964,7 +3953,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-config"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"lime-core",
|
||||
@@ -3980,7 +3969,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-core"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"aster-models",
|
||||
"async-trait",
|
||||
@@ -4036,7 +4025,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-gateway"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"axum 0.7.9",
|
||||
@@ -4066,7 +4055,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-infra"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dashmap 5.5.3",
|
||||
@@ -4086,7 +4075,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-knowledge"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
@@ -4099,7 +4088,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-mcp"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dirs 5.0.1",
|
||||
@@ -4115,7 +4104,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-media-runtime"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"base64 0.22.1",
|
||||
@@ -4147,7 +4136,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-processor"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"lime-core",
|
||||
@@ -4166,7 +4155,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-providers"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@@ -4221,7 +4210,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-server"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"aster-core",
|
||||
"async-stream",
|
||||
@@ -4265,7 +4254,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-server-utils"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"futures",
|
||||
@@ -4280,7 +4269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-services"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aster-core",
|
||||
@@ -4323,7 +4312,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-skills"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dirs 5.0.1",
|
||||
@@ -4341,7 +4330,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lime-websocket"
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
@@ -4458,15 +4447,6 @@ dependencies = [
|
||||
"tendril",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
@@ -7887,14 +7867,10 @@ version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex-automata",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ exclude = [
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "1.61.0"
|
||||
version = "1.62.0"
|
||||
edition = "2021"
|
||||
authors = ["coso"]
|
||||
repository = "https://github.com/aiclientproxy/lime"
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
[package]
|
||||
name = "app-server-agent-backend"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "app-server-agent-backend"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
aster.workspace = true
|
||||
lime-agent.workspace = true
|
||||
lime-core.workspace = true
|
||||
lime-services.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,19 +35,38 @@ pub use app_server_protocol::AutomationSchedulerConfigUpdateResponse;
|
||||
pub use app_server_protocol::AutomationSchedulerStatusResponse;
|
||||
pub use app_server_protocol::CapabilityListParams;
|
||||
pub use app_server_protocol::EvidenceExportParams;
|
||||
pub use app_server_protocol::FileSystemCreateDirectoryParams;
|
||||
pub use app_server_protocol::FileSystemCreateFileParams;
|
||||
pub use app_server_protocol::FileSystemDeleteFileParams;
|
||||
pub use app_server_protocol::FileSystemDirectoryListing;
|
||||
pub use app_server_protocol::FileSystemFileEntry;
|
||||
pub use app_server_protocol::FileSystemFilePreview;
|
||||
pub use app_server_protocol::FileSystemListDirectoryParams;
|
||||
pub use app_server_protocol::FileSystemMutationResponse;
|
||||
pub use app_server_protocol::FileSystemReadFilePreviewParams;
|
||||
pub use app_server_protocol::FileSystemRenameFileParams;
|
||||
pub use app_server_protocol::InitializeParams;
|
||||
use app_server_protocol::JsonRpcErrorResponse;
|
||||
use app_server_protocol::JsonRpcMessage;
|
||||
use app_server_protocol::JsonRpcNotification;
|
||||
use app_server_protocol::JsonRpcRequest;
|
||||
use app_server_protocol::JsonRpcResponse;
|
||||
pub use app_server_protocol::KnowledgeCompilePackParams;
|
||||
pub use app_server_protocol::KnowledgeCompilePackResponse;
|
||||
pub use app_server_protocol::KnowledgeContextResolutionResponse;
|
||||
pub use app_server_protocol::KnowledgeImportSourceParams;
|
||||
pub use app_server_protocol::KnowledgeImportSourceResponse;
|
||||
pub use app_server_protocol::KnowledgeListPacksParams;
|
||||
pub use app_server_protocol::KnowledgeListPacksResponse;
|
||||
pub use app_server_protocol::KnowledgeReadPackParams;
|
||||
pub use app_server_protocol::KnowledgeReadPackResponse;
|
||||
pub use app_server_protocol::KnowledgeResolveContextParams;
|
||||
pub use app_server_protocol::KnowledgeSetDefaultPackParams;
|
||||
pub use app_server_protocol::KnowledgeSetDefaultPackResponse;
|
||||
pub use app_server_protocol::KnowledgeUpdatePackStatusParams;
|
||||
pub use app_server_protocol::KnowledgeUpdatePackStatusResponse;
|
||||
pub use app_server_protocol::KnowledgeValidateContextRunParams;
|
||||
pub use app_server_protocol::KnowledgeValidateContextRunResponse;
|
||||
pub use app_server_protocol::McpPromptListResponse;
|
||||
pub use app_server_protocol::McpResourceListResponse;
|
||||
pub use app_server_protocol::McpServerListResponse;
|
||||
@@ -61,6 +80,13 @@ use app_server_protocol::RequestId;
|
||||
pub use app_server_protocol::SkillListResponse;
|
||||
pub use app_server_protocol::SkillReadParams;
|
||||
pub use app_server_protocol::SkillReadResponse;
|
||||
pub use app_server_protocol::UsageStatsDailyTrendsListResponse;
|
||||
pub use app_server_protocol::UsageStatsDailyUsage;
|
||||
pub use app_server_protocol::UsageStatsModelRankingListResponse;
|
||||
pub use app_server_protocol::UsageStatsModelUsage;
|
||||
pub use app_server_protocol::UsageStatsRangeParams;
|
||||
pub use app_server_protocol::UsageStatsReadResponse;
|
||||
pub use app_server_protocol::UsageStatsSummary;
|
||||
pub use app_server_protocol::WorkspaceEnsureParams;
|
||||
pub use app_server_protocol::WorkspaceEnsureReadyResponse;
|
||||
pub use app_server_protocol::WorkspaceListResponse;
|
||||
@@ -100,11 +126,22 @@ pub use app_server_protocol::METHOD_AUTOMATION_SCHEDULE_PREVIEW;
|
||||
pub use app_server_protocol::METHOD_AUTOMATION_SCHEDULE_VALIDATE;
|
||||
pub use app_server_protocol::METHOD_CAPABILITY_LIST;
|
||||
pub use app_server_protocol::METHOD_EVIDENCE_EXPORT;
|
||||
pub use app_server_protocol::METHOD_FILE_SYSTEM_CREATE_DIRECTORY;
|
||||
pub use app_server_protocol::METHOD_FILE_SYSTEM_CREATE_FILE;
|
||||
pub use app_server_protocol::METHOD_FILE_SYSTEM_DELETE_FILE;
|
||||
pub use app_server_protocol::METHOD_FILE_SYSTEM_LIST_DIRECTORY;
|
||||
pub use app_server_protocol::METHOD_FILE_SYSTEM_READ_FILE_PREVIEW;
|
||||
pub use app_server_protocol::METHOD_FILE_SYSTEM_RENAME_FILE;
|
||||
pub use app_server_protocol::METHOD_INITIALIZE;
|
||||
pub use app_server_protocol::METHOD_INITIALIZED;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_CONTEXT_RESOLVE;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_PACK_COMPILE;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_PACK_DEFAULT_SET;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_PACK_LIST;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_PACK_READ;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_PACK_STATUS_UPDATE;
|
||||
pub use app_server_protocol::METHOD_KNOWLEDGE_SOURCE_IMPORT;
|
||||
pub use app_server_protocol::METHOD_MCP_PROMPT_LIST;
|
||||
pub use app_server_protocol::METHOD_MCP_RESOURCE_LIST;
|
||||
pub use app_server_protocol::METHOD_MCP_SERVER_LIST;
|
||||
@@ -120,6 +157,9 @@ pub use app_server_protocol::METHOD_MODEL_SYNC_STATE_READ;
|
||||
pub use app_server_protocol::METHOD_PROJECT_MEMORY_READ;
|
||||
pub use app_server_protocol::METHOD_SKILL_LIST;
|
||||
pub use app_server_protocol::METHOD_SKILL_READ;
|
||||
pub use app_server_protocol::METHOD_USAGE_STATS_DAILY_TRENDS_LIST;
|
||||
pub use app_server_protocol::METHOD_USAGE_STATS_MODEL_RANKING_LIST;
|
||||
pub use app_server_protocol::METHOD_USAGE_STATS_READ;
|
||||
pub use app_server_protocol::METHOD_WORKSPACE_BY_PATH_READ;
|
||||
pub use app_server_protocol::METHOD_WORKSPACE_DEFAULT_ENSURE;
|
||||
pub use app_server_protocol::METHOD_WORKSPACE_DEFAULT_READ;
|
||||
@@ -337,6 +377,55 @@ impl AppServerClient {
|
||||
self.typed_request(typed::list_knowledge_packs(params))
|
||||
}
|
||||
|
||||
pub fn read_knowledge_pack(
|
||||
&mut self,
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::read_knowledge_pack(params))
|
||||
}
|
||||
|
||||
pub fn import_knowledge_source(
|
||||
&mut self,
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::import_knowledge_source(params))
|
||||
}
|
||||
|
||||
pub fn compile_knowledge_pack(
|
||||
&mut self,
|
||||
params: KnowledgeCompilePackParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::compile_knowledge_pack(params))
|
||||
}
|
||||
|
||||
pub fn set_default_knowledge_pack(
|
||||
&mut self,
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::set_default_knowledge_pack(params))
|
||||
}
|
||||
|
||||
pub fn update_knowledge_pack_status(
|
||||
&mut self,
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::update_knowledge_pack_status(params))
|
||||
}
|
||||
|
||||
pub fn resolve_knowledge_context(
|
||||
&mut self,
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::resolve_knowledge_context(params))
|
||||
}
|
||||
|
||||
pub fn validate_knowledge_context_run(
|
||||
&mut self,
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::validate_knowledge_context_run(params))
|
||||
}
|
||||
|
||||
pub fn list_automation_jobs(&mut self) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::list_automation_jobs())
|
||||
}
|
||||
@@ -446,6 +535,27 @@ impl AppServerClient {
|
||||
self.typed_request(typed::read_project_memory(params))
|
||||
}
|
||||
|
||||
pub fn read_usage_stats(
|
||||
&mut self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::read_usage_stats(params))
|
||||
}
|
||||
|
||||
pub fn list_usage_stats_model_ranking(
|
||||
&mut self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::list_usage_stats_model_ranking(params))
|
||||
}
|
||||
|
||||
pub fn list_usage_stats_daily_trends(
|
||||
&mut self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::list_usage_stats_daily_trends(params))
|
||||
}
|
||||
|
||||
pub fn list_models(&mut self, params: ModelListParams) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::list_models(params))
|
||||
}
|
||||
@@ -498,6 +608,34 @@ impl AppServerClient {
|
||||
self.typed_request(typed::read_file_preview(params))
|
||||
}
|
||||
|
||||
pub fn create_file(
|
||||
&mut self,
|
||||
params: FileSystemCreateFileParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::create_file(params))
|
||||
}
|
||||
|
||||
pub fn create_directory(
|
||||
&mut self,
|
||||
params: FileSystemCreateDirectoryParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::create_directory(params))
|
||||
}
|
||||
|
||||
pub fn rename_file(
|
||||
&mut self,
|
||||
params: FileSystemRenameFileParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::rename_file(params))
|
||||
}
|
||||
|
||||
pub fn delete_file(
|
||||
&mut self,
|
||||
params: FileSystemDeleteFileParams,
|
||||
) -> Result<JsonRpcRequest, ClientError> {
|
||||
self.typed_request(typed::delete_file(params))
|
||||
}
|
||||
|
||||
pub fn export_evidence(
|
||||
&mut self,
|
||||
params: EvidenceExportParams,
|
||||
@@ -669,6 +807,48 @@ pub mod typed {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_PACK_LIST, params)
|
||||
}
|
||||
|
||||
pub fn read_knowledge_pack(
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> TypedRequest<KnowledgeReadPackParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_PACK_READ, params)
|
||||
}
|
||||
|
||||
pub fn import_knowledge_source(
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> TypedRequest<KnowledgeImportSourceParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_SOURCE_IMPORT, params)
|
||||
}
|
||||
|
||||
pub fn compile_knowledge_pack(
|
||||
params: KnowledgeCompilePackParams,
|
||||
) -> TypedRequest<KnowledgeCompilePackParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_PACK_COMPILE, params)
|
||||
}
|
||||
|
||||
pub fn set_default_knowledge_pack(
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> TypedRequest<KnowledgeSetDefaultPackParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_PACK_DEFAULT_SET, params)
|
||||
}
|
||||
|
||||
pub fn update_knowledge_pack_status(
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> TypedRequest<KnowledgeUpdatePackStatusParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_PACK_STATUS_UPDATE, params)
|
||||
}
|
||||
|
||||
pub fn resolve_knowledge_context(
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> TypedRequest<KnowledgeResolveContextParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_CONTEXT_RESOLVE, params)
|
||||
}
|
||||
|
||||
pub fn validate_knowledge_context_run(
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> TypedRequest<KnowledgeValidateContextRunParams> {
|
||||
TypedRequest::new(METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE, params)
|
||||
}
|
||||
|
||||
pub fn list_automation_jobs() -> TypedRequest<serde_json::Value> {
|
||||
TypedRequest::new(METHOD_AUTOMATION_JOB_LIST, serde_json::json!({}))
|
||||
}
|
||||
@@ -770,6 +950,22 @@ pub mod typed {
|
||||
TypedRequest::new(METHOD_PROJECT_MEMORY_READ, params)
|
||||
}
|
||||
|
||||
pub fn read_usage_stats(params: UsageStatsRangeParams) -> TypedRequest<UsageStatsRangeParams> {
|
||||
TypedRequest::new(METHOD_USAGE_STATS_READ, params)
|
||||
}
|
||||
|
||||
pub fn list_usage_stats_model_ranking(
|
||||
params: UsageStatsRangeParams,
|
||||
) -> TypedRequest<UsageStatsRangeParams> {
|
||||
TypedRequest::new(METHOD_USAGE_STATS_MODEL_RANKING_LIST, params)
|
||||
}
|
||||
|
||||
pub fn list_usage_stats_daily_trends(
|
||||
params: UsageStatsRangeParams,
|
||||
) -> TypedRequest<UsageStatsRangeParams> {
|
||||
TypedRequest::new(METHOD_USAGE_STATS_DAILY_TRENDS_LIST, params)
|
||||
}
|
||||
|
||||
pub fn list_models(params: ModelListParams) -> TypedRequest<ModelListParams> {
|
||||
TypedRequest::new(METHOD_MODEL_LIST, params)
|
||||
}
|
||||
@@ -816,6 +1012,30 @@ pub mod typed {
|
||||
TypedRequest::new(METHOD_FILE_SYSTEM_READ_FILE_PREVIEW, params)
|
||||
}
|
||||
|
||||
pub fn create_file(
|
||||
params: FileSystemCreateFileParams,
|
||||
) -> TypedRequest<FileSystemCreateFileParams> {
|
||||
TypedRequest::new(METHOD_FILE_SYSTEM_CREATE_FILE, params)
|
||||
}
|
||||
|
||||
pub fn create_directory(
|
||||
params: FileSystemCreateDirectoryParams,
|
||||
) -> TypedRequest<FileSystemCreateDirectoryParams> {
|
||||
TypedRequest::new(METHOD_FILE_SYSTEM_CREATE_DIRECTORY, params)
|
||||
}
|
||||
|
||||
pub fn rename_file(
|
||||
params: FileSystemRenameFileParams,
|
||||
) -> TypedRequest<FileSystemRenameFileParams> {
|
||||
TypedRequest::new(METHOD_FILE_SYSTEM_RENAME_FILE, params)
|
||||
}
|
||||
|
||||
pub fn delete_file(
|
||||
params: FileSystemDeleteFileParams,
|
||||
) -> TypedRequest<FileSystemDeleteFileParams> {
|
||||
TypedRequest::new(METHOD_FILE_SYSTEM_DELETE_FILE, params)
|
||||
}
|
||||
|
||||
pub fn export_evidence(params: EvidenceExportParams) -> TypedRequest<EvidenceExportParams> {
|
||||
TypedRequest::new(METHOD_EVIDENCE_EXPORT, params)
|
||||
}
|
||||
@@ -1137,6 +1357,62 @@ mod tests {
|
||||
include_archived: true,
|
||||
})
|
||||
.expect("knowledge packs");
|
||||
let knowledge_detail = client
|
||||
.read_knowledge_pack(KnowledgeReadPackParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
name: "sample-product".to_string(),
|
||||
})
|
||||
.expect("knowledge pack detail");
|
||||
let imported_knowledge_source = client
|
||||
.import_knowledge_source(KnowledgeImportSourceParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
pack_name: "sample-product".to_string(),
|
||||
description: None,
|
||||
pack_type: None,
|
||||
language: None,
|
||||
source_file_name: None,
|
||||
source_text: Some("示例产品事实".to_string()),
|
||||
})
|
||||
.expect("knowledge source import");
|
||||
let compiled_knowledge_pack = client
|
||||
.compile_knowledge_pack(KnowledgeCompilePackParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
name: "sample-product".to_string(),
|
||||
builder_runtime: Some(json!({ "enabled": true })),
|
||||
})
|
||||
.expect("knowledge pack compile");
|
||||
let default_knowledge_pack = client
|
||||
.set_default_knowledge_pack(KnowledgeSetDefaultPackParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
name: "sample-product".to_string(),
|
||||
})
|
||||
.expect("knowledge pack default");
|
||||
let updated_knowledge_pack_status = client
|
||||
.update_knowledge_pack_status(KnowledgeUpdatePackStatusParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
name: "sample-product".to_string(),
|
||||
status: "ready".to_string(),
|
||||
})
|
||||
.expect("knowledge pack status");
|
||||
let knowledge_context = client
|
||||
.resolve_knowledge_context(KnowledgeResolveContextParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
name: "sample-product".to_string(),
|
||||
packs: Vec::new(),
|
||||
task: Some("写产品介绍".to_string()),
|
||||
max_chars: None,
|
||||
activation: None,
|
||||
write_run: true,
|
||||
run_reason: None,
|
||||
})
|
||||
.expect("knowledge context");
|
||||
let knowledge_context_validation = client
|
||||
.validate_knowledge_context_run(KnowledgeValidateContextRunParams {
|
||||
working_dir: "/workspace/project".to_string(),
|
||||
name: "sample-product".to_string(),
|
||||
run_path: "runs/context.json".to_string(),
|
||||
})
|
||||
.expect("knowledge context validation");
|
||||
let scheduler_config = client
|
||||
.read_automation_scheduler_config()
|
||||
.expect("automation scheduler config");
|
||||
@@ -1238,6 +1514,85 @@ mod tests {
|
||||
"includeArchived": true,
|
||||
})
|
||||
);
|
||||
assert_eq!(knowledge_detail.method, METHOD_KNOWLEDGE_PACK_READ);
|
||||
assert_eq!(
|
||||
knowledge_detail.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"name": "sample-product",
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
imported_knowledge_source.method,
|
||||
METHOD_KNOWLEDGE_SOURCE_IMPORT
|
||||
);
|
||||
assert_eq!(
|
||||
imported_knowledge_source.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"packName": "sample-product",
|
||||
"sourceText": "示例产品事实",
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
compiled_knowledge_pack.method,
|
||||
METHOD_KNOWLEDGE_PACK_COMPILE
|
||||
);
|
||||
assert_eq!(
|
||||
compiled_knowledge_pack.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"name": "sample-product",
|
||||
"builderRuntime": {
|
||||
"enabled": true,
|
||||
},
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
default_knowledge_pack.method,
|
||||
METHOD_KNOWLEDGE_PACK_DEFAULT_SET
|
||||
);
|
||||
assert_eq!(
|
||||
default_knowledge_pack.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"name": "sample-product",
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
updated_knowledge_pack_status.method,
|
||||
METHOD_KNOWLEDGE_PACK_STATUS_UPDATE
|
||||
);
|
||||
assert_eq!(
|
||||
updated_knowledge_pack_status.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"name": "sample-product",
|
||||
"status": "ready",
|
||||
})
|
||||
);
|
||||
assert_eq!(knowledge_context.method, METHOD_KNOWLEDGE_CONTEXT_RESOLVE);
|
||||
assert_eq!(
|
||||
knowledge_context.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"name": "sample-product",
|
||||
"task": "写产品介绍",
|
||||
"writeRun": true,
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
knowledge_context_validation.method,
|
||||
METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE
|
||||
);
|
||||
assert_eq!(
|
||||
knowledge_context_validation.params.expect("params"),
|
||||
json!({
|
||||
"workingDir": "/workspace/project",
|
||||
"name": "sample-product",
|
||||
"runPath": "runs/context.json",
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
scheduler_config.method,
|
||||
METHOD_AUTOMATION_SCHEDULER_CONFIG_READ
|
||||
@@ -1358,7 +1713,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_system_read_helpers_use_current_methods() {
|
||||
fn file_system_helpers_use_current_methods() {
|
||||
let mut client = AppServerClient::new();
|
||||
|
||||
let listing = client
|
||||
@@ -1372,6 +1727,28 @@ mod tests {
|
||||
max_size: Some(1024),
|
||||
})
|
||||
.expect("preview");
|
||||
let create_file = client
|
||||
.create_file(FileSystemCreateFileParams {
|
||||
path: "/workspace/new.md".to_string(),
|
||||
})
|
||||
.expect("create file");
|
||||
let create_directory = client
|
||||
.create_directory(FileSystemCreateDirectoryParams {
|
||||
path: "/workspace/new-dir".to_string(),
|
||||
})
|
||||
.expect("create directory");
|
||||
let rename_file = client
|
||||
.rename_file(FileSystemRenameFileParams {
|
||||
old_path: "/workspace/new.md".to_string(),
|
||||
new_path: "/workspace/renamed.md".to_string(),
|
||||
})
|
||||
.expect("rename file");
|
||||
let delete_file = client
|
||||
.delete_file(FileSystemDeleteFileParams {
|
||||
path: "/workspace/renamed.md".to_string(),
|
||||
recursive: Some(false),
|
||||
})
|
||||
.expect("delete file");
|
||||
|
||||
assert_eq!(listing.id, RequestId::Integer(1));
|
||||
assert_eq!(listing.method, METHOD_FILE_SYSTEM_LIST_DIRECTORY);
|
||||
@@ -1390,6 +1767,40 @@ mod tests {
|
||||
"maxSize": 1024,
|
||||
})
|
||||
);
|
||||
assert_eq!(create_file.id, RequestId::Integer(3));
|
||||
assert_eq!(create_file.method, METHOD_FILE_SYSTEM_CREATE_FILE);
|
||||
assert_eq!(
|
||||
create_file.params.expect("params"),
|
||||
json!({
|
||||
"path": "/workspace/new.md",
|
||||
})
|
||||
);
|
||||
assert_eq!(create_directory.id, RequestId::Integer(4));
|
||||
assert_eq!(create_directory.method, METHOD_FILE_SYSTEM_CREATE_DIRECTORY);
|
||||
assert_eq!(
|
||||
create_directory.params.expect("params"),
|
||||
json!({
|
||||
"path": "/workspace/new-dir",
|
||||
})
|
||||
);
|
||||
assert_eq!(rename_file.id, RequestId::Integer(5));
|
||||
assert_eq!(rename_file.method, METHOD_FILE_SYSTEM_RENAME_FILE);
|
||||
assert_eq!(
|
||||
rename_file.params.expect("params"),
|
||||
json!({
|
||||
"oldPath": "/workspace/new.md",
|
||||
"newPath": "/workspace/renamed.md",
|
||||
})
|
||||
);
|
||||
assert_eq!(delete_file.id, RequestId::Integer(6));
|
||||
assert_eq!(delete_file.method, METHOD_FILE_SYSTEM_DELETE_FILE);
|
||||
assert_eq!(
|
||||
delete_file.params.expect("params"),
|
||||
json!({
|
||||
"path": "/workspace/renamed.md",
|
||||
"recursive": false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1545,6 +1956,10 @@ mod tests {
|
||||
assert!(methods.contains(&METHOD_ARTIFACT_READ));
|
||||
assert!(methods.contains(&METHOD_FILE_SYSTEM_LIST_DIRECTORY));
|
||||
assert!(methods.contains(&METHOD_FILE_SYSTEM_READ_FILE_PREVIEW));
|
||||
assert!(methods.contains(&METHOD_FILE_SYSTEM_CREATE_FILE));
|
||||
assert!(methods.contains(&METHOD_FILE_SYSTEM_CREATE_DIRECTORY));
|
||||
assert!(methods.contains(&METHOD_FILE_SYSTEM_RENAME_FILE));
|
||||
assert!(methods.contains(&METHOD_FILE_SYSTEM_DELETE_FILE));
|
||||
assert!(methods.contains(&METHOD_EVIDENCE_EXPORT));
|
||||
assert!(methods.contains(&METHOD_AGENT_SESSION_TURN_START));
|
||||
assert!(methods.contains(&METHOD_WORKSPACE_LIST));
|
||||
@@ -1560,6 +1975,7 @@ mod tests {
|
||||
assert!(methods.contains(&METHOD_WORKSPACE_SKILL_BINDINGS_LIST));
|
||||
assert!(methods.contains(&METHOD_AGENT_APP_INSTALLED_LIST));
|
||||
assert!(methods.contains(&METHOD_KNOWLEDGE_PACK_LIST));
|
||||
assert!(methods.contains(&METHOD_KNOWLEDGE_PACK_READ));
|
||||
assert!(methods.contains(&METHOD_AUTOMATION_SCHEDULER_CONFIG_READ));
|
||||
assert!(methods.contains(&METHOD_AUTOMATION_SCHEDULER_CONFIG_UPDATE));
|
||||
assert!(methods.contains(&METHOD_AUTOMATION_SCHEDULER_STATUS));
|
||||
@@ -1583,6 +1999,12 @@ mod tests {
|
||||
assert!(is_app_server_request_method(
|
||||
METHOD_FILE_SYSTEM_READ_FILE_PREVIEW
|
||||
));
|
||||
assert!(is_app_server_request_method(METHOD_FILE_SYSTEM_CREATE_FILE));
|
||||
assert!(is_app_server_request_method(
|
||||
METHOD_FILE_SYSTEM_CREATE_DIRECTORY
|
||||
));
|
||||
assert!(is_app_server_request_method(METHOD_FILE_SYSTEM_RENAME_FILE));
|
||||
assert!(is_app_server_request_method(METHOD_FILE_SYSTEM_DELETE_FILE));
|
||||
assert!(is_app_server_request_method(METHOD_EVIDENCE_EXPORT));
|
||||
assert!(is_app_server_request_method(METHOD_WORKSPACE_LIST));
|
||||
assert!(is_app_server_request_method(METHOD_SKILL_LIST));
|
||||
@@ -1590,6 +2012,7 @@ mod tests {
|
||||
METHOD_AGENT_APP_INSTALLED_LIST
|
||||
));
|
||||
assert!(is_app_server_request_method(METHOD_KNOWLEDGE_PACK_LIST));
|
||||
assert!(is_app_server_request_method(METHOD_KNOWLEDGE_PACK_READ));
|
||||
assert!(is_app_server_request_method(
|
||||
METHOD_AUTOMATION_SCHEDULER_CONFIG_READ
|
||||
));
|
||||
|
||||
@@ -2991,6 +2991,51 @@
|
||||
"title": "EvidencePackSummary",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemCreateDirectoryParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "FileSystemCreateDirectoryParams",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemCreateFileParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "FileSystemCreateFileParams",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemDeleteFileParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"recursive": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "FileSystemDeleteFileParams",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemDirectoryListing": {
|
||||
"$defs": {
|
||||
"FileSystemFileEntry": {
|
||||
@@ -3221,6 +3266,11 @@
|
||||
"title": "FileSystemListDirectoryParams",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemMutationResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "FileSystemMutationResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemReadFilePreviewParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
@@ -3242,6 +3292,23 @@
|
||||
"title": "FileSystemReadFilePreviewParams",
|
||||
"type": "object"
|
||||
},
|
||||
"FileSystemRenameFileParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"newPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"newPath",
|
||||
"oldPath"
|
||||
],
|
||||
"title": "FileSystemRenameFileParams",
|
||||
"type": "object"
|
||||
},
|
||||
"InitializeParams": {
|
||||
"$defs": {
|
||||
"ClientCapabilities": {
|
||||
@@ -3630,6 +3697,188 @@
|
||||
"title": "JsonRpcResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeCompilePackParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"builderRuntime": true,
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeCompilePackParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeCompilePackResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"compiledView": true,
|
||||
"pack": true,
|
||||
"run": true,
|
||||
"selectedSourceCount": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"compiledView",
|
||||
"pack",
|
||||
"run",
|
||||
"selectedSourceCount"
|
||||
],
|
||||
"title": "KnowledgeCompilePackResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeContextResolutionResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"fencedContext": {
|
||||
"type": "string"
|
||||
},
|
||||
"grounding": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"missing": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"packName": {
|
||||
"type": "string"
|
||||
},
|
||||
"runId": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"runPath": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"selectedFiles": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"selectedViews": {
|
||||
"default": [],
|
||||
"items": true,
|
||||
"type": "array"
|
||||
},
|
||||
"sourceAnchors": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokenEstimate": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"default": [],
|
||||
"items": true,
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"fencedContext",
|
||||
"packName",
|
||||
"status",
|
||||
"tokenEstimate"
|
||||
],
|
||||
"title": "KnowledgeContextResolutionResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeImportSourceParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"language": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"packName": {
|
||||
"type": "string"
|
||||
},
|
||||
"packType": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"sourceFileName": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"sourceText": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"packName",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeImportSourceParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeImportSourceResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"pack": true,
|
||||
"source": true
|
||||
},
|
||||
"required": [
|
||||
"pack",
|
||||
"source"
|
||||
],
|
||||
"title": "KnowledgeImportSourceResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeListPacksParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
@@ -3669,6 +3918,259 @@
|
||||
"title": "KnowledgeListPacksResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeReadPackParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeReadPackParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeReadPackResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"pack": true
|
||||
},
|
||||
"required": [
|
||||
"pack"
|
||||
],
|
||||
"title": "KnowledgeReadPackResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeResolveContextPackParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"activation": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"title": "KnowledgeResolveContextPackParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeResolveContextParams": {
|
||||
"$defs": {
|
||||
"KnowledgeResolveContextPackParams": {
|
||||
"properties": {
|
||||
"activation": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"activation": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"maxChars": {
|
||||
"format": "uint",
|
||||
"minimum": 0,
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"packs": {
|
||||
"items": {
|
||||
"$ref": "#/$defs/KnowledgeResolveContextPackParams"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"runReason": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"task": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"writeRun": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeResolveContextParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeSetDefaultPackParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeSetDefaultPackParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeSetDefaultPackResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"defaultMarkerPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"defaultPackName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"defaultMarkerPath",
|
||||
"defaultPackName"
|
||||
],
|
||||
"title": "KnowledgeSetDefaultPackResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeUpdatePackStatusParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"status",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeUpdatePackStatusParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeUpdatePackStatusResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"clearedDefault": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pack": true,
|
||||
"previousStatus": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"clearedDefault",
|
||||
"pack",
|
||||
"previousStatus"
|
||||
],
|
||||
"title": "KnowledgeUpdatePackStatusResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeValidateContextRunParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"runPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"runPath",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeValidateContextRunParams",
|
||||
"type": "object"
|
||||
},
|
||||
"KnowledgeValidateContextRunResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"errors": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"runId": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"valid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warnings": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"valid"
|
||||
],
|
||||
"title": "KnowledgeValidateContextRunResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"McpPromptListResponse": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
@@ -4635,6 +5137,308 @@
|
||||
"title": "SkillReadResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsDailyTrendsListResponse": {
|
||||
"$defs": {
|
||||
"UsageStatsDailyUsage": {
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"date",
|
||||
"tokens"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"trends": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/$defs/UsageStatsDailyUsage"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "UsageStatsDailyTrendsListResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsDailyUsage": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"date",
|
||||
"tokens"
|
||||
],
|
||||
"title": "UsageStatsDailyUsage",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsModelRankingListResponse": {
|
||||
"$defs": {
|
||||
"UsageStatsModelUsage": {
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"percentage": {
|
||||
"format": "float",
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"model",
|
||||
"percentage",
|
||||
"tokens"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"ranking": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/$defs/UsageStatsModelUsage"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "UsageStatsModelRankingListResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsModelUsage": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"percentage": {
|
||||
"format": "float",
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"model",
|
||||
"percentage",
|
||||
"tokens"
|
||||
],
|
||||
"title": "UsageStatsModelUsage",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsRangeParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"timeRange": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"timeRange"
|
||||
],
|
||||
"title": "UsageStatsRangeParams",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsReadResponse": {
|
||||
"$defs": {
|
||||
"UsageStatsSummary": {
|
||||
"properties": {
|
||||
"monthlyConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTimeMinutes": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"monthlyConversations",
|
||||
"monthlyMessages",
|
||||
"monthlyTokens",
|
||||
"todayConversations",
|
||||
"todayMessages",
|
||||
"todayTokens",
|
||||
"totalConversations",
|
||||
"totalMessages",
|
||||
"totalTimeMinutes",
|
||||
"totalTokens"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"stats": {
|
||||
"$ref": "#/$defs/UsageStatsSummary"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"stats"
|
||||
],
|
||||
"title": "UsageStatsReadResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"UsageStatsSummary": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"monthlyConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTimeMinutes": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"monthlyConversations",
|
||||
"monthlyMessages",
|
||||
"monthlyTokens",
|
||||
"todayConversations",
|
||||
"todayMessages",
|
||||
"todayTokens",
|
||||
"totalConversations",
|
||||
"totalMessages",
|
||||
"totalTimeMinutes",
|
||||
"totalTokens"
|
||||
],
|
||||
"title": "UsageStatsSummary",
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceEnsureParams": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
@@ -4933,10 +5737,21 @@
|
||||
"connectOpenDeepLink/resolve",
|
||||
"connectRelayApiKey/save",
|
||||
"evidence/export",
|
||||
"fileSystem/createDirectory",
|
||||
"fileSystem/createFile",
|
||||
"fileSystem/deleteFile",
|
||||
"fileSystem/listDirectory",
|
||||
"fileSystem/readFilePreview",
|
||||
"fileSystem/renameFile",
|
||||
"initialize",
|
||||
"knowledgeContext/resolve",
|
||||
"knowledgeContextRun/validate",
|
||||
"knowledgePack/compile",
|
||||
"knowledgePack/default/set",
|
||||
"knowledgePack/list",
|
||||
"knowledgePack/read",
|
||||
"knowledgePack/source/import",
|
||||
"knowledgePack/status/update",
|
||||
"mcpPrompt/list",
|
||||
"mcpResource/list",
|
||||
"mcpServer/list",
|
||||
@@ -4970,6 +5785,9 @@
|
||||
"projectMemory/read",
|
||||
"skill/list",
|
||||
"skill/read",
|
||||
"usageStats/dailyTrends/list",
|
||||
"usageStats/modelRanking/list",
|
||||
"usageStats/read",
|
||||
"workspace/byPath/read",
|
||||
"workspace/default/ensure",
|
||||
"workspace/default/read",
|
||||
|
||||
@@ -138,6 +138,18 @@
|
||||
"kind": "request",
|
||||
"method": "evidence/export"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "fileSystem/createDirectory"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "fileSystem/createFile"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "fileSystem/deleteFile"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "fileSystem/listDirectory"
|
||||
@@ -146,6 +158,10 @@
|
||||
"kind": "request",
|
||||
"method": "fileSystem/readFilePreview"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "fileSystem/renameFile"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "initialize"
|
||||
@@ -154,10 +170,38 @@
|
||||
"kind": "notification",
|
||||
"method": "initialized"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgeContext/resolve"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgeContextRun/validate"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgePack/compile"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgePack/default/set"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgePack/list"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgePack/read"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgePack/source/import"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "knowledgePack/status/update"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "mcpPrompt/list"
|
||||
@@ -290,6 +334,18 @@
|
||||
"kind": "request",
|
||||
"method": "skill/read"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "usageStats/dailyTrends/list"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "usageStats/modelRanking/list"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "usageStats/read"
|
||||
},
|
||||
{
|
||||
"kind": "request",
|
||||
"method": "workspace/byPath/read"
|
||||
@@ -416,15 +472,35 @@
|
||||
"EvidenceExportResponse",
|
||||
"EvidencePackArtifact",
|
||||
"EvidencePackSummary",
|
||||
"FileSystemCreateDirectoryParams",
|
||||
"FileSystemCreateFileParams",
|
||||
"FileSystemDeleteFileParams",
|
||||
"FileSystemDirectoryListing",
|
||||
"FileSystemFileEntry",
|
||||
"FileSystemFilePreview",
|
||||
"FileSystemListDirectoryParams",
|
||||
"FileSystemMutationResponse",
|
||||
"FileSystemReadFilePreviewParams",
|
||||
"FileSystemRenameFileParams",
|
||||
"InitializeParams",
|
||||
"InitializeResponse",
|
||||
"KnowledgeCompilePackParams",
|
||||
"KnowledgeCompilePackResponse",
|
||||
"KnowledgeContextResolutionResponse",
|
||||
"KnowledgeImportSourceParams",
|
||||
"KnowledgeImportSourceResponse",
|
||||
"KnowledgeListPacksParams",
|
||||
"KnowledgeListPacksResponse",
|
||||
"KnowledgeReadPackParams",
|
||||
"KnowledgeReadPackResponse",
|
||||
"KnowledgeResolveContextPackParams",
|
||||
"KnowledgeResolveContextParams",
|
||||
"KnowledgeSetDefaultPackParams",
|
||||
"KnowledgeSetDefaultPackResponse",
|
||||
"KnowledgeUpdatePackStatusParams",
|
||||
"KnowledgeUpdatePackStatusResponse",
|
||||
"KnowledgeValidateContextRunParams",
|
||||
"KnowledgeValidateContextRunResponse",
|
||||
"McpPromptListResponse",
|
||||
"McpResourceListResponse",
|
||||
"McpServerListResponse",
|
||||
@@ -480,6 +556,13 @@
|
||||
"SkillListResponse",
|
||||
"SkillReadParams",
|
||||
"SkillReadResponse",
|
||||
"UsageStatsDailyTrendsListResponse",
|
||||
"UsageStatsDailyUsage",
|
||||
"UsageStatsModelRankingListResponse",
|
||||
"UsageStatsModelUsage",
|
||||
"UsageStatsRangeParams",
|
||||
"UsageStatsReadResponse",
|
||||
"UsageStatsSummary",
|
||||
"WorkspaceEnsureParams",
|
||||
"WorkspaceEnsureReadyResponse",
|
||||
"WorkspaceListResponse",
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "FileSystemCreateDirectoryParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "FileSystemCreateFileParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"recursive": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "FileSystemDeleteFileParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "FileSystemMutationResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"newPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"oldPath": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"newPath",
|
||||
"oldPath"
|
||||
],
|
||||
"title": "FileSystemRenameFileParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"builderRuntime": true,
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeCompilePackParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"compiledView": true,
|
||||
"pack": true,
|
||||
"run": true,
|
||||
"selectedSourceCount": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"compiledView",
|
||||
"pack",
|
||||
"run",
|
||||
"selectedSourceCount"
|
||||
],
|
||||
"title": "KnowledgeCompilePackResponse",
|
||||
"type": "object"
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"fencedContext": {
|
||||
"type": "string"
|
||||
},
|
||||
"grounding": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"missing": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"packName": {
|
||||
"type": "string"
|
||||
},
|
||||
"runId": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"runPath": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"selectedFiles": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"selectedViews": {
|
||||
"default": [],
|
||||
"items": true,
|
||||
"type": "array"
|
||||
},
|
||||
"sourceAnchors": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokenEstimate": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"default": [],
|
||||
"items": true,
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"fencedContext",
|
||||
"packName",
|
||||
"status",
|
||||
"tokenEstimate"
|
||||
],
|
||||
"title": "KnowledgeContextResolutionResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"language": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"packName": {
|
||||
"type": "string"
|
||||
},
|
||||
"packType": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"sourceFileName": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"sourceText": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"packName",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeImportSourceParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"pack": true,
|
||||
"source": true
|
||||
},
|
||||
"required": [
|
||||
"pack",
|
||||
"source"
|
||||
],
|
||||
"title": "KnowledgeImportSourceResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeReadPackParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"pack": true
|
||||
},
|
||||
"required": [
|
||||
"pack"
|
||||
],
|
||||
"title": "KnowledgeReadPackResponse",
|
||||
"type": "object"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"activation": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"title": "KnowledgeResolveContextPackParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"$defs": {
|
||||
"KnowledgeResolveContextPackParams": {
|
||||
"properties": {
|
||||
"activation": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"activation": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"maxChars": {
|
||||
"format": "uint",
|
||||
"minimum": 0,
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"packs": {
|
||||
"items": {
|
||||
"$ref": "#/$defs/KnowledgeResolveContextPackParams"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"runReason": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"task": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"writeRun": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeResolveContextParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeSetDefaultPackParams",
|
||||
"type": "object"
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"defaultMarkerPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"defaultPackName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"defaultMarkerPath",
|
||||
"defaultPackName"
|
||||
],
|
||||
"title": "KnowledgeSetDefaultPackResponse",
|
||||
"type": "object"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"status",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeUpdatePackStatusParams",
|
||||
"type": "object"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"clearedDefault": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pack": true,
|
||||
"previousStatus": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"clearedDefault",
|
||||
"pack",
|
||||
"previousStatus"
|
||||
],
|
||||
"title": "KnowledgeUpdatePackStatusResponse",
|
||||
"type": "object"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"runPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"workingDir": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"runPath",
|
||||
"workingDir"
|
||||
],
|
||||
"title": "KnowledgeValidateContextRunParams",
|
||||
"type": "object"
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"errors": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"runId": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"valid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warnings": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"valid"
|
||||
],
|
||||
"title": "KnowledgeValidateContextRunResponse",
|
||||
"type": "object"
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$defs": {
|
||||
"UsageStatsDailyUsage": {
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"date",
|
||||
"tokens"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"trends": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/$defs/UsageStatsDailyUsage"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "UsageStatsDailyTrendsListResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"date": {
|
||||
"type": "string"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"date",
|
||||
"tokens"
|
||||
],
|
||||
"title": "UsageStatsDailyUsage",
|
||||
"type": "object"
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"$defs": {
|
||||
"UsageStatsModelUsage": {
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"percentage": {
|
||||
"format": "float",
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"model",
|
||||
"percentage",
|
||||
"tokens"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"ranking": {
|
||||
"default": [],
|
||||
"items": {
|
||||
"$ref": "#/$defs/UsageStatsModelUsage"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "UsageStatsModelRankingListResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"conversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"percentage": {
|
||||
"format": "float",
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversations",
|
||||
"model",
|
||||
"percentage",
|
||||
"tokens"
|
||||
],
|
||||
"title": "UsageStatsModelUsage",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"timeRange": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"timeRange"
|
||||
],
|
||||
"title": "UsageStatsRangeParams",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"$defs": {
|
||||
"UsageStatsSummary": {
|
||||
"properties": {
|
||||
"monthlyConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTimeMinutes": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"monthlyConversations",
|
||||
"monthlyMessages",
|
||||
"monthlyTokens",
|
||||
"todayConversations",
|
||||
"todayMessages",
|
||||
"todayTokens",
|
||||
"totalConversations",
|
||||
"totalMessages",
|
||||
"totalTimeMinutes",
|
||||
"totalTokens"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"stats": {
|
||||
"$ref": "#/$defs/UsageStatsSummary"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"stats"
|
||||
],
|
||||
"title": "UsageStatsReadResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"monthlyConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"monthlyTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"todayTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalConversations": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalMessages": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTimeMinutes": {
|
||||
"format": "uint32",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"totalTokens": {
|
||||
"format": "uint64",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"monthlyConversations",
|
||||
"monthlyMessages",
|
||||
"monthlyTokens",
|
||||
"todayConversations",
|
||||
"todayMessages",
|
||||
"todayTokens",
|
||||
"totalConversations",
|
||||
"totalMessages",
|
||||
"totalTimeMinutes",
|
||||
"totalTokens"
|
||||
],
|
||||
"title": "UsageStatsSummary",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -20,6 +20,11 @@ pub const V0_SCHEMA_TYPE_NAMES: &[&str] = &[
|
||||
"ArtifactReadResponse",
|
||||
"FileSystemListDirectoryParams",
|
||||
"FileSystemReadFilePreviewParams",
|
||||
"FileSystemCreateFileParams",
|
||||
"FileSystemCreateDirectoryParams",
|
||||
"FileSystemRenameFileParams",
|
||||
"FileSystemDeleteFileParams",
|
||||
"FileSystemMutationResponse",
|
||||
"FileSystemDirectoryListing",
|
||||
"FileSystemFileEntry",
|
||||
"FileSystemFilePreview",
|
||||
@@ -48,13 +53,44 @@ pub const V0_SCHEMA_TYPE_NAMES: &[&str] = &[
|
||||
"WorkspaceSkillBindingsListResponse",
|
||||
"WorkspaceRegisteredSkillsListParams",
|
||||
"WorkspaceRegisteredSkillsListResponse",
|
||||
"AgentAppLocalPackageInspectParams",
|
||||
"AgentAppLocalPackageInspectResponse",
|
||||
"AgentAppFetchCloudPackageParams",
|
||||
"AgentAppCloudReleaseDescriptor",
|
||||
"AgentAppPackageCacheEntry",
|
||||
"AgentAppPackageIdentity",
|
||||
"AgentAppInstalledSaveParams",
|
||||
"AgentAppInstalledDisabledSetParams",
|
||||
"AgentAppInstalledListResponse",
|
||||
"AgentAppUninstallRehearsalParams",
|
||||
"AgentAppUninstallRehearsalResponse",
|
||||
"AgentAppUninstallRehearsalTarget",
|
||||
"AgentAppUninstallParams",
|
||||
"AgentAppUninstallResponse",
|
||||
"AgentAppDeleteDataExecutionEvidence",
|
||||
"AgentAppDeleteDataTargetEvidence",
|
||||
"AgentAppDeleteDataPostDeleteResidualAudit",
|
||||
"AgentAppUiRuntimeStartParams",
|
||||
"AgentAppUiRuntimeStatusParams",
|
||||
"AgentAppUiRuntimeStopParams",
|
||||
"AgentAppUiRuntimeStatusResponse",
|
||||
"KnowledgeListPacksParams",
|
||||
"KnowledgeListPacksResponse",
|
||||
"KnowledgeReadPackParams",
|
||||
"KnowledgeReadPackResponse",
|
||||
"KnowledgeImportSourceParams",
|
||||
"KnowledgeImportSourceResponse",
|
||||
"KnowledgeCompilePackParams",
|
||||
"KnowledgeCompilePackResponse",
|
||||
"KnowledgeSetDefaultPackParams",
|
||||
"KnowledgeSetDefaultPackResponse",
|
||||
"KnowledgeUpdatePackStatusParams",
|
||||
"KnowledgeUpdatePackStatusResponse",
|
||||
"KnowledgeResolveContextPackParams",
|
||||
"KnowledgeResolveContextParams",
|
||||
"KnowledgeContextResolutionResponse",
|
||||
"KnowledgeValidateContextRunParams",
|
||||
"KnowledgeValidateContextRunResponse",
|
||||
"AutomationSchedulerConfigReadResponse",
|
||||
"AutomationSchedulerConfigUpdateParams",
|
||||
"AutomationSchedulerConfigUpdateResponse",
|
||||
@@ -81,6 +117,13 @@ pub const V0_SCHEMA_TYPE_NAMES: &[&str] = &[
|
||||
"McpResourceListResponse",
|
||||
"ProjectMemoryReadParams",
|
||||
"ProjectMemoryReadResponse",
|
||||
"UsageStatsRangeParams",
|
||||
"UsageStatsSummary",
|
||||
"UsageStatsReadResponse",
|
||||
"UsageStatsModelUsage",
|
||||
"UsageStatsModelRankingListResponse",
|
||||
"UsageStatsDailyUsage",
|
||||
"UsageStatsDailyTrendsListResponse",
|
||||
"ModelListParams",
|
||||
"ModelListResponse",
|
||||
"ModelPreferencesListResponse",
|
||||
@@ -162,6 +205,10 @@ pub const METHOD_CAPABILITY_LIST: &str = "capability/list";
|
||||
pub const METHOD_ARTIFACT_READ: &str = "artifact/read";
|
||||
pub const METHOD_FILE_SYSTEM_LIST_DIRECTORY: &str = "fileSystem/listDirectory";
|
||||
pub const METHOD_FILE_SYSTEM_READ_FILE_PREVIEW: &str = "fileSystem/readFilePreview";
|
||||
pub const METHOD_FILE_SYSTEM_CREATE_FILE: &str = "fileSystem/createFile";
|
||||
pub const METHOD_FILE_SYSTEM_CREATE_DIRECTORY: &str = "fileSystem/createDirectory";
|
||||
pub const METHOD_FILE_SYSTEM_RENAME_FILE: &str = "fileSystem/renameFile";
|
||||
pub const METHOD_FILE_SYSTEM_DELETE_FILE: &str = "fileSystem/deleteFile";
|
||||
pub const METHOD_EVIDENCE_EXPORT: &str = "evidence/export";
|
||||
pub const METHOD_AGENT_SESSION_LIST: &str = "agentSession/list";
|
||||
pub const METHOD_AGENT_SESSION_UPDATE: &str = "agentSession/update";
|
||||
@@ -177,11 +224,25 @@ pub const METHOD_SKILL_LIST: &str = "skill/list";
|
||||
pub const METHOD_SKILL_READ: &str = "skill/read";
|
||||
pub const METHOD_WORKSPACE_SKILL_BINDINGS_LIST: &str = "workspaceSkillBindings/list";
|
||||
pub const METHOD_WORKSPACE_REGISTERED_SKILLS_LIST: &str = "workspaceRegisteredSkills/list";
|
||||
pub const METHOD_AGENT_APP_LOCAL_PACKAGE_INSPECT: &str = "agentAppLocalPackage/inspect";
|
||||
pub const METHOD_AGENT_APP_PACKAGE_FETCH_CLOUD: &str = "agentAppPackage/fetchCloud";
|
||||
pub const METHOD_AGENT_APP_INSTALLED_SAVE: &str = "agentAppInstalled/save";
|
||||
pub const METHOD_AGENT_APP_INSTALLED_LIST: &str = "agentAppInstalled/list";
|
||||
pub const METHOD_AGENT_APP_INSTALLED_DISABLED_SET: &str = "agentAppInstalled/disabled/set";
|
||||
pub const METHOD_AGENT_APP_INSTALLED_UNINSTALL_REHEARSAL: &str =
|
||||
"agentAppInstalled/uninstall/rehearsal";
|
||||
pub const METHOD_AGENT_APP_INSTALLED_UNINSTALL: &str = "agentAppInstalled/uninstall";
|
||||
pub const METHOD_AGENT_APP_UI_RUNTIME_START: &str = "agentAppUiRuntime/start";
|
||||
pub const METHOD_AGENT_APP_UI_RUNTIME_STATUS: &str = "agentAppUiRuntime/status";
|
||||
pub const METHOD_AGENT_APP_UI_RUNTIME_STOP: &str = "agentAppUiRuntime/stop";
|
||||
pub const METHOD_KNOWLEDGE_PACK_LIST: &str = "knowledgePack/list";
|
||||
pub const METHOD_KNOWLEDGE_PACK_READ: &str = "knowledgePack/read";
|
||||
pub const METHOD_KNOWLEDGE_SOURCE_IMPORT: &str = "knowledgePack/source/import";
|
||||
pub const METHOD_KNOWLEDGE_PACK_COMPILE: &str = "knowledgePack/compile";
|
||||
pub const METHOD_KNOWLEDGE_PACK_DEFAULT_SET: &str = "knowledgePack/default/set";
|
||||
pub const METHOD_KNOWLEDGE_PACK_STATUS_UPDATE: &str = "knowledgePack/status/update";
|
||||
pub const METHOD_KNOWLEDGE_CONTEXT_RESOLVE: &str = "knowledgeContext/resolve";
|
||||
pub const METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE: &str = "knowledgeContextRun/validate";
|
||||
pub const METHOD_AUTOMATION_SCHEDULER_CONFIG_READ: &str = "automationScheduler/config/read";
|
||||
pub const METHOD_AUTOMATION_SCHEDULER_CONFIG_UPDATE: &str = "automationScheduler/config/update";
|
||||
pub const METHOD_AUTOMATION_SCHEDULER_STATUS: &str = "automationScheduler/status";
|
||||
@@ -201,6 +262,9 @@ pub const METHOD_MCP_TOOL_LIST: &str = "mcpTool/list";
|
||||
pub const METHOD_MCP_PROMPT_LIST: &str = "mcpPrompt/list";
|
||||
pub const METHOD_MCP_RESOURCE_LIST: &str = "mcpResource/list";
|
||||
pub const METHOD_PROJECT_MEMORY_READ: &str = "projectMemory/read";
|
||||
pub const METHOD_USAGE_STATS_READ: &str = "usageStats/read";
|
||||
pub const METHOD_USAGE_STATS_MODEL_RANKING_LIST: &str = "usageStats/modelRanking/list";
|
||||
pub const METHOD_USAGE_STATS_DAILY_TRENDS_LIST: &str = "usageStats/dailyTrends/list";
|
||||
pub const METHOD_MODEL_LIST: &str = "model/list";
|
||||
pub const METHOD_MODEL_PREFERENCES_LIST: &str = "modelPreferences/list";
|
||||
pub const METHOD_MODEL_SYNC_STATE_READ: &str = "modelSyncState/read";
|
||||
@@ -276,6 +340,22 @@ pub const APP_SERVER_METHODS: &[AppServerMethodSpec] = &[
|
||||
method: METHOD_FILE_SYSTEM_READ_FILE_PREVIEW,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_FILE_SYSTEM_CREATE_FILE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_FILE_SYSTEM_CREATE_DIRECTORY,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_FILE_SYSTEM_RENAME_FILE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_FILE_SYSTEM_DELETE_FILE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_EVIDENCE_EXPORT,
|
||||
kind: AppServerMethodKind::Request,
|
||||
@@ -336,10 +416,34 @@ pub const APP_SERVER_METHODS: &[AppServerMethodSpec] = &[
|
||||
method: METHOD_WORKSPACE_REGISTERED_SKILLS_LIST,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_LOCAL_PACKAGE_INSPECT,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_PACKAGE_FETCH_CLOUD,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_INSTALLED_SAVE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_INSTALLED_LIST,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_INSTALLED_DISABLED_SET,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_INSTALLED_UNINSTALL_REHEARSAL,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_INSTALLED_UNINSTALL,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AGENT_APP_UI_RUNTIME_START,
|
||||
kind: AppServerMethodKind::Request,
|
||||
@@ -356,6 +460,34 @@ pub const APP_SERVER_METHODS: &[AppServerMethodSpec] = &[
|
||||
method: METHOD_KNOWLEDGE_PACK_LIST,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_PACK_READ,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_SOURCE_IMPORT,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_PACK_COMPILE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_PACK_DEFAULT_SET,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_PACK_STATUS_UPDATE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_CONTEXT_RESOLVE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_AUTOMATION_SCHEDULER_CONFIG_READ,
|
||||
kind: AppServerMethodKind::Request,
|
||||
@@ -432,6 +564,18 @@ pub const APP_SERVER_METHODS: &[AppServerMethodSpec] = &[
|
||||
method: METHOD_PROJECT_MEMORY_READ,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_USAGE_STATS_READ,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_USAGE_STATS_MODEL_RANKING_LIST,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_USAGE_STATS_DAILY_TRENDS_LIST,
|
||||
kind: AppServerMethodKind::Request,
|
||||
},
|
||||
AppServerMethodSpec {
|
||||
method: METHOD_MODEL_LIST,
|
||||
kind: AppServerMethodKind::Request,
|
||||
@@ -755,6 +899,37 @@ pub struct FileSystemReadFilePreviewParams {
|
||||
pub max_size: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileSystemCreateFileParams {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileSystemCreateDirectoryParams {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileSystemRenameFileParams {
|
||||
pub old_path: String,
|
||||
pub new_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileSystemDeleteFileParams {
|
||||
pub path: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub recursive: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileSystemMutationResponse {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FileSystemDirectoryListing {
|
||||
@@ -1083,6 +1258,102 @@ pub struct WorkspaceRegisteredSkillsListResponse {
|
||||
pub skills: Vec<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppLocalPackageInspectParams {
|
||||
pub app_dir: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppLocalPackageInspectResponse {
|
||||
pub source_kind: String,
|
||||
pub source_uri: String,
|
||||
pub app_dir: String,
|
||||
pub app_markdown: String,
|
||||
pub manifest: serde_json::Value,
|
||||
pub manifest_hash: String,
|
||||
pub package_hash: String,
|
||||
pub inspected_at: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppFetchCloudPackageParams {
|
||||
pub descriptor: AgentAppCloudReleaseDescriptor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppCloudReleaseDescriptor {
|
||||
pub source_uri: String,
|
||||
pub app_id: String,
|
||||
pub version: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub release_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub tenant_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub tenant_enablement_ref: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub channel: Option<String>,
|
||||
pub package_url: String,
|
||||
pub package_hash: String,
|
||||
pub manifest_hash: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub signature_ref: Option<String>,
|
||||
pub loaded_at: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppPackageCacheEntry {
|
||||
pub app_id: String,
|
||||
pub identity: AgentAppPackageIdentity,
|
||||
pub manifest_snapshot: serde_json::Value,
|
||||
pub package_hash: String,
|
||||
pub manifest_hash: String,
|
||||
pub cache_path: String,
|
||||
pub cached_at: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppPackageIdentity {
|
||||
pub source_kind: String,
|
||||
pub source_uri: String,
|
||||
pub app_id: String,
|
||||
pub app_version: String,
|
||||
pub package_hash: String,
|
||||
pub manifest_hash: String,
|
||||
pub loaded_at: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub release_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub tenant_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub tenant_enablement_ref: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub channel: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub signature_ref: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppInstalledSaveParams {
|
||||
pub state: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppInstalledDisabledSetParams {
|
||||
pub app_id: String,
|
||||
pub disabled: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppInstalledListResponse {
|
||||
@@ -1092,6 +1363,110 @@ pub struct AgentAppInstalledListResponse {
|
||||
pub issues: Vec<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppUninstallRehearsalParams {
|
||||
pub app_id: String,
|
||||
pub mode: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppUninstallRehearsalResponse {
|
||||
pub app_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub package_hash: Option<String>,
|
||||
pub mode: String,
|
||||
pub generated_at: String,
|
||||
pub deleted_target_count: usize,
|
||||
pub retained_target_count: usize,
|
||||
#[serde(default)]
|
||||
pub targets: Vec<AgentAppUninstallRehearsalTarget>,
|
||||
#[serde(default)]
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppUninstallRehearsalTarget {
|
||||
pub kind: String,
|
||||
pub value: String,
|
||||
pub safe_to_delete: bool,
|
||||
pub action: String,
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppUninstallParams {
|
||||
pub app_id: String,
|
||||
pub mode: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub confirmation_phrase: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppUninstallResponse {
|
||||
pub status: String,
|
||||
pub rehearsal: AgentAppUninstallRehearsalResponse,
|
||||
pub list: AgentAppInstalledListResponse,
|
||||
pub removed_target_count: usize,
|
||||
pub missing_target_count: usize,
|
||||
#[serde(default)]
|
||||
pub blocker_codes: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub delete_evidence: Option<AgentAppDeleteDataExecutionEvidence>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppDeleteDataExecutionEvidence {
|
||||
pub status: String,
|
||||
pub generated_at: String,
|
||||
pub data_root: String,
|
||||
#[serde(default)]
|
||||
pub removed_targets: Vec<AgentAppDeleteDataTargetEvidence>,
|
||||
#[serde(default)]
|
||||
pub missing_targets: Vec<AgentAppDeleteDataTargetEvidence>,
|
||||
#[serde(default)]
|
||||
pub retained_targets: Vec<AgentAppDeleteDataTargetEvidence>,
|
||||
#[serde(default)]
|
||||
pub blocked_targets: Vec<AgentAppDeleteDataTargetEvidence>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub failed_target: Option<AgentAppDeleteDataTargetEvidence>,
|
||||
#[serde(default)]
|
||||
pub blocker_codes: Vec<String>,
|
||||
pub post_delete_residual_audit: AgentAppDeleteDataPostDeleteResidualAudit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppDeleteDataTargetEvidence {
|
||||
pub kind: String,
|
||||
pub value: String,
|
||||
pub action: String,
|
||||
pub reason: String,
|
||||
pub status: String,
|
||||
#[serde(default)]
|
||||
pub blocker_codes: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppDeleteDataPostDeleteResidualAudit {
|
||||
pub status: String,
|
||||
pub checked_at: String,
|
||||
pub checked_target_count: usize,
|
||||
pub remaining_target_count: usize,
|
||||
#[serde(default)]
|
||||
pub remaining_targets: Vec<AgentAppDeleteDataTargetEvidence>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub failed_target: Option<AgentAppDeleteDataTargetEvidence>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentAppUiRuntimeStartParams {
|
||||
@@ -1150,6 +1525,167 @@ pub struct KnowledgeListPacksResponse {
|
||||
pub packs: Vec<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeReadPackParams {
|
||||
pub working_dir: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeReadPackResponse {
|
||||
pub pack: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeImportSourceParams {
|
||||
pub working_dir: String,
|
||||
pub pack_name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub pack_type: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub language: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_file_name: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_text: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeImportSourceResponse {
|
||||
pub pack: serde_json::Value,
|
||||
pub source: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeCompilePackParams {
|
||||
pub working_dir: String,
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub builder_runtime: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeCompilePackResponse {
|
||||
pub pack: serde_json::Value,
|
||||
pub selected_source_count: u32,
|
||||
pub compiled_view: serde_json::Value,
|
||||
pub run: serde_json::Value,
|
||||
#[serde(default)]
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeSetDefaultPackParams {
|
||||
pub working_dir: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeSetDefaultPackResponse {
|
||||
pub default_pack_name: String,
|
||||
pub default_marker_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeUpdatePackStatusParams {
|
||||
pub working_dir: String,
|
||||
pub name: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeUpdatePackStatusResponse {
|
||||
pub pack: serde_json::Value,
|
||||
pub previous_status: String,
|
||||
pub cleared_default: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeResolveContextPackParams {
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub activation: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeResolveContextParams {
|
||||
pub working_dir: String,
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub packs: Vec<KnowledgeResolveContextPackParams>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub task: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub max_chars: Option<usize>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub activation: Option<String>,
|
||||
#[serde(default)]
|
||||
pub write_run: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub run_reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeContextResolutionResponse {
|
||||
pub pack_name: String,
|
||||
pub status: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub grounding: Option<String>,
|
||||
#[serde(default)]
|
||||
pub selected_views: Vec<serde_json::Value>,
|
||||
#[serde(default)]
|
||||
pub selected_files: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub source_anchors: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub warnings: Vec<serde_json::Value>,
|
||||
#[serde(default)]
|
||||
pub missing: Vec<String>,
|
||||
pub token_estimate: u32,
|
||||
pub fenced_context: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub run_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub run_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeValidateContextRunParams {
|
||||
pub working_dir: String,
|
||||
pub name: String,
|
||||
pub run_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct KnowledgeValidateContextRunResponse {
|
||||
pub valid: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub run_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub status: Option<String>,
|
||||
#[serde(default)]
|
||||
pub errors: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AutomationSchedulerConfigReadResponse {
|
||||
@@ -1286,6 +1822,64 @@ pub struct ProjectMemoryReadResponse {
|
||||
pub memory: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsRangeParams {
|
||||
pub time_range: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsSummary {
|
||||
pub total_conversations: u32,
|
||||
pub total_messages: u32,
|
||||
pub total_tokens: u64,
|
||||
pub total_time_minutes: u32,
|
||||
pub monthly_conversations: u32,
|
||||
pub monthly_messages: u32,
|
||||
pub monthly_tokens: u64,
|
||||
pub today_conversations: u32,
|
||||
pub today_messages: u32,
|
||||
pub today_tokens: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsReadResponse {
|
||||
pub stats: UsageStatsSummary,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsModelUsage {
|
||||
pub model: String,
|
||||
pub conversations: u32,
|
||||
pub tokens: u64,
|
||||
pub percentage: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsModelRankingListResponse {
|
||||
#[serde(default)]
|
||||
pub ranking: Vec<UsageStatsModelUsage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsDailyUsage {
|
||||
pub date: String,
|
||||
pub conversations: u32,
|
||||
pub tokens: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsageStatsDailyTrendsListResponse {
|
||||
#[serde(default)]
|
||||
pub trends: Vec<UsageStatsDailyUsage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ModelListParams {
|
||||
@@ -2594,6 +3188,10 @@ mod tests {
|
||||
METHOD_ARTIFACT_READ,
|
||||
METHOD_FILE_SYSTEM_LIST_DIRECTORY,
|
||||
METHOD_FILE_SYSTEM_READ_FILE_PREVIEW,
|
||||
METHOD_FILE_SYSTEM_CREATE_FILE,
|
||||
METHOD_FILE_SYSTEM_CREATE_DIRECTORY,
|
||||
METHOD_FILE_SYSTEM_RENAME_FILE,
|
||||
METHOD_FILE_SYSTEM_DELETE_FILE,
|
||||
METHOD_EVIDENCE_EXPORT,
|
||||
METHOD_AGENT_SESSION_LIST,
|
||||
METHOD_AGENT_SESSION_UPDATE,
|
||||
@@ -2614,6 +3212,7 @@ mod tests {
|
||||
METHOD_AGENT_APP_UI_RUNTIME_STATUS,
|
||||
METHOD_AGENT_APP_UI_RUNTIME_STOP,
|
||||
METHOD_KNOWLEDGE_PACK_LIST,
|
||||
METHOD_KNOWLEDGE_PACK_READ,
|
||||
METHOD_AUTOMATION_SCHEDULER_CONFIG_READ,
|
||||
METHOD_AUTOMATION_SCHEDULER_CONFIG_UPDATE,
|
||||
METHOD_AUTOMATION_SCHEDULER_STATUS,
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
use crate::AgentAppCloudReleaseDescriptor;
|
||||
use crate::AgentAppDeleteDataExecutionEvidence;
|
||||
use crate::AgentAppDeleteDataPostDeleteResidualAudit;
|
||||
use crate::AgentAppDeleteDataTargetEvidence;
|
||||
use crate::AgentAppFetchCloudPackageParams;
|
||||
use crate::AgentAppInstalledDisabledSetParams;
|
||||
use crate::AgentAppInstalledListResponse;
|
||||
use crate::AgentAppInstalledSaveParams;
|
||||
use crate::AgentAppLocalPackageInspectParams;
|
||||
use crate::AgentAppLocalPackageInspectResponse;
|
||||
use crate::AgentAppPackageCacheEntry;
|
||||
use crate::AgentAppPackageIdentity;
|
||||
use crate::AgentAppUninstallParams;
|
||||
use crate::AgentAppUninstallRehearsalParams;
|
||||
use crate::AgentAppUninstallRehearsalResponse;
|
||||
use crate::AgentAppUninstallRehearsalTarget;
|
||||
use crate::AgentAppUninstallResponse;
|
||||
use crate::AgentAppUiRuntimeStartParams;
|
||||
use crate::AgentAppUiRuntimeStatusParams;
|
||||
use crate::AgentAppUiRuntimeStatusResponse;
|
||||
@@ -72,11 +88,16 @@ use crate::EvidenceExportParams;
|
||||
use crate::EvidenceExportResponse;
|
||||
use crate::EvidencePackArtifact;
|
||||
use crate::EvidencePackSummary;
|
||||
use crate::FileSystemCreateDirectoryParams;
|
||||
use crate::FileSystemCreateFileParams;
|
||||
use crate::FileSystemDeleteFileParams;
|
||||
use crate::FileSystemDirectoryListing;
|
||||
use crate::FileSystemFileEntry;
|
||||
use crate::FileSystemFilePreview;
|
||||
use crate::FileSystemListDirectoryParams;
|
||||
use crate::FileSystemMutationResponse;
|
||||
use crate::FileSystemReadFilePreviewParams;
|
||||
use crate::FileSystemRenameFileParams;
|
||||
use crate::InitializeParams;
|
||||
use crate::InitializeResponse;
|
||||
use crate::JsonRpcError;
|
||||
@@ -85,8 +106,23 @@ use crate::JsonRpcMessage;
|
||||
use crate::JsonRpcNotification;
|
||||
use crate::JsonRpcRequest;
|
||||
use crate::JsonRpcResponse;
|
||||
use crate::KnowledgeCompilePackParams;
|
||||
use crate::KnowledgeCompilePackResponse;
|
||||
use crate::KnowledgeContextResolutionResponse;
|
||||
use crate::KnowledgeImportSourceParams;
|
||||
use crate::KnowledgeImportSourceResponse;
|
||||
use crate::KnowledgeListPacksParams;
|
||||
use crate::KnowledgeListPacksResponse;
|
||||
use crate::KnowledgeReadPackParams;
|
||||
use crate::KnowledgeReadPackResponse;
|
||||
use crate::KnowledgeResolveContextPackParams;
|
||||
use crate::KnowledgeResolveContextParams;
|
||||
use crate::KnowledgeSetDefaultPackParams;
|
||||
use crate::KnowledgeSetDefaultPackResponse;
|
||||
use crate::KnowledgeUpdatePackStatusParams;
|
||||
use crate::KnowledgeUpdatePackStatusResponse;
|
||||
use crate::KnowledgeValidateContextRunParams;
|
||||
use crate::KnowledgeValidateContextRunResponse;
|
||||
use crate::McpPromptListResponse;
|
||||
use crate::McpResourceListResponse;
|
||||
use crate::McpServerListResponse;
|
||||
@@ -143,6 +179,13 @@ use crate::ServerInfo;
|
||||
use crate::SkillListResponse;
|
||||
use crate::SkillReadParams;
|
||||
use crate::SkillReadResponse;
|
||||
use crate::UsageStatsDailyTrendsListResponse;
|
||||
use crate::UsageStatsDailyUsage;
|
||||
use crate::UsageStatsModelRankingListResponse;
|
||||
use crate::UsageStatsModelUsage;
|
||||
use crate::UsageStatsRangeParams;
|
||||
use crate::UsageStatsReadResponse;
|
||||
use crate::UsageStatsSummary;
|
||||
use crate::WorkspaceEnsureParams;
|
||||
use crate::WorkspaceEnsureReadyResponse;
|
||||
use crate::WorkspaceListResponse;
|
||||
@@ -301,6 +344,11 @@ fn v0_schemas() -> Vec<GeneratedJsonSchema> {
|
||||
typed_schema::<ArtifactReadResponse>("ArtifactReadResponse"),
|
||||
typed_schema::<FileSystemListDirectoryParams>("FileSystemListDirectoryParams"),
|
||||
typed_schema::<FileSystemReadFilePreviewParams>("FileSystemReadFilePreviewParams"),
|
||||
typed_schema::<FileSystemCreateFileParams>("FileSystemCreateFileParams"),
|
||||
typed_schema::<FileSystemCreateDirectoryParams>("FileSystemCreateDirectoryParams"),
|
||||
typed_schema::<FileSystemRenameFileParams>("FileSystemRenameFileParams"),
|
||||
typed_schema::<FileSystemDeleteFileParams>("FileSystemDeleteFileParams"),
|
||||
typed_schema::<FileSystemMutationResponse>("FileSystemMutationResponse"),
|
||||
typed_schema::<FileSystemDirectoryListing>("FileSystemDirectoryListing"),
|
||||
typed_schema::<FileSystemFileEntry>("FileSystemFileEntry"),
|
||||
typed_schema::<FileSystemFilePreview>("FileSystemFilePreview"),
|
||||
@@ -331,13 +379,46 @@ fn v0_schemas() -> Vec<GeneratedJsonSchema> {
|
||||
typed_schema::<WorkspaceRegisteredSkillsListResponse>(
|
||||
"WorkspaceRegisteredSkillsListResponse",
|
||||
),
|
||||
typed_schema::<AgentAppLocalPackageInspectParams>("AgentAppLocalPackageInspectParams"),
|
||||
typed_schema::<AgentAppLocalPackageInspectResponse>("AgentAppLocalPackageInspectResponse"),
|
||||
typed_schema::<AgentAppFetchCloudPackageParams>("AgentAppFetchCloudPackageParams"),
|
||||
typed_schema::<AgentAppCloudReleaseDescriptor>("AgentAppCloudReleaseDescriptor"),
|
||||
typed_schema::<AgentAppPackageCacheEntry>("AgentAppPackageCacheEntry"),
|
||||
typed_schema::<AgentAppPackageIdentity>("AgentAppPackageIdentity"),
|
||||
typed_schema::<AgentAppInstalledSaveParams>("AgentAppInstalledSaveParams"),
|
||||
typed_schema::<AgentAppInstalledDisabledSetParams>("AgentAppInstalledDisabledSetParams"),
|
||||
typed_schema::<AgentAppInstalledListResponse>("AgentAppInstalledListResponse"),
|
||||
typed_schema::<AgentAppUninstallRehearsalParams>("AgentAppUninstallRehearsalParams"),
|
||||
typed_schema::<AgentAppUninstallRehearsalResponse>("AgentAppUninstallRehearsalResponse"),
|
||||
typed_schema::<AgentAppUninstallRehearsalTarget>("AgentAppUninstallRehearsalTarget"),
|
||||
typed_schema::<AgentAppUninstallParams>("AgentAppUninstallParams"),
|
||||
typed_schema::<AgentAppUninstallResponse>("AgentAppUninstallResponse"),
|
||||
typed_schema::<AgentAppDeleteDataExecutionEvidence>("AgentAppDeleteDataExecutionEvidence"),
|
||||
typed_schema::<AgentAppDeleteDataTargetEvidence>("AgentAppDeleteDataTargetEvidence"),
|
||||
typed_schema::<AgentAppDeleteDataPostDeleteResidualAudit>(
|
||||
"AgentAppDeleteDataPostDeleteResidualAudit",
|
||||
),
|
||||
typed_schema::<AgentAppUiRuntimeStartParams>("AgentAppUiRuntimeStartParams"),
|
||||
typed_schema::<AgentAppUiRuntimeStatusParams>("AgentAppUiRuntimeStatusParams"),
|
||||
typed_schema::<AgentAppUiRuntimeStopParams>("AgentAppUiRuntimeStopParams"),
|
||||
typed_schema::<AgentAppUiRuntimeStatusResponse>("AgentAppUiRuntimeStatusResponse"),
|
||||
typed_schema::<KnowledgeListPacksParams>("KnowledgeListPacksParams"),
|
||||
typed_schema::<KnowledgeListPacksResponse>("KnowledgeListPacksResponse"),
|
||||
typed_schema::<KnowledgeReadPackParams>("KnowledgeReadPackParams"),
|
||||
typed_schema::<KnowledgeReadPackResponse>("KnowledgeReadPackResponse"),
|
||||
typed_schema::<KnowledgeImportSourceParams>("KnowledgeImportSourceParams"),
|
||||
typed_schema::<KnowledgeImportSourceResponse>("KnowledgeImportSourceResponse"),
|
||||
typed_schema::<KnowledgeCompilePackParams>("KnowledgeCompilePackParams"),
|
||||
typed_schema::<KnowledgeCompilePackResponse>("KnowledgeCompilePackResponse"),
|
||||
typed_schema::<KnowledgeSetDefaultPackParams>("KnowledgeSetDefaultPackParams"),
|
||||
typed_schema::<KnowledgeSetDefaultPackResponse>("KnowledgeSetDefaultPackResponse"),
|
||||
typed_schema::<KnowledgeUpdatePackStatusParams>("KnowledgeUpdatePackStatusParams"),
|
||||
typed_schema::<KnowledgeUpdatePackStatusResponse>("KnowledgeUpdatePackStatusResponse"),
|
||||
typed_schema::<KnowledgeResolveContextPackParams>("KnowledgeResolveContextPackParams"),
|
||||
typed_schema::<KnowledgeResolveContextParams>("KnowledgeResolveContextParams"),
|
||||
typed_schema::<KnowledgeContextResolutionResponse>("KnowledgeContextResolutionResponse"),
|
||||
typed_schema::<KnowledgeValidateContextRunParams>("KnowledgeValidateContextRunParams"),
|
||||
typed_schema::<KnowledgeValidateContextRunResponse>("KnowledgeValidateContextRunResponse"),
|
||||
typed_schema::<AutomationSchedulerConfigReadResponse>(
|
||||
"AutomationSchedulerConfigReadResponse",
|
||||
),
|
||||
@@ -370,6 +451,13 @@ fn v0_schemas() -> Vec<GeneratedJsonSchema> {
|
||||
typed_schema::<McpResourceListResponse>("McpResourceListResponse"),
|
||||
typed_schema::<ProjectMemoryReadParams>("ProjectMemoryReadParams"),
|
||||
typed_schema::<ProjectMemoryReadResponse>("ProjectMemoryReadResponse"),
|
||||
typed_schema::<UsageStatsRangeParams>("UsageStatsRangeParams"),
|
||||
typed_schema::<UsageStatsSummary>("UsageStatsSummary"),
|
||||
typed_schema::<UsageStatsReadResponse>("UsageStatsReadResponse"),
|
||||
typed_schema::<UsageStatsModelUsage>("UsageStatsModelUsage"),
|
||||
typed_schema::<UsageStatsModelRankingListResponse>("UsageStatsModelRankingListResponse"),
|
||||
typed_schema::<UsageStatsDailyUsage>("UsageStatsDailyUsage"),
|
||||
typed_schema::<UsageStatsDailyTrendsListResponse>("UsageStatsDailyTrendsListResponse"),
|
||||
typed_schema::<ModelListParams>("ModelListParams"),
|
||||
typed_schema::<ModelListResponse>("ModelListResponse"),
|
||||
typed_schema::<ModelPreferencesListResponse>("ModelPreferencesListResponse"),
|
||||
|
||||
@@ -34,11 +34,16 @@ lime-skills.workspace = true
|
||||
lime-services.workspace = true
|
||||
reqwest.workspace = true
|
||||
rusqlite.workspace = true
|
||||
scopeguard.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_yaml.workspace = true
|
||||
sha2.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
url.workspace = true
|
||||
uuid.workspace = true
|
||||
zip.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
use crate::RuntimeCoreError;
|
||||
use async_trait::async_trait;
|
||||
use lime_agent::{
|
||||
execute_skill_prompt, execute_skill_workflow, AsterAgentState, SkillEventEmitter,
|
||||
SkillExecutionError, SkillPromptExecution, SkillWorkflowExecution,
|
||||
};
|
||||
use lime_core::database;
|
||||
use lime_knowledge::{KnowledgeBuilderRuntimeExecution, KnowledgeBuilderRuntimePlan};
|
||||
use lime_skills::{ExecutionCallback, LoadedSkillDefinition};
|
||||
use std::sync::Arc;
|
||||
|
||||
const DEFAULT_SKILL_PROVIDER: &str = "anthropic";
|
||||
const DEFAULT_SKILL_MODEL: &str = "claude-sonnet-4-20250514";
|
||||
const FALLBACK_TOOL_CAPABLE_PROVIDERS: &[(&str, &str)] = &[
|
||||
("anthropic", "claude-sonnet-4-20250514"),
|
||||
("openai", "gpt-4o"),
|
||||
("gemini", "gemini-2.0-flash"),
|
||||
];
|
||||
|
||||
#[async_trait]
|
||||
pub trait KnowledgeBuilderRuntimeExecutor: Send + Sync {
|
||||
async fn execute(
|
||||
&self,
|
||||
plan: KnowledgeBuilderRuntimePlan,
|
||||
) -> Result<KnowledgeBuilderRuntimeExecution, RuntimeCoreError>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NativeKnowledgeBuilderRuntimeExecutor {
|
||||
agent_state: AsterAgentState,
|
||||
}
|
||||
|
||||
impl NativeKnowledgeBuilderRuntimeExecutor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
agent_state: AsterAgentState::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl KnowledgeBuilderRuntimeExecutor for NativeKnowledgeBuilderRuntimeExecutor {
|
||||
async fn execute(
|
||||
&self,
|
||||
plan: KnowledgeBuilderRuntimePlan,
|
||||
) -> Result<KnowledgeBuilderRuntimeExecution, RuntimeCoreError> {
|
||||
Ok(execute_native_knowledge_builder_skill(&self.agent_state, plan).await)
|
||||
}
|
||||
}
|
||||
|
||||
async fn execute_native_knowledge_builder_skill(
|
||||
agent_state: &AsterAgentState,
|
||||
plan: KnowledgeBuilderRuntimePlan,
|
||||
) -> KnowledgeBuilderRuntimeExecution {
|
||||
let result = execute_builder_skill(agent_state, &plan).await;
|
||||
|
||||
match result {
|
||||
Ok(output) if output.success => KnowledgeBuilderRuntimeExecution {
|
||||
skill_name: plan.skill_name,
|
||||
execution_id: plan.execution_id,
|
||||
session_id: Some(plan.session_id),
|
||||
status: "succeeded".to_string(),
|
||||
provider: plan.provider_override,
|
||||
model: plan.model_override,
|
||||
output: output.output,
|
||||
error: None,
|
||||
},
|
||||
Ok(output) => KnowledgeBuilderRuntimeExecution {
|
||||
skill_name: plan.skill_name,
|
||||
execution_id: plan.execution_id,
|
||||
session_id: Some(plan.session_id),
|
||||
status: "failed".to_string(),
|
||||
provider: plan.provider_override,
|
||||
model: plan.model_override,
|
||||
output: output.output,
|
||||
error: output
|
||||
.error
|
||||
.or_else(|| Some("Builder Skill 执行失败".to_string())),
|
||||
},
|
||||
Err(error) => KnowledgeBuilderRuntimeExecution {
|
||||
skill_name: plan.skill_name,
|
||||
execution_id: plan.execution_id,
|
||||
session_id: Some(plan.session_id),
|
||||
status: "failed".to_string(),
|
||||
provider: plan.provider_override,
|
||||
model: plan.model_override,
|
||||
output: None,
|
||||
error: Some(error),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn execute_builder_skill(
|
||||
agent_state: &AsterAgentState,
|
||||
plan: &KnowledgeBuilderRuntimePlan,
|
||||
) -> Result<lime_agent::SkillExecutionResult, String> {
|
||||
let db = database::init_database()?;
|
||||
let skill = load_executable_builder_skill(&plan.skill_name)?;
|
||||
let (requested_provider, requested_model) = resolve_requested_provider(&skill, plan);
|
||||
configure_builder_provider(
|
||||
agent_state,
|
||||
&db,
|
||||
&plan.session_id,
|
||||
&requested_provider,
|
||||
&requested_model,
|
||||
)
|
||||
.await?;
|
||||
let user_input = build_skill_user_input(&plan.user_input, &plan.request_context);
|
||||
let callback = NoopSkillExecutionCallback;
|
||||
let emitter = noop_skill_event_emitter();
|
||||
|
||||
if skill.execution_mode == "workflow" {
|
||||
execute_skill_workflow(SkillWorkflowExecution {
|
||||
aster_state: agent_state,
|
||||
skill: &skill,
|
||||
user_input: &user_input,
|
||||
user_visible_input: Some(plan.user_input.as_str()),
|
||||
images: &[],
|
||||
execution_id: &plan.execution_id,
|
||||
session_id: &plan.session_id,
|
||||
callback: &callback,
|
||||
memory_prompt: None,
|
||||
emitter,
|
||||
})
|
||||
.await
|
||||
.map_err(map_skill_execution_error)
|
||||
} else {
|
||||
execute_skill_prompt(SkillPromptExecution {
|
||||
aster_state: agent_state,
|
||||
skill: &skill,
|
||||
user_input: &user_input,
|
||||
user_visible_input: Some(plan.user_input.as_str()),
|
||||
images: &[],
|
||||
execution_id: &plan.execution_id,
|
||||
session_id: &plan.session_id,
|
||||
memory_prompt: None,
|
||||
emitter,
|
||||
})
|
||||
.await
|
||||
.map_err(map_skill_execution_error)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_executable_builder_skill(skill_name: &str) -> Result<LoadedSkillDefinition, String> {
|
||||
let skill = lime_skills::find_skill_by_name(skill_name)?;
|
||||
if !skill.standard_compliance.validation_errors.is_empty() {
|
||||
return Err(format!(
|
||||
"Skill '{}' 未通过标准校验: {}",
|
||||
skill.skill_name,
|
||||
skill.standard_compliance.validation_errors.join("; ")
|
||||
));
|
||||
}
|
||||
if skill.disable_model_invocation {
|
||||
return Err(format!("Skill '{skill_name}' 已禁用模型调用,无法执行"));
|
||||
}
|
||||
Ok(skill)
|
||||
}
|
||||
|
||||
fn resolve_requested_provider(
|
||||
skill: &LoadedSkillDefinition,
|
||||
plan: &KnowledgeBuilderRuntimePlan,
|
||||
) -> (String, String) {
|
||||
let requested_provider = plan
|
||||
.provider_override
|
||||
.clone()
|
||||
.or_else(|| skill.provider.clone())
|
||||
.unwrap_or_else(|| DEFAULT_SKILL_PROVIDER.to_string());
|
||||
let requested_model = plan
|
||||
.model_override
|
||||
.clone()
|
||||
.or_else(|| skill.model.clone())
|
||||
.unwrap_or_else(|| DEFAULT_SKILL_MODEL.to_string());
|
||||
(requested_provider, requested_model)
|
||||
}
|
||||
|
||||
async fn configure_builder_provider(
|
||||
agent_state: &AsterAgentState,
|
||||
db: &lime_core::database::DbConnection,
|
||||
session_id: &str,
|
||||
requested_provider: &str,
|
||||
requested_model: &str,
|
||||
) -> Result<(), String> {
|
||||
let mut configure_result = agent_state
|
||||
.configure_provider_from_pool(db, requested_provider, requested_model, session_id, None)
|
||||
.await;
|
||||
|
||||
if configure_result.is_err() {
|
||||
tracing::warn!(
|
||||
"[knowledge_builder_runtime] 首选 Provider {} 配置失败: {:?},尝试 fallback",
|
||||
requested_provider,
|
||||
configure_result.as_ref().err()
|
||||
);
|
||||
|
||||
for (fallback_provider, fallback_model) in FALLBACK_TOOL_CAPABLE_PROVIDERS {
|
||||
if *fallback_provider == requested_provider {
|
||||
continue;
|
||||
}
|
||||
match agent_state
|
||||
.configure_provider_from_pool(db, fallback_provider, fallback_model, session_id, None)
|
||||
.await
|
||||
{
|
||||
Ok(config) => {
|
||||
tracing::info!(
|
||||
"[knowledge_builder_runtime] Fallback 到 {} / {} 成功",
|
||||
fallback_provider,
|
||||
fallback_model
|
||||
);
|
||||
configure_result = Ok(config);
|
||||
break;
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!(
|
||||
"[knowledge_builder_runtime] Fallback {} 也失败: {}",
|
||||
fallback_provider,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure_result.map(|_| ()).map_err(|error| {
|
||||
format!(
|
||||
"无法配置任何可用的 Provider(需要支持工具调用的 Provider,如 Anthropic、OpenAI 或 Google): {error}"
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn build_skill_user_input(user_input: &str, request_context: &serde_json::Value) -> String {
|
||||
let serialized_context = serde_json::to_string_pretty(request_context)
|
||||
.unwrap_or_else(|_| request_context.to_string());
|
||||
let normalized_user_input = user_input.trim();
|
||||
if normalized_user_input.is_empty() {
|
||||
return format!(
|
||||
"以下是调用方提供的结构化上下文,请严格按字段含义执行:\n```json\n{serialized_context}\n```"
|
||||
);
|
||||
}
|
||||
|
||||
format!(
|
||||
"以下是调用方提供的结构化上下文,请严格按字段含义执行:\n```json\n{serialized_context}\n```\n\n用户原始输入:\n{normalized_user_input}"
|
||||
)
|
||||
}
|
||||
|
||||
fn map_skill_execution_error(error: SkillExecutionError) -> String {
|
||||
match error {
|
||||
SkillExecutionError::SessionInitFailed(message) => message,
|
||||
}
|
||||
}
|
||||
|
||||
fn noop_skill_event_emitter() -> SkillEventEmitter {
|
||||
Arc::new(|_, _| {})
|
||||
}
|
||||
|
||||
struct NoopSkillExecutionCallback;
|
||||
|
||||
impl ExecutionCallback for NoopSkillExecutionCallback {
|
||||
fn on_step_start(
|
||||
&self,
|
||||
_step_id: &str,
|
||||
_step_name: &str,
|
||||
_current_step: usize,
|
||||
_total_steps: usize,
|
||||
) {
|
||||
}
|
||||
|
||||
fn on_step_complete(&self, _step_id: &str, _output: &str) {}
|
||||
|
||||
fn on_step_error(&self, _step_id: &str, _error: &str, _will_retry: bool) {}
|
||||
|
||||
fn on_complete(&self, _success: bool, _final_output: Option<&str>, _error: Option<&str>) {}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ mod aster_backend;
|
||||
mod backend_event;
|
||||
mod capability;
|
||||
mod external_backend;
|
||||
mod knowledge_builder_runtime;
|
||||
mod local_data_source;
|
||||
mod processor;
|
||||
mod runtime;
|
||||
@@ -86,6 +87,8 @@ pub use capability::CapabilitySource;
|
||||
pub use external_backend::ExternalBackend;
|
||||
pub use external_backend::ExternalBackendConfig;
|
||||
pub use external_backend::DEFAULT_EXTERNAL_BACKEND_TIMEOUT_MS;
|
||||
pub use knowledge_builder_runtime::KnowledgeBuilderRuntimeExecutor;
|
||||
pub use knowledge_builder_runtime::NativeKnowledgeBuilderRuntimeExecutor;
|
||||
pub use local_data_source::LocalAppDataSource;
|
||||
use processor::event_notification_jsonrpc;
|
||||
use processor::RequestProcessor;
|
||||
|
||||
@@ -42,8 +42,22 @@ use app_server_protocol::ConnectOpenDeepLinkResolveResponse;
|
||||
use app_server_protocol::ConnectPayload;
|
||||
use app_server_protocol::ConnectRelayApiKeySaveParams;
|
||||
use app_server_protocol::ConnectRelayApiKeySaveResponse;
|
||||
use app_server_protocol::KnowledgeCompilePackResponse;
|
||||
use app_server_protocol::KnowledgeContextResolutionResponse;
|
||||
use app_server_protocol::KnowledgeImportSourceParams;
|
||||
use app_server_protocol::KnowledgeImportSourceResponse;
|
||||
use app_server_protocol::KnowledgeListPacksParams;
|
||||
use app_server_protocol::KnowledgeListPacksResponse;
|
||||
use app_server_protocol::KnowledgeReadPackParams;
|
||||
use app_server_protocol::KnowledgeReadPackResponse;
|
||||
use app_server_protocol::KnowledgeResolveContextPackParams;
|
||||
use app_server_protocol::KnowledgeResolveContextParams;
|
||||
use app_server_protocol::KnowledgeSetDefaultPackParams;
|
||||
use app_server_protocol::KnowledgeSetDefaultPackResponse;
|
||||
use app_server_protocol::KnowledgeUpdatePackStatusParams;
|
||||
use app_server_protocol::KnowledgeUpdatePackStatusResponse;
|
||||
use app_server_protocol::KnowledgeValidateContextRunParams;
|
||||
use app_server_protocol::KnowledgeValidateContextRunResponse;
|
||||
use app_server_protocol::McpPromptListResponse;
|
||||
use app_server_protocol::McpResourceListResponse;
|
||||
use app_server_protocol::McpServerListResponse;
|
||||
@@ -94,6 +108,13 @@ use app_server_protocol::ProjectMemoryReadResponse;
|
||||
use app_server_protocol::SkillListResponse;
|
||||
use app_server_protocol::SkillReadParams;
|
||||
use app_server_protocol::SkillReadResponse;
|
||||
use app_server_protocol::UsageStatsDailyTrendsListResponse;
|
||||
use app_server_protocol::UsageStatsDailyUsage;
|
||||
use app_server_protocol::UsageStatsModelRankingListResponse;
|
||||
use app_server_protocol::UsageStatsModelUsage;
|
||||
use app_server_protocol::UsageStatsRangeParams;
|
||||
use app_server_protocol::UsageStatsReadResponse;
|
||||
use app_server_protocol::UsageStatsSummary;
|
||||
use app_server_protocol::WorkspaceEnsureParams;
|
||||
use app_server_protocol::WorkspaceEnsureReadyResponse;
|
||||
use app_server_protocol::WorkspaceListResponse;
|
||||
@@ -143,6 +164,7 @@ use lime_services::api_key_provider_service::ApiKeyProviderService;
|
||||
use lime_services::mcp_service::McpService;
|
||||
use lime_services::model_registry_service::FetchModelsResult;
|
||||
use lime_services::model_registry_service::ModelRegistryService;
|
||||
use lime_services::usage_statistics_service;
|
||||
use lime_skills::find_skill_by_name;
|
||||
use lime_skills::get_skill_roots;
|
||||
use lime_skills::load_skill_from_file;
|
||||
@@ -534,6 +556,156 @@ impl AppDataSource for LocalAppDataSource {
|
||||
})
|
||||
}
|
||||
|
||||
async fn read_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> Result<KnowledgeReadPackResponse, RuntimeCoreError> {
|
||||
let pack = lime_knowledge::get_knowledge_pack(lime_knowledge::KnowledgeGetPackRequest {
|
||||
working_dir: params.working_dir,
|
||||
name: params.name,
|
||||
})
|
||||
.map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeReadPackResponse {
|
||||
pack: value_from_serializable(pack)?,
|
||||
})
|
||||
}
|
||||
|
||||
async fn import_knowledge_source(
|
||||
&self,
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> Result<KnowledgeImportSourceResponse, RuntimeCoreError> {
|
||||
let response =
|
||||
lime_knowledge::import_knowledge_source(lime_knowledge::KnowledgeImportSourceRequest {
|
||||
working_dir: params.working_dir,
|
||||
pack_name: params.pack_name,
|
||||
description: params.description,
|
||||
pack_type: params.pack_type,
|
||||
language: params.language,
|
||||
source_file_name: params.source_file_name,
|
||||
source_text: params.source_text,
|
||||
})
|
||||
.map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeImportSourceResponse {
|
||||
pack: value_from_serializable(response.pack)?,
|
||||
source: value_from_serializable(response.source)?,
|
||||
})
|
||||
}
|
||||
|
||||
async fn compile_knowledge_pack(
|
||||
&self,
|
||||
request: lime_knowledge::KnowledgeCompilePackRequest,
|
||||
) -> Result<KnowledgeCompilePackResponse, RuntimeCoreError> {
|
||||
let response = lime_knowledge::compile_knowledge_pack(request).map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeCompilePackResponse {
|
||||
pack: value_from_serializable(response.pack)?,
|
||||
selected_source_count: response.selected_source_count,
|
||||
compiled_view: value_from_serializable(response.compiled_view)?,
|
||||
run: value_from_serializable(response.run)?,
|
||||
warnings: response.warnings,
|
||||
})
|
||||
}
|
||||
|
||||
async fn set_default_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<KnowledgeSetDefaultPackResponse, RuntimeCoreError> {
|
||||
let response = lime_knowledge::set_default_knowledge_pack(
|
||||
lime_knowledge::KnowledgeSetDefaultPackRequest {
|
||||
working_dir: params.working_dir,
|
||||
name: params.name,
|
||||
},
|
||||
)
|
||||
.map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeSetDefaultPackResponse {
|
||||
default_pack_name: response.default_pack_name,
|
||||
default_marker_path: response.default_marker_path,
|
||||
})
|
||||
}
|
||||
|
||||
async fn update_knowledge_pack_status(
|
||||
&self,
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<KnowledgeUpdatePackStatusResponse, RuntimeCoreError> {
|
||||
let response = lime_knowledge::update_knowledge_pack_status(
|
||||
lime_knowledge::KnowledgeUpdatePackStatusRequest {
|
||||
working_dir: params.working_dir,
|
||||
name: params.name,
|
||||
status: params.status,
|
||||
},
|
||||
)
|
||||
.map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeUpdatePackStatusResponse {
|
||||
pack: value_from_serializable(response.pack)?,
|
||||
previous_status: response.previous_status,
|
||||
cleared_default: response.cleared_default,
|
||||
})
|
||||
}
|
||||
|
||||
async fn resolve_knowledge_context(
|
||||
&self,
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> Result<KnowledgeContextResolutionResponse, RuntimeCoreError> {
|
||||
let response = lime_knowledge::resolve_knowledge_context(
|
||||
lime_knowledge::KnowledgeResolveContextRequest {
|
||||
working_dir: params.working_dir,
|
||||
name: params.name,
|
||||
packs: params
|
||||
.packs
|
||||
.into_iter()
|
||||
.map(to_lime_knowledge_context_pack_request)
|
||||
.collect(),
|
||||
task: params.task,
|
||||
max_chars: params.max_chars,
|
||||
activation: params.activation,
|
||||
write_run: params.write_run,
|
||||
run_reason: params.run_reason,
|
||||
},
|
||||
)
|
||||
.map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeContextResolutionResponse {
|
||||
pack_name: response.pack_name,
|
||||
status: response.status,
|
||||
grounding: response.grounding,
|
||||
selected_views: values_from_serializable_vec(response.selected_views)?,
|
||||
selected_files: response.selected_files,
|
||||
source_anchors: response.source_anchors,
|
||||
warnings: values_from_serializable_vec(response.warnings)?,
|
||||
missing: response.missing,
|
||||
token_estimate: response.token_estimate,
|
||||
fenced_context: response.fenced_context,
|
||||
run_id: response.run_id,
|
||||
run_path: response.run_path,
|
||||
})
|
||||
}
|
||||
|
||||
async fn validate_knowledge_context_run(
|
||||
&self,
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<KnowledgeValidateContextRunResponse, RuntimeCoreError> {
|
||||
let response = lime_knowledge::validate_knowledge_context_run(
|
||||
lime_knowledge::KnowledgeValidateContextRunRequest {
|
||||
working_dir: params.working_dir,
|
||||
name: params.name,
|
||||
run_path: params.run_path,
|
||||
},
|
||||
)
|
||||
.map_err(data_error)?;
|
||||
|
||||
Ok(KnowledgeValidateContextRunResponse {
|
||||
valid: response.valid,
|
||||
run_id: response.run_id,
|
||||
status: response.status,
|
||||
errors: response.errors,
|
||||
warnings: response.warnings,
|
||||
})
|
||||
}
|
||||
|
||||
async fn list_automation_jobs(&self) -> Result<AutomationJobListResponse, RuntimeCoreError> {
|
||||
let conn = database::lock_db(&self.db).map_err(data_error)?;
|
||||
let jobs = AutomationJobDao::list(&conn).map_err(data_error)?;
|
||||
@@ -848,6 +1020,66 @@ impl AppDataSource for LocalAppDataSource {
|
||||
})
|
||||
}
|
||||
|
||||
async fn read_usage_stats(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsReadResponse, RuntimeCoreError> {
|
||||
let conn = database::lock_db(&self.db).map_err(data_error)?;
|
||||
let stats = usage_statistics_service::get_usage_stats_from_db(¶ms.time_range, &conn)
|
||||
.map_err(data_error)?;
|
||||
Ok(UsageStatsReadResponse {
|
||||
stats: UsageStatsSummary {
|
||||
total_conversations: stats.total_conversations,
|
||||
total_messages: stats.total_messages,
|
||||
total_tokens: stats.total_tokens,
|
||||
total_time_minutes: stats.total_time_minutes,
|
||||
monthly_conversations: stats.monthly_conversations,
|
||||
monthly_messages: stats.monthly_messages,
|
||||
monthly_tokens: stats.monthly_tokens,
|
||||
today_conversations: stats.today_conversations,
|
||||
today_messages: stats.today_messages,
|
||||
today_tokens: stats.today_tokens,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async fn list_usage_stats_model_ranking(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsModelRankingListResponse, RuntimeCoreError> {
|
||||
let conn = database::lock_db(&self.db).map_err(data_error)?;
|
||||
let ranking =
|
||||
usage_statistics_service::get_model_usage_ranking_from_db(¶ms.time_range, &conn)
|
||||
.map_err(data_error)?
|
||||
.into_iter()
|
||||
.map(|item| UsageStatsModelUsage {
|
||||
model: item.model,
|
||||
conversations: item.conversations,
|
||||
tokens: item.tokens,
|
||||
percentage: item.percentage,
|
||||
})
|
||||
.collect();
|
||||
Ok(UsageStatsModelRankingListResponse { ranking })
|
||||
}
|
||||
|
||||
async fn list_usage_stats_daily_trends(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsDailyTrendsListResponse, RuntimeCoreError> {
|
||||
let conn = database::lock_db(&self.db).map_err(data_error)?;
|
||||
let trends =
|
||||
usage_statistics_service::get_daily_usage_trends_from_db(¶ms.time_range, &conn)
|
||||
.map_err(data_error)?
|
||||
.into_iter()
|
||||
.map(|item| UsageStatsDailyUsage {
|
||||
date: item.date,
|
||||
conversations: item.conversations,
|
||||
tokens: item.tokens,
|
||||
})
|
||||
.collect();
|
||||
Ok(UsageStatsDailyTrendsListResponse { trends })
|
||||
}
|
||||
|
||||
async fn list_models(
|
||||
&self,
|
||||
params: ModelListParams,
|
||||
@@ -2525,6 +2757,19 @@ fn values_from_serializable_vec<T: serde::Serialize>(
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn value_from_serializable<T: serde::Serialize>(value: T) -> Result<Value, RuntimeCoreError> {
|
||||
serde_json::to_value(value).map_err(data_error)
|
||||
}
|
||||
|
||||
fn to_lime_knowledge_context_pack_request(
|
||||
params: KnowledgeResolveContextPackParams,
|
||||
) -> lime_knowledge::KnowledgeResolveContextPackRequest {
|
||||
lime_knowledge::KnowledgeResolveContextPackRequest {
|
||||
name: params.name,
|
||||
activation: params.activation,
|
||||
}
|
||||
}
|
||||
|
||||
async fn load_connect_registry_best_effort() -> Option<connect::RelayRegistry> {
|
||||
let registry = connect::RelayRegistry::new(connect_registry_cache_path());
|
||||
if registry.load_from_cache().is_ok() {
|
||||
|
||||
@@ -26,8 +26,12 @@ use app_server_protocol::ConnectDeepLinkResolveParams;
|
||||
use app_server_protocol::ConnectOpenDeepLinkResolveParams;
|
||||
use app_server_protocol::ConnectRelayApiKeySaveParams;
|
||||
use app_server_protocol::EvidenceExportParams;
|
||||
use app_server_protocol::FileSystemCreateDirectoryParams;
|
||||
use app_server_protocol::FileSystemCreateFileParams;
|
||||
use app_server_protocol::FileSystemDeleteFileParams;
|
||||
use app_server_protocol::FileSystemListDirectoryParams;
|
||||
use app_server_protocol::FileSystemReadFilePreviewParams;
|
||||
use app_server_protocol::FileSystemRenameFileParams;
|
||||
use app_server_protocol::InitializeParams;
|
||||
use app_server_protocol::InitializeResponse;
|
||||
use app_server_protocol::JsonRpcError;
|
||||
@@ -36,7 +40,14 @@ use app_server_protocol::JsonRpcMessage;
|
||||
use app_server_protocol::JsonRpcNotification;
|
||||
use app_server_protocol::JsonRpcRequest;
|
||||
use app_server_protocol::JsonRpcResponse;
|
||||
use app_server_protocol::KnowledgeCompilePackParams;
|
||||
use app_server_protocol::KnowledgeImportSourceParams;
|
||||
use app_server_protocol::KnowledgeListPacksParams;
|
||||
use app_server_protocol::KnowledgeReadPackParams;
|
||||
use app_server_protocol::KnowledgeResolveContextParams;
|
||||
use app_server_protocol::KnowledgeSetDefaultPackParams;
|
||||
use app_server_protocol::KnowledgeUpdatePackStatusParams;
|
||||
use app_server_protocol::KnowledgeValidateContextRunParams;
|
||||
use app_server_protocol::ModelListParams;
|
||||
use app_server_protocol::ModelProviderAliasReadParams;
|
||||
use app_server_protocol::ModelProviderConfigExportParams;
|
||||
@@ -61,6 +72,7 @@ use app_server_protocol::ProjectMemoryReadParams;
|
||||
use app_server_protocol::ServerCapabilities;
|
||||
use app_server_protocol::ServerInfo;
|
||||
use app_server_protocol::SkillReadParams;
|
||||
use app_server_protocol::UsageStatsRangeParams;
|
||||
use app_server_protocol::WorkspaceEnsureParams;
|
||||
use app_server_protocol::WorkspacePathReadParams;
|
||||
use app_server_protocol::WorkspaceProjectPathResolveParams;
|
||||
@@ -99,11 +111,22 @@ use app_server_protocol::METHOD_CONNECT_DEEP_LINK_RESOLVE;
|
||||
use app_server_protocol::METHOD_CONNECT_OPEN_DEEP_LINK_RESOLVE;
|
||||
use app_server_protocol::METHOD_CONNECT_RELAY_API_KEY_SAVE;
|
||||
use app_server_protocol::METHOD_EVIDENCE_EXPORT;
|
||||
use app_server_protocol::METHOD_FILE_SYSTEM_CREATE_DIRECTORY;
|
||||
use app_server_protocol::METHOD_FILE_SYSTEM_CREATE_FILE;
|
||||
use app_server_protocol::METHOD_FILE_SYSTEM_DELETE_FILE;
|
||||
use app_server_protocol::METHOD_FILE_SYSTEM_LIST_DIRECTORY;
|
||||
use app_server_protocol::METHOD_FILE_SYSTEM_READ_FILE_PREVIEW;
|
||||
use app_server_protocol::METHOD_FILE_SYSTEM_RENAME_FILE;
|
||||
use app_server_protocol::METHOD_INITIALIZE;
|
||||
use app_server_protocol::METHOD_INITIALIZED;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_CONTEXT_RESOLVE;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_PACK_COMPILE;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_PACK_DEFAULT_SET;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_PACK_LIST;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_PACK_READ;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_PACK_STATUS_UPDATE;
|
||||
use app_server_protocol::METHOD_KNOWLEDGE_SOURCE_IMPORT;
|
||||
use app_server_protocol::METHOD_MCP_PROMPT_LIST;
|
||||
use app_server_protocol::METHOD_MCP_RESOURCE_LIST;
|
||||
use app_server_protocol::METHOD_MCP_SERVER_LIST;
|
||||
@@ -137,6 +160,9 @@ use app_server_protocol::METHOD_MODEL_SYNC_STATE_READ;
|
||||
use app_server_protocol::METHOD_PROJECT_MEMORY_READ;
|
||||
use app_server_protocol::METHOD_SKILL_LIST;
|
||||
use app_server_protocol::METHOD_SKILL_READ;
|
||||
use app_server_protocol::METHOD_USAGE_STATS_DAILY_TRENDS_LIST;
|
||||
use app_server_protocol::METHOD_USAGE_STATS_MODEL_RANKING_LIST;
|
||||
use app_server_protocol::METHOD_USAGE_STATS_READ;
|
||||
use app_server_protocol::METHOD_WORKSPACE_BY_PATH_READ;
|
||||
use app_server_protocol::METHOD_WORKSPACE_DEFAULT_ENSURE;
|
||||
use app_server_protocol::METHOD_WORKSPACE_DEFAULT_READ;
|
||||
@@ -211,6 +237,12 @@ impl RequestProcessor {
|
||||
METHOD_FILE_SYSTEM_READ_FILE_PREVIEW => {
|
||||
self.handle_file_system_read_file_preview(params).await
|
||||
}
|
||||
METHOD_FILE_SYSTEM_CREATE_FILE => self.handle_file_system_create_file(params).await,
|
||||
METHOD_FILE_SYSTEM_CREATE_DIRECTORY => {
|
||||
self.handle_file_system_create_directory(params).await
|
||||
}
|
||||
METHOD_FILE_SYSTEM_RENAME_FILE => self.handle_file_system_rename_file(params).await,
|
||||
METHOD_FILE_SYSTEM_DELETE_FILE => self.handle_file_system_delete_file(params).await,
|
||||
METHOD_EVIDENCE_EXPORT => self.handle_evidence_export(params).await,
|
||||
METHOD_AGENT_SESSION_LIST => self.handle_session_list(params).await,
|
||||
METHOD_AGENT_SESSION_UPDATE => self.handle_session_update(params).await,
|
||||
@@ -243,6 +275,19 @@ impl RequestProcessor {
|
||||
}
|
||||
METHOD_AGENT_APP_UI_RUNTIME_STOP => self.handle_agent_app_ui_runtime_stop(params).await,
|
||||
METHOD_KNOWLEDGE_PACK_LIST => self.handle_knowledge_pack_list(params).await,
|
||||
METHOD_KNOWLEDGE_PACK_READ => self.handle_knowledge_pack_read(params).await,
|
||||
METHOD_KNOWLEDGE_SOURCE_IMPORT => self.handle_knowledge_source_import(params).await,
|
||||
METHOD_KNOWLEDGE_PACK_COMPILE => self.handle_knowledge_pack_compile(params).await,
|
||||
METHOD_KNOWLEDGE_PACK_DEFAULT_SET => {
|
||||
self.handle_knowledge_pack_default_set(params).await
|
||||
}
|
||||
METHOD_KNOWLEDGE_PACK_STATUS_UPDATE => {
|
||||
self.handle_knowledge_pack_status_update(params).await
|
||||
}
|
||||
METHOD_KNOWLEDGE_CONTEXT_RESOLVE => self.handle_knowledge_context_resolve(params).await,
|
||||
METHOD_KNOWLEDGE_CONTEXT_RUN_VALIDATE => {
|
||||
self.handle_knowledge_context_run_validate(params).await
|
||||
}
|
||||
METHOD_AUTOMATION_SCHEDULER_CONFIG_READ => {
|
||||
self.handle_automation_scheduler_config_read().await
|
||||
}
|
||||
@@ -272,6 +317,13 @@ impl RequestProcessor {
|
||||
METHOD_MCP_PROMPT_LIST => self.handle_mcp_prompt_list().await,
|
||||
METHOD_MCP_RESOURCE_LIST => self.handle_mcp_resource_list().await,
|
||||
METHOD_PROJECT_MEMORY_READ => self.handle_project_memory_read(params).await,
|
||||
METHOD_USAGE_STATS_READ => self.handle_usage_stats_read(params).await,
|
||||
METHOD_USAGE_STATS_MODEL_RANKING_LIST => {
|
||||
self.handle_usage_stats_model_ranking_list(params).await
|
||||
}
|
||||
METHOD_USAGE_STATS_DAILY_TRENDS_LIST => {
|
||||
self.handle_usage_stats_daily_trends_list(params).await
|
||||
}
|
||||
METHOD_MODEL_LIST => self.handle_model_list(params).await,
|
||||
METHOD_MODEL_PREFERENCES_LIST => self.handle_model_preferences_list().await,
|
||||
METHOD_MODEL_SYNC_STATE_READ => self.handle_model_sync_state_read().await,
|
||||
@@ -640,6 +692,104 @@ impl RequestProcessor {
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_pack_read(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeReadPackParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.read_knowledge_pack(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_source_import(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeImportSourceParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.import_knowledge_source(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_pack_compile(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeCompilePackParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.compile_knowledge_pack(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_pack_default_set(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeSetDefaultPackParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.set_default_knowledge_pack(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_pack_status_update(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeUpdatePackStatusParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.update_knowledge_pack_status(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_context_resolve(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeResolveContextParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.resolve_knowledge_context(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_knowledge_context_run_validate(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: KnowledgeValidateContextRunParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.validate_knowledge_context_run(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_automation_job_list(&self) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let response = self
|
||||
@@ -874,6 +1024,48 @@ impl RequestProcessor {
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_usage_stats_read(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: UsageStatsRangeParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.read_usage_stats(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_usage_stats_model_ranking_list(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: UsageStatsRangeParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.list_usage_stats_model_ranking(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_usage_stats_daily_trends_list(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: UsageStatsRangeParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.list_usage_stats_daily_trends(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_model_list(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
@@ -1301,6 +1493,62 @@ impl RequestProcessor {
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_file_system_create_file(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: FileSystemCreateFileParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.create_file(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_file_system_create_directory(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: FileSystemCreateDirectoryParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.create_directory(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_file_system_rename_file(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: FileSystemRenameFileParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.rename_file(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_file_system_delete_file(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<RpcDispatch, JsonRpcError> {
|
||||
self.ensure_initialized()?;
|
||||
let params: FileSystemDeleteFileParams = parse_params(params)?;
|
||||
let response = self
|
||||
.runtime
|
||||
.delete_file(params)
|
||||
.await
|
||||
.map_err(to_jsonrpc_error)?;
|
||||
dispatch_result(response)
|
||||
}
|
||||
|
||||
async fn handle_evidence_export(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
@@ -1724,7 +1972,7 @@ mod tests {
|
||||
let blocked = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(1),
|
||||
METHOD_FILE_SYSTEM_LIST_DIRECTORY,
|
||||
METHOD_FILE_SYSTEM_CREATE_FILE,
|
||||
Some(json!({ "path": "." })),
|
||||
))
|
||||
.await
|
||||
@@ -1760,6 +2008,9 @@ mod tests {
|
||||
let temp_dir = tempfile::tempdir().expect("temp dir");
|
||||
let file_path = temp_dir.path().join("README.md");
|
||||
std::fs::write(&file_path, "# Lime").expect("write file");
|
||||
let created_file_path = temp_dir.path().join("created.txt");
|
||||
let created_dir_path = temp_dir.path().join("created-dir");
|
||||
let renamed_file_path = temp_dir.path().join("renamed.txt");
|
||||
let expected_dir_path = std::fs::canonicalize(temp_dir.path())
|
||||
.expect("canonical temp dir")
|
||||
.to_string_lossy()
|
||||
@@ -1790,9 +2041,89 @@ mod tests {
|
||||
other => panic!("expected response, got {other:?}"),
|
||||
}
|
||||
|
||||
let create_file_messages = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(5),
|
||||
METHOD_FILE_SYSTEM_CREATE_FILE,
|
||||
Some(json!({ "path": created_file_path })),
|
||||
))
|
||||
.await
|
||||
.expect("create file response");
|
||||
assert!(matches!(
|
||||
&create_file_messages[0],
|
||||
JsonRpcMessage::Response(response)
|
||||
if response.result == serde_json::json!({})
|
||||
));
|
||||
assert!(created_file_path.is_file());
|
||||
|
||||
let create_directory_messages = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(6),
|
||||
METHOD_FILE_SYSTEM_CREATE_DIRECTORY,
|
||||
Some(json!({ "path": created_dir_path })),
|
||||
))
|
||||
.await
|
||||
.expect("create directory response");
|
||||
assert!(matches!(
|
||||
&create_directory_messages[0],
|
||||
JsonRpcMessage::Response(response)
|
||||
if response.result == serde_json::json!({})
|
||||
));
|
||||
assert!(created_dir_path.is_dir());
|
||||
|
||||
let rename_file_messages = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(7),
|
||||
METHOD_FILE_SYSTEM_RENAME_FILE,
|
||||
Some(json!({
|
||||
"oldPath": created_file_path,
|
||||
"newPath": renamed_file_path,
|
||||
})),
|
||||
))
|
||||
.await
|
||||
.expect("rename file response");
|
||||
assert!(matches!(
|
||||
&rename_file_messages[0],
|
||||
JsonRpcMessage::Response(response)
|
||||
if response.result == serde_json::json!({})
|
||||
));
|
||||
assert!(!created_file_path.exists());
|
||||
assert!(renamed_file_path.is_file());
|
||||
|
||||
let delete_file_messages = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(8),
|
||||
METHOD_FILE_SYSTEM_DELETE_FILE,
|
||||
Some(json!({
|
||||
"path": renamed_file_path,
|
||||
"recursive": false,
|
||||
})),
|
||||
))
|
||||
.await
|
||||
.expect("delete file response");
|
||||
assert!(matches!(
|
||||
&delete_file_messages[0],
|
||||
JsonRpcMessage::Response(response)
|
||||
if response.result == serde_json::json!({})
|
||||
));
|
||||
assert!(!renamed_file_path.exists());
|
||||
|
||||
processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(9),
|
||||
METHOD_FILE_SYSTEM_DELETE_FILE,
|
||||
Some(json!({
|
||||
"path": created_dir_path,
|
||||
"recursive": true,
|
||||
})),
|
||||
))
|
||||
.await
|
||||
.expect("delete directory response");
|
||||
assert!(!created_dir_path.exists());
|
||||
|
||||
let preview_messages = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(4),
|
||||
RequestId::Integer(10),
|
||||
METHOD_FILE_SYSTEM_READ_FILE_PREVIEW,
|
||||
Some(json!({
|
||||
"path": file_path,
|
||||
@@ -1882,6 +2213,90 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn usage_stats_methods_require_initialized_and_return_current_dto() {
|
||||
let processor = RequestProcessor::new(RuntimeCore::default());
|
||||
let blocked = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(1),
|
||||
METHOD_USAGE_STATS_READ,
|
||||
Some(json!({ "timeRange": "month" })),
|
||||
))
|
||||
.await
|
||||
.expect("blocked response");
|
||||
assert!(matches!(
|
||||
&blocked[0],
|
||||
JsonRpcMessage::Error(error) if error.error.code == error_codes::NOT_INITIALIZED
|
||||
));
|
||||
|
||||
processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
RequestId::Integer(2),
|
||||
METHOD_INITIALIZE,
|
||||
Some(
|
||||
serde_json::to_value(InitializeParams {
|
||||
client_info: ClientInfo {
|
||||
name: "test-client".to_string(),
|
||||
title: None,
|
||||
version: None,
|
||||
},
|
||||
capabilities: ClientCapabilities::default(),
|
||||
})
|
||||
.expect("initialize params"),
|
||||
),
|
||||
))
|
||||
.await
|
||||
.expect("initialize");
|
||||
processor.handle_notification(JsonRpcNotification::new(
|
||||
METHOD_INITIALIZED,
|
||||
Some(json!({})),
|
||||
));
|
||||
|
||||
let cases = [
|
||||
(
|
||||
RequestId::Integer(3),
|
||||
METHOD_USAGE_STATS_READ,
|
||||
"stats",
|
||||
"object",
|
||||
),
|
||||
(
|
||||
RequestId::Integer(4),
|
||||
METHOD_USAGE_STATS_MODEL_RANKING_LIST,
|
||||
"ranking",
|
||||
"array",
|
||||
),
|
||||
(
|
||||
RequestId::Integer(5),
|
||||
METHOD_USAGE_STATS_DAILY_TRENDS_LIST,
|
||||
"trends",
|
||||
"array",
|
||||
),
|
||||
];
|
||||
|
||||
for (id, method, field, expected_kind) in cases {
|
||||
let messages = processor
|
||||
.handle_request(JsonRpcRequest::new(
|
||||
id,
|
||||
method,
|
||||
Some(json!({ "timeRange": "month" })),
|
||||
))
|
||||
.await
|
||||
.expect("usage stats response");
|
||||
|
||||
match &messages[0] {
|
||||
JsonRpcMessage::Response(response) => {
|
||||
let value = response.result.get(field).expect("response field");
|
||||
match expected_kind {
|
||||
"object" => assert!(value.is_object()),
|
||||
"array" => assert!(value.is_array()),
|
||||
other => panic!("unexpected expected kind {other}"),
|
||||
}
|
||||
}
|
||||
other => panic!("expected response, got {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn evidence_export_requires_initialized_and_returns_read_model_snapshot() {
|
||||
let runtime = RuntimeCore::default();
|
||||
|
||||
@@ -2,8 +2,20 @@ use crate::capability::capability_descriptor_allows_agent_turn_start;
|
||||
use crate::CapabilityInventorySource;
|
||||
use crate::CapabilityListContext;
|
||||
use crate::CapabilitySource;
|
||||
use crate::KnowledgeBuilderRuntimeExecutor;
|
||||
use crate::NativeKnowledgeBuilderRuntimeExecutor;
|
||||
use app_server_protocol::error_codes;
|
||||
use app_server_protocol::AgentAppFetchCloudPackageParams;
|
||||
use app_server_protocol::AgentAppInstalledDisabledSetParams;
|
||||
use app_server_protocol::AgentAppInstalledListResponse;
|
||||
use app_server_protocol::AgentAppInstalledSaveParams;
|
||||
use app_server_protocol::AgentAppLocalPackageInspectParams;
|
||||
use app_server_protocol::AgentAppLocalPackageInspectResponse;
|
||||
use app_server_protocol::AgentAppPackageCacheEntry;
|
||||
use app_server_protocol::AgentAppUninstallParams;
|
||||
use app_server_protocol::AgentAppUninstallRehearsalParams;
|
||||
use app_server_protocol::AgentAppUninstallRehearsalResponse;
|
||||
use app_server_protocol::AgentAppUninstallResponse;
|
||||
use app_server_protocol::AgentAppUiRuntimeStartParams;
|
||||
use app_server_protocol::AgentAppUiRuntimeStatusParams;
|
||||
use app_server_protocol::AgentAppUiRuntimeStatusResponse;
|
||||
@@ -68,14 +80,33 @@ use app_server_protocol::ConnectRelayApiKeySaveResponse;
|
||||
use app_server_protocol::EvidenceExportParams;
|
||||
use app_server_protocol::EvidenceExportResponse;
|
||||
use app_server_protocol::EvidencePackSummary;
|
||||
use app_server_protocol::FileSystemCreateDirectoryParams;
|
||||
use app_server_protocol::FileSystemCreateFileParams;
|
||||
use app_server_protocol::FileSystemDeleteFileParams;
|
||||
use app_server_protocol::FileSystemDirectoryListing;
|
||||
use app_server_protocol::FileSystemFileEntry;
|
||||
use app_server_protocol::FileSystemFilePreview;
|
||||
use app_server_protocol::FileSystemListDirectoryParams;
|
||||
use app_server_protocol::FileSystemMutationResponse;
|
||||
use app_server_protocol::FileSystemReadFilePreviewParams;
|
||||
use app_server_protocol::FileSystemRenameFileParams;
|
||||
use app_server_protocol::JsonRpcError;
|
||||
use app_server_protocol::KnowledgeCompilePackParams;
|
||||
use app_server_protocol::KnowledgeCompilePackResponse;
|
||||
use app_server_protocol::KnowledgeContextResolutionResponse;
|
||||
use app_server_protocol::KnowledgeImportSourceParams;
|
||||
use app_server_protocol::KnowledgeImportSourceResponse;
|
||||
use app_server_protocol::KnowledgeListPacksParams;
|
||||
use app_server_protocol::KnowledgeListPacksResponse;
|
||||
use app_server_protocol::KnowledgeReadPackParams;
|
||||
use app_server_protocol::KnowledgeReadPackResponse;
|
||||
use app_server_protocol::KnowledgeResolveContextParams;
|
||||
use app_server_protocol::KnowledgeSetDefaultPackParams;
|
||||
use app_server_protocol::KnowledgeSetDefaultPackResponse;
|
||||
use app_server_protocol::KnowledgeUpdatePackStatusParams;
|
||||
use app_server_protocol::KnowledgeUpdatePackStatusResponse;
|
||||
use app_server_protocol::KnowledgeValidateContextRunParams;
|
||||
use app_server_protocol::KnowledgeValidateContextRunResponse;
|
||||
use app_server_protocol::McpPromptListResponse;
|
||||
use app_server_protocol::McpResourceListResponse;
|
||||
use app_server_protocol::McpServerListResponse;
|
||||
@@ -125,6 +156,10 @@ use app_server_protocol::ProjectMemoryReadResponse;
|
||||
use app_server_protocol::SkillListResponse;
|
||||
use app_server_protocol::SkillReadParams;
|
||||
use app_server_protocol::SkillReadResponse;
|
||||
use app_server_protocol::UsageStatsDailyTrendsListResponse;
|
||||
use app_server_protocol::UsageStatsModelRankingListResponse;
|
||||
use app_server_protocol::UsageStatsRangeParams;
|
||||
use app_server_protocol::UsageStatsReadResponse;
|
||||
use app_server_protocol::WorkspaceEnsureParams;
|
||||
use app_server_protocol::WorkspaceEnsureReadyResponse;
|
||||
use app_server_protocol::WorkspaceListResponse;
|
||||
@@ -336,11 +371,76 @@ pub trait AppDataSource: Send + Sync {
|
||||
&self,
|
||||
) -> Result<AgentAppInstalledListResponse, RuntimeCoreError>;
|
||||
|
||||
async fn inspect_agent_app_local_package(
|
||||
&self,
|
||||
params: AgentAppLocalPackageInspectParams,
|
||||
) -> Result<AgentAppLocalPackageInspectResponse, RuntimeCoreError>;
|
||||
|
||||
async fn fetch_agent_app_cloud_package(
|
||||
&self,
|
||||
params: AgentAppFetchCloudPackageParams,
|
||||
) -> Result<AgentAppPackageCacheEntry, RuntimeCoreError>;
|
||||
|
||||
async fn save_agent_app_installed(
|
||||
&self,
|
||||
params: AgentAppInstalledSaveParams,
|
||||
) -> Result<serde_json::Value, RuntimeCoreError>;
|
||||
|
||||
async fn set_agent_app_installed_disabled(
|
||||
&self,
|
||||
params: AgentAppInstalledDisabledSetParams,
|
||||
) -> Result<AgentAppInstalledListResponse, RuntimeCoreError>;
|
||||
|
||||
async fn preview_agent_app_uninstall(
|
||||
&self,
|
||||
params: AgentAppUninstallRehearsalParams,
|
||||
) -> Result<AgentAppUninstallRehearsalResponse, RuntimeCoreError>;
|
||||
|
||||
async fn uninstall_agent_app(
|
||||
&self,
|
||||
params: AgentAppUninstallParams,
|
||||
) -> Result<AgentAppUninstallResponse, RuntimeCoreError>;
|
||||
|
||||
async fn list_knowledge_packs(
|
||||
&self,
|
||||
params: KnowledgeListPacksParams,
|
||||
) -> Result<KnowledgeListPacksResponse, RuntimeCoreError>;
|
||||
|
||||
async fn read_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> Result<KnowledgeReadPackResponse, RuntimeCoreError>;
|
||||
|
||||
async fn import_knowledge_source(
|
||||
&self,
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> Result<KnowledgeImportSourceResponse, RuntimeCoreError>;
|
||||
|
||||
async fn compile_knowledge_pack(
|
||||
&self,
|
||||
request: lime_knowledge::KnowledgeCompilePackRequest,
|
||||
) -> Result<KnowledgeCompilePackResponse, RuntimeCoreError>;
|
||||
|
||||
async fn set_default_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<KnowledgeSetDefaultPackResponse, RuntimeCoreError>;
|
||||
|
||||
async fn update_knowledge_pack_status(
|
||||
&self,
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<KnowledgeUpdatePackStatusResponse, RuntimeCoreError>;
|
||||
|
||||
async fn resolve_knowledge_context(
|
||||
&self,
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> Result<KnowledgeContextResolutionResponse, RuntimeCoreError>;
|
||||
|
||||
async fn validate_knowledge_context_run(
|
||||
&self,
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<KnowledgeValidateContextRunResponse, RuntimeCoreError>;
|
||||
|
||||
async fn list_automation_jobs(&self) -> Result<AutomationJobListResponse, RuntimeCoreError>;
|
||||
|
||||
async fn list_mcp_servers(&self) -> Result<McpServerListResponse, RuntimeCoreError> {
|
||||
@@ -488,6 +588,21 @@ pub trait AppDataSource: Send + Sync {
|
||||
params: ProjectMemoryReadParams,
|
||||
) -> Result<ProjectMemoryReadResponse, RuntimeCoreError>;
|
||||
|
||||
async fn read_usage_stats(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsReadResponse, RuntimeCoreError>;
|
||||
|
||||
async fn list_usage_stats_model_ranking(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsModelRankingListResponse, RuntimeCoreError>;
|
||||
|
||||
async fn list_usage_stats_daily_trends(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsDailyTrendsListResponse, RuntimeCoreError>;
|
||||
|
||||
async fn list_models(
|
||||
&self,
|
||||
params: ModelListParams,
|
||||
@@ -912,6 +1027,69 @@ impl AppDataSource for NoopAppDataSource {
|
||||
Ok(KnowledgeListPacksResponse::default())
|
||||
}
|
||||
|
||||
async fn read_knowledge_pack(
|
||||
&self,
|
||||
_params: KnowledgeReadPackParams,
|
||||
) -> Result<KnowledgeReadPackResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgePack/read is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn import_knowledge_source(
|
||||
&self,
|
||||
_params: KnowledgeImportSourceParams,
|
||||
) -> Result<KnowledgeImportSourceResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgePack/source/import is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn compile_knowledge_pack(
|
||||
&self,
|
||||
_request: lime_knowledge::KnowledgeCompilePackRequest,
|
||||
) -> Result<KnowledgeCompilePackResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgePack/compile is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn set_default_knowledge_pack(
|
||||
&self,
|
||||
_params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<KnowledgeSetDefaultPackResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgePack/default/set is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn update_knowledge_pack_status(
|
||||
&self,
|
||||
_params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<KnowledgeUpdatePackStatusResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgePack/status/update is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn resolve_knowledge_context(
|
||||
&self,
|
||||
_params: KnowledgeResolveContextParams,
|
||||
) -> Result<KnowledgeContextResolutionResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgeContext/resolve is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn validate_knowledge_context_run(
|
||||
&self,
|
||||
_params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<KnowledgeValidateContextRunResponse, RuntimeCoreError> {
|
||||
Err(RuntimeCoreError::Backend(
|
||||
"knowledgeContextRun/validate is not available without an app data source".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn list_automation_jobs(&self) -> Result<AutomationJobListResponse, RuntimeCoreError> {
|
||||
Ok(AutomationJobListResponse::default())
|
||||
}
|
||||
@@ -945,6 +1123,27 @@ impl AppDataSource for NoopAppDataSource {
|
||||
Ok(ProjectMemoryReadResponse::default())
|
||||
}
|
||||
|
||||
async fn read_usage_stats(
|
||||
&self,
|
||||
_params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsReadResponse, RuntimeCoreError> {
|
||||
Ok(UsageStatsReadResponse::default())
|
||||
}
|
||||
|
||||
async fn list_usage_stats_model_ranking(
|
||||
&self,
|
||||
_params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsModelRankingListResponse, RuntimeCoreError> {
|
||||
Ok(UsageStatsModelRankingListResponse::default())
|
||||
}
|
||||
|
||||
async fn list_usage_stats_daily_trends(
|
||||
&self,
|
||||
_params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsDailyTrendsListResponse, RuntimeCoreError> {
|
||||
Ok(UsageStatsDailyTrendsListResponse::default())
|
||||
}
|
||||
|
||||
async fn list_models(
|
||||
&self,
|
||||
_params: ModelListParams,
|
||||
@@ -1154,6 +1353,7 @@ pub struct RuntimeCore {
|
||||
capability_source: Arc<dyn CapabilitySource>,
|
||||
artifact_content_provider: Arc<dyn ArtifactContentProvider>,
|
||||
evidence_export_provider: Arc<dyn EvidenceExportProvider>,
|
||||
knowledge_builder_runtime_executor: Arc<dyn KnowledgeBuilderRuntimeExecutor>,
|
||||
app_data_source: Arc<dyn AppDataSource>,
|
||||
}
|
||||
|
||||
@@ -1291,6 +1491,19 @@ fn file_system_file_preview_from_service(
|
||||
}
|
||||
}
|
||||
|
||||
fn file_system_required_path(
|
||||
path: String,
|
||||
method: &'static str,
|
||||
) -> Result<String, RuntimeCoreError> {
|
||||
let path = path.trim();
|
||||
if path.is_empty() {
|
||||
return Err(RuntimeCoreError::Backend(format!(
|
||||
"path is required for {method}"
|
||||
)));
|
||||
}
|
||||
Ok(path.to_string())
|
||||
}
|
||||
|
||||
fn stored_session_hidden_from_user_recents(stored: &StoredSession) -> bool {
|
||||
stored
|
||||
.session
|
||||
@@ -1493,6 +1706,7 @@ impl RuntimeCore {
|
||||
capability_source,
|
||||
artifact_content_provider,
|
||||
evidence_export_provider,
|
||||
knowledge_builder_runtime_executor: Arc::new(NativeKnowledgeBuilderRuntimeExecutor::new()),
|
||||
app_data_source: Arc::new(NoopAppDataSource),
|
||||
}
|
||||
}
|
||||
@@ -1502,6 +1716,14 @@ impl RuntimeCore {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_knowledge_builder_runtime_executor(
|
||||
mut self,
|
||||
executor: Arc<dyn KnowledgeBuilderRuntimeExecutor>,
|
||||
) -> Self {
|
||||
self.knowledge_builder_runtime_executor = executor;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn event_appender(&self) -> RuntimeCoreEventAppender {
|
||||
RuntimeCoreEventAppender {
|
||||
state: self.state.clone(),
|
||||
@@ -1813,6 +2035,72 @@ impl RuntimeCore {
|
||||
Ok(file_system_file_preview_from_service(preview))
|
||||
}
|
||||
|
||||
pub async fn create_file(
|
||||
&self,
|
||||
params: FileSystemCreateFileParams,
|
||||
) -> Result<FileSystemMutationResponse, RuntimeCoreError> {
|
||||
let path = file_system_required_path(params.path, "fileSystem/createFile")?;
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
handle.block_on(lime_services::file_browser_service::create_file(path))
|
||||
})
|
||||
.await
|
||||
.map_err(|error| RuntimeCoreError::Backend(format!("文件创建任务失败: {error}")))?
|
||||
.map_err(RuntimeCoreError::Backend)?;
|
||||
Ok(FileSystemMutationResponse::default())
|
||||
}
|
||||
|
||||
pub async fn create_directory(
|
||||
&self,
|
||||
params: FileSystemCreateDirectoryParams,
|
||||
) -> Result<FileSystemMutationResponse, RuntimeCoreError> {
|
||||
let path = file_system_required_path(params.path, "fileSystem/createDirectory")?;
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
handle.block_on(lime_services::file_browser_service::create_directory(path))
|
||||
})
|
||||
.await
|
||||
.map_err(|error| RuntimeCoreError::Backend(format!("目录创建任务失败: {error}")))?
|
||||
.map_err(RuntimeCoreError::Backend)?;
|
||||
Ok(FileSystemMutationResponse::default())
|
||||
}
|
||||
|
||||
pub async fn rename_file(
|
||||
&self,
|
||||
params: FileSystemRenameFileParams,
|
||||
) -> Result<FileSystemMutationResponse, RuntimeCoreError> {
|
||||
let old_path = file_system_required_path(params.old_path, "fileSystem/renameFile.oldPath")?;
|
||||
let new_path = file_system_required_path(params.new_path, "fileSystem/renameFile.newPath")?;
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
handle.block_on(lime_services::file_browser_service::rename_file(
|
||||
old_path, new_path,
|
||||
))
|
||||
})
|
||||
.await
|
||||
.map_err(|error| RuntimeCoreError::Backend(format!("文件重命名任务失败: {error}")))?
|
||||
.map_err(RuntimeCoreError::Backend)?;
|
||||
Ok(FileSystemMutationResponse::default())
|
||||
}
|
||||
|
||||
pub async fn delete_file(
|
||||
&self,
|
||||
params: FileSystemDeleteFileParams,
|
||||
) -> Result<FileSystemMutationResponse, RuntimeCoreError> {
|
||||
let path = file_system_required_path(params.path, "fileSystem/deleteFile")?;
|
||||
let recursive = params.recursive.unwrap_or(false);
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
handle.block_on(lime_services::file_browser_service::delete_file(
|
||||
path, recursive,
|
||||
))
|
||||
})
|
||||
.await
|
||||
.map_err(|error| RuntimeCoreError::Backend(format!("文件删除任务失败: {error}")))?
|
||||
.map_err(RuntimeCoreError::Backend)?;
|
||||
Ok(FileSystemMutationResponse::default())
|
||||
}
|
||||
|
||||
pub async fn list_workspace_skill_bindings(
|
||||
&self,
|
||||
params: WorkspaceSkillBindingsListParams,
|
||||
@@ -1943,6 +2231,90 @@ impl RuntimeCore {
|
||||
self.app_data_source.list_knowledge_packs(params).await
|
||||
}
|
||||
|
||||
pub async fn read_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> Result<KnowledgeReadPackResponse, RuntimeCoreError> {
|
||||
self.app_data_source.read_knowledge_pack(params).await
|
||||
}
|
||||
|
||||
pub async fn import_knowledge_source(
|
||||
&self,
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> Result<KnowledgeImportSourceResponse, RuntimeCoreError> {
|
||||
self.app_data_source.import_knowledge_source(params).await
|
||||
}
|
||||
|
||||
pub async fn compile_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeCompilePackParams,
|
||||
) -> Result<KnowledgeCompilePackResponse, RuntimeCoreError> {
|
||||
let mut request = Self::to_lime_knowledge_compile_pack_request(params)?;
|
||||
if let Some(plan) = lime_knowledge::plan_knowledge_builder_runtime(&request)
|
||||
.map_err(RuntimeCoreError::Backend)?
|
||||
{
|
||||
request.builder_execution = Some(
|
||||
self.knowledge_builder_runtime_executor
|
||||
.execute(plan)
|
||||
.await?,
|
||||
);
|
||||
}
|
||||
self.app_data_source.compile_knowledge_pack(request).await
|
||||
}
|
||||
|
||||
fn to_lime_knowledge_compile_pack_request(
|
||||
params: KnowledgeCompilePackParams,
|
||||
) -> Result<lime_knowledge::KnowledgeCompilePackRequest, RuntimeCoreError> {
|
||||
Ok(lime_knowledge::KnowledgeCompilePackRequest {
|
||||
working_dir: params.working_dir,
|
||||
name: params.name,
|
||||
builder_runtime: params
|
||||
.builder_runtime
|
||||
.map(serde_json::from_value)
|
||||
.transpose()
|
||||
.map_err(|error| {
|
||||
RuntimeCoreError::Backend(format!(
|
||||
"knowledgePack/compile builderRuntime 参数无效: {error}"
|
||||
))
|
||||
})?,
|
||||
builder_execution: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn set_default_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<KnowledgeSetDefaultPackResponse, RuntimeCoreError> {
|
||||
self.app_data_source
|
||||
.set_default_knowledge_pack(params)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_knowledge_pack_status(
|
||||
&self,
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<KnowledgeUpdatePackStatusResponse, RuntimeCoreError> {
|
||||
self.app_data_source
|
||||
.update_knowledge_pack_status(params)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn resolve_knowledge_context(
|
||||
&self,
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> Result<KnowledgeContextResolutionResponse, RuntimeCoreError> {
|
||||
self.app_data_source.resolve_knowledge_context(params).await
|
||||
}
|
||||
|
||||
pub async fn validate_knowledge_context_run(
|
||||
&self,
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<KnowledgeValidateContextRunResponse, RuntimeCoreError> {
|
||||
self.app_data_source
|
||||
.validate_knowledge_context_run(params)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_automation_jobs(
|
||||
&self,
|
||||
) -> Result<AutomationJobListResponse, RuntimeCoreError> {
|
||||
@@ -2072,6 +2444,31 @@ impl RuntimeCore {
|
||||
self.app_data_source.read_project_memory(params).await
|
||||
}
|
||||
|
||||
pub async fn read_usage_stats(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsReadResponse, RuntimeCoreError> {
|
||||
self.app_data_source.read_usage_stats(params).await
|
||||
}
|
||||
|
||||
pub async fn list_usage_stats_model_ranking(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsModelRankingListResponse, RuntimeCoreError> {
|
||||
self.app_data_source
|
||||
.list_usage_stats_model_ranking(params)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_usage_stats_daily_trends(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsDailyTrendsListResponse, RuntimeCoreError> {
|
||||
self.app_data_source
|
||||
.list_usage_stats_daily_trends(params)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_models(
|
||||
&self,
|
||||
params: ModelListParams,
|
||||
@@ -4550,6 +4947,57 @@ mod tests {
|
||||
NoopAppDataSource.list_knowledge_packs(params).await
|
||||
}
|
||||
|
||||
async fn read_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> Result<KnowledgeReadPackResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.read_knowledge_pack(params).await
|
||||
}
|
||||
|
||||
async fn import_knowledge_source(
|
||||
&self,
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> Result<KnowledgeImportSourceResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.import_knowledge_source(params).await
|
||||
}
|
||||
|
||||
async fn compile_knowledge_pack(
|
||||
&self,
|
||||
request: lime_knowledge::KnowledgeCompilePackRequest,
|
||||
) -> Result<KnowledgeCompilePackResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.compile_knowledge_pack(request).await
|
||||
}
|
||||
|
||||
async fn set_default_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<KnowledgeSetDefaultPackResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.set_default_knowledge_pack(params).await
|
||||
}
|
||||
|
||||
async fn update_knowledge_pack_status(
|
||||
&self,
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<KnowledgeUpdatePackStatusResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.update_knowledge_pack_status(params).await
|
||||
}
|
||||
|
||||
async fn resolve_knowledge_context(
|
||||
&self,
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> Result<KnowledgeContextResolutionResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.resolve_knowledge_context(params).await
|
||||
}
|
||||
|
||||
async fn validate_knowledge_context_run(
|
||||
&self,
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<KnowledgeValidateContextRunResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource
|
||||
.validate_knowledge_context_run(params)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_automation_jobs(
|
||||
&self,
|
||||
) -> Result<AutomationJobListResponse, RuntimeCoreError> {
|
||||
@@ -4563,6 +5011,31 @@ mod tests {
|
||||
NoopAppDataSource.read_project_memory(params).await
|
||||
}
|
||||
|
||||
async fn read_usage_stats(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsReadResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.read_usage_stats(params).await
|
||||
}
|
||||
|
||||
async fn list_usage_stats_model_ranking(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsModelRankingListResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource
|
||||
.list_usage_stats_model_ranking(params)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_usage_stats_daily_trends(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsDailyTrendsListResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource
|
||||
.list_usage_stats_daily_trends(params)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_models(
|
||||
&self,
|
||||
params: ModelListParams,
|
||||
|
||||
@@ -269,6 +269,57 @@ impl AppDataSource for PersistedSessionArchiveDataSource {
|
||||
NoopAppDataSource.list_knowledge_packs(params).await
|
||||
}
|
||||
|
||||
async fn read_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeReadPackParams,
|
||||
) -> Result<KnowledgeReadPackResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.read_knowledge_pack(params).await
|
||||
}
|
||||
|
||||
async fn import_knowledge_source(
|
||||
&self,
|
||||
params: KnowledgeImportSourceParams,
|
||||
) -> Result<KnowledgeImportSourceResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.import_knowledge_source(params).await
|
||||
}
|
||||
|
||||
async fn compile_knowledge_pack(
|
||||
&self,
|
||||
request: lime_knowledge::KnowledgeCompilePackRequest,
|
||||
) -> Result<KnowledgeCompilePackResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.compile_knowledge_pack(request).await
|
||||
}
|
||||
|
||||
async fn set_default_knowledge_pack(
|
||||
&self,
|
||||
params: KnowledgeSetDefaultPackParams,
|
||||
) -> Result<KnowledgeSetDefaultPackResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.set_default_knowledge_pack(params).await
|
||||
}
|
||||
|
||||
async fn update_knowledge_pack_status(
|
||||
&self,
|
||||
params: KnowledgeUpdatePackStatusParams,
|
||||
) -> Result<KnowledgeUpdatePackStatusResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.update_knowledge_pack_status(params).await
|
||||
}
|
||||
|
||||
async fn resolve_knowledge_context(
|
||||
&self,
|
||||
params: KnowledgeResolveContextParams,
|
||||
) -> Result<KnowledgeContextResolutionResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.resolve_knowledge_context(params).await
|
||||
}
|
||||
|
||||
async fn validate_knowledge_context_run(
|
||||
&self,
|
||||
params: KnowledgeValidateContextRunParams,
|
||||
) -> Result<KnowledgeValidateContextRunResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource
|
||||
.validate_knowledge_context_run(params)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_automation_jobs(&self) -> Result<AutomationJobListResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.list_automation_jobs().await
|
||||
}
|
||||
@@ -280,6 +331,31 @@ impl AppDataSource for PersistedSessionArchiveDataSource {
|
||||
NoopAppDataSource.read_project_memory(params).await
|
||||
}
|
||||
|
||||
async fn read_usage_stats(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsReadResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource.read_usage_stats(params).await
|
||||
}
|
||||
|
||||
async fn list_usage_stats_model_ranking(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsModelRankingListResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource
|
||||
.list_usage_stats_model_ranking(params)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_usage_stats_daily_trends(
|
||||
&self,
|
||||
params: UsageStatsRangeParams,
|
||||
) -> Result<UsageStatsDailyTrendsListResponse, RuntimeCoreError> {
|
||||
NoopAppDataSource
|
||||
.list_usage_stats_daily_trends(params)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn list_models(
|
||||
&self,
|
||||
params: ModelListParams,
|
||||
|
||||
@@ -65,6 +65,7 @@ pub mod mcp_service;
|
||||
pub mod model_registry_service;
|
||||
pub mod persona_service;
|
||||
pub mod prompt_service;
|
||||
pub mod usage_statistics_service;
|
||||
// 依赖其他 services 的服务
|
||||
pub mod ai_summary_service;
|
||||
pub mod project_context_builder;
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
//! 对话与模型使用统计服务。
|
||||
|
||||
use chrono::{DateTime, Datelike, Duration, Local, TimeZone, Timelike};
|
||||
use lime_core::database::dao::agent::{AgentDao, AgentModelPatternMatch};
|
||||
use lime_core::database::dao::orchestrator::OrchestratorDao;
|
||||
use lime_core::database::ConversationWindowSummary;
|
||||
use rusqlite::Connection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const GENERAL_MODE_PATTERN: &str = "general:%";
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UsageStatsResponse {
|
||||
pub total_conversations: u32,
|
||||
pub total_messages: u32,
|
||||
pub total_tokens: u64,
|
||||
pub total_time_minutes: u32,
|
||||
pub monthly_conversations: u32,
|
||||
pub monthly_messages: u32,
|
||||
pub monthly_tokens: u64,
|
||||
pub today_conversations: u32,
|
||||
pub today_messages: u32,
|
||||
pub today_tokens: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ModelUsage {
|
||||
pub model: String,
|
||||
pub conversations: u32,
|
||||
pub tokens: u64,
|
||||
pub percentage: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DailyUsage {
|
||||
pub date: String,
|
||||
pub conversations: u32,
|
||||
pub tokens: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct ConversationStats {
|
||||
total_conversations: u32,
|
||||
total_messages: u32,
|
||||
monthly_conversations: u32,
|
||||
monthly_messages: u32,
|
||||
today_conversations: u32,
|
||||
today_messages: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct ConversationWindowTriplet {
|
||||
total: ConversationWindowSummary,
|
||||
monthly: ConversationWindowSummary,
|
||||
today: ConversationWindowSummary,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct TokenStats {
|
||||
total_tokens: u64,
|
||||
monthly_tokens: u64,
|
||||
today_tokens: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RawModelUsage {
|
||||
model: String,
|
||||
conversations: u64,
|
||||
tokens: u64,
|
||||
}
|
||||
|
||||
pub fn get_usage_stats_from_db(
|
||||
time_range: &str,
|
||||
conn: &Connection,
|
||||
) -> Result<UsageStatsResponse, String> {
|
||||
validate_time_range(time_range)?;
|
||||
|
||||
let now = Local::now();
|
||||
let today_start = start_of_day(now);
|
||||
let month_start = start_of_month(now);
|
||||
|
||||
let general_windows =
|
||||
build_window_triplet(conn, summarize_general_window, &today_start, &month_start)?;
|
||||
let agent_windows =
|
||||
build_window_triplet(conn, summarize_agent_window, &today_start, &month_start)?;
|
||||
let general_stats = build_conversation_stats(general_windows);
|
||||
let agent_stats = build_conversation_stats(agent_windows);
|
||||
|
||||
let token_stats = query_token_stats(
|
||||
conn,
|
||||
&today_start,
|
||||
&month_start,
|
||||
general_windows,
|
||||
agent_windows,
|
||||
)?;
|
||||
|
||||
Ok(UsageStatsResponse {
|
||||
total_conversations: general_stats.total_conversations + agent_stats.total_conversations,
|
||||
total_messages: general_stats.total_messages + agent_stats.total_messages,
|
||||
total_tokens: token_stats.total_tokens,
|
||||
total_time_minutes: (token_stats.total_tokens / 600) as u32,
|
||||
monthly_conversations: general_stats.monthly_conversations
|
||||
+ agent_stats.monthly_conversations,
|
||||
monthly_messages: general_stats.monthly_messages + agent_stats.monthly_messages,
|
||||
monthly_tokens: token_stats.monthly_tokens,
|
||||
today_conversations: general_stats.today_conversations + agent_stats.today_conversations,
|
||||
today_messages: general_stats.today_messages + agent_stats.today_messages,
|
||||
today_tokens: token_stats.today_tokens,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_model_usage_ranking_from_db(
|
||||
time_range: &str,
|
||||
conn: &Connection,
|
||||
) -> Result<Vec<ModelUsage>, String> {
|
||||
let range_start = resolve_range_start(time_range)?;
|
||||
|
||||
let mut usages = query_model_usage_from_stats_table(conn, range_start)?;
|
||||
if usages.is_empty() {
|
||||
usages = query_model_usage_from_agent_messages(conn, range_start)?;
|
||||
}
|
||||
|
||||
Ok(build_model_usage_response(usages))
|
||||
}
|
||||
|
||||
pub fn get_daily_usage_trends_from_db(
|
||||
time_range: &str,
|
||||
conn: &Connection,
|
||||
) -> Result<Vec<DailyUsage>, String> {
|
||||
let days = resolve_range_days(time_range)?;
|
||||
let use_actual_tokens = OrchestratorDao::has_model_usage_stats(conn)
|
||||
.map_err(|e| format!("检查 model_usage_stats 失败: {e}"))?;
|
||||
|
||||
let mut daily_usage = Vec::new();
|
||||
for i in (0..days).rev() {
|
||||
let date = Local::now() - Duration::days(i);
|
||||
let day_start = start_of_day(date);
|
||||
let day_end = day_start + Duration::days(1);
|
||||
let day_start_ts = day_start.timestamp_millis();
|
||||
let day_end_ts = day_end.timestamp_millis();
|
||||
let day_key = day_start.format("%Y-%m-%d").to_string();
|
||||
let general_window = summarize_general_window(conn, Some(day_start_ts), Some(day_end_ts))
|
||||
.map_err(|e| format!("查询通用日摘要失败: {e}"))?;
|
||||
let agent_window = summarize_agent_window(conn, Some(day_start_ts), Some(day_end_ts))
|
||||
.map_err(|e| format!("查询 Agent 日摘要失败: {e}"))?;
|
||||
|
||||
let tokens = if use_actual_tokens {
|
||||
let day_tokens = OrchestratorDao::get_model_usage_tokens_on(conn, &day_key)
|
||||
.map_err(|e| format!("查询模型日 Token 失败: {e}"))?;
|
||||
clamp_i64_to_u64(day_tokens)
|
||||
} else {
|
||||
chars_to_estimated_tokens(general_window.content_chars + agent_window.content_chars)
|
||||
};
|
||||
|
||||
daily_usage.push(DailyUsage {
|
||||
date: day_key,
|
||||
conversations: clamp_i64_to_u32(
|
||||
general_window.session_count + agent_window.session_count,
|
||||
),
|
||||
tokens,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(daily_usage)
|
||||
}
|
||||
|
||||
fn validate_time_range(time_range: &str) -> Result<(), String> {
|
||||
match time_range {
|
||||
"week" | "month" | "all" => Ok(()),
|
||||
_ => Err("无效的时间范围".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_range_days(time_range: &str) -> Result<i64, String> {
|
||||
match time_range {
|
||||
"week" => Ok(7),
|
||||
"month" => Ok(30),
|
||||
"all" => Ok(90),
|
||||
_ => Err("无效的时间范围".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_range_start(time_range: &str) -> Result<Option<DateTime<Local>>, String> {
|
||||
let now = Local::now();
|
||||
match time_range {
|
||||
"week" => Ok(Some(now - Duration::days(7))),
|
||||
"month" => Ok(Some(now - Duration::days(30))),
|
||||
"all" => Ok(None),
|
||||
_ => Err("无效的时间范围".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn start_of_day(now: DateTime<Local>) -> DateTime<Local> {
|
||||
now.with_hour(0)
|
||||
.and_then(|dt| dt.with_minute(0))
|
||||
.and_then(|dt| dt.with_second(0))
|
||||
.and_then(|dt| dt.with_nanosecond(0))
|
||||
.unwrap_or(now)
|
||||
}
|
||||
|
||||
fn start_of_month(now: DateTime<Local>) -> DateTime<Local> {
|
||||
now.with_day(1)
|
||||
.and_then(|dt| dt.with_hour(0))
|
||||
.and_then(|dt| dt.with_minute(0))
|
||||
.and_then(|dt| dt.with_second(0))
|
||||
.and_then(|dt| dt.with_nanosecond(0))
|
||||
.unwrap_or_else(|| start_of_day(now))
|
||||
}
|
||||
|
||||
fn clamp_i64_to_u32(value: i64) -> u32 {
|
||||
value.clamp(0, u32::MAX as i64) as u32
|
||||
}
|
||||
|
||||
fn clamp_i64_to_u64(value: i64) -> u64 {
|
||||
value.max(0) as u64
|
||||
}
|
||||
|
||||
fn chars_to_estimated_tokens(chars: i64) -> u64 {
|
||||
if chars <= 0 {
|
||||
return 0;
|
||||
}
|
||||
((chars as f64) / 4.0).ceil() as u64
|
||||
}
|
||||
|
||||
fn format_sqlite_datetime(timestamp_ms: i64) -> String {
|
||||
Local
|
||||
.timestamp_millis_opt(timestamp_ms)
|
||||
.single()
|
||||
.map(|dt| dt.format("%Y-%m-%d %H:%M:%S").to_string())
|
||||
.unwrap_or_else(|| Local::now().format("%Y-%m-%d %H:%M:%S").to_string())
|
||||
}
|
||||
|
||||
fn summarize_unified_window(
|
||||
conn: &Connection,
|
||||
match_mode: AgentModelPatternMatch,
|
||||
from_timestamp_ms: Option<i64>,
|
||||
to_timestamp_ms: Option<i64>,
|
||||
) -> Result<ConversationWindowSummary, String> {
|
||||
let from_text = from_timestamp_ms.map(format_sqlite_datetime);
|
||||
let to_text = to_timestamp_ms.map(format_sqlite_datetime);
|
||||
|
||||
AgentDao::summarize_by_model_pattern(
|
||||
conn,
|
||||
GENERAL_MODE_PATTERN,
|
||||
match_mode,
|
||||
from_text.as_deref(),
|
||||
to_text.as_deref(),
|
||||
)
|
||||
.map_err(|e| match match_mode {
|
||||
AgentModelPatternMatch::Like => format!("查询 unified general 摘要失败: {e}"),
|
||||
AgentModelPatternMatch::NotLike => format!("查询非通用 unified 摘要失败: {e}"),
|
||||
})
|
||||
}
|
||||
|
||||
fn summarize_general_window(
|
||||
conn: &Connection,
|
||||
from_timestamp_ms: Option<i64>,
|
||||
to_timestamp_ms: Option<i64>,
|
||||
) -> Result<ConversationWindowSummary, String> {
|
||||
summarize_unified_window(
|
||||
conn,
|
||||
AgentModelPatternMatch::Like,
|
||||
from_timestamp_ms,
|
||||
to_timestamp_ms,
|
||||
)
|
||||
}
|
||||
|
||||
fn summarize_agent_window(
|
||||
conn: &Connection,
|
||||
from_timestamp_ms: Option<i64>,
|
||||
to_timestamp_ms: Option<i64>,
|
||||
) -> Result<ConversationWindowSummary, String> {
|
||||
summarize_unified_window(
|
||||
conn,
|
||||
AgentModelPatternMatch::NotLike,
|
||||
from_timestamp_ms,
|
||||
to_timestamp_ms,
|
||||
)
|
||||
}
|
||||
|
||||
fn build_window_triplet(
|
||||
conn: &Connection,
|
||||
summarize_window: impl Fn(
|
||||
&Connection,
|
||||
Option<i64>,
|
||||
Option<i64>,
|
||||
) -> Result<ConversationWindowSummary, String>,
|
||||
today_start: &DateTime<Local>,
|
||||
month_start: &DateTime<Local>,
|
||||
) -> Result<ConversationWindowTriplet, String> {
|
||||
let today_ts = today_start.timestamp_millis();
|
||||
let month_ts = month_start.timestamp_millis();
|
||||
|
||||
Ok(ConversationWindowTriplet {
|
||||
total: summarize_window(conn, None, None)?,
|
||||
monthly: summarize_window(conn, Some(month_ts), None)?,
|
||||
today: summarize_window(conn, Some(today_ts), None)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_conversation_stats(windows: ConversationWindowTriplet) -> ConversationStats {
|
||||
ConversationStats {
|
||||
total_conversations: clamp_i64_to_u32(windows.total.session_count),
|
||||
total_messages: clamp_i64_to_u32(windows.total.message_count),
|
||||
monthly_conversations: clamp_i64_to_u32(windows.monthly.session_count),
|
||||
monthly_messages: clamp_i64_to_u32(windows.monthly.message_count),
|
||||
today_conversations: clamp_i64_to_u32(windows.today.session_count),
|
||||
today_messages: clamp_i64_to_u32(windows.today.message_count),
|
||||
}
|
||||
}
|
||||
|
||||
fn query_token_stats(
|
||||
conn: &Connection,
|
||||
today_start: &DateTime<Local>,
|
||||
month_start: &DateTime<Local>,
|
||||
general_windows: ConversationWindowTriplet,
|
||||
agent_windows: ConversationWindowTriplet,
|
||||
) -> Result<TokenStats, String> {
|
||||
if let Some(actual_tokens) = query_model_usage_table_tokens(conn, today_start, month_start)? {
|
||||
return Ok(actual_tokens);
|
||||
}
|
||||
|
||||
Ok(TokenStats {
|
||||
total_tokens: chars_to_estimated_tokens(
|
||||
general_windows.total.content_chars + agent_windows.total.content_chars,
|
||||
),
|
||||
monthly_tokens: chars_to_estimated_tokens(
|
||||
general_windows.monthly.content_chars + agent_windows.monthly.content_chars,
|
||||
),
|
||||
today_tokens: chars_to_estimated_tokens(
|
||||
general_windows.today.content_chars + agent_windows.today.content_chars,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
fn query_model_usage_table_tokens(
|
||||
conn: &Connection,
|
||||
today_start: &DateTime<Local>,
|
||||
month_start: &DateTime<Local>,
|
||||
) -> Result<Option<TokenStats>, String> {
|
||||
if !OrchestratorDao::has_model_usage_stats(conn)
|
||||
.map_err(|e| format!("查询 model_usage_stats 行数失败: {e}"))?
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let month_key = month_start.format("%Y-%m-%d").to_string();
|
||||
let today_key = today_start.format("%Y-%m-%d").to_string();
|
||||
let total_tokens = OrchestratorDao::get_total_model_usage_tokens(conn)
|
||||
.map_err(|e| format!("查询总 Token 统计失败: {e}"))?;
|
||||
let monthly_tokens = OrchestratorDao::get_model_usage_tokens_since(conn, &month_key)
|
||||
.map_err(|e| format!("查询本月 Token 统计失败: {e}"))?;
|
||||
let today_tokens = OrchestratorDao::get_model_usage_tokens_on(conn, &today_key)
|
||||
.map_err(|e| format!("查询今日 Token 统计失败: {e}"))?;
|
||||
|
||||
Ok(Some(TokenStats {
|
||||
total_tokens: clamp_i64_to_u64(total_tokens),
|
||||
monthly_tokens: clamp_i64_to_u64(monthly_tokens),
|
||||
today_tokens: clamp_i64_to_u64(today_tokens),
|
||||
}))
|
||||
}
|
||||
|
||||
fn query_model_usage_from_stats_table(
|
||||
conn: &Connection,
|
||||
range_start: Option<DateTime<Local>>,
|
||||
) -> Result<Vec<RawModelUsage>, String> {
|
||||
if !OrchestratorDao::has_model_usage_stats(conn)
|
||||
.map_err(|e| format!("检查模型统计表失败: {e}"))?
|
||||
{
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let start_key = range_start.map(|start| start.format("%Y-%m-%d").to_string());
|
||||
let rows = OrchestratorDao::list_model_usage_aggregates(conn, start_key.as_deref(), 20)
|
||||
.map_err(|e| format!("执行模型统计查询失败: {e}"))?;
|
||||
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(|row| RawModelUsage {
|
||||
model: row.model_id,
|
||||
conversations: clamp_i64_to_u64(row.request_count),
|
||||
tokens: clamp_i64_to_u64(row.total_tokens),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn query_model_usage_from_agent_messages(
|
||||
conn: &Connection,
|
||||
range_start: Option<DateTime<Local>>,
|
||||
) -> Result<Vec<RawModelUsage>, String> {
|
||||
let start_str = range_start.map(|start| start.format("%Y-%m-%d %H:%M:%S").to_string());
|
||||
let rows = AgentDao::list_model_usage_by_model_pattern(
|
||||
conn,
|
||||
GENERAL_MODE_PATTERN,
|
||||
AgentModelPatternMatch::NotLike,
|
||||
start_str.as_deref(),
|
||||
20,
|
||||
)
|
||||
.map_err(|e| format!("查询 Agent 模型排行失败: {e}"))?;
|
||||
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(|row| RawModelUsage {
|
||||
model: row.model,
|
||||
conversations: row.conversations,
|
||||
tokens: chars_to_estimated_tokens(row.content_chars as i64),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn build_model_usage_response(usages: Vec<RawModelUsage>) -> Vec<ModelUsage> {
|
||||
if usages.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let total_tokens: u64 = usages.iter().map(|item| item.tokens).sum();
|
||||
let total_conversations: u64 = usages.iter().map(|item| item.conversations).sum();
|
||||
|
||||
usages
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
let denominator = if total_tokens > 0 {
|
||||
total_tokens
|
||||
} else {
|
||||
total_conversations.max(1)
|
||||
};
|
||||
let numerator = if total_tokens > 0 {
|
||||
item.tokens
|
||||
} else {
|
||||
item.conversations
|
||||
};
|
||||
ModelUsage {
|
||||
model: item.model,
|
||||
conversations: item.conversations.min(u32::MAX as u64) as u32,
|
||||
tokens: item.tokens,
|
||||
percentage: ((numerator as f64 / denominator as f64) * 100.0) as f32,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -286,7 +286,6 @@ pub fn run() {
|
||||
.manage(webview_manager_state)
|
||||
.manage(chrome_profile_manager_state)
|
||||
.manage(update_check_service_state)
|
||||
.manage(commands::update_cmd::UpdateInstallSessionState::default())
|
||||
.manage(session_files_state)
|
||||
.manage(context_memory_service)
|
||||
.manage(recording_service)
|
||||
@@ -856,17 +855,6 @@ pub fn run() {
|
||||
}
|
||||
});
|
||||
|
||||
// 启动后台更新检查任务
|
||||
let app_handle_for_update = app.handle().clone();
|
||||
let update_service_for_task = update_check_service_clone.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
crate::commands::update_cmd::start_background_update_check(
|
||||
app_handle_for_update,
|
||||
update_service_for_task,
|
||||
).await;
|
||||
});
|
||||
tracing::info!("[启动] 后台更新检查任务已启动");
|
||||
|
||||
// 启动会话文件清理任务(清理 30 天前的过期会话)
|
||||
tauri::async_runtime::spawn(async move {
|
||||
// 延迟 10 秒执行,避免影响启动性能
|
||||
@@ -1178,7 +1166,6 @@ pub fn run() {
|
||||
commands::capability_draft_cmd::capability_draft_get,
|
||||
commands::capability_draft_cmd::capability_draft_verify,
|
||||
commands::capability_draft_cmd::capability_draft_register,
|
||||
commands::capability_draft_cmd::capability_draft_list_registered_skills,
|
||||
commands::capability_draft_cmd::capability_draft_submit_approval_session_inputs,
|
||||
commands::capability_draft_cmd::capability_draft_execute_controlled_get,
|
||||
// Agent App commands
|
||||
@@ -1200,22 +1187,11 @@ pub fn run() {
|
||||
commands::agent_app_runtime_cmd::host_response::agent_app_runtime_submit_host_response,
|
||||
// Skill Execution commands
|
||||
commands::skill_exec_cmd::execute_skill,
|
||||
commands::skill_exec_cmd::list_executable_skills,
|
||||
commands::skill_exec_cmd::get_skill_detail,
|
||||
// Execution run commands
|
||||
commands::execution_run_cmd::execution_run_list,
|
||||
commands::execution_run_cmd::execution_run_get,
|
||||
commands::execution_run_cmd::execution_run_get_general_workbench_state,
|
||||
commands::execution_run_cmd::execution_run_list_general_workbench_history,
|
||||
// Agent Knowledge commands
|
||||
commands::knowledge_cmd::knowledge_import_source,
|
||||
commands::knowledge_cmd::knowledge_compile_pack,
|
||||
commands::knowledge_cmd::knowledge_list_packs,
|
||||
commands::knowledge_cmd::knowledge_get_pack,
|
||||
commands::knowledge_cmd::knowledge_set_default_pack,
|
||||
commands::knowledge_cmd::knowledge_update_pack_status,
|
||||
commands::knowledge_cmd::knowledge_resolve_context,
|
||||
commands::knowledge_cmd::knowledge_validate_context_run,
|
||||
// Ecommerce Review Reply commands
|
||||
commands::ecommerce_review_reply_cmd::execute_ecommerce_review_reply,
|
||||
commands::browser_runtime_cmd::open_browser_runtime_debugger_window,
|
||||
@@ -1290,8 +1266,6 @@ pub fn run() {
|
||||
commands::aster_agent_cmd::command_api::provider_api::aster_agent_status,
|
||||
commands::aster_agent_cmd::command_api::provider_api::aster_agent_reset,
|
||||
commands::aster_agent_cmd::command_api::provider_api::aster_agent_configure_provider,
|
||||
commands::aster_agent_cmd::app_server_host::app_server_handle_json_lines,
|
||||
commands::aster_agent_cmd::app_server_host::app_server_drain_events,
|
||||
commands::aster_agent_cmd::command_api::runtime_api::agent_runtime_submit_turn,
|
||||
commands::aster_agent_cmd::command_api::runtime_api::agent_runtime_interrupt_turn,
|
||||
commands::aster_agent_cmd::command_api::runtime_api::agent_runtime_compact_session,
|
||||
@@ -1395,10 +1369,6 @@ pub fn run() {
|
||||
crate::services::sysinfo_service::subscribe_sysinfo,
|
||||
crate::services::sysinfo_service::unsubscribe_sysinfo,
|
||||
// File browser commands
|
||||
crate::services::file_browser_service::create_file,
|
||||
crate::services::file_browser_service::create_directory,
|
||||
crate::services::file_browser_service::delete_file,
|
||||
crate::services::file_browser_service::rename_file,
|
||||
crate::services::file_browser_service::get_file_name,
|
||||
// Webview commands
|
||||
commands::webview_cmd::create_webview_panel,
|
||||
@@ -1434,22 +1404,6 @@ pub fn run() {
|
||||
commands::experimental_cmd::get_experimental_config,
|
||||
commands::experimental_cmd::save_experimental_config,
|
||||
commands::hotkey_cmd::validate_shortcut,
|
||||
// Update Check commands
|
||||
commands::update_cmd::check_update,
|
||||
commands::update_cmd::check_for_updates,
|
||||
commands::update_cmd::start_update_install_session,
|
||||
commands::update_cmd::get_update_install_session,
|
||||
commands::update_cmd::download_update,
|
||||
commands::update_cmd::get_update_check_settings,
|
||||
commands::update_cmd::set_update_check_settings,
|
||||
commands::update_cmd::get_update_notification_metrics,
|
||||
commands::update_cmd::record_update_notification_action,
|
||||
commands::update_cmd::skip_update_version,
|
||||
commands::update_cmd::remind_update_later,
|
||||
commands::update_cmd::dismiss_update_notification,
|
||||
commands::update_cmd::update_last_check_timestamp,
|
||||
commands::update_cmd::close_update_window,
|
||||
commands::update_cmd::test_update_window,
|
||||
// Session Files commands
|
||||
commands::session_files_cmd::session_files_create,
|
||||
commands::session_files_cmd::session_files_exists,
|
||||
@@ -1493,15 +1447,6 @@ pub fn run() {
|
||||
commands::workspace_cmd::get_project_context,
|
||||
commands::workspace_cmd::build_project_system_prompt,
|
||||
// Persona commands
|
||||
commands::persona_cmd::create_persona,
|
||||
commands::persona_cmd::list_personas,
|
||||
commands::persona_cmd::get_persona,
|
||||
commands::persona_cmd::update_persona,
|
||||
commands::persona_cmd::delete_persona,
|
||||
commands::persona_cmd::set_default_persona,
|
||||
commands::persona_cmd::list_persona_templates,
|
||||
commands::persona_cmd::get_default_persona,
|
||||
commands::persona_cmd::generate_persona,
|
||||
// Material commands
|
||||
commands::material_cmd::upload_material,
|
||||
commands::material_cmd::import_material_from_url,
|
||||
@@ -1566,10 +1511,6 @@ pub fn run() {
|
||||
commands::memory_cmd::outline_node_update,
|
||||
commands::memory_cmd::outline_node_delete,
|
||||
commands::memory_cmd::project_memory_get,
|
||||
// Usage Stats commands
|
||||
commands::usage_stats_cmd::get_usage_stats,
|
||||
commands::usage_stats_cmd::get_model_usage_ranking,
|
||||
commands::usage_stats_cmd::get_daily_usage_trends,
|
||||
// Memory Management commands
|
||||
commands::memory_management_cmd::memory_runtime_get_stats,
|
||||
commands::memory_management_cmd::memory_runtime_get_overview,
|
||||
@@ -1603,8 +1544,6 @@ pub fn run() {
|
||||
commands::voice_test_cmd::test_tts,
|
||||
commands::voice_test_cmd::get_available_voices,
|
||||
// File Upload commands
|
||||
commands::file_upload_cmd::upload_avatar,
|
||||
commands::file_upload_cmd::delete_avatar,
|
||||
// ASR commands
|
||||
commands::asr_cmd::get_asr_credentials,
|
||||
commands::asr_cmd::add_asr_credential,
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
//! A2UI 表单 Tauri 命令
|
||||
//! Legacy A2UI form Tauri commands.
|
||||
//!
|
||||
//! 提供 A2UI 表单的前端 API,包括:
|
||||
//! - 创建表单记录
|
||||
//! - 保存表单数据
|
||||
//! - 提交表单
|
||||
//! - 查询表单
|
||||
//! A2UI 表单交互已收敛到 Agent Chat current action-request / workspace runtime;
|
||||
//! 不要恢复这组旧 Tauri DB wrapper 作为生产表单事实源。
|
||||
|
||||
use tauri::State;
|
||||
|
||||
use crate::database::dao::a2ui_form_dao::{
|
||||
A2UIForm, A2UIFormDao, A2UIFormError, CreateA2UIFormRequest,
|
||||
};
|
||||
use crate::database::dao::a2ui_form_dao::A2UIForm;
|
||||
use crate::database::DbConnection;
|
||||
|
||||
// ============================================================================
|
||||
@@ -20,9 +15,12 @@ use crate::database::DbConnection;
|
||||
/// 命令结果类型
|
||||
type CmdResult<T> = Result<T, String>;
|
||||
|
||||
/// 将 A2UIFormError 转换为字符串
|
||||
fn map_err(e: A2UIFormError) -> String {
|
||||
e.to_string()
|
||||
const DEPRECATED_A2UI_FORM_COMMAND_MESSAGE: &str =
|
||||
"A2UI 表单 Tauri DB 命令已退场;请使用 Agent Chat current action-request / workspace runtime 主链";
|
||||
|
||||
fn deprecated_a2ui_form_command_error(command: &str) -> String {
|
||||
tracing::warn!("[A2UIForm] legacy Tauri command `{}` 已退场", command);
|
||||
format!("{command} 已退场;{DEPRECATED_A2UI_FORM_COMMAND_MESSAGE}")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -32,76 +30,68 @@ fn map_err(e: A2UIFormError) -> String {
|
||||
/// 创建 A2UI 表单记录
|
||||
#[tauri::command]
|
||||
pub async fn create_a2ui_form(
|
||||
db: State<'_, DbConnection>,
|
||||
message_id: i64,
|
||||
session_id: String,
|
||||
a2ui_response_json: String,
|
||||
form_data_json: Option<String>,
|
||||
_db: State<'_, DbConnection>,
|
||||
_message_id: i64,
|
||||
_session_id: String,
|
||||
_a2ui_response_json: String,
|
||||
_form_data_json: Option<String>,
|
||||
) -> CmdResult<A2UIForm> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
|
||||
let req = CreateA2UIFormRequest {
|
||||
message_id,
|
||||
session_id,
|
||||
a2ui_response_json,
|
||||
form_data_json,
|
||||
};
|
||||
|
||||
A2UIFormDao::create(&conn, &req).map_err(map_err)
|
||||
Err(deprecated_a2ui_form_command_error("create_a2ui_form"))
|
||||
}
|
||||
|
||||
/// 获取单个表单
|
||||
#[tauri::command]
|
||||
pub async fn get_a2ui_form(db: State<'_, DbConnection>, id: String) -> CmdResult<Option<A2UIForm>> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
A2UIFormDao::get(&conn, &id).map_err(map_err)
|
||||
pub async fn get_a2ui_form(
|
||||
_db: State<'_, DbConnection>,
|
||||
_id: String,
|
||||
) -> CmdResult<Option<A2UIForm>> {
|
||||
Err(deprecated_a2ui_form_command_error("get_a2ui_form"))
|
||||
}
|
||||
|
||||
/// 根据消息 ID 获取表单列表
|
||||
#[tauri::command]
|
||||
pub async fn get_a2ui_forms_by_message(
|
||||
db: State<'_, DbConnection>,
|
||||
message_id: i64,
|
||||
_db: State<'_, DbConnection>,
|
||||
_message_id: i64,
|
||||
) -> CmdResult<Vec<A2UIForm>> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
A2UIFormDao::get_by_message(&conn, message_id).map_err(map_err)
|
||||
Err(deprecated_a2ui_form_command_error(
|
||||
"get_a2ui_forms_by_message",
|
||||
))
|
||||
}
|
||||
|
||||
/// 根据会话 ID 获取所有表单
|
||||
#[tauri::command]
|
||||
pub async fn get_a2ui_forms_by_session(
|
||||
db: State<'_, DbConnection>,
|
||||
session_id: String,
|
||||
_db: State<'_, DbConnection>,
|
||||
_session_id: String,
|
||||
) -> CmdResult<Vec<A2UIForm>> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
A2UIFormDao::get_by_session(&conn, &session_id).map_err(map_err)
|
||||
Err(deprecated_a2ui_form_command_error(
|
||||
"get_a2ui_forms_by_session",
|
||||
))
|
||||
}
|
||||
|
||||
/// 更新表单数据(用户填写的内容)
|
||||
#[tauri::command]
|
||||
pub async fn save_a2ui_form_data(
|
||||
db: State<'_, DbConnection>,
|
||||
id: String,
|
||||
form_data_json: String,
|
||||
_db: State<'_, DbConnection>,
|
||||
_id: String,
|
||||
_form_data_json: String,
|
||||
) -> CmdResult<A2UIForm> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
A2UIFormDao::update_form_data(&conn, &id, &form_data_json).map_err(map_err)
|
||||
Err(deprecated_a2ui_form_command_error("save_a2ui_form_data"))
|
||||
}
|
||||
|
||||
/// 提交表单
|
||||
#[tauri::command]
|
||||
pub async fn submit_a2ui_form(
|
||||
db: State<'_, DbConnection>,
|
||||
id: String,
|
||||
form_data_json: String,
|
||||
_db: State<'_, DbConnection>,
|
||||
_id: String,
|
||||
_form_data_json: String,
|
||||
) -> CmdResult<A2UIForm> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
A2UIFormDao::submit(&conn, &id, &form_data_json).map_err(map_err)
|
||||
Err(deprecated_a2ui_form_command_error("submit_a2ui_form"))
|
||||
}
|
||||
|
||||
/// 删除表单
|
||||
#[tauri::command]
|
||||
pub async fn delete_a2ui_form(db: State<'_, DbConnection>, id: String) -> CmdResult<()> {
|
||||
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
|
||||
A2UIFormDao::delete(&conn, &id).map_err(map_err)
|
||||
pub async fn delete_a2ui_form(_db: State<'_, DbConnection>, _id: String) -> CmdResult<()> {
|
||||
Err(deprecated_a2ui_form_command_error("delete_a2ui_form"))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::agent::AsterAgentState;
|
||||
use crate::app::LogState;
|
||||
use crate::commands::api_key_provider_cmd::ApiKeyProviderServiceState;
|
||||
use crate::commands::aster_agent_cmd::app_server_host::{
|
||||
app_server_handle_json_lines, AppServerHandleJsonLinesRequest,
|
||||
};
|
||||
use crate::commands::aster_agent_cmd::app_server_host::handle_in_process_app_server_json_lines;
|
||||
use crate::commands::aster_agent_cmd::RuntimeCommandContext;
|
||||
use crate::config::GlobalConfigManagerState;
|
||||
use crate::database::DbConnection;
|
||||
use crate::mcp::McpManagerState;
|
||||
@@ -77,9 +76,8 @@ pub(super) async fn invoke_agent_app_runtime_app_server_value(
|
||||
Some(params),
|
||||
)),
|
||||
)?];
|
||||
let response = handle_agent_app_runtime_app_server_lines(app, lines).await?;
|
||||
let message = response
|
||||
.lines
|
||||
let response_lines = handle_agent_app_runtime_app_server_lines(app, lines).await?;
|
||||
let message = response_lines
|
||||
.iter()
|
||||
.filter_map(|line| serde_json::from_str::<app_server::JsonRpcMessage>(line).ok())
|
||||
.find_map(|message| match message {
|
||||
@@ -144,20 +142,18 @@ async fn ensure_agent_app_runtime_app_server_initialized(app: AppHandle) -> Resu
|
||||
async fn handle_agent_app_runtime_app_server_lines(
|
||||
app: AppHandle,
|
||||
lines: Vec<String>,
|
||||
) -> Result<crate::commands::aster_agent_cmd::app_server_host::AppServerHandleJsonLinesResult, String>
|
||||
{
|
||||
app_server_handle_json_lines(
|
||||
) -> Result<Vec<String>, String> {
|
||||
let runtime = RuntimeCommandContext::new(
|
||||
app.clone(),
|
||||
app.state::<AsterAgentState>(),
|
||||
app.state::<DbConnection>(),
|
||||
app.state::<ApiKeyProviderServiceState>(),
|
||||
app.state::<LogState>(),
|
||||
app.state::<GlobalConfigManagerState>(),
|
||||
app.state::<McpManagerState>(),
|
||||
app.state::<AutomationServiceState>(),
|
||||
AppServerHandleJsonLinesRequest { lines },
|
||||
)
|
||||
.await
|
||||
app.state::<AsterAgentState>().inner(),
|
||||
app.state::<DbConnection>().inner(),
|
||||
app.state::<ApiKeyProviderServiceState>().inner(),
|
||||
app.state::<LogState>().inner(),
|
||||
app.state::<GlobalConfigManagerState>().inner(),
|
||||
app.state::<McpManagerState>().inner(),
|
||||
app.state::<AutomationServiceState>().inner(),
|
||||
);
|
||||
handle_in_process_app_server_json_lines(runtime, lines).await
|
||||
}
|
||||
|
||||
fn serialize_app_server_line(message: app_server::JsonRpcMessage) -> Result<String, String> {
|
||||
|
||||
@@ -1473,36 +1473,6 @@ static TAURI_APP_SERVER: OnceLock<InProcessAppServerState> = OnceLock::new();
|
||||
|
||||
struct InProcessAppServerState {
|
||||
server: AppServer,
|
||||
outbound: tokio::sync::Mutex<tokio::sync::broadcast::Receiver<JsonRpcMessage>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AppServerHandleJsonLinesRequest {
|
||||
pub(crate) lines: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AppServerHandleJsonLinesResult {
|
||||
pub(crate) lines: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AppServerDrainEventsRequest {
|
||||
#[serde(default = "default_app_server_drain_limit")]
|
||||
pub(crate) limit: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct AppServerDrainEventsResult {
|
||||
pub(crate) lines: Vec<String>,
|
||||
}
|
||||
|
||||
fn default_app_server_drain_limit() -> usize {
|
||||
100
|
||||
}
|
||||
|
||||
fn in_process_app_server(runtime: RuntimeCommandContext) -> &'static InProcessAppServerState {
|
||||
@@ -1533,42 +1503,17 @@ fn in_process_app_server(runtime: RuntimeCommandContext) -> &'static InProcessAp
|
||||
),
|
||||
);
|
||||
let _ = app_server_bridge.set(server.event_bridge());
|
||||
let outbound = server.subscribe_outbound_messages();
|
||||
InProcessAppServerState {
|
||||
server,
|
||||
outbound: tokio::sync::Mutex::new(outbound),
|
||||
}
|
||||
InProcessAppServerState { server }
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn app_server_handle_json_lines(
|
||||
app: tauri::AppHandle,
|
||||
state: tauri::State<'_, crate::agent::AsterAgentState>,
|
||||
db: tauri::State<'_, crate::database::DbConnection>,
|
||||
api_key_provider_service: tauri::State<
|
||||
'_,
|
||||
crate::commands::api_key_provider_cmd::ApiKeyProviderServiceState,
|
||||
>,
|
||||
logs: tauri::State<'_, crate::LogState>,
|
||||
config_manager: tauri::State<'_, crate::config::GlobalConfigManagerState>,
|
||||
mcp_manager: tauri::State<'_, crate::mcp::McpManagerState>,
|
||||
automation_state: tauri::State<'_, crate::services::automation_service::AutomationServiceState>,
|
||||
request: AppServerHandleJsonLinesRequest,
|
||||
) -> Result<AppServerHandleJsonLinesResult, String> {
|
||||
let runtime = RuntimeCommandContext::new(
|
||||
app,
|
||||
state.inner(),
|
||||
db.inner(),
|
||||
api_key_provider_service.inner(),
|
||||
logs.inner(),
|
||||
config_manager.inner(),
|
||||
mcp_manager.inner(),
|
||||
automation_state.inner(),
|
||||
);
|
||||
pub(crate) async fn handle_in_process_app_server_json_lines(
|
||||
runtime: RuntimeCommandContext,
|
||||
request_lines: Vec<String>,
|
||||
) -> Result<Vec<String>, String> {
|
||||
let app_server = in_process_app_server(runtime);
|
||||
let mut lines = Vec::new();
|
||||
for line in request.lines {
|
||||
for line in request_lines {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.is_empty() {
|
||||
continue;
|
||||
@@ -1580,52 +1525,7 @@ pub(crate) async fn app_server_handle_json_lines(
|
||||
.map_err(|error| error.to_string())?;
|
||||
lines.extend(responses);
|
||||
}
|
||||
Ok(AppServerHandleJsonLinesResult { lines })
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn app_server_drain_events(
|
||||
app: tauri::AppHandle,
|
||||
state: tauri::State<'_, crate::agent::AsterAgentState>,
|
||||
db: tauri::State<'_, crate::database::DbConnection>,
|
||||
api_key_provider_service: tauri::State<
|
||||
'_,
|
||||
crate::commands::api_key_provider_cmd::ApiKeyProviderServiceState,
|
||||
>,
|
||||
logs: tauri::State<'_, crate::LogState>,
|
||||
config_manager: tauri::State<'_, crate::config::GlobalConfigManagerState>,
|
||||
mcp_manager: tauri::State<'_, crate::mcp::McpManagerState>,
|
||||
automation_state: tauri::State<'_, crate::services::automation_service::AutomationServiceState>,
|
||||
request: AppServerDrainEventsRequest,
|
||||
) -> Result<AppServerDrainEventsResult, String> {
|
||||
let runtime = RuntimeCommandContext::new(
|
||||
app,
|
||||
state.inner(),
|
||||
db.inner(),
|
||||
api_key_provider_service.inner(),
|
||||
logs.inner(),
|
||||
config_manager.inner(),
|
||||
mcp_manager.inner(),
|
||||
automation_state.inner(),
|
||||
);
|
||||
let app_server = in_process_app_server(runtime);
|
||||
let limit = request.limit.clamp(1, 1000);
|
||||
let mut receiver = app_server.outbound.lock().await;
|
||||
let mut lines = Vec::new();
|
||||
while lines.len() < limit {
|
||||
match receiver.try_recv() {
|
||||
Ok(message) => {
|
||||
let mut line =
|
||||
serde_json::to_string(&message).map_err(|error| error.to_string())?;
|
||||
line.push('\n');
|
||||
lines.push(line);
|
||||
}
|
||||
Err(tokio::sync::broadcast::error::TryRecvError::Empty) => break,
|
||||
Err(tokio::sync::broadcast::error::TryRecvError::Lagged(_)) => continue,
|
||||
Err(tokio::sync::broadcast::error::TryRecvError::Closed) => break,
|
||||
}
|
||||
}
|
||||
Ok(AppServerDrainEventsResult { lines })
|
||||
Ok(lines)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use crate::agent_tools::catalog::LIME_SEARCH_WEB_IMAGES_TOOL_NAME;
|
||||
use crate::app::AppState;
|
||||
use crate::commands::image_search_cmd::{
|
||||
use crate::services::image_search_service::{
|
||||
get_pexels_api_key_from_app_state, search_web_images_with_pexels_api_key, WebImageSearchRequest,
|
||||
};
|
||||
use tauri::Manager;
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
use crate::services::capability_draft_service::{
|
||||
create_capability_draft, execute_capability_draft_controlled_get, get_capability_draft,
|
||||
list_capability_drafts, list_workspace_registered_skills, register_capability_draft,
|
||||
list_capability_drafts, register_capability_draft,
|
||||
submit_capability_draft_approval_session_inputs, verify_capability_draft,
|
||||
CapabilityDraftRecord, CreateCapabilityDraftRequest,
|
||||
ExecuteCapabilityDraftControlledGetRequest, ExecuteCapabilityDraftControlledGetResult,
|
||||
GetCapabilityDraftRequest, ListCapabilityDraftsRequest, ListWorkspaceRegisteredSkillsRequest,
|
||||
GetCapabilityDraftRequest, ListCapabilityDraftsRequest,
|
||||
RegisterCapabilityDraftRequest, RegisterCapabilityDraftResult,
|
||||
SubmitCapabilityDraftApprovalSessionInputsRequest,
|
||||
SubmitCapabilityDraftApprovalSessionInputsResult, VerifyCapabilityDraftRequest,
|
||||
VerifyCapabilityDraftResult, WorkspaceRegisteredSkillRecord,
|
||||
VerifyCapabilityDraftResult,
|
||||
};
|
||||
|
||||
#[tauri::command]
|
||||
@@ -50,13 +50,6 @@ pub fn capability_draft_register(
|
||||
register_capability_draft(request)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn capability_draft_list_registered_skills(
|
||||
request: ListWorkspaceRegisteredSkillsRequest,
|
||||
) -> Result<Vec<WorkspaceRegisteredSkillRecord>, String> {
|
||||
list_workspace_registered_skills(request)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn capability_draft_submit_approval_session_inputs(
|
||||
request: SubmitCapabilityDraftApprovalSessionInputsRequest,
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
use crate::services::companion_service::{
|
||||
self, CompanionLaunchPetRequest, CompanionLaunchPetResult, CompanionPetCommandRequest,
|
||||
CompanionLaunchPetRequest, CompanionLaunchPetResult, CompanionPetCommandRequest,
|
||||
CompanionPetSendResult, CompanionPetStatus, CompanionServiceState,
|
||||
};
|
||||
use tauri::{AppHandle, State};
|
||||
|
||||
const DEPRECATED_COMPANION_COMMAND: &str =
|
||||
"Companion Tauri 命令已退场;请接入 Electron Desktop Host current 桌宠壳能力。";
|
||||
|
||||
fn deprecated_companion_command() -> String {
|
||||
DEPRECATED_COMPANION_COMMAND.to_string()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn companion_get_pet_status(
|
||||
companion_state: State<'_, CompanionServiceState>,
|
||||
) -> Result<CompanionPetStatus, String> {
|
||||
companion_service::get_pet_status_global(companion_state.inner()).await
|
||||
let _ = companion_state;
|
||||
Err(deprecated_companion_command())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -17,12 +25,8 @@ pub async fn companion_launch_pet(
|
||||
companion_state: State<'_, CompanionServiceState>,
|
||||
request: Option<CompanionLaunchPetRequest>,
|
||||
) -> Result<CompanionLaunchPetResult, String> {
|
||||
companion_service::launch_pet_global(
|
||||
companion_state.inner(),
|
||||
app_handle,
|
||||
request.unwrap_or_default(),
|
||||
)
|
||||
.await
|
||||
let _ = (app_handle, companion_state, request);
|
||||
Err(deprecated_companion_command())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -30,5 +34,6 @@ pub async fn companion_send_pet_command(
|
||||
companion_state: State<'_, CompanionServiceState>,
|
||||
request: CompanionPetCommandRequest,
|
||||
) -> Result<CompanionPetSendResult, String> {
|
||||
companion_service::send_pet_command_global(companion_state.inner(), request).await
|
||||
let _ = (companion_state, request);
|
||||
Err(deprecated_companion_command())
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
use crate::config::{
|
||||
Config, ConfigManager, ExportBundle, ExportOptions as ExportServiceOptions, ExportService,
|
||||
ImportOptions as ImportServiceOptions, ImportService, ValidationResult,
|
||||
};
|
||||
use crate::models::app_type::AppType;
|
||||
use crate::config::{Config, ValidationResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use tauri::AppHandle;
|
||||
use tauri_plugin_autostart::ManagerExt;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::process::CommandExt;
|
||||
const DEPRECATED_CONFIG_COMMAND: &str = "旧 Tauri 配置/CLI/autostart 命令已下线;生产配置、实验开关和桌面壳能力必须经 Electron Desktop Host / App Server current 主链。";
|
||||
|
||||
fn deprecated_config_command<T>(command: &str) -> Result<T, String> {
|
||||
Err(format!("{DEPRECATED_CONFIG_COMMAND} command={command}"))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ConfigStatus {
|
||||
@@ -18,99 +15,19 @@ pub struct ConfigStatus {
|
||||
pub has_env: bool,
|
||||
}
|
||||
|
||||
/// Get the config directory path for an app type
|
||||
fn get_config_dir(app_type: &AppType) -> Option<PathBuf> {
|
||||
let home = dirs::home_dir()?;
|
||||
match app_type {
|
||||
AppType::Claude => Some(home.join(".claude")),
|
||||
AppType::Codex => Some(home.join(".codex")),
|
||||
AppType::Gemini => Some(home.join(".gemini")),
|
||||
AppType::Lime => dirs::config_dir().map(|d| d.join("lime")),
|
||||
}
|
||||
#[tauri::command]
|
||||
pub fn get_config_status(_app_type: String) -> Result<ConfigStatus, String> {
|
||||
deprecated_config_command("get_config_status")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_config_status(app_type: String) -> Result<ConfigStatus, String> {
|
||||
let app = app_type.parse::<AppType>().map_err(|e| e.to_string())?;
|
||||
let config_dir = get_config_dir(&app).ok_or("Cannot determine config directory")?;
|
||||
|
||||
let main_config = match app {
|
||||
AppType::Claude => config_dir.join("settings.json"),
|
||||
AppType::Codex => config_dir.join("auth.json"),
|
||||
AppType::Gemini => config_dir.join(".env"),
|
||||
AppType::Lime => config_dir.join("config.yaml"),
|
||||
};
|
||||
|
||||
let has_env = match app {
|
||||
AppType::Claude => {
|
||||
config_dir.join("settings.json").exists()
|
||||
&& std::fs::read_to_string(config_dir.join("settings.json"))
|
||||
.map(|s| s.contains("env"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
AppType::Codex => config_dir.join("auth.json").exists(),
|
||||
AppType::Gemini => config_dir.join(".env").exists(),
|
||||
AppType::Lime => {
|
||||
config_dir.join("config.yaml").exists() || config_dir.join("config.json").exists()
|
||||
}
|
||||
};
|
||||
|
||||
let exists = match app {
|
||||
AppType::Lime => {
|
||||
config_dir.join("config.yaml").exists() || config_dir.join("config.json").exists()
|
||||
}
|
||||
_ => main_config.exists(),
|
||||
};
|
||||
|
||||
Ok(ConfigStatus {
|
||||
exists,
|
||||
path: config_dir.to_string_lossy().to_string(),
|
||||
has_env,
|
||||
})
|
||||
pub fn get_config_dir_path(_app_type: String) -> Result<String, String> {
|
||||
deprecated_config_command("get_config_dir_path")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_config_dir_path(app_type: String) -> Result<String, String> {
|
||||
let app = app_type.parse::<AppType>().map_err(|e| e.to_string())?;
|
||||
let config_dir = get_config_dir(&app).ok_or("Cannot determine config directory")?;
|
||||
Ok(config_dir.to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn open_config_folder(_handle: AppHandle, app_type: String) -> Result<bool, String> {
|
||||
let app = app_type.parse::<AppType>().map_err(|e| e.to_string())?;
|
||||
let config_dir = get_config_dir(&app).ok_or("Cannot determine config directory")?;
|
||||
|
||||
if !config_dir.exists() {
|
||||
std::fs::create_dir_all(&config_dir).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
std::process::Command::new("open")
|
||||
.arg(&config_dir)
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
std::process::Command::new("explorer")
|
||||
.arg(&config_dir)
|
||||
.creation_flags(0x08000000) // CREATE_NO_WINDOW
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
std::process::Command::new("xdg-open")
|
||||
.arg(&config_dir)
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
pub async fn open_config_folder(_handle: AppHandle, _app_type: String) -> Result<bool, String> {
|
||||
deprecated_config_command("open_config_folder")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -120,465 +37,127 @@ pub struct ToolVersion {
|
||||
pub installed: bool,
|
||||
}
|
||||
|
||||
/// 检测工具版本的辅助函数
|
||||
fn check_tool_version(command: &str, args: &[&str]) -> Option<String> {
|
||||
// 在 Windows 上,先尝试直接执行命令
|
||||
let mut cmd = std::process::Command::new(command);
|
||||
cmd.args(args);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
|
||||
|
||||
let output = cmd.output().ok();
|
||||
|
||||
// 如果直接执行失败,在 Windows 上尝试通过 PowerShell 执行
|
||||
#[cfg(target_os = "windows")]
|
||||
let output = output.or_else(|| {
|
||||
std::process::Command::new("powershell")
|
||||
.args(["-Command", &format!("{} {}", command, args.join(" "))])
|
||||
.creation_flags(0x08000000)
|
||||
.output()
|
||||
.ok()
|
||||
});
|
||||
|
||||
output
|
||||
.and_then(|o| {
|
||||
if o.status.success() {
|
||||
// 先尝试 stdout,失败则尝试 stderr
|
||||
String::from_utf8(o.stdout.clone())
|
||||
.or_else(|_| String::from_utf8(o.stderr))
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_tool_versions() -> Result<Vec<ToolVersion>, String> {
|
||||
let mut versions = Vec::new();
|
||||
|
||||
// 定义要检测的工具列表
|
||||
let tools = vec![
|
||||
("Claude CLI", "claude", vec!["--version"]),
|
||||
("Codex", "codex", vec!["--version"]),
|
||||
("Gemini CLI", "gemini", vec!["--version"]),
|
||||
];
|
||||
|
||||
for (name, command, args) in tools {
|
||||
let version = check_tool_version(command, &args);
|
||||
|
||||
versions.push(ToolVersion {
|
||||
name: name.to_string(),
|
||||
version: version.clone(),
|
||||
installed: version.is_some(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(versions)
|
||||
deprecated_config_command("get_tool_versions")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_auto_launch_status(app: AppHandle) -> Result<bool, String> {
|
||||
let autostart_manager = app.autolaunch();
|
||||
autostart_manager
|
||||
.is_enabled()
|
||||
.map_err(|e| format!("Failed to get autostart status: {e}"))
|
||||
pub async fn get_auto_launch_status(_app: AppHandle) -> Result<bool, String> {
|
||||
deprecated_config_command("get_auto_launch_status")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn set_auto_launch(app: AppHandle, enabled: bool) -> Result<bool, String> {
|
||||
let autostart_manager = app.autolaunch();
|
||||
|
||||
if enabled {
|
||||
autostart_manager
|
||||
.enable()
|
||||
.map_err(|e| format!("Failed to enable autostart: {e}"))?;
|
||||
} else {
|
||||
autostart_manager
|
||||
.disable()
|
||||
.map_err(|e| format!("Failed to disable autostart: {e}"))?;
|
||||
}
|
||||
|
||||
Ok(enabled)
|
||||
pub async fn set_auto_launch(_app: AppHandle, _enabled: bool) -> Result<bool, String> {
|
||||
deprecated_config_command("set_auto_launch")
|
||||
}
|
||||
|
||||
// ============ Config Import/Export Commands ============
|
||||
|
||||
/// 配置导出选项
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct ExportOptions {
|
||||
/// 是否脱敏敏感信息(API 密钥等)
|
||||
pub redact_secrets: bool,
|
||||
}
|
||||
|
||||
/// 配置导出结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ExportResult {
|
||||
/// YAML 配置内容
|
||||
pub content: String,
|
||||
/// 建议的文件名
|
||||
pub suggested_filename: String,
|
||||
}
|
||||
|
||||
/// 导出配置为 YAML 字符串
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `config` - 当前配置
|
||||
/// * `redact_secrets` - 是否脱敏敏感信息
|
||||
#[tauri::command]
|
||||
pub fn export_config(config: Config, redact_secrets: bool) -> Result<ExportResult, String> {
|
||||
let manager = ConfigManager::new(PathBuf::from("temp.yaml"));
|
||||
let mut manager_with_config = manager;
|
||||
manager_with_config.set_config(config);
|
||||
|
||||
let content = manager_with_config
|
||||
.export(redact_secrets)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// 生成带时间戳的文件名
|
||||
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
|
||||
let suffix = if redact_secrets { "_redacted" } else { "" };
|
||||
let suggested_filename = format!("lime_config_{timestamp}{suffix}.yaml");
|
||||
|
||||
Ok(ExportResult {
|
||||
content,
|
||||
suggested_filename,
|
||||
})
|
||||
pub fn export_config(_config: Config, _redact_secrets: bool) -> Result<ExportResult, String> {
|
||||
deprecated_config_command("export_config")
|
||||
}
|
||||
|
||||
/// 配置导入选项
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
pub struct ImportOptions {
|
||||
/// 是否合并到现有配置(true)或替换(false)
|
||||
pub merge: bool,
|
||||
}
|
||||
|
||||
/// 配置导入结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ImportResult {
|
||||
/// 是否成功
|
||||
pub success: bool,
|
||||
/// 导入后的配置
|
||||
pub config: Config,
|
||||
/// 警告信息(如果有)
|
||||
pub warnings: Vec<String>,
|
||||
}
|
||||
|
||||
/// 验证配置 YAML 格式
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `yaml_content` - YAML 配置字符串
|
||||
#[tauri::command]
|
||||
pub fn validate_config_yaml(yaml_content: String) -> Result<Config, String> {
|
||||
ConfigManager::parse_yaml(&yaml_content).map_err(|e| e.to_string())
|
||||
pub fn validate_config_yaml(_yaml_content: String) -> Result<Config, String> {
|
||||
deprecated_config_command("validate_config_yaml")
|
||||
}
|
||||
|
||||
/// 导入配置
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `current_config` - 当前配置
|
||||
/// * `yaml_content` - 要导入的 YAML 配置字符串
|
||||
/// * `merge` - 是否合并到现有配置(true)或替换(false)
|
||||
#[tauri::command]
|
||||
pub fn import_config(
|
||||
current_config: Config,
|
||||
yaml_content: String,
|
||||
merge: bool,
|
||||
_current_config: Config,
|
||||
_yaml_content: String,
|
||||
_merge: bool,
|
||||
) -> Result<ImportResult, String> {
|
||||
let mut manager = ConfigManager::new(PathBuf::from("temp.yaml"));
|
||||
manager.set_config(current_config);
|
||||
|
||||
let mut warnings = Vec::new();
|
||||
|
||||
// 先验证 YAML 格式
|
||||
let imported_config = ConfigManager::parse_yaml(&yaml_content).map_err(|e| e.to_string())?;
|
||||
|
||||
// 检查是否包含脱敏的密钥
|
||||
if imported_config.server.api_key == "***REDACTED***" {
|
||||
warnings.push("导入的配置包含脱敏的 API 密钥,将保留原有值".to_string());
|
||||
}
|
||||
if imported_config
|
||||
.providers
|
||||
.openai
|
||||
.api_key
|
||||
.as_ref()
|
||||
.map(|k| k == "***REDACTED***")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
warnings.push("导入的配置包含脱敏的 OpenAI API 密钥,将保留原有值".to_string());
|
||||
}
|
||||
if imported_config
|
||||
.providers
|
||||
.claude
|
||||
.api_key
|
||||
.as_ref()
|
||||
.map(|k| k == "***REDACTED***")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
warnings.push("导入的配置包含脱敏的 Claude API 密钥,将保留原有值".to_string());
|
||||
}
|
||||
|
||||
// 执行导入
|
||||
manager
|
||||
.import(&yaml_content, merge)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// 如果导入的配置包含脱敏的密钥,恢复原有值
|
||||
let final_config = manager.config().clone();
|
||||
|
||||
Ok(ImportResult {
|
||||
success: true,
|
||||
config: final_config,
|
||||
warnings,
|
||||
})
|
||||
deprecated_config_command("import_config")
|
||||
}
|
||||
|
||||
/// 获取配置文件路径信息
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ConfigPathInfo {
|
||||
/// YAML 配置文件路径
|
||||
pub yaml_path: String,
|
||||
/// JSON 配置文件路径(旧版)
|
||||
pub json_path: String,
|
||||
/// YAML 配置是否存在
|
||||
pub yaml_exists: bool,
|
||||
/// JSON 配置是否存在
|
||||
pub json_exists: bool,
|
||||
}
|
||||
|
||||
/// 获取配置文件路径信息
|
||||
#[tauri::command]
|
||||
pub fn get_config_paths() -> Result<ConfigPathInfo, String> {
|
||||
let yaml_path = ConfigManager::default_config_path();
|
||||
let json_path = dirs::config_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("."))
|
||||
.join("lime")
|
||||
.join("config.json");
|
||||
|
||||
Ok(ConfigPathInfo {
|
||||
yaml_path: yaml_path.to_string_lossy().to_string(),
|
||||
json_path: json_path.to_string_lossy().to_string(),
|
||||
yaml_exists: yaml_path.exists(),
|
||||
json_exists: json_path.exists(),
|
||||
})
|
||||
deprecated_config_command("get_config_paths")
|
||||
}
|
||||
|
||||
// ============ Enhanced Export/Import Commands (using ExportService/ImportService) ============
|
||||
|
||||
/// 统一导出选项
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UnifiedExportOptions {
|
||||
/// 是否包含配置
|
||||
pub include_config: bool,
|
||||
/// 是否包含凭证
|
||||
pub include_credentials: bool,
|
||||
/// 是否脱敏敏感信息
|
||||
pub redact_secrets: bool,
|
||||
}
|
||||
|
||||
/// 统一导出结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UnifiedExportResult {
|
||||
/// 导出包内容(JSON 格式)
|
||||
pub content: String,
|
||||
/// 建议的文件名
|
||||
pub suggested_filename: String,
|
||||
/// 是否已脱敏
|
||||
pub redacted: bool,
|
||||
/// 是否包含配置
|
||||
pub has_config: bool,
|
||||
/// 是否包含凭证
|
||||
pub has_credentials: bool,
|
||||
}
|
||||
|
||||
/// 导出完整的配置和凭证包
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `config` - 当前配置
|
||||
/// * `options` - 导出选项
|
||||
///
|
||||
/// # Requirements: 3.1, 3.2
|
||||
#[tauri::command]
|
||||
pub fn export_bundle(
|
||||
config: Config,
|
||||
options: UnifiedExportOptions,
|
||||
_config: Config,
|
||||
_options: UnifiedExportOptions,
|
||||
) -> Result<UnifiedExportResult, String> {
|
||||
let export_options = ExportServiceOptions {
|
||||
include_config: options.include_config,
|
||||
include_credentials: options.include_credentials,
|
||||
redact_secrets: options.redact_secrets,
|
||||
};
|
||||
|
||||
// 获取应用版本
|
||||
let app_version = env!("CARGO_PKG_VERSION").to_string();
|
||||
|
||||
let bundle =
|
||||
ExportService::export(&config, &export_options, &app_version).map_err(|e| e.to_string())?;
|
||||
|
||||
let content = bundle.to_json().map_err(|e| e.to_string())?;
|
||||
|
||||
// 生成带时间戳的文件名
|
||||
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
|
||||
let suffix = if options.redact_secrets {
|
||||
"_redacted"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let scope = match (options.include_config, options.include_credentials) {
|
||||
(true, true) => "full",
|
||||
(true, false) => "config",
|
||||
(false, true) => "credentials",
|
||||
(false, false) => "empty",
|
||||
};
|
||||
let suggested_filename = format!("lime_{scope}_{timestamp}{suffix}.json");
|
||||
|
||||
Ok(UnifiedExportResult {
|
||||
content,
|
||||
suggested_filename,
|
||||
redacted: bundle.redacted,
|
||||
has_config: bundle.has_config(),
|
||||
has_credentials: bundle.has_credentials(),
|
||||
})
|
||||
deprecated_config_command("export_bundle")
|
||||
}
|
||||
|
||||
/// 仅导出配置为 YAML
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `config` - 当前配置
|
||||
/// * `redact_secrets` - 是否脱敏敏感信息
|
||||
///
|
||||
/// # Requirements: 3.1, 5.1
|
||||
#[tauri::command]
|
||||
pub fn export_config_yaml(config: Config, redact_secrets: bool) -> Result<ExportResult, String> {
|
||||
let content = ExportService::export_yaml(&config, redact_secrets).map_err(|e| e.to_string())?;
|
||||
|
||||
// 生成带时间戳的文件名
|
||||
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
|
||||
let suffix = if redact_secrets { "_redacted" } else { "" };
|
||||
let suggested_filename = format!("lime_config_{timestamp}{suffix}.yaml");
|
||||
|
||||
Ok(ExportResult {
|
||||
content,
|
||||
suggested_filename,
|
||||
})
|
||||
pub fn export_config_yaml(_config: Config, _redact_secrets: bool) -> Result<ExportResult, String> {
|
||||
deprecated_config_command("export_config_yaml")
|
||||
}
|
||||
|
||||
/// 验证导入内容
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `content` - 导入内容(JSON 导出包或 YAML 配置)
|
||||
///
|
||||
/// # Requirements: 4.1, 4.2
|
||||
#[tauri::command]
|
||||
pub fn validate_import(content: String) -> Result<ValidationResult, String> {
|
||||
Ok(ImportService::validate(&content))
|
||||
pub fn validate_import(_content: String) -> Result<ValidationResult, String> {
|
||||
deprecated_config_command("validate_import")
|
||||
}
|
||||
|
||||
/// 导入完整的导出包
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `current_config` - 当前配置
|
||||
/// * `content` - 导出包内容(JSON 格式)
|
||||
/// * `merge` - 是否合并到现有配置
|
||||
///
|
||||
/// # Requirements: 4.1, 4.3
|
||||
#[tauri::command]
|
||||
pub fn import_bundle(
|
||||
current_config: Config,
|
||||
content: String,
|
||||
merge: bool,
|
||||
_current_config: Config,
|
||||
_content: String,
|
||||
_merge: bool,
|
||||
) -> Result<ImportResult, String> {
|
||||
// 首先尝试解析为 ExportBundle
|
||||
if let Ok(bundle) = ExportBundle::from_json(&content) {
|
||||
let options = ImportServiceOptions { merge };
|
||||
let result =
|
||||
ImportService::import(&bundle, ¤t_config, &options, ¤t_config.auth_dir)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
return Ok(ImportResult {
|
||||
success: result.success,
|
||||
config: result.config,
|
||||
warnings: result.warnings,
|
||||
});
|
||||
}
|
||||
|
||||
// 尝试解析为 YAML 配置
|
||||
let options = ImportServiceOptions { merge };
|
||||
let result = ImportService::import_yaml(&content, ¤t_config, &options)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(ImportResult {
|
||||
success: result.success,
|
||||
config: result.config,
|
||||
warnings: result.warnings,
|
||||
})
|
||||
deprecated_config_command("import_bundle")
|
||||
}
|
||||
|
||||
// ============ Path Utility Commands ============
|
||||
|
||||
/// 展开路径中的 tilde (~) 为用户主目录
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `path` - 要展开的路径字符串
|
||||
///
|
||||
/// # Returns
|
||||
/// 展开后的完整路径字符串
|
||||
///
|
||||
/// # Requirements: 2.3
|
||||
#[tauri::command]
|
||||
pub fn expand_path(path: String) -> Result<String, String> {
|
||||
use crate::config::expand_tilde;
|
||||
|
||||
let expanded = expand_tilde(&path);
|
||||
Ok(expanded.to_string_lossy().to_string())
|
||||
pub fn expand_path(_path: String) -> Result<String, String> {
|
||||
deprecated_config_command("expand_path")
|
||||
}
|
||||
|
||||
/// 打开认证目录
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `path` - 认证目录路径(支持 tilde 展开)
|
||||
///
|
||||
/// # Requirements: 2.2
|
||||
#[tauri::command]
|
||||
pub async fn open_auth_dir(path: String) -> Result<bool, String> {
|
||||
use crate::config::expand_tilde;
|
||||
|
||||
let expanded = expand_tilde(&path);
|
||||
|
||||
// 确保目录存在
|
||||
if !expanded.exists() {
|
||||
std::fs::create_dir_all(&expanded).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
std::process::Command::new("open")
|
||||
.arg(&expanded)
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
std::process::Command::new("explorer")
|
||||
.arg(&expanded)
|
||||
.creation_flags(0x08000000) // CREATE_NO_WINDOW
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
std::process::Command::new("xdg-open")
|
||||
.arg(&expanded)
|
||||
.spawn()
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
pub async fn open_auth_dir(_path: String) -> Result<bool, String> {
|
||||
deprecated_config_command("open_auth_dir")
|
||||
}
|
||||
|
||||
@@ -1,38 +1,24 @@
|
||||
//! Lime Connect 命令模块
|
||||
//! Connect legacy Tauri 命令模块
|
||||
//!
|
||||
//! 提供 Deep Link 协议处理和中转商 API Key 管理的 Tauri 命令。
|
||||
//! Connect 生产路径已迁移到 Electron deep link bridge 与 App Server JSON-RPC。
|
||||
//! 本模块仅保留启动期仍引用的状态 / DTO,以及旧 Tauri 命令的 fail-closed 退场面。
|
||||
//!
|
||||
//! ## 功能
|
||||
//! ## Current 主链
|
||||
//!
|
||||
//! - Deep Link 协议处理和事件发送
|
||||
//! - 中转商注册表查询和刷新
|
||||
//! - API Key 集成到 API Key Provider 系统
|
||||
//! - 统计回调(Webhook)
|
||||
//! `Electron protocol/open-url -> frontend connect API -> App Server JSON-RPC`
|
||||
//!
|
||||
//! ## Tauri 命令
|
||||
//! ## Deprecated Tauri 命令
|
||||
//!
|
||||
//! - `get_relay_info` - 查询中转商信息
|
||||
//! - `save_relay_api_key` - 保存 API Key(添加到 API Key Provider 系统)
|
||||
//! - `refresh_relay_registry` - 刷新注册表
|
||||
//! - `handle_deep_link` - 处理 Deep Link URL
|
||||
//! - `send_connect_callback` - 发送统计回调
|
||||
//!
|
||||
//! _Requirements: 1.4, 2.3, 4.1, 5.3_
|
||||
//! 旧命令只返回 `DEPRECATED_CONNECT_COMMAND`,不得继续承接 registry / API Key / webhook 业务事实。
|
||||
|
||||
use crate::connect::{
|
||||
parse_deep_link, parse_open_deep_link, send_cancelled_callback, send_error_callback,
|
||||
send_success_callback, ConnectPayload, DeepLinkError, OpenDeepLinkPayload, RelayInfo,
|
||||
RelayRegistry,
|
||||
};
|
||||
use crate::database::dao::api_key_provider::ApiProviderType;
|
||||
use crate::database::DbConnection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tauri::{AppHandle, Emitter, State};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use super::api_key_provider_cmd::ApiKeyProviderServiceState;
|
||||
use crate::connect::{ConnectPayload, OpenDeepLinkPayload, RelayInfo, RelayRegistry};
|
||||
|
||||
const CURRENT_CONNECT_PATH: &str = "Electron deep link bridge -> App Server JSON-RPC current 主链";
|
||||
|
||||
/// Connect 模块状态
|
||||
///
|
||||
@@ -68,42 +54,15 @@ pub struct ConnectError {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl From<DeepLinkError> for ConnectError {
|
||||
fn from(err: DeepLinkError) -> Self {
|
||||
let (code, message) = match &err {
|
||||
DeepLinkError::InvalidUrl(msg) => ("INVALID_URL".to_string(), msg.clone()),
|
||||
DeepLinkError::MissingRelay => (
|
||||
"MISSING_RELAY".to_string(),
|
||||
"缺少必填参数: relay".to_string(),
|
||||
),
|
||||
DeepLinkError::MissingKey => {
|
||||
("MISSING_KEY".to_string(), "缺少必填参数: key".to_string())
|
||||
}
|
||||
DeepLinkError::MissingKind => {
|
||||
("MISSING_KIND".to_string(), "缺少必填参数: kind".to_string())
|
||||
}
|
||||
DeepLinkError::MissingSlug => {
|
||||
("MISSING_SLUG".to_string(), "缺少必填参数: slug".to_string())
|
||||
}
|
||||
DeepLinkError::InvalidOpenKind(kind) => (
|
||||
"INVALID_OPEN_KIND".to_string(),
|
||||
format!("无效的 open kind: {kind}"),
|
||||
),
|
||||
DeepLinkError::InvalidOpenAction(action) => (
|
||||
"INVALID_OPEN_ACTION".to_string(),
|
||||
format!("无效的 open action: {action}"),
|
||||
),
|
||||
};
|
||||
ConnectError { code, message }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::connect::RegistryError> for ConnectError {
|
||||
fn from(err: crate::connect::RegistryError) -> Self {
|
||||
ConnectError {
|
||||
code: "REGISTRY_ERROR".to_string(),
|
||||
message: err.to_string(),
|
||||
}
|
||||
fn deprecated_connect_command_error(command: &str) -> ConnectError {
|
||||
tracing::warn!(
|
||||
"[Connect] legacy Tauri command `{}` 已退场;请改走 {}",
|
||||
command,
|
||||
CURRENT_CONNECT_PATH
|
||||
);
|
||||
ConnectError {
|
||||
code: "DEPRECATED_CONNECT_COMMAND".to_string(),
|
||||
message: format!("{command} 已退场;Connect 只能走 {CURRENT_CONNECT_PATH}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,74 +86,22 @@ pub async fn init_connect_state(app_data_dir: PathBuf) -> Result<ConnectState, C
|
||||
Ok(ConnectState { registry })
|
||||
}
|
||||
|
||||
/// 处理 Deep Link URL
|
||||
///
|
||||
/// 解析 Deep Link URL,查询中转商信息,并发送事件到前端
|
||||
///
|
||||
/// _Requirements: 1.4_
|
||||
/// 旧 Tauri deep link 命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn handle_deep_link(
|
||||
app: AppHandle,
|
||||
state: State<'_, ConnectStateWrapper>,
|
||||
url: String,
|
||||
) -> Result<DeepLinkResult, ConnectError> {
|
||||
tracing::info!("[Connect] 处理 Deep Link: {}", url);
|
||||
|
||||
// 解析 Deep Link
|
||||
let payload = parse_deep_link(&url)?;
|
||||
|
||||
// 查询中转商信息
|
||||
let (relay_info, is_verified) = {
|
||||
let state_guard = state.0.read().await;
|
||||
if let Some(connect_state) = state_guard.as_ref() {
|
||||
let info = connect_state.registry.get(&payload.relay);
|
||||
let verified = info.is_some();
|
||||
(info, verified)
|
||||
} else {
|
||||
(None, false)
|
||||
}
|
||||
};
|
||||
|
||||
let result = DeepLinkResult {
|
||||
payload: payload.clone(),
|
||||
relay_info: relay_info.clone(),
|
||||
is_verified,
|
||||
};
|
||||
|
||||
// 发送事件到前端
|
||||
// _Requirements: 1.4_
|
||||
if let Err(e) = app.emit("deep-link-connect", &result) {
|
||||
tracing::error!("[Connect] 发送 deep-link-connect 事件失败: {}", e);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
pub async fn handle_deep_link(_url: String) -> Result<DeepLinkResult, ConnectError> {
|
||||
Err(deprecated_connect_command_error("handle_deep_link"))
|
||||
}
|
||||
|
||||
/// 旧 Tauri open deep link 命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn handle_open_deep_link(url: String) -> Result<OpenDeepLinkResult, ConnectError> {
|
||||
tracing::info!("[Connect] 处理官网 Deep Link: {}", url);
|
||||
let payload = parse_open_deep_link(&url)?;
|
||||
|
||||
Ok(OpenDeepLinkResult { payload })
|
||||
pub async fn handle_open_deep_link(_url: String) -> Result<OpenDeepLinkResult, ConnectError> {
|
||||
Err(deprecated_connect_command_error("handle_open_deep_link"))
|
||||
}
|
||||
|
||||
/// 查询中转商信息
|
||||
///
|
||||
/// _Requirements: 2.3_
|
||||
/// 旧 Tauri registry 查询命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn get_relay_info(
|
||||
state: State<'_, ConnectStateWrapper>,
|
||||
relay_id: String,
|
||||
) -> Result<Option<RelayInfo>, ConnectError> {
|
||||
let state_guard = state.0.read().await;
|
||||
if let Some(connect_state) = state_guard.as_ref() {
|
||||
Ok(connect_state.registry.get(&relay_id))
|
||||
} else {
|
||||
Err(ConnectError {
|
||||
code: "NOT_INITIALIZED".to_string(),
|
||||
message: "Connect 模块未初始化".to_string(),
|
||||
})
|
||||
}
|
||||
pub async fn get_relay_info(_relay_id: String) -> Result<Option<RelayInfo>, ConnectError> {
|
||||
Err(deprecated_connect_command_error("get_relay_info"))
|
||||
}
|
||||
|
||||
/// 保存 API Key 的返回结果
|
||||
@@ -210,153 +117,26 @@ pub struct SaveApiKeyResult {
|
||||
pub is_new_provider: bool,
|
||||
}
|
||||
|
||||
/// 保存 API Key
|
||||
///
|
||||
/// 将 API Key 添加到 API Key Provider 系统。
|
||||
/// 如果中转商对应的 Provider 不存在,会自动创建一个自定义 Provider。
|
||||
///
|
||||
/// _Requirements: 4.1_
|
||||
/// 旧 Tauri API Key 保存命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn save_relay_api_key(
|
||||
state: State<'_, ConnectStateWrapper>,
|
||||
db: State<'_, DbConnection>,
|
||||
api_key_service: State<'_, ApiKeyProviderServiceState>,
|
||||
relay_id: String,
|
||||
api_key: String,
|
||||
name: Option<String>,
|
||||
_relay_id: String,
|
||||
_api_key: String,
|
||||
_name: Option<String>,
|
||||
) -> Result<SaveApiKeyResult, ConnectError> {
|
||||
let state_guard = state.0.read().await;
|
||||
let connect_state = state_guard.as_ref().ok_or_else(|| ConnectError {
|
||||
code: "NOT_INITIALIZED".to_string(),
|
||||
message: "Connect 模块未初始化".to_string(),
|
||||
})?;
|
||||
|
||||
// 获取中转商信息以确定协议类型和 base_url
|
||||
let relay_info = connect_state
|
||||
.registry
|
||||
.get(&relay_id)
|
||||
.ok_or_else(|| ConnectError {
|
||||
code: "RELAY_NOT_FOUND".to_string(),
|
||||
message: format!("中转商 {relay_id} 不在注册表中"),
|
||||
})?;
|
||||
|
||||
let protocol = relay_info.api.protocol.to_lowercase();
|
||||
let base_url = relay_info.api.base_url.clone();
|
||||
|
||||
// 确定 API Provider 类型
|
||||
let provider_type = if protocol == "claude" || protocol == "anthropic" {
|
||||
ApiProviderType::Anthropic
|
||||
} else {
|
||||
ApiProviderType::Openai
|
||||
};
|
||||
|
||||
// 生成 Provider ID(使用 connect- 前缀 + 中转商 ID)
|
||||
let provider_id = format!("connect-{relay_id}");
|
||||
|
||||
// 检查 Provider 是否已存在
|
||||
let existing_provider = api_key_service
|
||||
.0
|
||||
.get_provider(&db, &provider_id)
|
||||
.map_err(|e| ConnectError {
|
||||
code: "GET_PROVIDER_FAILED".to_string(),
|
||||
message: format!("查询 Provider 失败: {e}"),
|
||||
})?;
|
||||
|
||||
let (final_provider_id, is_new_provider) = if existing_provider.is_some() {
|
||||
// Provider 已存在,直接使用
|
||||
(provider_id, false)
|
||||
} else {
|
||||
// 创建新的自定义 Provider
|
||||
let provider_name = name
|
||||
.clone()
|
||||
.unwrap_or_else(|| format!("[Connect] {}", relay_info.name));
|
||||
let new_provider = api_key_service
|
||||
.0
|
||||
.add_custom_provider(
|
||||
&db,
|
||||
provider_name,
|
||||
provider_type,
|
||||
base_url,
|
||||
None, // api_version
|
||||
None, // project
|
||||
None, // location
|
||||
None, // region
|
||||
None, // prompt_cache_mode
|
||||
)
|
||||
.map_err(|e| ConnectError {
|
||||
code: "CREATE_PROVIDER_FAILED".to_string(),
|
||||
message: format!("创建 Provider 失败: {e}"),
|
||||
})?;
|
||||
|
||||
tracing::info!(
|
||||
"[Connect] 创建新 Provider: id={}, name={}",
|
||||
new_provider.id,
|
||||
new_provider.name
|
||||
);
|
||||
|
||||
(new_provider.id, true)
|
||||
};
|
||||
|
||||
// 添加 API Key 到 Provider
|
||||
let key_alias = name.or_else(|| Some(format!("[Connect] {}", relay_info.name)));
|
||||
let api_key_entry = api_key_service
|
||||
.0
|
||||
.add_api_key(&db, &final_provider_id, &api_key, key_alias.clone(), false)
|
||||
.map_err(|e| ConnectError {
|
||||
code: "ADD_API_KEY_FAILED".to_string(),
|
||||
message: format!("添加 API Key 失败: {e}"),
|
||||
})?;
|
||||
|
||||
tracing::info!(
|
||||
"[Connect] 已添加 API Key: relay={}, provider_id={}, key_id={}",
|
||||
relay_id,
|
||||
final_provider_id,
|
||||
api_key_entry.id
|
||||
);
|
||||
|
||||
Ok(SaveApiKeyResult {
|
||||
provider_id: final_provider_id,
|
||||
key_id: api_key_entry.id,
|
||||
provider_name: key_alias.unwrap_or_else(|| relay_info.name.clone()),
|
||||
is_new_provider,
|
||||
})
|
||||
Err(deprecated_connect_command_error("save_relay_api_key"))
|
||||
}
|
||||
|
||||
/// 刷新中转商注册表
|
||||
///
|
||||
/// _Requirements: 2.5_
|
||||
/// 旧 Tauri registry 刷新命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn refresh_relay_registry(
|
||||
state: State<'_, ConnectStateWrapper>,
|
||||
) -> Result<usize, ConnectError> {
|
||||
let state_guard = state.0.read().await;
|
||||
if let Some(connect_state) = state_guard.as_ref() {
|
||||
connect_state.registry.load_from_remote().await?;
|
||||
let count = connect_state.registry.len();
|
||||
tracing::info!("[Connect] 注册表已刷新,共 {} 个中转商", count);
|
||||
Ok(count)
|
||||
} else {
|
||||
Err(ConnectError {
|
||||
code: "NOT_INITIALIZED".to_string(),
|
||||
message: "Connect 模块未初始化".to_string(),
|
||||
})
|
||||
}
|
||||
pub async fn refresh_relay_registry() -> Result<usize, ConnectError> {
|
||||
Err(deprecated_connect_command_error("refresh_relay_registry"))
|
||||
}
|
||||
|
||||
/// 获取所有中转商列表
|
||||
/// 旧 Tauri registry 列表命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn list_relay_providers(
|
||||
state: State<'_, ConnectStateWrapper>,
|
||||
) -> Result<Vec<RelayInfo>, ConnectError> {
|
||||
let state_guard = state.0.read().await;
|
||||
if let Some(connect_state) = state_guard.as_ref() {
|
||||
Ok(connect_state.registry.list())
|
||||
} else {
|
||||
Err(ConnectError {
|
||||
code: "NOT_INITIALIZED".to_string(),
|
||||
message: "Connect 模块未初始化".to_string(),
|
||||
})
|
||||
}
|
||||
pub async fn list_relay_providers() -> Result<Vec<RelayInfo>, ConnectError> {
|
||||
Err(deprecated_connect_command_error("list_relay_providers"))
|
||||
}
|
||||
|
||||
/// 回调状态类型
|
||||
@@ -371,85 +151,15 @@ pub enum CallbackStatusType {
|
||||
Error,
|
||||
}
|
||||
|
||||
/// 发送统计回调
|
||||
///
|
||||
/// 在用户确认/取消配置后调用,向中转商发送统计回调
|
||||
///
|
||||
/// _Requirements: 5.3_
|
||||
/// 旧 Tauri webhook 回调命令已退场。
|
||||
#[tauri::command]
|
||||
pub async fn send_connect_callback(
|
||||
state: State<'_, ConnectStateWrapper>,
|
||||
relay_id: String,
|
||||
api_key: String,
|
||||
status: CallbackStatusType,
|
||||
ref_code: Option<String>,
|
||||
error_code: Option<String>,
|
||||
error_message: Option<String>,
|
||||
_relay_id: String,
|
||||
_api_key: String,
|
||||
_status: CallbackStatusType,
|
||||
_ref_code: Option<String>,
|
||||
_error_code: Option<String>,
|
||||
_error_message: Option<String>,
|
||||
) -> Result<bool, ConnectError> {
|
||||
tracing::info!(
|
||||
"[Connect] 发送统计回调: relay={}, status={:?}",
|
||||
relay_id,
|
||||
status
|
||||
);
|
||||
|
||||
// 获取中转商信息
|
||||
let relay_info = {
|
||||
let state_guard = state.0.read().await;
|
||||
if let Some(connect_state) = state_guard.as_ref() {
|
||||
connect_state.registry.get(&relay_id)
|
||||
} else {
|
||||
return Err(ConnectError {
|
||||
code: "NOT_INITIALIZED".to_string(),
|
||||
message: "Connect 模块未初始化".to_string(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 检查是否配置了 webhook
|
||||
let webhook = match relay_info {
|
||||
Some(info) => info.webhook,
|
||||
None => {
|
||||
tracing::debug!("[Connect] 中转商 {} 不在注册表中,跳过回调", relay_id);
|
||||
return Ok(false);
|
||||
}
|
||||
};
|
||||
|
||||
let webhook = match webhook {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
tracing::debug!("[Connect] 中转商 {} 未配置 webhook,跳过回调", relay_id);
|
||||
return Ok(false);
|
||||
}
|
||||
};
|
||||
|
||||
let callback_url = match webhook.callback_url {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
tracing::debug!("[Connect] 中转商 {} webhook 配置不完整,跳过回调", relay_id);
|
||||
return Ok(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 发送回调(异步,不阻塞)
|
||||
match status {
|
||||
CallbackStatusType::Success => {
|
||||
send_success_callback(&callback_url, &relay_id, &api_key, ref_code);
|
||||
}
|
||||
CallbackStatusType::Cancelled => {
|
||||
send_cancelled_callback(&callback_url, &relay_id, &api_key, ref_code);
|
||||
}
|
||||
CallbackStatusType::Error => {
|
||||
send_error_callback(
|
||||
&callback_url,
|
||||
&relay_id,
|
||||
&api_key,
|
||||
ref_code,
|
||||
error_code.as_deref().unwrap_or("UNKNOWN"),
|
||||
error_message.as_deref().unwrap_or("未知错误"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tracing::info!("[Connect] 统计回调已触发: relay={}", relay_id);
|
||||
Ok(true)
|
||||
Err(deprecated_connect_command_error("send_connect_callback"))
|
||||
}
|
||||
|
||||
@@ -1,121 +1,26 @@
|
||||
//! 文档导入 Tauri 命令
|
||||
//!
|
||||
//! 提供文档导入和解析功能。
|
||||
//! 文档导入 / 导出 legacy Tauri 命令退场占位。
|
||||
|
||||
use crate::commands::session_files_cmd::SessionFilesState;
|
||||
use std::path::Path;
|
||||
use tauri::State;
|
||||
const DEPRECATED_DOCUMENT_IMPORT_COMMAND_MESSAGE: &str =
|
||||
"文档导入 / 导出 legacy Tauri 命令已退场,请使用 App Server 或 Electron Desktop Host current 文件通道。";
|
||||
|
||||
/// 支持的文档格式
|
||||
const SUPPORTED_DOC_EXTENSIONS: &[&str] = &["md", "txt"];
|
||||
|
||||
/// 文档文件最大大小(5MB)
|
||||
const MAX_DOC_SIZE: u64 = 5 * 1024 * 1024;
|
||||
|
||||
/// 验证文件是否为支持的文档格式
|
||||
fn is_supported_document(file_path: &str) -> bool {
|
||||
let path = Path::new(file_path);
|
||||
if let Some(ext) = path.extension() {
|
||||
let ext_str = ext.to_string_lossy().to_lowercase();
|
||||
return SUPPORTED_DOC_EXTENSIONS.contains(&ext_str.as_str());
|
||||
}
|
||||
false
|
||||
fn deprecated_document_import_command() -> Result<(), String> {
|
||||
Err(DEPRECATED_DOCUMENT_IMPORT_COMMAND_MESSAGE.to_string())
|
||||
}
|
||||
|
||||
/// 导入文档内容
|
||||
///
|
||||
/// # 参数
|
||||
/// - `file_path`: 本地文档文件路径
|
||||
///
|
||||
/// # 返回
|
||||
/// 返回文档的文本内容
|
||||
#[tauri::command]
|
||||
pub async fn import_document(file_path: String) -> Result<String, String> {
|
||||
// 验证文件格式
|
||||
if !is_supported_document(&file_path) {
|
||||
return Err(format!(
|
||||
"不支持的文档格式。支持的格式:{}",
|
||||
SUPPORTED_DOC_EXTENSIONS.join(", ")
|
||||
));
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
let path = Path::new(&file_path);
|
||||
if !path.exists() {
|
||||
return Err("文件不存在".to_string());
|
||||
}
|
||||
|
||||
// 检查文件大小
|
||||
let metadata = std::fs::metadata(path).map_err(|e| format!("读取文件元数据失败: {}", e))?;
|
||||
if metadata.len() > MAX_DOC_SIZE {
|
||||
return Err(format!(
|
||||
"文档文件过大(最大 {}MB)",
|
||||
MAX_DOC_SIZE / 1024 / 1024
|
||||
));
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
let content = std::fs::read_to_string(path).map_err(|e| format!("读取文件失败: {}", e))?;
|
||||
|
||||
Ok(content)
|
||||
pub async fn import_document() -> Result<(), String> {
|
||||
deprecated_document_import_command()
|
||||
}
|
||||
|
||||
/// 导入文档并保存到会话
|
||||
///
|
||||
/// # 参数
|
||||
/// - `session_id`: 会话ID
|
||||
/// - `file_path`: 本地文档文件路径
|
||||
///
|
||||
/// # 返回
|
||||
/// 返回文档内容和保存的文件名
|
||||
#[tauri::command]
|
||||
pub async fn import_document_to_session(
|
||||
state: State<'_, SessionFilesState>,
|
||||
session_id: String,
|
||||
file_path: String,
|
||||
) -> Result<(String, String), String> {
|
||||
// 导入文档内容
|
||||
let content = import_document(file_path.clone()).await?;
|
||||
|
||||
// 生成文件名
|
||||
let path = Path::new(&file_path);
|
||||
let file_name = path
|
||||
.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.ok_or("无效的文件名")?;
|
||||
|
||||
// 保存到会话文件系统
|
||||
super::session_files_cmd::session_files_save_file(
|
||||
state,
|
||||
session_id,
|
||||
file_name.to_string(),
|
||||
content.clone(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok((content, file_name.to_string()))
|
||||
pub async fn import_document_to_session() -> Result<(), String> {
|
||||
deprecated_document_import_command()
|
||||
}
|
||||
|
||||
/// 保存导出的文档到指定路径
|
||||
///
|
||||
/// # 参数
|
||||
/// - `file_path`: 用户选择的目标文件路径
|
||||
/// - `content`: 要写入的文本内容
|
||||
#[tauri::command]
|
||||
pub async fn save_exported_document(file_path: String, content: String) -> Result<(), String> {
|
||||
let path = Path::new(&file_path);
|
||||
|
||||
if file_path.trim().is_empty() {
|
||||
return Err("导出路径不能为空".to_string());
|
||||
}
|
||||
|
||||
if let Some(parent) = path.parent() {
|
||||
if parent.as_os_str().is_empty() {
|
||||
return std::fs::write(path, content).map_err(|e| format!("保存导出文件失败: {}", e));
|
||||
}
|
||||
std::fs::create_dir_all(parent).map_err(|e| format!("创建导出目录失败: {}", e))?;
|
||||
}
|
||||
|
||||
std::fs::write(path, content).map_err(|e| format!("保存导出文件失败: {}", e))?;
|
||||
Ok(())
|
||||
pub async fn save_exported_document() -> Result<(), String> {
|
||||
deprecated_document_import_command()
|
||||
}
|
||||
|
||||
@@ -1,95 +1,37 @@
|
||||
//! 电商差评回复 Tauri 命令
|
||||
//!
|
||||
//! 提供电商差评回复的专门接口,封装 Skill 执行逻辑
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::State;
|
||||
|
||||
use crate::agent::AsterAgentState;
|
||||
use crate::commands::api_key_provider_cmd::ApiKeyProviderServiceState;
|
||||
use crate::config::GlobalConfigManagerState;
|
||||
use crate::database::DbConnection;
|
||||
use crate::skills::{execute_named_skill, SkillExecutionRequest, SkillExecutionResult};
|
||||
use crate::skills::SkillExecutionResult;
|
||||
|
||||
const DEPRECATED_ECOMMERCE_REVIEW_REPLY_COMMAND: &str =
|
||||
"旧电商差评回复 Tauri 快捷命令已下线;生产技能执行必须经 Agent / Skill current 主链。";
|
||||
|
||||
/// 电商差评回复请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EcommerceReviewReplyRequest {
|
||||
/// 电商平台
|
||||
pub platform: String,
|
||||
/// 差评链接
|
||||
pub review_url: String,
|
||||
/// 回复语气
|
||||
pub tone: String,
|
||||
/// 回复长度
|
||||
pub length: String,
|
||||
/// 自定义模板 (可选)
|
||||
pub template: Option<String>,
|
||||
/// AI 模型
|
||||
pub model: Option<String>,
|
||||
/// 执行 ID (可选)
|
||||
pub execution_id: Option<String>,
|
||||
}
|
||||
|
||||
/// 执行电商差评回复
|
||||
///
|
||||
/// 这是一个便捷接口,封装了 execute_skill 的调用
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `app_handle` - Tauri AppHandle
|
||||
/// * `db` - 数据库连接
|
||||
/// * `aster_state` - Aster Agent 状态
|
||||
/// * `request` - 电商差评回复请求
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(SkillExecutionResult)` - 执行结果
|
||||
/// * `Err(String)` - 错误信息
|
||||
#[tauri::command]
|
||||
pub async fn execute_ecommerce_review_reply(
|
||||
app_handle: tauri::AppHandle,
|
||||
db: State<'_, DbConnection>,
|
||||
api_key_provider_service: State<'_, ApiKeyProviderServiceState>,
|
||||
config_manager: State<'_, GlobalConfigManagerState>,
|
||||
aster_state: State<'_, AsterAgentState>,
|
||||
request: EcommerceReviewReplyRequest,
|
||||
_app_handle: tauri::AppHandle,
|
||||
_db: tauri::State<'_, DbConnection>,
|
||||
_api_key_provider_service: tauri::State<'_, ApiKeyProviderServiceState>,
|
||||
_config_manager: tauri::State<'_, GlobalConfigManagerState>,
|
||||
_aster_state: tauri::State<'_, AsterAgentState>,
|
||||
_request: EcommerceReviewReplyRequest,
|
||||
) -> Result<SkillExecutionResult, String> {
|
||||
tracing::info!(
|
||||
"[execute_ecommerce_review_reply] 开始执行: platform={}, url={}",
|
||||
request.platform,
|
||||
request.review_url
|
||||
);
|
||||
|
||||
// 构建用户输入
|
||||
let user_input = format!(
|
||||
"平台: {}\n差评链接: {}\n回复语气: {}\n回复长度: {}{}",
|
||||
request.platform,
|
||||
request.review_url,
|
||||
request.tone,
|
||||
request.length,
|
||||
request
|
||||
.template
|
||||
.as_ref()
|
||||
.map(|t| format!("\n自定义模板: {t}"))
|
||||
.unwrap_or_default()
|
||||
);
|
||||
|
||||
execute_named_skill(
|
||||
&app_handle,
|
||||
db.inner(),
|
||||
api_key_provider_service.inner(),
|
||||
config_manager.inner(),
|
||||
aster_state.inner(),
|
||||
SkillExecutionRequest {
|
||||
skill_name: "ecommerce-review-reply".to_string(),
|
||||
user_input,
|
||||
images: Vec::new(),
|
||||
request_context: None,
|
||||
provider_override: Some("anthropic".to_string()),
|
||||
model_override: request.model,
|
||||
execution_id: request.execution_id,
|
||||
session_id: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
Err(format!(
|
||||
"{DEPRECATED_ECOMMERCE_REVIEW_REPLY_COMMAND} command=execute_ecommerce_review_reply"
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user