跳转到正文

Sitoo App SDK 开发者手册 ​

维护日期:2026-10-06。适用 SDK:@pi-market/sdk@0.0.3。能力、任务、资源包声明契约版本:1。

在线阅读源见开发者文档站,浏览器接入见浏览器 SDK 参考,兼容规范见标准。新增能力发现、业务 JSON 存储、图像任务列表与结构化 AppSdkError。本文的可信 Host 接口不能直接暴露给第三方应用。

本文依据实际源码。版本以 package.json 为准,公开行为变更同步更新本手册和 更新记录,见 维护规则。

1. 阅读路线与支持范围 ​

新应用先读 2–5 节,再按需阅读任务、配置、审批、MCP 和生图。完整参考是资料应用的 契约、命令、服务、任务转换、MCP 服务。

状态能力
已实现catalog、schema、帮助/命令、任务校验、配置、审批票据、MCP 桥、平台生图接口
应用负责业务服务、任务持久化、执行/取消/恢复、产物核验、领域安全、独立 UI
平台集成者接线注册 Provider、React 路由、IPC、账户服务和可信审批入口
已接入首版静态 spkg、签名市场、安装/更新/回滚、隔离 UI、浏览器客户端、平台能力绑定
设计中第三方后端 OS 沙盒、完整通用调度器、自动迁移、独立资源包市场与模型能力代理

可信后端仍需仓库内接线。静态 UI 应用可独立打包、上架、安装,不修改 Desktop;只允许首版已列出的平台能力。工作区 SDK 仍 private;开发工具输出独立 npm 目录包和无依赖浏览器 client,不表示已发布公共 npm。完整步骤见 开发工具快速开始。

2. 模块与依赖 ​

根目录要求 Node >=24,使用 pnpm workspace、ESM 和严格 TypeScript。应用依赖声明 "@pi-market/sdk": "workspace:*",沿用仓库 tsconfig;实际运行需支持当前 TypeScript 源码入口。

入口用途与边界
@pi-market/sdkmanifest、契约、任务/产物、catalog、命令/schema、配置声明、资源包/图像类型;无 Host 文件存储 API
@pi-market/sdk/hostApplicationHost、ApplicationProvider、AppApprovalTarget、AppConfigState;仅可信服务端/主进程
@pi-market/sdk/mcpregisterAppCapabilities;使用官方 MCP SDK 的可信服务端桥
@pi-market/sdk/uicreateAppClient;只在平台的隔离应用 iframe 内使用,不暴露完整 Desktop API

