前端 SDK

Preview

本预览版本供接口评估与集成规划使用。API 和数据结构可能在正式发布前调整。

快速开始

提供获取 Nuva 用户 token 的函数,再使用 createNuva() 初始化客户端。

TypeScript
import { createNuva, Message } from "@nuva/sdk";

const nuva = createNuva({
  getAccessToken: getNuvaAccessToken,
});

const main = await nuva.sessions.getMain();
const agent = nuva.agent({ sessionId: main.id });
const receipt = await agent.send(Message.text("开始广告创作,请先列出需要的产品资料。"));

getNuvaAccessToken(): Promise<string> 由应用提供,返回有效的 Nuva 用户 token;获取失败时抛出错误。

配置项类型说明
getAccessToken() => Promise<string>返回当前登录用户的 Nuva 访问 token。获取失败时抛出错误。

每个登录用户复用一个客户端实例。退出或切换账号时调用 nuva.close(),然后为新用户创建实例。服务凭证仅配置在后端。

业务对象 API

按业务类型读取和操作数据。每个对象拥有独立 ID;方法返回对应的 Product、Script、Directing Plan 等业务类型。

SDK 入口对象内容
nuva.productsProduct产品 brief、事实、来源和制作要求。
nuva.recipesRecipe可复用的创作指导及其版本。
nuva.scriptsScript创意、叙事、台词和画面意图。
nuva.directingPlansDirecting Plan落实到具体引用的角色和素材,以及细化的镜头安排。
nuva.promptsPrompt实际提交给生成模型的提示文本及其引用关系。
nuva.assetsAsset上传或生成的图片、视频、音频,以及位置、元数据和来源。
nuva.adsAd一条成片及其完整制作溯源的容器;制作中可尚未有成片。
nuva.batchesBatch多个 Ad 的集合,用于一起查看和推进。
nuva.experimentsExperiment实验或探索目标、广告成员、观察、证据和结论。
nuva.adMappingsAd Mapping实际投放视频与平台、账户及广告标识的对应关系。

读取对象

TypeScript
const script = await nuva.scripts.get(scriptId);
const plan = await nuva.directingPlans.get(planId);
const prompt = await nuva.prompts.get(promptId);
const ad = await nuva.ads.get(adId);
const batch = await nuva.batches.get(batchId);

get(id) 读取当前版本。需要读取消息、审核或制作流程中引用的确定版本时,传入 revision:

TypeScript
const script = await nuva.scripts.get(scriptRef.id, {
  revision: scriptRef.revision,
});

await agent.send(
  Message.create().mention(script).text("修改开场,保留其他内容。")
);

消息和业务对象的引用仍包含类型、ID 和版本。读取时使用相应类型的客户端;读取本身不触发 Agent 或生成任务。

制作关系

Script → Directing Plan → 多个 Prompt → 视频素材 → 成片

对象在流程中的作用
Script表达创作意图与内容,可用于不同的导演计划。
Directing Plan基于脚本,将角色、产品等概念落实为具体引用,并补充动作、构图、运镜和时间安排。
Prompt由导演计划形成,保存实际提交给模型的提示文本。多个 Prompt 可覆盖不同镜头;同一 Prompt 可生成多个候选素材。
Ad关联一条选定成片及其脚本、导演计划、提示词、素材和制作来源。
Batch组织多个 Ad;不替代 Ad 自身的制作关系。

Script、Directing Plan 和 Prompt 分别拥有 ID。引用确定的上游版本,保留实际采用的输入。修改脚本后,已有导演计划、提示词和素材仍可追溯到原版本。

独立生成操作可以接收直接输入。有已保存的来源时使用真实引用;没有时保存实际输入。

实验与投放

experiments 保存目标、广告成员、观察和结论。分析可以比较跨实验的广告,也可以从直接选定的广告开始;保留实际使用的证据和时间范围。

