@anna-ai/app-runtime

中文文档
0.27.0发布于 2026/10/30MITES Module零依赖近 30 天下载 2149

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

中文使用文档
文档目录12 节
  1. 在 Anna App 包内使用
  2. 电线信封
  3. RPC 超时
  4. 剧本来自何处
  5. 版本
  6. 目录
  7. 代理运行输出封顶( V0. 26. 0)
  8. 主机上下文:主题和语言(v0.24.0)
  9. 媒体生成(v0.20
  10. 音乐创作 (v0.23
  11. 图像 async 任务和重新签名( v0. 25. 0)
  12. 模型认知选项(v0.220

@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 :

<!-- index.html -->
<script src="./app.js" type="module"></script>
// 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 超时

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

// 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 完全针状和起伏 程序.

目录

单个文件 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模型上. 逐项披露 现在,最后信息被缩短:

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方法.

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 的倒置以备独立预览 :

: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:

// 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。 。 。 .

// 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;没有新的赠款).

// 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从不收取附加费.

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 组件 — 平台使用的相同文件 /llm 在开发者中 指挥所游乐场.

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

版本与发布记录

@anna-ai/app-runtime 共发布 22 个版本,首次发布于 2026/04/30;过去 12 个月发布了 22 个版本。

版本发布日期距今
0.27.0latest2026/10/308 天前
0.26.02026/10/2315 天前
0.25.02026/10/2117 天前
0.23.02026/10/2018 天前
0.21.02026/10/1622 天前
0.20.02026/10/0929 天前

关于 @anna-ai/app-runtime 的常见问题

@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 和提交记录判断。