浏览器消费声明,权威 schema 校验在服务端,勿为此放开 unsafe-eval。应用不导入 @earendil-works/* 或 Desktop 内部 Runtime,不维护第二份 Agent loop。

建议 contract.ts 声明、service.ts 业务、commands.ts 调用桥、tasks.ts 通用视图、host.ts 可信集成。声明文件不导入业务文件系统。React/assistant-ui 工作先读 UI 指导。

3. 最小接入示例 ​

这是无文件/付费操作的服务端教学示例。固定账户仅用于演示;生产使用真实账户 scope。UI 路由和业务持久化需另接入。

ts
import {
  AppCatalog,
  appHelp,
  parseAppCommand,
  type AppInvocationContract,
  type RegisteredApp,
} from '@pi-market/sdk';
import { ApplicationHost, type ApplicationProvider } from '@pi-market/sdk/host';

const contract: AppInvocationContract = {
  contractVersion: 1,
  appId: 'example.hello',
  name: '问候示例',
  version: '0.1.0',
  description: '演示确定性调用。',
  uiEntry: 'hello',
  help: '输入 问候 name="小明";输入 help 查看帮助。',
  capabilities: [
    {
      id: 'greet',
      name: '问候',
      aliases: ['hello'],
      description: '返回问候,不产生外部副作用。',
      inputSchema: {
        type: 'object',
        additionalProperties: false,
        required: ['name'],
        properties: { name: { type: 'string', minLength: 1, maxLength: 40 } },
      },
      examples: ['问候 name="小明"'],
      permissions: [],
      requiresTask: false,
      requiresConfirmation: false,
    },
  ],
};
const registration: RegisteredApp = {
  manifest: {
    id: contract.appId,
    name: contract.name,
    version: contract.version,
    sdkRange: '>=0.0.1 <1.0.0',
    aiRuntime: 'none',
    permissions: [],
    ui: { entry: contract.uiEntry },
  },
  invocation: contract,
};
const provider: ApplicationProvider = {
  async invoke(input) {
    const parsed = parseAppCommand(contract, input);
    if (parsed.kind === 'natural') return undefined;
    if (parsed.kind === 'help') return appHelp(contract, parsed.ability?.id);
    return { appId: contract.appId, status: 'success', text: `你好,${parsed.parameters.name}!` };
  },
  async listTasks() {
    return [];
  },
  async getTask() {
    throw new Error('示例没有任务。');
  },
};
const host = new ApplicationHost(new AppCatalog([registration]), '.cache/sdk-guide-example', () =>
  'a'.repeat(64),
);
host.register(contract.appId, provider);
console.log(await host.invoke(contract.appId, '问候 name="小明"'));
console.log(await host.invoke(contract.appId, 'help'));

运行应输出 success 问候及帮助;空 name、未知参数和重复参数应拒绝。本例不使用配置存储,不创建目录。将代码保存到 SDK 目录的临时 .ts 文件,可由当前 Node 运行;不要将固定演示身份用于产品。

真实 Desktop 集成步骤:

  1. 在 app-catalog.ts 注册 RegisteredApp。
  2. 在 main.ts 账户服务初始化链注册 Provider,绑定当前账户数据。
  3. 给 uiEntry 注册 React 路由与打开应用入口。当前是路由标识,不是动态加载 HTML。
  4. 复用现有列表/任务/配置 IPC;新增 UI 桥定义明确类型、preload 接口与主进程校验。
  5. 模型调用另接 MCP 服务与运行时配置。catalog 不自动创建 UI 或启动 MCP。

4. 注册与声明 ​

RegisteredApp 为 manifest、invocation、可选 configuration。AppCatalog 校验 semver/SDK 范围、ID、重复 ID、契约版本、能力别名及 manifest/契约 ID、版本和 UI 一致性;不执行应用或安装依赖。

字段当前含义
id / appId稳定 ID,不使用显示名称作为身份
version / sdkRangesemver 版本与范围;0.0.1 阶段不承诺未来完全兼容
aiRuntime类型支持 pi/custom/none;声明不自动启动执行器或模型通道
permissions字符串声明;Host 没有完整权限代理或 OS 沙盒
packageDependencies类型已有 Pi 包依赖描述;应用依赖的自动下载/启用尚未实现
ui / uiEntry当前编译期入口,须相互一致

能力必填 id/name/aliases/description/inputSchema/examples/permissions/requiresTask/requiresConfirmation。至少一项能力,schema 为 object 且有 properties。推荐 additionalProperties=false,明确 required、长度及数量限额。

requiresTask 不自动创建任务或强制完整状态机;业务服务检查归属。requiresConfirmation 可拦截 Host 的明确命令,但不能保护绕过 Host 的未检查业务函数。

5. 命令、帮助与自然语言 ​

  • @ 应用后为空、help、帮助返回本地帮助;能力 帮助 查看单项。
  • 明确命令为 能力 key=value,含空格字符串用双引号;布尔 true/false,数值普通十进制,对象/数组使用 JSON。
  • 参数键当前只支持字母开头的字母数字,不用下划线/连字符。输入上限 10000 字符。
  • parseAppCommand 返回 help、command 或 natural。command.parameters 仍为字符串,虽校验时进行了类型转换,业务层仍须转换,不能把 "false" 当真值。
  • 解析时临时去掉 required 中 task,允许应用提示选任务;应用必须检查缺失/重名,不能默认选第一项。
  • formatAppCommand 对结构化参数做完整 schema 校验并转义;复杂 JSON 优先使用它生成命令。
  • natural 不是已发起模型请求,Provider 通常返回 undefined,交现有路由处理;不能直接作为 shell 命令。

工具函数:validateAppSchema(schema)、validateAppValue(schema,value)、parseAppCommand(contract,input)、formatAppCommand(contract,abilityId,parameters)、appHelp(contract,abilityId?)。

6. Provider、任务与产物 ​

ApplicationProvider 必需 invoke(input)、listTasks()、getTask(id),可选 executeApproved(target)。Host 提供 register(appId,provider)、invoke(appId,input)、listTasks(appId)、getTask(appId,id)。

AppCommandReply 为 appId/status/text,可附 runId/revision;status 为 success/processing/needs-input/needs-approval,表示调用结果,不代替持久任务状态。

AppTask 必含 id/appId/appVersion/contractVersion=1/title/revision(正整数)/status/updatedAt/artifacts;status 为 draft、queued、running、needs-input、needs-approval、completed、failed、cancelled。可附 phase/progress/error/resourceSnapshots。

AppOutput 必含 id/kind/resource,resource 为 local-file、local-directory 或 url,可附 name/mediaType/bytes/sha256。描述不授予文件权限、不保证文件或 URL 有效;真实生成、核验并保存后才报告交付成功。

Host 验证格式、归属、请求任务 ID 与列表重复 ID;持久化、领域状态机、版本迁移、幂等、取消/恢复和文件摘要由业务服务实现。账户在异步调用结束后变化,不证明副作用未发生,查询真实任务,不能直接重跑。

旧 AppRunReference/AppRunStatus/AppArtifact 保留资料领域兼容。新应用用 AppTask/AppOutput;scanning/review/delivering 等领域阶段映射为 phase,不塞进通用 status。

7. 配置与凭据 ​

configuration 声明 version/schema/defaults,可选 fields(placeholder/options)与 credentialSlots(id/label/required)。defaults 必须符合 schema。通用表单仅支持基础字段,复杂对象需专用 UI。

Host.configuration(appId) 返回 AppConfigState(appId/version/revision/values/credentials);credentials 只含布尔配置状态。Host.saveConfiguration(appId,revision,values,credentials?) 保存;revision 过期刷新后再编辑,不能覆盖。

存储在 Host.root 下 <scope>/<appId>/configuration.json,Desktop 使用 userData/applications。scope 为真实账户对应的 64 位小写十六进制标识,首次未保存 revision=0。

Desktop 注入 safeStorage crypto。凭据省略 slot 保留、空字符串删除、非空加密保存;未声明字段或无安全存储拒绝。required 为声明,业务执行仍需检查凭据是否存在。

Host.credential(appId,slot) 只用于可信服务端,不给 renderer/模型。配置损坏或 version 不兼容时拒绝覆盖;没有自动迁移器,修改 defaults 不替换已保存值。

8. 审批与安全 ​

当前图像能力已接入 Runtime 三模式;requiresConfirmation 的应用明确命令返回 needs-approval,引导可信 UI 审阅。不能宣称所有 Provider 都自动接入独立评审模型。

AppApprovalTarget 为 appId/capabilityId/taskId/revision/payload。可信入口审阅真实参数后调用 Host.approve(target) 获得票据,再 Host.executeApproved(target,ticket)。任务必须处于 needs-approval,能力声明 requiresConfirmation,revision 匹配。

票据绑定账户与完整目标,有效 60 秒、一次消费;参数变化/重放拒绝。账户切换平台调用 host.approvals.revoke();取消仍由业务服务处理。当前指纹基于 JSON.stringify,保持目标结构与序列化顺序,不随意重组。

AppApprovalLedger 是宿主内部机制,issue/consume 不暴露为应用或模型工具。payload 包含所有真实执行参数,服务执行前复验。模型 approved=true、资源文本、MCP 注解和 manifest 声明不能替代授权。

Host 面向可信内置 Provider,不是第三方安全沙盒。目录/链接/网络/付费/幂等保护需真实服务实现;安装权限与 OS 沙盒见 设计框架。

9. MCP 接入 ​

registerAppCapabilities(server,contract,invoke) 在官方 McpServer 注册 get_capabilities 与 invoke_capability。后者接受 id 和结构化 parameters,校验/格式化后调用同一服务,返回文本及 structuredContent。

invoke 绑定经过授权的服务入口;桥不提供认证、HTTP 服务、传输或审批。每应用独立 server 或明确适配路由,不在同 server 重复注册这些同名工具。

MCP 调用需保留 needs-approval,不能签票或绕过服务门禁。网络层另处理鉴权、loopback、Host/Origin、请求限额、账户与 token 失效。资料应用 host.ts 提供参考;annotations 只是提示。

10. sitoo_image 共享图像能力 ​

声明 manifest.permissions 含 sitoo_image:generate。平台 host.registerImages(provider) 注册唯一提供者,可信应用用 host.images(appId) 获得绑定身份的 AppImages;第三方 UI 不能直接获取 Host。

方法行为
getCapabilities()获取 enabled/configured、模型/比例/尺寸/参考图上限
generate(request)prompt 必填;可选 aspectRatio/resolution=1K或2K或4K/references;返回任务
getTask(id)/listTasks()查询应用归属任务,不重新提交
getArtifact(id)返回 PNG dataUrl,大图按需读取

模型/凭据由平台配置,request 不接受任意模型/密钥。Host 检查身份和声明权限,实际限额、审批、参考图安全由提供者处理。

SitooImageTask 有 submitting/queued/running/unknown 等专用状态,不等同 AppTask。未知结果先核对,不能自动重试收费请求。cancellation=false,取消等待不是取消上游。completed 不保证作品已保存,结合 artifacts.stored/archived 判断。

confirmBeforeGenerate 为遗留字段,不能绕过审批模式。详见 图像能力。

11. 行业资源包 ​

appResourcePackSchema.parse/safeParse 校验 AppResourcePack。字段为 contractVersion=1、id/version、targetAppId/appVersionRange、name/description/industries/license、可选 source、resources。

资源项含 id/kind/path/sha256/license,可选 attribution;kind 为 design-rule/style/reference/template/font/delivery-spec/checklist。路径用 /,拒绝穿越/冒号/反斜线、重复 ID 和大小写重复路径;包版本目前限普通 x.y.z。

仅校验声明,不核验实际文件哈希、不验证签名、不下载解压、不自动检查目标版本。调用方另用 semver 检查兼容。AppResourceSnapshot 为 packId/version/sha256,记录真实任务选择。

包不增加权限和执行入口;素材许可逐项核查,业务文本不能覆盖系统规则。只按任务读取所需规则,安装整包本身不占对话 Token。

12. 常见错误 ​

AppContractError.code 可供程序处理,以下是当前常见值,不是永久完整枚举。

错误码处理
INCOMPATIBLE_APP/INVALID_APP/INVALID_CAPABILITY修正版本、ID、契约和 schema
UNKNOWN_APP/APP_UNAVAILABLE检查 catalog 与 Provider,声明存在不代表执行器已加载
UNKNOWN_CAPABILITY/INVALID_PARAMETERS展示帮助及合法示例,不猜参数
LOGIN_REQUIRED/SESSION_CHANGED核对 scope,账户切换后重新绑定并查询真实结果
INVALID_TASK检查格式、归属、ID 和状态
STALE_PLAN/APPROVAL_REQUIRED/INVALID_APPROVAL重读方案重新审阅,不重放票据
NO_CONFIGURATION/INVALID_CONFIGURATION/CONFIGURATION_VERSION核对声明/文件/版本,保留原数据
STALE_CONFIGURATION/INVALID_CREDENTIAL/CREDENTIAL_STORAGE刷新配置、检查 slot 与安全存储,禁止明文回退
PERMISSION_REQUIRED/CAPABILITY_UNAVAILABLE检查生图权限及平台提供者

业务错误需应用定义。不要吞异常后报 success,也不要把 SDK 参数拒绝误判成任务未收费或未执行。

13. 验证与交付 ​

仓库根目录运行:

powershell
node node_modules/pnpm/bin/pnpm.cjs --filter @pi-market/sdk typecheck
node node_modules/pnpm/bin/pnpm.cjs --filter @pi-market/sdk test

应用另外检查业务类型和测试:独立 UI/@ 同任务、缺任务/重名/revision 变化、跨账户、授权拒绝、票据重放、取消/重启、失败产物、收费和交付幂等。用真实临时文件、模拟费用通道及故障场景;模拟测试不代表真实上游验收。

资料链路可参考 node scripts/verify-materials.ts,不是任意新应用的通用验证器。桌面接线执行相关 Desktop 回归,代码交付按根 AGENTS 验证、提交、启动。

开发工具已提供 create/pack/check/init-market/publish。安装、更新、回滚和卸载通过 Desktop 市场 UI 完成;参见快速开始。不是公开 REST 接口或公共 npm 发布服务。

13.1 静态包与浏览器契约 ​

AppPackage / appPackageSchema / validateAppPackage / safeAppPath 由根入口导出。包格式版本 1,execution 必须 static-platform;files 声明普通文件摘要和尺寸,bindings 绑定能力到 text.echo 或 images.generate。具体限制见快速开始。应用不能通过声明新增宿主工具或安装依赖;图像权限由平台执行,requiresConfirmation 不替代平台审批。

createAppClient() 返回 invoke、images、resources、configuration、dispose。invoke 参数为 capability、符合能力 schema 的 parameters、可选 UUID requestId;返回绑定能力结果,拒绝时抛 Error。图像结果是现有 SitooImageTask,按同一请求 ID 幂等;不要将提交结果当成已交付。images.getCapabilities/getTask/getArtifact 只访问本应用获准的配置与任务,watchTask 提供每两秒的有界轮询订阅(不是服务端事件)。resources.list/read 读取随包声明与最多 64 KB 的已校验文本,返回版本和 SHA-256 快照。configuration.get/save 使用声明式 schema、revision 和账户独立配置,不支持第三方凭据槽。dispose 撤销监听和未完成请求,不取消上游付费任务。

AppCatalog.add/remove 和 ApplicationHost.unregister 供可信宿主激活/停用包,不向应用 UI 授权。AppImages.generate 以及 AppImageProvider.generate 新增可选 requestId,旧代码不传仍兼容。0.0.2 为新增接口;旧包声明 sdkRange 必须包含 0.0.2,固定 0.0.1 的包需要明确更新兼容范围。

14. 手册持续更新 ​

公共 API/行为变更同批更新手册和 CHANGELOG;版本变化明确旧写法、新写法、兼容影响与数据迁移。类型存在但行为未实现继续标记,完成后再更新支持范围。示例改动验证类型与执行,行为改动运行有效测试。

规则已写入 SDK AGENTS,属于后续开发要求;目前没有自动 CI 文档一致性检查器,不能承诺自动生成手册。

弃用迁移:defineApp/tools → RegisteredApp/catalog 与能力契约/Provider;旧领域任务映射 AppTask;UI、MCP、审批需要真实接线,仅替换类型不足以完成迁移。