广告发布后,通过 adMappings 回传实际视频与平台广告的对应关系,将投放数据连接到正确的 Ad 和制作来源。

产品记录

产品表单通过 nuva.products 直接读写资料,无需先建立会话。

方法输入返回值
products.create(input)产品表单数据。已保存的产品记录。
products.get(id, options?)产品 ID;可通过 options.revision 指定版本。对应版本的 Product。
products.update({ base, data })读取到的产品记录 base,以及编辑后的产品数据 data。保存后的产品新版本。
TypeScript
const product = await nuva.products.create(productForm);
const current = await nuva.products.get(product.ref.id);

const saved = await nuva.products.update({
  base: current,
  data: editedBrief,
});

产品资料包括 brief、事实及其来源、要求和输入素材。保持未修改事实的来源信息。保存成功后使用返回的记录和新版本。

base.ref.revision 是写入前提。记录已被其他操作更新时返回 REVISION_CONFLICT;保留编辑内容,读取新版本后重新确认修改。

脚本记录与生成

方法输入返回值
scripts.get(id, options?)脚本 ID;可通过 options.revision 指定版本。对应版本的 Script。
scripts.update({ base, data })读取到的脚本记录 base,以及编辑后的脚本内容 data。保存后的脚本新版本。
scripts.generate(request)脚本生成请求。新生成并保存的脚本记录。

直接修改

TypeScript
const script = await nuva.scripts.get(scriptId);
const revised = await nuva.scripts.update({
  base: script,
  data: editedScript,
});

update() 保存编辑内容并校验版本与可编辑字段;它不会调用模型重新创作。历史版本保持可查询。已有导演计划、提示词和视频不会被这次保存自动改写。

生成后交给 Agent 修改

TypeScript
const script = await nuva.scripts.generate(scriptRequest);

await agent.send(
  Message.create()
    .mention(script)
    .text("把开场改得更自然,保留其他内容。")
);

每次新的生成请求返回独立结果。Agent 根据脚本引用读取其内容和已保存的输入。直接保存产品或脚本后,相关会话在继续工作时获得记录更新信息,无需补发一条聊天消息来同步数据。

会话状态与订阅

agent.subscribe(listener) 立即提供当前会话状态,并在消息或状态变化时再次调用 listener。返回值是取消订阅函数。

TypeScript
const unsubscribe = agent.subscribe((state) => {
  if (state.status === "loading") return;
  if (state.status === "error") {
    console.error(state.error);
    return;
  }

  console.log(state.status, state.messages.items);
});

// 不再需要接收更新时调用 unsubscribe()。

每次回调收到的 state 包含以下字段:

字段值 / 类型说明
statusloading | error | idle | running | waiting_for_response初次加载使用 loading/error。加载完成后直接显示 Agent 执行状态。
sessionSession会话 ID、类型、标题及所属用户;完成加载后可用。
messagesPage<MessageView>已加载的消息及历史分页游标;完成加载后可用。
callIdsreadonly string[]waiting_for_response 状态下正在等待的调用 ID。
errorNuvaErrorInfo初次加载失败的原因,或已有数据的同步错误。

重连或加载更早消息时,保留已有内容与最后已知的执行状态。同步失败通过 error 报告,恢复同步后清除。send/respond 的操作错误由各自的 Promise 返回。

取消订阅只停止本地更新,已开始的服务端工作继续运行。

消息与引用

发送消息

TypeScript
await agent.send(Message.text("继续修改第二条脚本。"));

await agent.send(
  Message.create()
    .text("修改 ")
    .mention(script)
    .text(" 的开场,保留其他内容。")
);

await agent.send(
  Message.create().replyTo(existingMessage).text("使用这一版。")
);
方法参数用途
Message.text()string创建纯文本消息。
Message.create().text()string追加文字。
.mention()RecordLink在文字中插入记录引用。
.attach()RecordLink添加消息附件。
.quote()RecordLink | MessageView, string引用记录或消息中的选定文字。
.replyTo()MessageView指定被回复的消息。

