diff --git a/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.i18n.yaml index b069fead12..28cf5298c9 100644 --- a/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.i18n.yaml @@ -9,11 +9,11 @@ en: 129d30508926bbc5 zh: 15feff44556fc9b7 /agent-note-office-skills-in-every-deployment-with-one-office-kit-package/decision: - en: 1f3d54764b002e44 - zh: a9180e274648898c + en: 2605a9eddd6f91e6 + zh: 08536ad09042586d /agent-note-office-skills-in-every-deployment-with-one-office-kit-package/alternatives-considered: - en: dbf6832a4ba0107d - zh: b707f4c3bef6a7bc + en: 167c52da0171028f + zh: 9c87c2370d0719df /agent-note-office-skills-in-every-deployment-with-one-office-kit-package/consequences: - en: bd68079f92d2d06f - zh: 547b29beee76fc52 + en: bddb3b01e056346e + zh: 5372842365a10641 diff --git a/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.md b/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.md index 2309f6c624..d0288b6dff 100644 --- a/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.md +++ b/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.md @@ -14,7 +14,7 @@ The [Web bundle](../../../../packages/bundle/web-app/cordis.patch.yml) and the [ The bundled Python environment ([`tool-workspace-dependencies`](../../../../packages/skill/tool-workspace-dependencies/README.md)) mounts only in Desktop and in the SDK when a primary runtime is available. `skill-office` declares `pythonEnvironment: 'workspace-dependencies' | 'user'` explicitly; each bundle row selects the value for its deployment. The default is `'workspace-dependencies'` because older SDK patches replace the complete `config` of the `skill-office` row; such a patch omits the new key and keeps the bundled-environment instructions it was written for. -[`@deepseek-ai/dsh-office-kit`](../../../../packages/document/office-kit/README.md) owns Kit location and the shared conversion service. Its `/locate` entry accepts only explicit arguments: the consumer's own `import.meta.resolve` lookup. Native engine paths use ASAR-unpacked mapping. It reads no environment variables, and the entry imports only Node built-in modules as values, so a consumer can depend on it without loading Cordis services, Schemastery, or Kit. The [on-demand Office tools](2026-10-31-native-office-tool.md) run Kit operations inside the Host, so no deployment publishes Kit CLI paths or Office executable variables. +[`@deepseek-ai/dsh-office-kit`](../../../../packages/document/office-kit/README.md) owns Kit location and the shared conversion service. Kit location is an internal implementation of the provider and is not exported: the provider passes its own `import.meta.resolve` lookup, and native engine paths use ASAR-unpacked mapping. Location reads no environment variables. The [on-demand Office tools](2026-10-31-native-office-tool.md) run Kit operations inside the Host, so no deployment publishes Kit CLI paths or Office executable variables. An absent Kit degrades instead of failing a load. The conversion service registers and rejects conversions with code `unavailable`, retaining only a successful Kit import and reporting each distinct failure once; the `office_render`, `office_convert`, and `office_recalculate` tools stay registered and return that message when called. @@ -30,7 +30,7 @@ An absent Kit degrades instead of failing a load. The conversion service registe **Fail the conversion row when Kit is absent.** This reports the absence at load, which the misconfiguration rule prefers, but the absence belongs to the deployment rather than the configuration, and it disables preview rendering paths and dependent skills that do not need Kit. -**Keep a separate locator package.** A package without Cordis dependencies isolates `skill-office` from the service, but duplicates release, dependency-policy, and documentation configuration for one closely coupled component. The `/locate` subpath provides the same import isolation. +**Keep a separate locator package.** A package without Cordis dependencies isolates `skill-office` from the service, but duplicates release, dependency-policy, and documentation configuration for one closely coupled component. No consumer outside the provider needs to locate Kit, so the location logic stays inside the provider. ## Consequences @@ -38,4 +38,4 @@ Ordinary Web and SDK sessions without a bundled environment list the four Office Processes launched from the Desktop built-in terminal inherit `DSH_PRIMARY_RUNTIME`, so the SDK uses its bundled environment. The shell publishes no Kit location; child applications resolve their own Kit. -Verification covers the `/locate` import restriction, Kit lookup and engine resolution, conversion retry after a missing or unloadable Kit, deduplicated warnings, the `office_*` tools' `unavailable` results with an absent Kit, recorded Web and SDK sessions that list the Office skills, and Office profile end-to-end tests. +Verification covers Kit lookup from the provider's Kit entry ([kit-lookup.spec.ts](../../../../packages/document/office-kit/tests/kit-lookup.spec.ts)), engine resolution and ASAR-unpacked path mapping ([engine-package.spec.ts](../../../../packages/document/office-kit/tests/engine-package.spec.ts)), independent engine resolution per Kit installation ([anchors.spec.ts](../../../../packages/document/office-kit/tests/anchors.spec.ts)), conversion retry after a missing or unloadable Kit, deduplicated warnings, the `office_*` tools' `unavailable` results with an absent Kit, recorded Web and SDK sessions that list the Office skills, and Office profile end-to-end tests. diff --git a/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.zh.md b/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.zh.md index b14276170d..9be80330d1 100644 --- a/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-26-cross-deployment-office-kit.zh.md @@ -14,7 +14,7 @@ Status: implemented 内置 Python 环境([`tool-workspace-dependencies`](../../../../packages/skill/tool-workspace-dependencies/README.zh.md))只在 Desktop 以及有主运行时的 SDK 中挂载。`skill-office` 显式声明 `pythonEnvironment: 'workspace-dependencies' | 'user'`,由各 bundle 的配置行按部署选择取值。默认值为 `'workspace-dependencies'`,因为旧 SDK patch 会整体替换 `skill-office` 行的 `config`;这样的 patch 不含新键,仍保留它所针对的内置环境说明。 -[`@deepseek-ai/dsh-office-kit`](../../../../packages/document/office-kit/README.zh.md) 负责 Kit 定位和共享转换服务。其 `/locate` 入口只接收显式参数:消费方自己的 `import.meta.resolve` 查找函数。原生引擎路径使用 ASAR 解包映射。它不读取环境变量,且入口只以值的形式导入 Node 内置模块,因此消费方可以依赖它而不加载 Cordis 服务、Schemastery 或 Kit。[按需激活的 Office 工具](2026-10-31-native-office-tool.zh.md)在 Host 内执行 Kit 操作,因此任何部署都不发布 Kit CLI 路径或 Office 可执行文件变量。 +[`@deepseek-ai/dsh-office-kit`](../../../../packages/document/office-kit/README.zh.md) 负责 Kit 定位和共享转换服务。Kit 定位是提供方的内部实现,不对外导出:提供方传入自己的 `import.meta.resolve` 查找函数,原生引擎路径使用 ASAR 解包映射。定位不读取环境变量。[按需激活的 Office 工具](2026-10-31-native-office-tool.zh.md)在 Host 内执行 Kit 操作,因此任何部署都不发布 Kit CLI 路径或 Office 可执行文件变量。 Kit 缺失时降级,而不是加载失败。转换服务照常注册,以代码 `unavailable` 拒绝转换,只保留成功的 Kit 导入,并对每种不同的失败只报告一次;`office_render`、`office_convert` 和 `office_recalculate` 工具保持注册并在调用时返回该消息。 @@ -30,7 +30,7 @@ Kit 缺失时降级,而不是加载失败。转换服务照常注册,以代 **Kit 缺失时让转换配置行失败。** 这样能在加载时报告缺失,符合配置错误应尽早报告的规则;但缺失属于部署环境而非配置,而且会停用不需要 Kit 的预览渲染路径和依赖技能。 -**保留独立的定位包。** 没有 Cordis 依赖的独立包可以让 `skill-office` 与服务隔离,但要为一个紧密耦合的组件重复维护发布、依赖策略和文档配置。`/locate` 子路径提供了同样的导入隔离。 +**保留独立的定位包。** 没有 Cordis 依赖的独立包可以让 `skill-office` 与服务隔离,但要为一个紧密耦合的组件重复维护发布、依赖策略和文档配置。提供方以外没有消费方需要定位 Kit,因此定位逻辑留在提供方内部。 ## 影响 @@ -38,4 +38,4 @@ Kit 缺失时降级,而不是加载失败。转换服务照常注册,以代 从 Desktop 内置终端启动的进程会继承 `DSH_PRIMARY_RUNTIME`,因此 SDK 使用其内置环境。Desktop 壳不发布 Kit 位置;子应用自行解析自己的 Kit。 -验证覆盖 `/locate` 的导入限制、Kit 查找与引擎解析、Kit 缺失或无法加载后的转换重试、去重后的警告、Kit 缺失时 `office_*` 工具的 `unavailable` 结果、列出 Office 技能的录制 Web 与 SDK 会话,以及 Office profile 端到端测试。 +验证覆盖从提供方 Kit 入口查找 Kit([kit-lookup.spec.ts](../../../../packages/document/office-kit/tests/kit-lookup.spec.ts))、引擎解析与 ASAR 解包路径映射([engine-package.spec.ts](../../../../packages/document/office-kit/tests/engine-package.spec.ts))、按 Kit 安装独立解析引擎([anchors.spec.ts](../../../../packages/document/office-kit/tests/anchors.spec.ts))、Kit 缺失或无法加载后的转换重试、去重后的警告、Kit 缺失时 `office_*` 工具的 `unavailable` 结果、列出 Office 技能的录制 Web 与 SDK 会话,以及 Office profile 端到端测试。 diff --git a/apps/desktop/packaging/README.i18n.yaml b/apps/desktop/packaging/README.i18n.yaml index 61d5d71cfb..707cf5d160 100644 --- a/apps/desktop/packaging/README.i18n.yaml +++ b/apps/desktop/packaging/README.i18n.yaml @@ -45,8 +45,8 @@ en: b42f103358d0dfd7 zh: a534164ad9eb00da /desktop-packaging/runtime-file-selection-and-installation-checks: - en: 2a1763aa66d82272 - zh: cfd44dc5a0b7f528 + en: d3a8410de52fb3a7 + zh: e4faaaa1a5ead5d6 /desktop-packaging/desktop-runtime-preparation: en: 84be38ab3136fff7 zh: bb4ed12ee0e1dfa0 diff --git a/apps/desktop/packaging/README.md b/apps/desktop/packaging/README.md index c1da3a4698..b6a98f8b2f 100644 --- a/apps/desktop/packaging/README.md +++ b/apps/desktop/packaging/README.md @@ -252,7 +252,7 @@ Desktop packs workspace packages locally and installs external dependencies thro The [Electron shell file list](../scripts/electron-builder-config.mjs) excludes recognized JavaScript/CSS/TypeScript source maps and TypeScript build caches from the separate `resources/app.asar/node_modules` dependency collection. These exclusions preserve runtime code, native modules, WASM, data files (including ordinary `.map` assets), licenses, and notices; [shell archive tests](../tests/shell-file-selection.spec.ts) check retained bytes and exclusions. -The [Office conversion provider](../../../packages/document/office-kit/README.md) is a Host service mounted by web-app, so every application that loads web-app, including `dsh web` and Desktop, provides it together with the [Office tools](../../../packages/document/tool-office/README.md). The provider and its [`/locate` entry](../../../packages/document/office-kit/README.md#locate-kit) resolve the Kit's engine, including the mapping of native engine manifests to unpacked physical directories. Desktop packaging only carries and unpacks the engine: it carries the target’s declared native engine, or WASM when the kit declares no matching native target, and preparation rejects a missing target engine before packaging. The complete Office dependencies, including the JavaScript libraries and the selected engine’s executables, data, licenses, and notices, are unpacked under `resources/app.asar.unpacked/dsh/node_modules/`. The Desktop shell passes `DSH_PRIMARY_RUNTIME` in [main.ts](../src/main.ts) and no Kit location. Office skills are available in every application that loads web-app; only Desktop mounts the bundled Python environment (`workspace-dependencies`). On macOS, the native helper receives the JIT entitlement required by [LibreOffice’s UNO bridge](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in). The Computer Use helper applications under `@deepseek-ai/dsh-experimental-cua-macos/native/bin` are also unpacked whole under `resources/app.asar.unpacked/dsh/node_modules/`, and the provider opens that copy. +The [Office conversion provider](../../../packages/document/office-kit/README.md) is a Host service mounted by web-app, so every application that loads web-app, including `dsh web` and Desktop, provides it together with the [Office tools](../../../packages/document/tool-office/README.md). The provider [resolves the Kit's engine itself](../../../packages/document/office-kit/README.md#understand-the-implementation), including the mapping of native engine manifests to unpacked physical directories. Desktop packaging only carries and unpacks the engine: it carries the target’s declared native engine, or WASM when the kit declares no matching native target, and preparation rejects a missing target engine before packaging. The complete Office dependencies, including the JavaScript libraries and the selected engine’s executables, data, licenses, and notices, are unpacked under `resources/app.asar.unpacked/dsh/node_modules/`. The Desktop shell passes `DSH_PRIMARY_RUNTIME` in [main.ts](../src/main.ts) and no Kit location. Office skills are available in every application that loads web-app; only Desktop mounts the bundled Python environment (`workspace-dependencies`). On macOS, the native helper receives the JIT entitlement required by [LibreOffice’s UNO bridge](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in). The Computer Use helper applications under `@deepseek-ai/dsh-experimental-cua-macos/native/bin` are also unpacked whole under `resources/app.asar.unpacked/dsh/node_modules/`, and the provider opens that copy. The packaged application runs compiled JavaScript and pre-generated Typert metadata; it does not compile TypeScript plugins. Source-level debugger navigation and editor declarations remain available in development packages. [Copy-policy tests](../tests/runtime-file-policy.spec.ts) cover exclusions and retained assets; The [payload smoke](../tests/fixtures/runtime-payload-smoke.mjs) runs under Electron RunAsNode before the Host smoke and final inventory verification. The payload smoke resolves the search tool’s ripgrep executable and verifies text search and file enumeration. Signed Windows builds run these checks after dependency signing; other builds run them during `prepare:dsh`. The [Host smoke](../scripts/smoke-runtime.ts) creates DOCX, XLSX, and PPTX inputs with bundled Python and runs each through the real Office provider: PDF conversion, PNG rendering, conversion to the matching OpenDocument format, and, for XLSX, recalculation, checking each output's signature. Every assembled application, including directory and unsigned builds, repeats the payload and Host checks against ASAR. Archive integrity checks compare the complete archived descriptor with preparation, file bytes and membership in both archive and unpacked trees, recorded executable flags for archived files, and physical permissions for unpacked files. Conversion failures stop packaging before a release record is written; macOS DMG/ZIP builds run these checks before notarization. diff --git a/apps/desktop/packaging/README.zh.md b/apps/desktop/packaging/README.zh.md index 3d77fca58c..c403090d7f 100644 --- a/apps/desktop/packaging/README.zh.md +++ b/apps/desktop/packaging/README.zh.md @@ -252,7 +252,7 @@ Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安 [Electron 外壳文件清单](../scripts/electron-builder-config.mjs)从单独收集的 `resources/app.asar/node_modules` 依赖中排除已识别的 JavaScript/CSS/TypeScript source map 和 TypeScript 构建缓存。这些排除规则保留运行时代码、原生模块、WASM、数据文件(包括普通 `.map` 资源)、许可证和 notices;[外壳归档测试](../tests/shell-file-selection.spec.ts)检查保留文件的字节和排除项。 -[Office 转换提供方](../../../packages/document/office-kit/README.zh.md)是 web-app 挂载的 Host 服务,因此所有加载 web-app 的应用(包括 `dsh web` 和 Desktop)都提供它以及 [Office 工具](../../../packages/document/tool-office/README.zh.md)。该提供方及其 [`/locate` 入口](../../../packages/document/office-kit/README.zh.md#locate-kit)解析 Kit 的引擎,包括把原生引擎清单映射到解包后的实体目录。Desktop 打包只负责携带和解包引擎:携带目标声明的原生引擎;kit 未声明匹配的原生目标时携带 WASM;目标引擎缺失时,准备阶段在打包前拒绝。完整的 Office 依赖(包括 JavaScript 库以及所选引擎的可执行文件、数据、许可证和声明)解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下。Desktop 壳在 [main.ts](../src/main.ts) 中传入 `DSH_PRIMARY_RUNTIME`,不传 Kit 位置。所有加载 web-app 的应用都提供 Office 技能;只有 Desktop 挂载内置 Python 环境(`workspace-dependencies`)。在 macOS 上,原生 helper 获得 [LibreOffice UNO 桥](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in)所需的 JIT 权限。 `@deepseek-ai/dsh-experimental-cua-macos/native/bin` 下的 Computer Use helper 应用也整体解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下,提供方打开该副本。 +[Office 转换提供方](../../../packages/document/office-kit/README.zh.md)是 web-app 挂载的 Host 服务,因此所有加载 web-app 的应用(包括 `dsh web` 和 Desktop)都提供它以及 [Office 工具](../../../packages/document/tool-office/README.zh.md)。该提供方[自行解析 Kit 的引擎](../../../packages/document/office-kit/README.zh.md#understand-the-implementation),包括把原生引擎清单映射到解包后的实体目录。Desktop 打包只负责携带和解包引擎:携带目标声明的原生引擎;kit 未声明匹配的原生目标时携带 WASM;目标引擎缺失时,准备阶段在打包前拒绝。完整的 Office 依赖(包括 JavaScript 库以及所选引擎的可执行文件、数据、许可证和声明)解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下。Desktop 壳在 [main.ts](../src/main.ts) 中传入 `DSH_PRIMARY_RUNTIME`,不传 Kit 位置。所有加载 web-app 的应用都提供 Office 技能;只有 Desktop 挂载内置 Python 环境(`workspace-dependencies`)。在 macOS 上,原生 helper 获得 [LibreOffice UNO 桥](https://github.com/LibreOffice/core/blob/master/sysui/desktop/macosx/hardened_runtime.xcent.in)所需的 JIT 权限。`@deepseek-ai/dsh-experimental-cua-macos/native/bin` 下的 Computer Use helper 应用也整体解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下,提供方打开该副本。 `@deepseek-ai/dsh-experimental-cua-macos/native/bin` 下的 Computer Use helper 应用也整体解包到 `resources/app.asar.unpacked/dsh/node_modules/` 下,提供方打开该副本。 打包应用运行编译后的 JavaScript 和预生成的 Typert 元数据,不编译 TypeScript 插件。源码级调试导航和编辑器声明仍可从开发包中获取。[复制规则测试](../tests/runtime-file-policy.spec.ts)覆盖排除项和保留资源;[产物 smoke](../tests/fixtures/runtime-payload-smoke.mjs) 在 Host smoke 和最终清单验证之前,使用 Electron RunAsNode 执行。产物 smoke 解析搜索工具使用的 ripgrep 可执行文件,并验证文本搜索和文件枚举。Windows 签名构建在依赖签名后运行这些检查;其他构建在 `prepare:dsh` 中运行。[Host smoke](../scripts/smoke-runtime.ts) 使用捆绑的 Python 创建 DOCX、XLSX 和 PPTX 输入,并通过真实 Office 提供方逐一执行:PDF 转换、PNG 渲染、转换为对应的 OpenDocument 格式,以及针对 XLSX 的重算,检查每个输出的签名。每个组装后的应用(包括目录包和未签名构建)都会针对 ASAR 重复产物和 Host 检查。归档完整性检查将归档内完整描述符与准备结果比对,并核对归档和解包目录中的文件内容与清单、归档内文件记录的执行标志,以及解包文件的物理权限。转换失败会在写入发布记录前终止打包;macOS DMG/ZIP 构建在公证前执行这些检查。 diff --git a/docs/subsystems/office-kit.i18n.yaml b/docs/subsystems/office-kit.i18n.yaml index aa3bb95aaa..4f7dd739b6 100644 --- a/docs/subsystems/office-kit.i18n.yaml +++ b/docs/subsystems/office-kit.i18n.yaml @@ -6,8 +6,8 @@ en: ba1e27aece3a68c3 zh: 50ca71dd6c6a5438 /office-kit/ownership: - en: fa3d0415d6cbcfd3 - zh: f1f1a9641133f916 + en: 26905a1cd6947042 + zh: 16c00f451ddd15b0 /office-kit/requests-and-results: en: 4ae99f63ed85ce7f zh: 0db77cfc734788b1 diff --git a/docs/subsystems/office-kit.md b/docs/subsystems/office-kit.md index fde59caba3..63e694233a 100644 --- a/docs/subsystems/office-kit.md +++ b/docs/subsystems/office-kit.md @@ -8,7 +8,7 @@ The [document package family](../../packages/document/README.md) renders, conver | Owner | Responsibility | |---|---| -| [office-kit](../../packages/document/office-kit/README.md) | `ctx.officeKit`: shared LibreOffice rendering, conversion, and recalculation, bounded admission, output caching, and the per-Session output store; `/locate`, whose contract the package README owns: the caller's Kit entry, engine manifests from that installation, and native paths mapped to ASAR unpacked directories | +| [office-kit](../../packages/document/office-kit/README.md) | `ctx.officeKit`: shared LibreOffice rendering, conversion, and recalculation, bounded admission, output caching, and the per-Session output store; resolution of the provider's own Kit entry, engine manifests from that installation, and native paths mapped to ASAR unpacked directories | | [tool-office](../../packages/document/tool-office/README.md) | The on-demand `office_render`, `office_convert`, and `office_recalculate` tools: rendered images in tool results and converted or recalculated files returned for a shell copy | | [Web bundle](../../packages/bundle/web-app/README.md) and [SDK bundle](../../packages/bundle/sdk-app/README.md) | One configurable provider and `tool-office` shared by Host consumers | | [Office preview Client](../../packages/client/ui-sidebar-documentpreview/README.md#office-preview) | Office extension selection, PDF reuse, and missing-font notices | diff --git a/docs/subsystems/office-kit.zh.md b/docs/subsystems/office-kit.zh.md index 4d98b7dc51..385acbe192 100644 --- a/docs/subsystems/office-kit.zh.md +++ b/docs/subsystems/office-kit.zh.md @@ -8,7 +8,7 @@ | 所有者 | 职责 | |---|---| -| [office-kit](../../packages/document/office-kit/README.zh.md) | `ctx.officeKit`:共享 LibreOffice 渲染、转换与重算,有界准入、输出缓存和按 Session 划分的输出存储;`/locate`(契约由包 README 拥有):调用方的 Kit 入口、从该安装定位的引擎清单,以及映射到 ASAR 解包目录的原生路径 | +| [office-kit](../../packages/document/office-kit/README.zh.md) | `ctx.officeKit`:共享 LibreOffice 渲染、转换与重算,有界准入、输出缓存和按 Session 划分的输出存储;解析提供方自身的 Kit 入口、从该安装定位的引擎清单,以及映射到 ASAR 解包目录的原生路径 | | [tool-office](../../packages/document/tool-office/README.zh.md) | 按需激活的 `office_render`、`office_convert` 和 `office_recalculate` 工具:工具结果中的渲染图片,以及供 shell 复制的转换或重算文件 | | [Web bundle](../../packages/bundle/web-app/README.zh.md)与 [SDK bundle](../../packages/bundle/sdk-app/README.zh.md) | 由宿主消费者共享的单个可配置提供方及 `tool-office` | | [Office 预览 Client](../../packages/client/ui-sidebar-documentpreview/README.zh.md#office-preview) | Office 扩展名选择、PDF 复用和缺失字体提示 | diff --git a/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.i18n.yaml b/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.i18n.yaml index d361462866..3a53c97963 100644 --- a/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.i18n.yaml +++ b/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.i18n.yaml @@ -9,8 +9,8 @@ en: 4cbd51f0c6f0a9b9 zh: 2dffded2531f5144 /office-operation-skills-are-replaced-by-office-tools/change: - en: 63cc30fc8082d93e - zh: f5e1e4c54aac8bfc + en: 0781bed511c577fc + zh: 046098b87627786e /office-operation-skills-are-replaced-by-office-tools/migration: - en: 4b5517aad30b382e - zh: 9e648a24c9d67b55 + en: f7310e388e760885 + zh: 555d58d5236384db diff --git a/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.md b/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.md index 2c78052afd..a70adc65b8 100644 --- a/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.md +++ b/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.md @@ -9,23 +9,23 @@ English | [中文](guide.zh.md) ## Change -`@deepseek-ai/dsh-skill-office` no longer registers the `office-render`, `office-recalculate`, and `office-export-pdf` skills; it registers the `office` router and the `office-docx`, `office-pptx`, and `office-xlsx` authoring skills. Invoking or loading a removed skill finds no skill. After an Office skill loads, the model calls [`office_render`, `office_convert`, and `office_recalculate`](../../../../packages/document/tool-office/README.md) from the following step. +`@deepseek-ai/dsh-skill-office` no longer registers the `office-render`, `office-recalculate`, and `office-export-pdf` skills; it registers the `office` router and the `office-docx`, `office-pptx`, and `office-xlsx` authoring skills. After an Office skill loads, the model calls [`office_render`, `office_convert`, and `office_recalculate`](../../../../packages/document/tool-office/README.md) from the following step. Configuration changes: | Removed | Replacement | |---|---| -| `skill-office` keys `node` and `cli` | None; the Office tools run conversions in the Host | +| `skill-office` keys `node` and `cli` | None; Office tools convert in the Host | | `DSH_BUNDLED_OFFICE_CLI` and `DSH_BUNDLED_OFFICE_NODE` | None; no component reads them | | `DSH_BUNDLED_PRIMARY_RUNTIME` | `DSH_PRIMARY_RUNTIME` | `skill-office` gains `pythonEnvironment`. Its default, `'workspace-dependencies'`, directs the Python skills to `load_workspace_dependencies`; a composition without `@deepseek-ai/dsh-tool-workspace-dependencies` must set `'user'`. `DSH_BUNDLED_OFFICE_SKILLS` keeps its meaning. -The Office tools run the native LibreOffice Kit engine in the Host process, outside the shell sandbox and PTC permissions, so it parses untrusted documents with the Host user's permissions; inputs remain subject to the filesystem backend's read authority. The `office-kit` row gains `outputDirectory` (default `$DSH_HOME/office-kit/outputs`), `outputRetentionMs`, and `maxOutputStoreBytes`. +The Office tools parse untrusted documents with the native LibreOffice Kit engine in the Host process, outside the shell sandbox and PTC permissions, with the Host user's permissions; the filesystem backend still authorizes inputs. The `office-kit` row gains `outputDirectory` (default `$DSH_HOME/office-kit/outputs`), `outputRetentionMs`, and `maxOutputStoreBytes`. -The Web profile, and the SDK profile without a primary runtime, now list the Office skills in the first request context and `/` menu. +The Web profile, and the SDK profile without a primary runtime, list the Office skills in the first request context and `/` menu. -This affects users and prompts that use the removed skills, compositions and launchers that set the removed keys or variables, copies of the skill folders referenced by `assetRoot`, saved `standard` or `ptc` presets, deployments that rely on the shell sandbox for document parsing, and tests that pin the first request context or `/` menu. +This affects users and prompts of the removed skills, compositions and launchers setting the removed keys or variables, `assetRoot` skill copies, saved `standard` or `ptc` presets, deployments relying on the shell sandbox for document parsing, and tests pinning the first request context or `/` menu. ## Migration @@ -35,7 +35,7 @@ This affects users and prompts that use the removed skills, compositions and lau - `office-export-pdf`: `office_convert` with `format: "pdf"`. 2. Remove `node` and `cli` from every `skill-office` row in `cordis.yml`, patches, and overlays. Set `pythonEnvironment: user` unless the composition mounts `@deepseek-ai/dsh-tool-workspace-dependencies`. 3. Compositions that mount `@deepseek-ai/dsh-skill-office` without the shipped bundles also mount `@deepseek-ai/dsh-office-kit` and `@deepseek-ai/dsh-tool-office`. -4. In launchers, stop setting `DSH_BUNDLED_OFFICE_CLI` and `DSH_BUNDLED_OFFICE_NODE`, and rename `DSH_BUNDLED_PRIMARY_RUNTIME` to `DSH_PRIMARY_RUNTIME`. +4. In launchers, stop setting `DSH_BUNDLED_OFFICE_CLI` and `DSH_BUNDLED_OFFICE_NODE`, and rename `DSH_BUNDLED_PRIMARY_RUNTIME` to `DSH_PRIMARY_RUNTIME`. The Python SDK prefers a set or inherited `DSH_PRIMARY_RUNTIME`, even empty, over its download cache; Desktop's built-in terminal and model shells inherit it, so `unset DSH_PRIMARY_RUNTIME` there to use the cache. 5. In a copy referenced by `assetRoot`, replace the four remaining folders with the installed package's `assets/` and delete the three removed skill folders. 6. A `standard` or `ptc` preset saved from the Agent Preset editor replaces the shipped plugin list, so its Sessions lack the Office tools. Add this row to the saved list, or to `config.plugins` of the `preset-standard` or `preset-ptc` row in `$DSH_HOME/profiles//cordis.patch.yml` (``: `web` or `desktop`): @@ -45,5 +45,5 @@ This affects users and prompts that use the removed skills, compositions and lau ``` 7. Deployments that require sandboxed document parsing omit `@deepseek-ai/dsh-tool-office`. -8. Update expected first request contexts and `/` menus to include the Office skills. -9. Confirm: in a new `standard` or `ptc` Session, after `/office`, a PDF export request produces an `office_convert` call that returns a temporary PDF path or the `unavailable` message. +8. Update expected first request contexts and `/` menus with the Office skills. +9. Confirm: in a new `standard` or `ptc` Session, send `/office`, then a separate PDF export request; it produces an `office_convert` call that returns a temporary PDF path or the `unavailable` message. diff --git a/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.zh.md b/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.zh.md index 58b983c3fa..d13bf44a9b 100644 --- a/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.zh.md +++ b/docs/upgrade-guide/v0.2.2-alpha.2/office-operation-tools/guide.zh.md @@ -9,23 +9,23 @@ description: "删除 `office-render`、`office-recalculate` 和 `office-export-p ## 变更 -`@deepseek-ai/dsh-skill-office` 不再注册 `office-render`、`office-recalculate` 和 `office-export-pdf` 技能,只注册 `office` 路由技能,以及 `office-docx`、`office-pptx` 和 `office-xlsx` 编写技能。调用或加载已删除的技能会找不到技能。加载 Office 技能后,模型从下一步起调用 [`office_render`、`office_convert` 和 `office_recalculate`](../../../../packages/document/tool-office/README.zh.md)。 +`@deepseek-ai/dsh-skill-office` 不再注册 `office-render`、`office-recalculate` 和 `office-export-pdf` 技能,只注册 `office` 路由技能,以及 `office-docx`、`office-pptx` 和 `office-xlsx` 编写技能。加载 Office 技能后,模型从下一步起调用 [`office_render`、`office_convert` 和 `office_recalculate`](../../../../packages/document/tool-office/README.zh.md)。 配置变化: | 已删除 | 替代 | |---|---| -| `skill-office` 配置键 `node` 和 `cli` | 无;Office 工具在 Host 中执行转换 | +| `skill-office` 配置键 `node` 和 `cli` | 无;Office 工具在 Host 中转换 | | `DSH_BUNDLED_OFFICE_CLI` 和 `DSH_BUNDLED_OFFICE_NODE` | 无;不再有组件读取它们 | | `DSH_BUNDLED_PRIMARY_RUNTIME` | `DSH_PRIMARY_RUNTIME` | `skill-office` 新增 `pythonEnvironment`。默认值 `'workspace-dependencies'` 让 Python 技能调用 `load_workspace_dependencies`;没有挂载 `@deepseek-ai/dsh-tool-workspace-dependencies` 的组合必须设为 `'user'`。`DSH_BUNDLED_OFFICE_SKILLS` 含义不变。 -Office 工具在 Host 进程内运行原生 LibreOffice Kit 引擎,不受 shell 沙箱和 PTC 权限约束,因此以 Host 用户的权限解析不可信的文档;输入仍受文件系统后端的读取授权限制。`office-kit` 条目新增 `outputDirectory`(默认 `$DSH_HOME/office-kit/outputs`)、`outputRetentionMs` 和 `maxOutputStoreBytes`。 +Office 工具在 Host 进程内用原生 LibreOffice Kit 引擎解析不可信的文档,不受 shell 沙箱和 PTC 权限约束,并具有 Host 用户的权限;输入仍由文件系统后端授权。`office-kit` 条目新增 `outputDirectory`(默认 `$DSH_HOME/office-kit/outputs`)、`outputRetentionMs` 和 `maxOutputStoreBytes`。 -Web profile,以及没有 primary runtime 的 SDK profile,现在会在首次请求上下文和 `/` 菜单中列出 Office 技能。 +Web profile,以及没有 primary runtime 的 SDK profile,会在首次请求上下文和 `/` 菜单中列出 Office 技能。 -受影响的有:使用已删除技能的用户和提示词,设置了已删除配置键或环境变量的组合和启动器,`assetRoot` 引用的技能目录副本,已保存的 `standard` 或 `ptc` 预设,依赖 shell 沙箱解析文档的部署,以及固定了首次请求上下文或 `/` 菜单的测试。 +受影响的有:使用已删除技能的用户和提示词,设置了已删除配置键或环境变量的组合和启动器,`assetRoot` 技能副本,已保存的 `standard` 或 `ptc` 预设,依赖 shell 沙箱解析文档的部署,以及固定了首次请求上下文或 `/` 菜单的测试。 ## 迁移 @@ -35,7 +35,7 @@ Web profile,以及没有 primary runtime 的 SDK profile,现在会在首次 - `office-export-pdf`:`office_convert`,`format` 为 `"pdf"`。 2. 从 `cordis.yml`、patch 和 overlay 的所有 `skill-office` 行中删除 `node` 和 `cli`。除非组合挂载了 `@deepseek-ai/dsh-tool-workspace-dependencies`,否则设置 `pythonEnvironment: user`。 3. 不使用随发行版 bundle、自行挂载 `@deepseek-ai/dsh-skill-office` 的组合,同时挂载 `@deepseek-ai/dsh-office-kit` 和 `@deepseek-ai/dsh-tool-office`。 -4. 在启动器中不再设置 `DSH_BUNDLED_OFFICE_CLI` 和 `DSH_BUNDLED_OFFICE_NODE`,并把 `DSH_BUNDLED_PRIMARY_RUNTIME` 改名为 `DSH_PRIMARY_RUNTIME`。 +4. 在启动器中不再设置 `DSH_BUNDLED_OFFICE_CLI` 和 `DSH_BUNDLED_OFFICE_NODE`,并把 `DSH_BUNDLED_PRIMARY_RUNTIME` 改名为 `DSH_PRIMARY_RUNTIME`。Python SDK 优先使用环境中设置或继承的 `DSH_PRIMARY_RUNTIME`(空值也一样),其次才是下载缓存;Desktop 内置终端和模型 shell 会继承该变量,因此要在其中使用缓存,先执行 `unset DSH_PRIMARY_RUNTIME`。 5. 在 `assetRoot` 引用的副本中,用已安装包 `assets/` 下的对应目录替换其余四个目录,并删除三个已删除技能的目录。 6. 在 Agent 预设编辑器中保存过的 `standard` 或 `ptc` 预设会替换随发行版提供的插件列表,因此其 Session 没有 Office 工具。把下面这一行加入已保存的列表,或加入 `$DSH_HOME/profiles//cordis.patch.yml` 中 `preset-standard` 或 `preset-ptc` 行的 `config.plugins`(``:`web` 或 `desktop`): @@ -45,5 +45,5 @@ Web profile,以及没有 primary runtime 的 SDK profile,现在会在首次 ``` 7. 需要在沙箱中解析文档的部署不挂载 `@deepseek-ai/dsh-tool-office`。 -8. 更新首次请求上下文和 `/` 菜单的预期结果,加入 Office 技能。 -9. 确认:在 `standard` 或 `ptc` 的新 Session 中执行 `/office` 后,导出 PDF 的请求会产生一次 `office_convert` 调用,返回临时 PDF 路径或 `unavailable` 消息。 +8. 更新首次请求上下文和 `/` 菜单的预期结果,使其包含 Office 技能。 +9. 确认:在 `standard` 或 `ptc` 的新 Session 中发送 `/office`,再另发一条导出 PDF 的请求;该请求会产生一次 `office_convert` 调用,返回临时 PDF 路径或 `unavailable` 消息。 diff --git a/packages/bundle/web-app/README.i18n.yaml b/packages/bundle/web-app/README.i18n.yaml index 8c8259478d..8f085826af 100644 --- a/packages/bundle/web-app/README.i18n.yaml +++ b/packages/bundle/web-app/README.i18n.yaml @@ -69,11 +69,11 @@ en: 8732b94114bef9e0 zh: ab5f53bf541fae12 /deepseek-ai-dsh-web-app/model-experience/office-skills/what-the-model-sees: - en: 63ae1144027bdbab - zh: 20a4a08d14e74c2f + en: b6dc92ddf435f514 + zh: b907228a20afbd96 /deepseek-ai-dsh-web-app/model-experience/office-skills/token-effect: - en: e9ca0baef5de7a6e - zh: affb091495596cde + en: 9d9154d07ac52174 + zh: fcc6938b68025409 /deepseek-ai-dsh-web-app/model-experience/office-skills/kv-cache-effect: en: 43f28f4e120df7bb zh: 3b4e0d384986b293 diff --git a/packages/bundle/web-app/README.md b/packages/bundle/web-app/README.md index 566f8676b3..c61599cf5b 100644 --- a/packages/bundle/web-app/README.md +++ b/packages/bundle/web-app/README.md @@ -168,11 +168,11 @@ None; the plugin contributes no system-prompt text. #### What the model sees -The skill catalog lists the Office router and six Office skills in every profile. The loaded Python skills end with a Python environment section: on Desktop it directs the model to `load_workspace_dependencies`; elsewhere it directs the model to the project's or user's existing Python. +The skill catalog lists the Office router and three Office authoring skills in every profile. The loaded Python skills end with a Python environment section: on Desktop it directs the model to `load_workspace_dependencies`; elsewhere it directs the model to the project's or user's existing Python. #### Token effect -The seven catalog summaries in each initial catalog; loaded skill bodies only when the model requests them. +The four catalog summaries in each initial catalog; loaded skill bodies only when the model requests them. #### KV Cache effect diff --git a/packages/bundle/web-app/README.zh.md b/packages/bundle/web-app/README.zh.md index 22ea93741e..0f8dbc35b4 100644 --- a/packages/bundle/web-app/README.zh.md +++ b/packages/bundle/web-app/README.zh.md @@ -168,11 +168,11 @@ URL 行与浏览器交接都是就绪信号:监督方一观察到该行就发 #### 模型看到什么 -所有 profile 的技能目录都列出 Office 路由和六个 Office 技能。加载的 Python 技能末尾带一节 Python 环境说明:Desktop 上指引模型调用 `load_workspace_dependencies`;其他 profile 指引模型使用项目或用户已有的 Python。 +所有 profile 的技能目录都列出 Office 路由和三个 Office 创作技能。加载的 Python 技能末尾带一节 Python 环境说明:Desktop 上指引模型调用 `load_workspace_dependencies`;其他 profile 指引模型使用项目或用户已有的 Python。 #### Token 影响 -每个初始目录包含七条目录摘要;仅在模型请求时加载技能正文。 +每个初始目录包含四条目录摘要;仅在模型请求时加载技能正文。 #### KV Cache 影响 diff --git a/packages/document/README.i18n.yaml b/packages/document/README.i18n.yaml index 9a27c7747b..0f3aa8ae43 100644 --- a/packages/document/README.i18n.yaml +++ b/packages/document/README.i18n.yaml @@ -15,8 +15,8 @@ en: 1eb35b015a6c423f zh: a8a3dceee2c9e943 /document-office-documents/packages: - en: d5b4923f86ec13e1 - zh: 312ff5ac4ddf0e57 + en: 225177a571e9754d + zh: 466ffd3d6b89f95d /document-office-documents/related-documentation: en: b9691c6ee2c4db99 zh: 133970f11bfb85ee diff --git a/packages/document/README.md b/packages/document/README.md index f6458336f1..842485d538 100644 --- a/packages/document/README.md +++ b/packages/document/README.md @@ -26,7 +26,7 @@ Each package owns its configuration and lifetime rules; the subsystem reference | Package | Role | ctx key | |---|---|---| -| [office-kit](office-kit/README.md) | Authorized Office bytes to complete PDFs, PNG images, converted files, and recalculated workbooks with bounded queues and caching; consumer-anchored Kit entry and engine manifests through `/locate` | `ctx.officeKit` | +| [office-kit](office-kit/README.md) | Authorized Office bytes to complete PDFs, PNG images, converted files, and recalculated workbooks with bounded queues and caching; the provider resolves its own Kit entry, engine manifests, and ASAR-unpacked engine paths | `ctx.officeKit` | | [tool-office](tool-office/README.md) | `office_render`, `office_convert`, and `office_recalculate`, declared after an Office skill loads: render pages as images in the tool result, convert documents, and recalculate workbooks | — | ----- diff --git a/packages/document/README.zh.md b/packages/document/README.zh.md index 880ee3e50a..19cabc08b6 100644 --- a/packages/document/README.zh.md +++ b/packages/document/README.zh.md @@ -26,7 +26,7 @@ kind: "package-group" | 包 | 职责 | ctx 键 | |---|---|---| -| [office-kit](office-kit/README.zh.md) | 将已授权 Office 字节转换为完整 PDF、PNG 图片、转换后的文件和重算后的工作簿,并提供有界队列和缓存;通过 `/locate` 以消费方 Kit 为起点定位 Kit 入口和引擎清单 | `ctx.officeKit` | +| [office-kit](office-kit/README.zh.md) | 将已授权 Office 字节转换为完整 PDF、PNG 图片、转换后的文件和重算后的工作簿,并提供有界队列和缓存;提供方自行解析 Kit 入口、引擎清单和 ASAR 解包后的引擎路径 | `ctx.officeKit` | | [tool-office](tool-office/README.zh.md) | 加载 Office 技能后声明的 `office_render`、`office_convert` 和 `office_recalculate`:在工具结果中把页面渲染为图片、转换文档、重算工作簿 | — | ----- diff --git a/packages/document/office-kit/README.i18n.yaml b/packages/document/office-kit/README.i18n.yaml index 8d4684eb87..8e1778a342 100644 --- a/packages/document/office-kit/README.i18n.yaml +++ b/packages/document/office-kit/README.i18n.yaml @@ -30,8 +30,8 @@ en: cd1110fd1b70aaa0 zh: 623d77245348d129 /deepseek-ai-dsh-office-kit/known-limitations-and-deferred-work: - en: 84a398bf9544d7a7 - zh: bea8cf2fe57ae836 + en: 69c3e07db32dd27e + zh: 8c056a6253b9d0b0 /deepseek-ai-dsh-office-kit/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: 8ec3e73528ddb1a6 diff --git a/packages/document/office-kit/README.md b/packages/document/office-kit/README.md index 1cb0059d1e..1d8ae9c885 100644 --- a/packages/document/office-kit/README.md +++ b/packages/document/office-kit/README.md @@ -115,7 +115,7 @@ None; this service does not construct or modify model requests. - Conversion fidelity and installed native/WASM assets belong to `@deepseek-ai/libreoffice-kit`; this provider neither searches for system LibreOffice nor downloads an engine at runtime. - Queue waiting time is not bounded by `timeoutMs`, which starts only when kit conversion begins. - The provider locates only the Kit installation it resolves itself; it does not search other locations or install Kit or engines. -- Rendered images and converted files are returned as bytes; this service has no workspace output path, so each consumer owns publication. +- Rendered images are returned as bytes. Converted and recalculated files are stored in the provider's output directory, not in the workspace; the caller copies each file to its destination. - Mapping a native path does not verify that the unpacked copy exists. Kit rejects missing manifests or assets instead of treating them as an absent native package. diff --git a/packages/document/office-kit/README.zh.md b/packages/document/office-kit/README.zh.md index 3ddbeadf4a..5416322ec2 100644 --- a/packages/document/office-kit/README.zh.md +++ b/packages/document/office-kit/README.zh.md @@ -115,7 +115,7 @@ Remote 文件读取在查询转换缓存前重新检查内容读取授权和源 - 转换保真度和已安装的原生/WASM 资产由 `@deepseek-ai/libreoffice-kit` 负责;此提供方不查找系统 LibreOffice,也不在运行时下载引擎。 - `timeoutMs` 仅在 kit 开始转换时计时,不限制队列等待时间。 - 提供方只定位自身解析到的 Kit 安装;不搜索其他位置,也不安装 Kit 或引擎。 -- 渲染的图片和转换的文件以字节返回;此服务没有工作区输出路径,由各消费方负责发布。 +- 渲染的图片以字节返回。转换和重算后的文件存放在提供方的输出目录中,不写入工作区;由调用方把每个文件复制到目标位置。 - 映射原生路径时不验证解包副本是否存在。Kit 会拒绝缺失的清单或资源,而不会将其视为原生包缺失。 diff --git a/packages/document/tool-office/README.i18n.yaml b/packages/document/tool-office/README.i18n.yaml index fd4edbb909..12076b4d91 100644 --- a/packages/document/tool-office/README.i18n.yaml +++ b/packages/document/tool-office/README.i18n.yaml @@ -39,8 +39,8 @@ en: c4e3595dab58a800 zh: 65f7fcf46b1e3130 /deepseek-ai-dsh-tool-office/known-limitations-and-deferred-work: - en: c423feeb59afcf62 - zh: 9ddc3edb7f1cad76 + en: e0ef00aa70bb98c5 + zh: 9a13181df38062b7 /deepseek-ai-dsh-tool-office/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: e88aeb617ffb74ea diff --git a/packages/document/tool-office/README.md b/packages/document/tool-office/README.md index b77a181959..468e556e38 100644 --- a/packages/document/tool-office/README.md +++ b/packages/document/tool-office/README.md @@ -108,6 +108,7 @@ In native mode, activation during a conversation appends one `developer/message` - **Native engine in the Host process** — rendering, conversion, and recalculation that the model starts run the native LibreOffice Kit engine inside the Host process through `ctx.officeKit`, so the shell sandbox and PTC permissions do not confine them. Inputs remain subject to the filesystem backend's read authority. The native parser processes an untrusted document with the Host user's permissions. - **PTC activation does not survive resume or fork** — the PTC request header records only `run_code`, so a resumed or forked PTC Agent offers no Office bindings until the model loads an Office skill again; the removal and the re-addition each rewrite the system prompt, with the cache effect described under KV Cache effect. - **Plugin reload clears activation** — hot reload, or disabling and re-enabling the plugin, clears the in-memory marks. If a step runs in the meantime, its request header omits the three tools, and the model must load an Office skill again to restore them. +- **Direct invocation activates from the next step** — the tool set of a step is fixed before the content of a user-invoked skill such as `/office` is injected, so the first model request after the invocation declares no Office tools. The tools appear from the next model step. - Rendering fidelity, fonts, and pagination follow LibreOffice Kit and can differ from Microsoft Office. diff --git a/packages/document/tool-office/README.zh.md b/packages/document/tool-office/README.zh.md index 9edc1c53ca..bd3fa68bae 100644 --- a/packages/document/tool-office/README.zh.md +++ b/packages/document/tool-office/README.zh.md @@ -108,6 +108,7 @@ kind: "package-reference" - **原生引擎在 Host 进程内运行** — 由模型发起的渲染、转换和重算通过 `ctx.officeKit` 在 Host 进程内运行原生 LibreOffice Kit 引擎,因此不受 shell 沙箱和 PTC 权限约束。输入仍受文件系统后端读取权限的约束。原生解析器以 Host 用户的权限处理不可信的文档。 - **PTC 激活状态不跨恢复和分叉保留** — PTC 请求头只记录 `run_code`,因此恢复或分叉后的 PTC Agent 在模型重新加载 Office 技能前不提供 Office 绑定;移除和重新加入各重写一次系统提示,缓存影响见 KV Cache 影响一节。 - **插件重载会清除激活状态** — 热重载、或停用后再启用插件,会清空内存中的标记。如果期间运行过一步,该步的请求头不再包含这三个工具,模型须重新加载 Office 技能才能恢复。 +- **直接调用从下一步起激活** — 一步的工具集在用户调用的技能(如 `/office`)内容注入前就已确定,因此调用后的第一个模型请求不声明 Office 工具。这些工具从模型的下一步起出现。 - 渲染保真度、字体和分页取决于 LibreOffice Kit,可能与 Microsoft Office 不同。 diff --git a/packages/document/tool-office/src/content.ts b/packages/document/tool-office/src/content.ts index 6f0477386a..c0ac82beac 100644 --- a/packages/document/tool-office/src/content.ts +++ b/packages/document/tool-office/src/content.ts @@ -4,14 +4,15 @@ */ import type { ContentBlock } from '@deepseek-ai/dsh-llm' -import { AttachmentId, type ImageAttachmentRef } from '@deepseek-ai/dsh-attachment' -import type { OfficeConversionFormat } from '@deepseek-ai/dsh-office-kit' +import { AttachmentId, type ImageAttachmentRef, type ImageMediaType } from '@deepseek-ai/dsh-attachment' +import type { OfficeConversionFormat, OfficeRecalculationFormat } from '@deepseek-ai/dsh-office-kit' /** * One rendered image and the document location it shows. The attachment fields are those of the stored reference; - * storage normalization can re-encode a rendered PNG, so `mediaType` names the stored encoding. + * storage normalization keeps a rendered PNG or re-encodes it as JPEG or WebP, so `mediaType` names the stored encoding. */ -export interface OfficeRenderedImage extends Pick { +export interface OfficeRenderedImage extends Pick { + mediaType: Exclude /** One-based page or slide; absent for worksheet areas. */ page?: number /** Worksheet of a worksheet area. */ @@ -34,6 +35,12 @@ export interface OfficeRenderValue { missingFonts: string[] } +/** Output format of each file-producing operation. */ +export interface OfficeFileFormats { + convert: OfficeConversionFormat + recalculate: OfficeRecalculationFormat +} + /** Canonical result of `convert` and `recalculate`. */ export interface OfficeFileValue { operation: Operation @@ -41,7 +48,7 @@ export interface OfficeFileValue, Config> = z.object({ maxImageBytes: z.natural().min(1).max(Number.MAX_SAFE_INTEGER).default(32 * 1024 * 1024), }) -/** Stored encodings of a rendered image; attachment normalization can re-encode a PNG as JPEG or WebP. */ -const IMAGE_MEDIA_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const satisfies readonly ImageMediaType[] +/** Stored encodings of a rendered PNG: attachment normalization keeps it or re-encodes it as JPEG or WebP. */ +const IMAGE_MEDIA_TYPES = ['image/png', 'image/jpeg', 'image/webp'] as const satisfies readonly ImageMediaType[] const IMAGE_SCHEMA = { type: 'object', @@ -116,14 +117,17 @@ const PARAMETER_NAMES: Readonly> = { office_recalculate: Object.keys(RECALCULATE_PARAMETERS), } -const FILE_PROPERTIES = { - path: { type: 'string', required: true, description: 'Canonical absolute input path.' }, - file: { type: 'string', required: true, description: 'Absolute path of the temporary output file.' }, - format: { type: 'string', required: true, enum: OUTPUT_FORMATS }, - bytes: { type: 'integer', required: true }, - pageCount: { type: 'integer', description: 'Pages of a PDF output.' }, - missingFonts: MISSING_FONTS_SCHEMA, -} as const +/** Output schema properties of a file-producing operation whose `format` is one of `formats`. */ +function fileProperties(formats: Formats) { + return { + path: { type: 'string', required: true, description: 'Canonical absolute input path.' }, + file: { type: 'string', required: true, description: 'Absolute path of the temporary output file.' }, + format: { type: 'string', required: true, enum: formats }, + bytes: { type: 'integer', required: true }, + pageCount: { type: 'integer', description: 'Pages of a PDF output.' }, + missingFonts: MISSING_FONTS_SCHEMA, + } as const +} /** * Register Office tools admitted after a successful skill load or an earlier Office declaration. @@ -184,7 +188,7 @@ export function apply(ctx: Context, config: Config): void { parameters: CONVERT_PARAMETERS, output: { schema: { type: 'object', additionalProperties: false, properties: { - operation: { type: 'string', const: 'convert', required: true }, ...FILE_PROPERTIES, + operation: { type: 'string', const: 'convert', required: true }, ...fileProperties(OUTPUT_FORMATS), } }, render: (_args, value) => renderFileContent(value), presentationMeta: (_args, value) => ({ path: value.path, file: value.file }), @@ -206,7 +210,7 @@ export function apply(ctx: Context, config: Config): void { parameters: RECALCULATE_PARAMETERS, output: { schema: { type: 'object', additionalProperties: false, properties: { - operation: { type: 'string', const: 'recalculate', required: true }, ...FILE_PROPERTIES, + operation: { type: 'string', const: 'recalculate', required: true }, ...fileProperties(RECALCULATION_FORMATS), } }, render: (_args, value) => renderFileContent(value), presentationMeta: (_args, value) => ({ path: value.path, file: value.file }), @@ -356,11 +360,14 @@ async function render( images: result.images.map((image, index) => { // saveImages returns one reference per input, in input order. const ref = refs[index] as ImageAttachmentRef + const { mediaType } = ref + // Normalization of a PNG yields PNG, JPEG, or WebP. + if (mediaType === 'image/gif') throw new Error(`cannot render "${target.displayPath}": the attachment service stored a rendered PNG as GIF`) return { ...image.page === undefined ? {} : { page: image.page }, ...image.sheet === undefined ? {} : { sheet: image.sheet }, ...image.range === undefined ? {} : { range: image.range }, - attachmentId: ref.attachmentId, mediaType: ref.mediaType, bytes: ref.bytes, width: ref.width, height: ref.height, + attachmentId: ref.attachmentId, mediaType, bytes: ref.bytes, width: ref.width, height: ref.height, ...ref.originalDimensions === undefined ? {} : { originalDimensions: { ...ref.originalDimensions } }, } }), @@ -376,7 +383,8 @@ function outputOwner(ctx: Context, agent: Agent): string { } async function convertFile( - ctx: Context, kit: OfficeKit, agent: Agent, signal: AbortSignal, operation: Operation, args: OfficeConvertArgs | OfficeRecalculateArgs, + ctx: Context, kit: OfficeKit, agent: Agent, signal: AbortSignal, operation: Operation, + args: (OfficeConvertArgs | OfficeRecalculateArgs) & { format: OfficeFileFormats[Operation] }, target: FsTarget, source: OfficeKitSource, ): Promise> { const { format } = args diff --git a/packages/document/tool-office/tests/tool-office.spec.ts b/packages/document/tool-office/tests/tool-office.spec.ts index ebbc5453e6..0562a60f6e 100644 --- a/packages/document/tool-office/tests/tool-office.spec.ts +++ b/packages/document/tool-office/tests/tool-office.spec.ts @@ -209,6 +209,10 @@ describe('office schema', () => { expect(schemas[0]?.description).toBe('Render document pages, slides, or worksheet areas as images you can view.') expect(schemas[1]?.parameters).toMatchObject({ properties: { format: { enum: ['pdf', 'docx', 'odt', 'txt', 'xlsx', 'ods', 'csv', 'pptx', 'odp'] } } }) expect(schemas[2]?.parameters).toMatchObject({ properties: { format: { enum: ['xlsx', 'ods'] } } }) + const outputs = ctx.tools.definitions().map(definition => definition.output.schema) + expect(outputs[0]).toMatchObject({ properties: { images: { items: { properties: { mediaType: { enum: ['image/png', 'image/jpeg', 'image/webp'] } } } } } }) + expect(outputs[1]).toMatchObject({ properties: { format: { enum: ['pdf', 'docx', 'odt', 'txt', 'xlsx', 'ods', 'csv', 'pptx', 'odp'] } } }) + expect(outputs[2]).toMatchObject({ properties: { format: { enum: ['xlsx', 'ods'] } } }) for (const definition of ctx.tools.definitions()) { expect(definition.output.schema).toMatchObject({ type: 'object', properties: { operation: { const: definition.name.replace('office_', '') } } }) expect(definition.output.schema).not.toHaveProperty('oneOf') @@ -394,6 +398,15 @@ describe('render', () => { if (result.isError) throw new Error('render failed') expect(result.value).toMatchObject({ images: [{ originalDimensions: { width: 4, height: 4 } }] }) }) + + it('refuses a rendered image that attachment storage reports as GIF', async () => { + const { ctx } = await setup() + vi.spyOn(ctx.get('attachments')!, 'saveImages').mockResolvedValueOnce([{ + attachmentId: 'stored' as never, mediaType: 'image/gif', bytes: 1, width: 1, height: 1, + }]) + expect(text(await office(ctx, { operation: 'render', input: 'deck.pptx' }))) + .toContain(`cannot render "${join(dir, 'deck.pptx')}": the attachment service stored a rendered PNG as GIF`) + }) }) describe('Office service failures', () => { diff --git a/packages/skill/skill-office/README.i18n.yaml b/packages/skill/skill-office/README.i18n.yaml index 7bad2cd712..505b7c6e74 100644 --- a/packages/skill/skill-office/README.i18n.yaml +++ b/packages/skill/skill-office/README.i18n.yaml @@ -30,8 +30,8 @@ en: ed08fd35aa30c97c zh: 42e97ba44f07bcb5 /deepseek-ai-dsh-skill-office/model-experience/kv-cache-effect: - en: 4f5be3adfa364b3b - zh: 9c7ef5231d4e4a7d + en: 82649bba2b18f520 + zh: deb9b8c52d2205c6 /deepseek-ai-dsh-skill-office/known-limitations-and-deferred-work: en: af3a40fdd4da52d6 zh: 7e8a5aada81142e9 diff --git a/packages/skill/skill-office/README.md b/packages/skill/skill-office/README.md index 8ee68ab297..19d7f1171f 100644 --- a/packages/skill/skill-office/README.md +++ b/packages/skill/skill-office/README.md @@ -114,7 +114,7 @@ Indirectly, through `dsh-tool-skill`, which renders the initial Office summary a #### KV Cache effect -Skill results append to history, and loaded text or images remain after an operation finishes. With `tool-office` mounted, the first successful Office skill load enables the three tool declarations on the next step. A skill omitted or removed for unreadable resources changes the catalog, which a later step publishes as a catalog update. Character estimates use `ceil(characters / 4)`: the summary is at most 50 tokens and the router body at most 200; authoring bodies are at least 30% smaller than the combined authoring and operation guides. The appended Python environment section stays fixed while the configuration stays unchanged, and counts toward each skill body. Skill wrappers, the generic catalog, shell and Office tool declarations, and `load_workspace_dependencies` are separate costs, and these estimates are not server usage. +Skill results append to history, and loaded text or images remain after an operation finishes. With `tool-office` mounted, the first successful Office skill load enables the three tool declarations on the next step. A skill omitted or removed for unreadable resources changes the catalog, which a later step publishes as a catalog update. Character estimates use `ceil(characters / 4)`: the summary is at most 50 tokens and the router body at most 200; each authoring body is at most 70% of its recorded earlier estimate: 1,688 tokens for `office-docx`, 1,879 for `office-pptx`, and 2,330 for `office-xlsx`. The appended Python environment section stays fixed while the configuration stays unchanged, and counts toward each skill body. Skill wrappers, the generic catalog, shell and Office tool declarations, and `load_workspace_dependencies` are separate costs, and these estimates are not server usage. ## Known Limitations and Deferred Work diff --git a/packages/skill/skill-office/README.zh.md b/packages/skill/skill-office/README.zh.md index c87213b649..59ae307fb3 100644 --- a/packages/skill/skill-office/README.zh.md +++ b/packages/skill/skill-office/README.zh.md @@ -114,7 +114,7 @@ flowchart TD #### KV Cache 影响 -技能结果追加到历史中,操作完成后已加载文本或图片仍保留在历史中。挂载 `tool-office` 时,首次成功加载 Office 技能会在下一步启用三个工具声明。因资源不可读而省略或移除的技能会改变目录,后续步骤会将其作为目录更新发布。字符估算采用 `ceil(字符数 / 4)`:摘要最多 50 token,路由正文最多 200 token;创作正文比合并后的创作与操作指南至少减少 30%。配置不变时,追加的 Python 环境说明保持不变,并计入各技能正文。技能包装、通用目录、shell 与 Office 工具声明和 `load_workspace_dependencies` 单独计费;这些估算不等同于服务端 usage。 +技能结果追加到历史中,操作完成后已加载文本或图片仍保留在历史中。挂载 `tool-office` 时,首次成功加载 Office 技能会在下一步启用三个工具声明。因资源不可读而省略或移除的技能会改变目录,后续步骤会将其作为目录更新发布。字符估算采用 `ceil(字符数 / 4)`:摘要最多 50 token,路由正文最多 200 token;每个创作正文最多为其记录的早期估算的 70%:`office-docx` 为 1,688 token,`office-pptx` 为 1,879 token,`office-xlsx` 为 2,330 token。配置不变时,追加的 Python 环境说明保持不变,并计入各技能正文。技能包装、通用目录、shell 与 Office 工具声明和 `load_workspace_dependencies` 单独计费;这些估算不等同于服务端 usage。 ## 已知限制与后续工作 diff --git a/python/sdk-runtime/runtime-bootstrap.mjs b/python/sdk-runtime/runtime-bootstrap.mjs index 910cb11faf..a15d920ffd 100644 --- a/python/sdk-runtime/runtime-bootstrap.mjs +++ b/python/sdk-runtime/runtime-bootstrap.mjs @@ -89,7 +89,8 @@ if (resource !== undefined) { Reflect.deleteProperty(process.env, 'DSH_PTC_RUNTIME_NODE') await import('@deepseek-ai/dsh-ptc-runtime-node/process') } else if (selection === undefined) { - // A user-set DSH_PRIMARY_RUNTIME, including the empty opt-out, takes precedence over the downloaded cache. + // A DSH_PRIMARY_RUNTIME set or inherited from the environment, including the empty opt-out, takes precedence over the + // downloaded cache. if (cache !== undefined && existsSync(join(cache, 'primary', 'complete'))) { process.env.DSH_PRIMARY_RUNTIME ??= join(cache, 'primary', 'primary-runtime') } diff --git a/snapshots/session/office-progressive-ptc/system-prompt.expected.md b/snapshots/session/office-progressive-ptc/system-prompt.expected.md index 17fedc8982..4ed80b0fd2 100644 --- a/snapshots/session/office-progressive-ptc/system-prompt.expected.md +++ b/snapshots/session/office-progressive-ptc/system-prompt.expected.md @@ -975,7 +975,7 @@ interface ToolOutputMap { path: string; /** Absolute path of the temporary output file. */ file: string; - format: "pdf" | "docx" | "odt" | "txt" | "xlsx" | "ods" | "csv" | "pptx" | "odp"; + format: "xlsx" | "ods"; bytes: number; /** Pages of a PDF output. */ pageCount?: number; @@ -993,7 +993,7 @@ interface ToolOutputMap { sheet?: string; range?: string; attachmentId: string; - mediaType: "image/png" | "image/jpeg" | "image/webp" | "image/gif"; + mediaType: "image/png" | "image/jpeg" | "image/webp"; bytes: number; width: number; height: number;