# @anna-ai/app-runtime 中文文档

规范地址：https://npmcn.com/package/%40anna-ai/app-runtime/

版本：0\.27\.0
npm 元数据更新时间：2026-10-30T01:35:40.436Z
中文译文更新时间：2026-11-06T23:52:42.132Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40anna-ai/app-runtime
原文对照：https://npmcn.com/package/%40anna-ai/app-runtime/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：121 kB，3 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- 运行依赖：0 个
- 首次发布：2026-04-30T09:19:17.345Z
- 最新版本发布：2026-10-30T01:35:40.230Z
- 近 30 天下载量：2149（2026-10-06 至 2026-11-04，npm 官方下载统计）
- 已发布版本数：22（近 12 个月 22 个）

## 中文简介

Anna App浏览器运行时间 SDK. 由每个 Anna App iframe 装入;在 Message RPC 后桥上提供打出代理到主机(Anna 仪表板 /) `anna-app dev` (电话).

## 安装

```sh
npm install @anna-ai/app-runtime
```

也可以使用：`pnpm add @anna-ai/app-runtime`、`yarn add @anna-ai/app-runtime`、`bun add @anna-ai/app-runtime`

## README

# @anna-ai/app-runtime (英语)

Anna Apps 的浏览器运行时间 SDK. 每个Anna导入的本地ES模块 应用程序 iframe; 导出 `AnnaAppRuntime`,代表RPC调用 `postMessage` 到主机页面(制作中的Anna仪表板 `anna-app dev` (b) 利用当地发展手段.

> **0.3.1+ (单位:千美元)**: SDK是一个纯正的ES模块. 装入 `<script type="module">` + 键 `import { AnnaAppRuntime } from "…"`旧的 经典 `<script src>` + 键 `window.AnnaAppRuntime` 将全局删除.

## 在 Anna App 包内使用

使您的条目脚本成为模块并直接导入 SDK :

```html
<!-- index.html -->
<script src="./app.js" type="module"></script>
```

```js
// app.js
import { AnnaAppRuntime } from "/static/anna-apps/_sdk/latest/index.js";

const anna = await AnnaAppRuntime.connect();

await anna.window.set_title({ title: "My App" });

const out = await anna.tools.invoke({
  tool_id: "tool-twitter-handle-twitter-tool-abcd1234",
  method: "post_tweet",
  args: { text: "hi" },
});

anna.on("entry_payload", (p) => console.log(p));
```

> **不要用内线 `<script>`。 。 。 .** 捆绑的CSP是 `script-src 'self' <sdk-origin>` 没有 `unsafe-inline`/nonce,所以任何一个 内置脚本(包括将 SDK 连接到 )被屏蔽. 总是让你的条目 **外部** 模块 (单位:千美元)`<script src="app.js" type="module">`和 `import` 里面是SDK 里面是那个.

## 电线信封

```
{ kind: "req"|"res"|"event", id, ns, method, args | result | error }
```

主机验证每一次通话 与应用程序显示的ACL之前 转发到后端.

## RPC 超时

每个呼叫都有每个名称空间的默认;应用程序可以覆盖每个呼叫:

```js
// Use the namespace default (image: 180s)
const out = await anna.image.generate({ prompt: "..." });

// Override for one call (e.g. high-res / many images)
const out = await anna.image.generate(
  { prompt: "...", n: 4, size: "2048x2048" },
  { timeoutMs: 240000 }
);
```

| 命名空间 | 默认 | 理由 |
| --- | --- | --- |
| `image.*` | 180 s (简体中文) | 匹配主机的上游提供者超时( 种子 / Quen / 原生) |
| `upload.*` | 120 s (简体中文) | 大型多部分/谈判+确认 |
| `agent.*` | 300 s (简体中文) | `session.run` 循环模式 + 工具 多个回合 |
| `llm.*` | 180 s (简体中文) | 长期完成/大背景 |
| 其他的都一样 | 30s (中文(简体) ) | 存储 / 聊天 / 窗口 / prefs / fs / 工具 / 文物 |

超时是 _客户端_ 截止日期。 主机桥接没有 中止信号——后端总是运行到完成,但超时 承诺拒绝 `Error("RPC <ns>.<method> timed out after Nms")` 并放弃最终反应.

## 剧本来自何处

| 环境 | 来源 |
| --- | --- |
| 生产(安娜仪表板) | `matrix-nexus` 静态服务器, 路径 `/static/anna-apps/_sdk/<version>/index.js` |
| 本地 dev (`anna-app dev`(中文(简体) ) | `@anna-ai/cli` 调用服务器从它的 `node_modules` 并服务同一路径 |

捆绑的作者也是这样写的 `import { AnnaAppRuntime } from "/static/anna-apps/_sdk/latest/index.js"` ; URL是主机合同的一部分.

## 版本

此软件包的版本音轨 `dispatcher_version` (线条协议). 见 [`packages/VERSIONS.md`](https://npmcn.com/package/%40anna-ai/VERSIONS.md) 完全针状和起伏 程序.

## 目录

单个文件 `dist/index.js`原生ES模块(终到 `export { AnnaAppRuntime, ... }`),没有建设步骤,直接运行于任何现代 浏览器通过 `<script type="module">` 编号 : `import`。 。 。 .

## 代理运行输出封顶( V0. 26. 0)

主机为: 1.1.0-β.200 / 调度器 0.30 (论坛#403). 按呼输出 上限 `agent.session.run` 实值 `min(model output cap, 65 536)` 被夹住 模型的上下文预算储备金(占上下文的10%,——65 536)——例如:65 536 1M-context模型,20000在200K-context模型上. 逐项披露 现在,最后信息被缩短:

```js
const sess = await anna.agent.session({ submode: "auto" });
for await (const ev of sess.run({ content: prompt, maxTokens: 16384 })) {
  if (ev.event === "run_meta") console.log("cap:", ev.max_output_tokens);
  const tc = ev.choices?.[0]?.delta?.task_complete;
  if (tc?.truncated) {
    // status is still "completed": the graph ended normally, but the final
    // assistant message hit the per-call cap. Continue in the same session:
    // sess.run({ content: "continue exactly from: " + tail })
  }
}
```

-   `maxTokens?` (1.65536) 仅能 **下调** 封顶——永远不要在站台上方 型号。 关闭使用该模型自己的输出盖.
-   `task_complete.stop_reason` ∈ `endTurn | maxTokens | contentFilter | toolUse` (设置为 `llm.complete`是因为 `stopReason`(三); `truncated === (stop_reason === "maxTokens")`。 。 。 .
-   旧主机省略 `max_output_tokens` 编号 : `stop_reason` 编号 : `truncated`。 。 。 .

## 主机上下文:主题和语言(v0.24.0)

仪表盘告诉每个应用程序 **主题** 财务报告和审定财务报表 **UI 语言** 用户 选中, 因此 Apps 不再猜测 `prefers-color-scheme` 编号 : `navigator.language`。 。 。 . 不提供明确的赠款——这些是单向主播——应用广播(如: `auth.refresh`),从不调用RPC方法.

```js
const anna = await AnnaAppRuntime.connect();

anna.theme;      // 'light' | 'dark'           — already correct before the first paint
anna.themeMode;  // 'light' | 'dark' | 'system' — what the user picked
anna.locale;     // 'en' | 'zh-CN' | …          — dashboard UI language

// Subscribe; both replay the current value once, then fire on every change.
anna.onThemeChange(({ theme }) => { document.documentElement.dataset.theme = theme; });
anna.onLocaleChange(({ lang }) => i18n.setLocale(lang));
```

线条细节: Iframe URL 上的初始值 (单位:千美元)`…?wid=&t=&theme=light&themeMode=system&lang=zh-CN`并同步读取 内 `connect()`; 现场更改以 `{kind:"event", event:"theme.changed", payload:{theme, mode}}` 财务报告和审定财务报表 `{event:"locale.changed", payload:{lang}}`。旧宿主 - SDK回落到 `prefers-color-scheme` 财务报告和审定财务报表 `navigator.language`,因此保留 CSS 的倒置以备独立预览 :

```css
:root[data-theme="light"] { /* light tokens */ }
:root[data-theme="dark"]  { /* dark tokens  */ }
@media (prefers-color-scheme: dark) { :root:not([data-theme]) { /* dark tokens */ } }
```

## 媒体生成(v0.20

Async 视频任务 + 同步音频, 由每个应用程序打开 `media_grant` (显然必须宣布) `ui.host_api.video` 编号 : `.audio`:

```js
// One-shot sugar: submit + media_job events + getJob polling fallback
const job = await anna.video.generateAwait(
  { prompt: "Aerial drone shot over a misty pine forest", durationSec: 5,
    resolution: "768p", clientTag: "scene-3-broll" },
  { onProgress: (p) => bar.update(p), signal: abortController.signal }
);
video.src = job.result.url;         // presigned GET, ~30 min TTL

// URL expired (403)? Re-sign via getJob:
const fresh = await anna.video.getJob({ jobId: job.jobId });

// Raw job API: generate / getJob / cancelJob / listJobs
const { jobId, estimatedCostCU } = await anna.video.generate({ prompt: "..." });

// Sync TTS / STT
const speech = await anna.audio.speak({ text: "Welcome!", voice: "Cherry" });
const { text } = await anna.audio.transcribe({ audioUrl: "https://..." });

// Capability discovery: models, parameter space, CU pricing, remaining quota
const catalog = await anna.llm.catalog({ serviceType: "video_gen" });
```

### 音乐创作 (v0.23

Async 音乐工作( Y)`mjob_…`完全一样的工作API, `media_job` 活动及 以视频形式支付退款。 要求数 `ui.host_api.music` + 键 每个应用程序 `media_grant.music`。 。 。 .

```js
// Capability discovery first — models differ (lyrics vs prompt-embedded lyrics,
// fixed vs range length, mp3 vs wav, reference image …). Nothing is silently
// downgraded: an unsupported field fails with MUSIC_FEATURE_UNSUPPORTED (-32165)
// and error.data.alternatives lists models that do support it.
const { models } = await anna.llm.catalog({ serviceType: "music_gen" });
const m = models.find(x => x.isPlatformDefault);   // fal-ai/minimax-music/v2.6

const song = await anna.music.generateAwait(
  { prompt: "melancholic cinematic piano, slow ~70 BPM, rainy night",
    lyrics: "[Verse 1]\n…\n[Chorus]\n…",       // only when m.capabilities.lyrics
    model: m.modelName,
    clientTag: "scene-3-score",
    idempotencyKey: "canvas-node-8f3a-v2" },     // 24h replay → same job, no re-charge
  { onProgress: (p) => bar.update(p), signal: abortController.signal }
);
audio.src = song.result.url;     // presigned GET, ~30 min TTL; song.result.lyrics when returned
song.idempotentReplay;           // true when the key hit an existing job

// Range-length models (ElevenLabs / Stable Audio / ACE-Step) take durationSec;
// fixed-length models (MiniMax / Lyria) reject it. Instrumental-only models
// (Stable Audio) reject lyrics and instrumental:false.
await anna.music.generate({ prompt: "ambient pad", model: "fal-ai/ace-step", durationSec: 30, instrumental: true });
```

### 图像 async 任务和重新签名( v0. 25. 0)

`anna.image.generate` 编号 : `anna.image.edit` 保持同步和不变。 对于 2K/4K或 `quality: "high"` 使(60-120 s)选择相同的合成工作形状 作为视频/音乐—— `ijob_…` 编号, `media_job` 事件、预先持有 —— 结算 实际图像数量) ——退款——并重新签署任何已付文物 7天而不是在30min URL TTL之后丢失. 要求数 `ui.host_api.image` 列出新的方法名称+现有的 `image_grant` (单位:千美元)`allowGenerate` 编号 : `allowEdit`;没有新的赠款).

```js
// Same request body as image.generate, plus clientTag / idempotencyKey.
const job = await anna.image.generateAwait(
  { prompt: "A bold art-deco poster of the planet Mars", n: 2,
    model: "fal-ai/nano-banana-2", aspect_ratio: "9:16", params: { resolution: "4K" },
    clientTag: "poster-v3", idempotencyKey: `poster-v3:${attempt}` },   // 24h replay → same job, no re-charge
  { onProgress: (p) => status.textContent = `${p.state} · queue ${p.queuePosition ?? "-"}`,
    signal: abortController.signal }                                       // → image.cancelJob
);
job.result.images;        // [{url, r2Key, mimeType, width, height, expiresIn}] — url re-signed by getJob
job.billedCostCU;         // settled on actual output (≤ estimatedCostCU)

// Edit (optionally mask-based) as a job:
await anna.image.editAwait({ image_url, prompt: "replace the sky with aurora", mask_url, model: "openai/gpt-image-2" });

// Reload recovery / correlation — same four-pack as video / music:
const { jobs } = await anna.image.listJobs({ state: "running", clientTag: "poster-v3" });
const fresh = await anna.image.getJob({ jobId });      // every result.images[].url re-signed (~30 min)

// Re-sign already-paid artifacts (sync `images[].r2_key` or job `r2Key`), up to 7 days:
const { urls } = await anna.image.resign({ r2Keys: [img.images[0].r2_key, job.result.images[0].r2Key] });
// One key that is not yours → whole call fails with IMAGE_ASSET_NOT_FOUND (details.data.index).
```

表面错误为 `HostRpcError` 名称 : `IMAGE_JOB_NOT_FOUND`, (中文(简体) ), `IMAGE_JOB_NOT_CANCELLABLE`, (中文(简体) ), `IMAGE_CONTENT_REJECTED` (同时替换同步) 路径的前 `APP_PROVIDER_ERROR` 供养者安全拒绝者, `IMAGE_JOB_EXPIRED`, (中文(简体) ), `IMAGE_ASSET_NOT_FOUND`· ; `error.details.data` 现在携带 `allowed` 编号 : `alternatives` 编号 : `index`。 。 。 . `anna.llm.catalog` 图像条目报告 `capabilities.jobs` 还有, 对于 `image_edit`真实的 `options.n.max`。 。 。 .

### 模型认知选项(v0.220

每个 TTS / 图像模型描述它的取键在 `capabilities.options` (schema v2:) (中文(简体) ) `{type, min, max, step, values, default, scope, …}`) (中文(简体) ). 传出任何 他们进入 `params`; 一个模型不声明的密钥会被丢弃并重现到 `ignoredParams`从不收取附加费.

```js
const { models } = await anna.llm.catalog({ serviceType: "tts", voiceLanguage: "zh" });
const tts = models.find(m => m.isUserPreferred) ?? models.find(m => m.isPlatformDefault);
const out = await anna.audio.speak({
  text: "Welcome!",
  model: tts.modelName,
  voice: tts.capabilities.defaultVoice,
  params: { stability: 0.3, similarity_boost: 0.8 },   // keys from capabilities.options
});
out.params;         // what reached the provider
out.ignoredParams;  // e.g. ["similarity_boost"] on a model that only exposes stability

// Image: explicit model + size policy. `fit: "strict"` fails with
// IMAGE_SIZE_UNSUPPORTED (+ data.allowed) instead of snapping to the nearest size.
const img = await anna.image.generate({
  prompt: "A bold art-deco poster of the planet Mars",
  model: "fal-ai/nano-banana-2",
  aspect_ratio: "9:16",
  params: { resolution: "2K" },
  fit: "strict",
});
img.size; img.sizeAdjusted; img.images[0].width;   // real decoded dimensions
```

渲染器 `capabilities.options` 作为形式与共享 [`ModelOptionsForm`](https://anna.partners/developers/reference/model-options-form) 组件 — 平台使用的相同文件 `/llm` 在开发者中 指挥所游乐场.

费用为 **预收** 估计数中 `estimatedCostCU` 财务报告和审定财务报表 失败/离职/期满时全额退还。 中止 `generateAwait` 取消数 任务(队列=全额退款;运行取消是最佳效果).

## 常见问题

### @anna-ai/app-runtime 是什么？

Anna App浏览器运行时间 SDK\. 由每个 Anna App iframe 装入;在 Message RPC 后桥上提供打出代理到主机\(Anna 仪表板 /\) anna-app dev \(电话\)\.

### 如何安装 @anna-ai/app-runtime？

在项目目录运行 npm install @anna-ai/app-runtime，或使用 pnpm add / yarn add / bun add。

### @anna-ai/app-runtime 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/anna-ai\_\_app-runtime 是否存在。

### @anna-ai/app-runtime 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @anna-ai/app-runtime 可以商用吗？

@anna-ai/app-runtime 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @anna-ai/app-runtime 的下载量有多少？

根据 npm 官方下载统计，@anna-ai/app-runtime 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,149 次，日均约 72 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @anna-ai/app-runtime 还在维护吗？

最新版本 0\.27\.0 发布于 2026/10/30（8 天前）；至今共发布 22 个版本，其中过去 12 个月发布了 22 个；首次发布于 2026/04/30。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