构建方法返回新的消息值。send() 成功后返回已保存消息的引用;Agent 回复通过消息订阅到达。

JSON
{
  "requestId": "request_21",
  "message": {
    "sessionId": "work_product_a",
    "messageId": "message_12"
  }
}

记录引用

将业务 API 返回的对象传入 mention() 或 attach()。revision 指定记录版本。

JSON
{
  "ref": { "kind": "script", "id": "script_1", "revision": "1" },
  "label": "脚本 1"
}

接收消息

JSON
{
  "ref": { "sessionId": "work_product_a", "messageId": "message_10" },
  "role": "assistant",
  "createdAt": "2026-10-12T18:00:00Z",
  "state": "complete",
  "attachments": [],
  "content": [
    { "id": "part_text", "type": "text", "format": "markdown", "text": "脚本已生成。" },
    {
      "id": "part_script_1",
      "type": "resource",
      "record": {
        "ref": { "kind": "script", "id": "script_1", "revision": "1" },
        "label": "脚本 1"
      }
    }
  ]
}
字段说明
ref来源会话 sessionId 与消息 messageId。转发消息保留原引用。
roleuser 或 assistant。用户消息的 metadata.user 提供发送者身份。
content有序内容列表:text、mention、resource、quote、dynamic-tool 或 data-host-call。
statestreaming | complete | interrupted | failed。failed 时包含 error。
attachments消息附件列表。
replyTo可选的被回复消息引用。

按 SDK 返回的顺序显示 messages.items。流式更新会合并到原消息;无需自行拼接网络片段。

完整消息示例

客户端工具

问答、许可确认和内容审核通过消息中的 dynamic-tool 交互。使用 toolName 选择处理函数,使用 toolCallId 关联结果。

JSON
{
  "type": "dynamic-tool",
  "toolName": "nuva.review",
  "toolCallId": "call_17",
  "state": "input-available",
  "input": {
    "prompt": "请审核这条脚本。批准后将继续细化导演计划。",
    "records": [{ "kind": "script", "id": "script_1", "revision": "1" }]
  }
}
状态处理方式
input-available读取完整 input,显示交互内容并等待用户回应。
output-available从 output 读取已保存的结果。
output-error从 errorText 读取失败说明。

提交结果

将收到的工具调用和结果传入 respond()。结果必须符合该工具的 outputSchema。

TypeScript
// part 是消息中 state 为 input-available 的工具调用。
const receipt = await agent.respond(part, {
  decision: "reject",
  text: "先展示产品,再讲困扰。",
});

nuva.review 使用 decision: "approve" | "reject" 和 text。无补充说明时传入空字符串。方法在服务端保存结果后返回:

JSON
{
  "requestId": "request_22",
  "call": {
    "type": "dynamic-tool",
    "toolName": "nuva.review",
    "toolCallId": "call_17",
    "state": "output-available",
    "input": {
      "prompt": "请审核这条脚本。批准后将继续细化导演计划。",
      "records": [{ "kind": "script", "id": "script_1", "revision": "1" }]
    },
    "output": { "decision": "reject", "text": "先展示产品,再讲困扰。" }
  }
}

后续 Agent 回复继续通过消息订阅到达。仍在等待回应的调用可从历史消息或转发消息中提交。

提交执行错误

无法取得有效结果时调用 fail()。用户拒绝审核应作为正常结果传给 respond()。

TypeScript
await agent.fail(part, {
  code: "EDITOR_UNAVAILABLE",
  message: "脚本编辑器加载失败。",
});

返回值包含 requestId 和状态为 output-error 的 call。

Host call

通过 onHostCall() 订阅已注册的网站交互。将 toolName 映射到应用的页面、编辑器或其他操作。

TypeScript
const unsubscribe = agent.onHostCall((part) => {
  if (part.type === "dynamic-tool") {
    if (part.state !== "input-available") return;
    host.receive(part.toolName, part.input, part);
  } else {
    host.receive(part.data.toolName, part.data.input, part);
  }
});

// 不再处理 host call 时调用 unsubscribe()。

host.receive 是应用提供的处理函数。需要结果的 dynamic-tool 使用 respond() 或 fail() 回传结果。

不要求结果的 host call 使用 data-host-call。按其 input 执行应用操作,无需回传:

JSON
{
  "type": "data-host-call",
  "id": "host_19",
  "data": {
    "toolName": "workspace.showScripts",
    "input": {
      "records": [{ "kind": "script", "id": "script_1", "revision": "1" }]
    }
  }
}

Host call 同时保存在消息内容中。历史渲染只展示保存的内容;自动执行时按调用 ID 去重。

在服务端授权配置中启用对应 UI skill。前端处理函数使用该 skill 中注册的方法名和输入格式。

方法参考

方法返回类型用途
nuva.sessions.getMain()Promise<Session>读取当前用户的主会话。
nuva.sessions.list(query?)Promise<Page<Session>>分页读取可访问会话。
nuva.sessions.get(sessionId)Promise<Session>读取指定会话。
nuva.sessions.history(sessionId, query?)Promise<Page<MessageView>>读取已保存的消息历史。
nuva.sessions.getMessage(ref)Promise<MessageView>按 MessageRef 读取消息。
nuva.agent({ sessionId })AgentHandle取得该会话的操作句柄。
agent.send(message, options?)Promise<SendReceipt>保存用户消息。
agent.respond(part, output, options?)Promise<ResponseReceipt>保存客户端工具结果。
agent.fail(part, failure, options?)Promise<HostFailureReceipt>保存客户端工具执行错误。
agent.subscribe(listener)Unsubscribe立即读取当前状态,并接收后续状态更新。
agent.onHostCall(listener)Unsubscribe接收客户端工具及 host call。
agent.loadEarlierMessages()Promise<void>加载更早消息并更新 messages。
agent.listPendingCalls(query?)Promise<Page<DynamicToolUIPart>>读取 input-available 状态的调用,包括尚未加载的历史。
agent.getHostCall(id)Promise<DynamicToolUIPart | NotificationHostCall>按 toolCallId 或 host call ID 读取调用。
agent.refresh()Promise<void>重新同步状态;不会重发操作。
nuva.close()void关闭本地连接并清理客户端状态。

query 接受可选的 cursor 和 limit。返回页包含 items 和 nextCursor;nextCursor 为 null 时已到末页。options 接受可选的 requestId。

错误处理

操作失败时 Promise 抛出 NuvaError。读取 code、message、retryable 和可选的 requestId。

错误码处理方式
UNAUTHENTICATED检查 token 和应用登录状态。
FORBIDDEN检查用户授权范围。
NOT_FOUND核对会话、消息或记录 ID。
INVALID_INPUT按输入 Schema 修正参数。
REVISION_CONFLICT读取最新记录,核对后重新提交。
CALL_OBSOLETE读取当前有效的调用,重新确认待提交内容。
CALL_ALREADY_RESOLVED读取该调用已保存的结果。
REQUEST_ID_CONFLICT检查 requestId 是否被用于不同的输入。
RATE_LIMITED降低调用频率,按 retryable 决定是否重试。
UNSUPPORTED_CONTENT检查消息类型和 SDK 版本。
CONNECTION_ERROR / SERVICE_ERROR保留用户输入,检查接受状态后恢复或重试。

命令错误中的 acceptance 为 not_accepted 或 unknown。unknown 表示尚不能确认服务端是否已保存操作。

重试同一操作时复用相同 requestId 和输入。缺省 requestId 由 SDK 生成;发生状态不明的错误时,保留错误中的 requestId。send() 或 respond() 返回成功仅表示该次输入已保存,后续生成结果从消息订阅读取。

搜索当前文档