@lookio/sdk

中文文档
1.0.0发布于 2026/11/02MITTypeScriptESM + CJS零依赖

官方的Lookio TypeScript SDK:来自Node、Workers、Deno或服务器端应用的资源、助手和问题。

中文使用文档
文档目录18 节
  1. 安装
  2. 快速启动
  3. 问助理
  4. 流式传输答案
  5. 上传一个文件并等待,直到它准备好
  6. 迭代每个资源
  7. 设置站点的同步时间表
  8. 方法
  9. 幂等和重试
  10. 错误处理
  11. 学分
  12. 小部件
  13. 对话和最终用户
  14. 日志
  15. 类型
  16. 开发
  17. 安全
  18. 许可证

lookio

的官方TypeScript SDK Lookio. 问助理 一个问题,继续一段对话,或者把Lookio变成一个产品 服务器、Worker或脚本。

  • 零运行时依赖项。只有 fetch, Headers, AbortController, ReadableStream, TextDecoder 和 crypto.randomUUID.
  • 从API的OpenAPI文档键入。字段名是API自己的 snake_case,所以你在REST文档中读到的就是你得到的。
  • 安全重试、自动等幂键、输入错误、自动分页、 流的答案。

安装

npm install @lookio/sdk

运行在Node 18+、Cloudflare Workers、Deno、Bun和现代浏览器上(参见 安全注意 在浏览器中使用之前)。ESM和CommonJS。

快速启动

创建一个API密钥 开发人员工具. 对于一个只会问问题的产品, 选择 问问题 预设和限制关键的助手,它需要。 将密钥保存在服务器上,然后:

import { Lookio } from "@lookio/sdk";

const lookio = new Lookio({ apiKey: process.env.LOOKIO_API_KEY });
// or just `new Lookio()`: the key is read from LOOKIO_API_KEY when `process` exists

问助理

const answer = await lookio.assistants.ask("assistant_id", {
  question: "How much does the pro plan cost?",
});

console.log(answer.answer); // Markdown, citations appear as [1], [2]
for (const citation of answer.citations) {
  console.log(citation.n, citation.title, citation.source);
}
console.log(answer.credit_cost, answer.credits_remaining);

流式传输答案

const stream = lookio.assistants.askStream("assistant_id", {
  question: "Summarise our refund policy.",
});

for await (const text of stream.textStream()) {
  process.stdout.write(text);
}

const final = await stream.finalAnswer(); // the same fields as `ask`
console.log(final.citations.length, "citations");

流也是类型化事件的异步可迭代对象 ({ event: "status" | "delta" | "done" | "error", data }),事实也的确如此 abort(). 它可以读一次。 finalAnswer() 可以在之前,期间或 在读取后,单独调用它读取流到末尾。一个 error 事件 拒绝 finalAnswer() 然后从 textStream() 作为一个 LookioError (一个 InsufficientCreditsError 当工作空间的积分用完时)。一个流 结束时没有。 done 或者 error 事件抛出 StreamInterruptedError.

请求在您第一次读取流时开始。流永远不会重试, 即使在网络错误之后也不会:服务器没有记录流,所以重复 将被收费两次。

上传一个文件并等待,直到它准备好

import { readFile } from "node:fs/promises";

// Node 20+: stream from disk without loading the file in memory:
//   const file = await fs.openAsBlob("./handbook.pdf");
const file = new Blob([await readFile("./handbook.pdf")]);

const resource = await lookio.resources.uploadFile(file, "handbook.pdf", {
  title: "Employee handbook",
  tags: ["hr", "2026"],
  source: "Employee handbook, 2026 edition",
});
// resource.status is "queued": it is read and indexed in the background

const ready = await lookio.resources.waitUntilReady(resource.id);
console.log(ready.status); // "ready"

uploadFile 接受一个 Blob, File, ArrayBuffer, Uint8Array (所以是节点) Buffer)或网络 ReadableStream. API将文件作为原始字节,而不是 多部份,并要求 Content-Length: SDK会为所有事情计算它,但是 一条小溪,它需要 { contentLength: <bytes> } (一个Node流经过 Readable.toWeb). 流上传不能重新发送,因此不会重试。

waitUntilReady(id, { timeoutMs = 120000, intervalMs = 1500, signal }) 民意调查和 温柔地后退。它把 ResourceFailedError (与 statusDetail)如果…… 导入失败 WaitTimeoutError 如果时间到了。 ready_simulated 计数 准备好了。留下的资源 stale 一直轮询直到超时:调用 resources.reindex(id) 为它。对于短文本、页面或小文件,请忽略 { wait: true } 直接向 createText, createUrl, createSite, uploadFile 或者 get服务器最多等待15秒,以便大多数小导入返回 ready 在单个请求中。

迭代每个资源

for await (const resource of lookio.resources.iterate({ tag: "hr", status: "ready" })) {
  console.log(resource.id, resource.title);
}

// One page at a time, with the cursor you control:
const page = await lookio.resources.list({ limit: 50 });
console.log(page.data.length, page.hasMore, page.nextCursor);

// Or page by page, automatically:
for await (const p of lookio.resources.iterate().pages()) {
  console.log(p.data.length);
}

列表返回 { data, hasMore, nextCursor, limit?, requestId }. 相同的 iterate 存在于 conversations, publicAssistants, logs.*, sites.iteratePages(resourceId) 浏览一个站点的页面。

设置站点的同步时间表

resources.createSite 和 sites.updateRules 接受 manual, daily, weekly, monthly 或者一个区间,比如 every_3_days, every_2_weeks 或者 every_1_month. 限制是1-90天,1-52周和1-12个月。 重复的日程安排需要付费计划。如果 schedule 在创建时省略 一个站点,免费工作空间使用 manual 付费计划使用 weekly. 如果是的话 省略了 sites.updateRules,现有的时间表保持不变。

方法

所有东西都返回API data (列表返回一个页面)。每个方法都需要 { idempotencyKey?, timeoutMs?, signal? } 作为它的最后一个参数。

名称空间方法
account, credits, usageaccount.get(), credits.get(), usage.get({ from?, to?, granularity? })
resourceslist, iterate, get, createText, createUrl, createSite, uploadFile, update, delete, content, reindex, waitUntilReady, pages, iteratePages
sitespreview, pages, iteratePages, updateRules, retryFailed
tagslist, rename({ from, to }), delete(tag)
assistantslist, get, create, update, delete, ask, askStream, search, getPublication, publish, unpublish
publicAssistantslist, iterate, get
accesseslist, get, create, update, delete, createKey, updateKey, deleteKey
conversationslist, iterate, get, rename, delete, feedback
logsconversations.{list, iterate, get, stats}, answers.{list, iterate, stats}, indexing.{list, iterate, stats}, activity.{list, iterate}
widgetslist, get, create, update, delete, duplicate, setImage, clearImage, conversations.{list, iterate, get}
memberslist, updatePermissions(userId, { permissions, assistant_ids })
feedbacksend({ observed_problem, situation, expected_solution, ... })

client.request({ method, path, query?, body?, headers?, idempotencyKey? }) 以相同的授权到达任何端点,包括在此版本之后添加的端点, 重试和幂等。路径包括 /v1 它和整体解决了 JSON主体(data, has_more, request_id……)。 client.lastRequestId 拥有 最后一个成功响应的Id。

构造函数选项: apiKey, baseUrl (默认 https://api-v2.lookio.app), timeoutMs (60000), maxRetries (2), retryDelayMs (500)底 倒扣) fetch (你自己的实现), defaultHeaders, dangerouslyAllowBrowser. 请求携带 Authorization: Bearer <key> 和 X-Lookio-SDK: lookio-js/<version> (浏览器不允许页面设置 User-Agent)。

幂等和重试

每一个 POST (除了流)携带一个 Idempotency-Key header:选择的UUID 每次调用一次,每次重试都不变地重复,因此API运行请求 不管它到达多少次,一次重试的问题不会被收取两次费用。 通过 { idempotencyKey } 要自己选择钥匙,比如要 让你自己的重试循环也是安全的。API会在24小时内记住一个密钥。

SDK重试到 maxRetries 随着时间的推移,伴随着指数级的退缩和不安, 兑现 Retry-After (秒或HTTP日期):

失败获取,放置,删除帖子补丁
429重试重试重试(在门口被拒绝)
408,5xx,网络错误,超时重试重试(相同的键)不是重试 (变更可能已经生效)
其他4xx吗?从来没有从来没有从来没有

流式传输和流式上传永远不会重试。每次尝试都有自己的超时 (timeoutMs,每个客户或每个电话,默认60秒;它覆盖了一条小溪 等待第一个字节)。通过一项 signal 取消呼叫及其重试。

错误处理

每一次失败都是一次 LookioError所以一 instanceof 包括API的错误,a 断开连接和滥用SDK。

import { InsufficientCreditsError, LookioError, RateLimitError } from "@lookio/sdk";

try {
  await lookio.assistants.ask("assistant_id", { question: "..." });
} catch (e) {
  if (e instanceof InsufficientCreditsError) {
    console.log("Out of credits, top up here:", e.actionUrl);
  } else if (e instanceof RateLimitError) {
    console.log("Slow down, retry in", e.retryAfterSeconds, "seconds");
  } else if (e instanceof LookioError) {
    console.log(e.status, e.code, e.message, "request:", e.requestId);
  } else {
    throw e;
  }
}

分支 e.code (例如 insufficient_credits, rate_limited, resource_not_found),永远不要留言。字段: status (0时无回应 到达), code, type, param, requestId (引用它来支持), actionUrl, docsUrl, retryAfterSeconds.

类当
AuthenticationError401:没有钥匙,钥匙是错的,过期的或作废的
PermissionError403:范围缺失; feature_not_available,仅限管理员
NotFoundError404和410
ConflictError409
RateLimitError429,重试次数用完后
InsufficientCreditsError代码 insufficient_credits,已经 actionUrl
ConnectionError网络故障,请求超时(code: "request_timeout"), abort (code: "aborted")
ResourceFailedError, WaitTimeoutErrorwaitUntilReady
StreamInterruptedError流在其最终事件之前结束
LookioUsageErrorSDK被滥用了(没有密钥,流上传没有大小)。没有发送任何东西

不是API的错误信封(代理页面,空正文)的正文变成 一个通用的 LookioError 使用代码 http_error 以及消息中的状态文本。

学分

进口和其他一切都是免费的。 只有 assistants.ask 和 assistants.askStream 消费信用,对每一个问题,即使资源没有答案 (没有读取资源的助手被拒绝 assistant_has_no_resources 在任何信用被持有之前)。价格取决于 mode (flash 是 默认情况下, eco, deep),不管答案的长度是多少。这个 价格上涨 account.get():

const account = await lookio.account.get();
console.log(account.credit_balance);
console.log(account.credential.scopes); // a key without the `query` scope cannot ask
for (const mode of account.capabilities.query_modes) {
  console.log(mode.id, mode.credits, mode.available);
}

小部件

小部件是一个聊天框,它向匿名访问者显示一个助手 的网站。每个小部件都带有“准备粘贴”功能 snippets (bubble, embed, hosted, iframe),加上 settings, limits 和 stats.

const widget = await lookio.widgets.create({
  assistant_id: "assistant_id",
  name: "Docs help",
  allowed_domains: ["docs.acme.com"],
  settings: { accent: "#4F46E5", greeting: "Ask me anything about the docs." },
  limits: { monthly_credits: 5000 },
});
console.log(widget.snippets.bubble); // paste it in the page

await lookio.widgets.update(widget.id, { status: "paused" }); // shows nothing, answers nothing

for await (const chat of lookio.widgets.conversations.iterate(widget.id)) {
  console.log(chat.end_user, chat.message_count, chat.credits);
}
const full = await lookio.widgets.conversations.get(widget.id, "conversation_id");

update 是部分PATCH: settings 和 limits 逐字段更改,而 allowed_domains 作为一个整体被替换。范围: assistants:read 阅读, assistants:write 为了创建和更新, assistants:delete 删除。 访问者的回答将被计入工作区(插件的价格) mode, 受其限制 limits),所以 limits.monthly_credits 在你发布 片段。

对话和最终用户

每个答案都会保存在一次对话中(90天)。 assistants.ask 返回它 conversation_id 答案是 message_id;后续操作只发送新的 问题和 conversation_id, Lookio阅读历史本身。API密钥 继续它开始的对话:

const first = await lookio.assistants.ask("assistant_id", {
  question: "How much does the pro plan cost?",
  end_user: "user_42", // your own id for the person asking (optional)
});
const followUp = await lookio.assistants.ask("assistant_id", {
  question: "And for the annual plan?",
  conversationId: first.conversation_id!,
  end_user: "user_42", // a conversation can only be continued for the same end user
});

end_user 对用户的对话(以及工作空间的日志显示)进行分组 它); store: false 什么都不保留(两个id都返回) null,你保留 与自己对话 history). 列出、读取、重命名和删除键 与 lookio.conversations.* (list({ end_user }), get(id, { end_user }), delete(id): API密钥的会话也离开 日志),并转发用户的大拇指:

await lookio.conversations.feedback(first.conversation_id!, first.message_id!, {
  rating: "down", // "up", "down" or null to take it back
  comment: "The price is out of date.",
});

end_user 是标识符,而不是身份证明。从你的产品设置它 服务器上经过身份验证的会话。检查对话是否属于这个 人,然后再继续。不要信任由浏览器代码发送的id 检查它。

一个人自己的聊天记录是私人的:一个人的令牌列出了这些记录,并接受no 大拇指还在(feature_not_available,一个 PermissionError)。

日志

工作空间有四个日志,都是空闲的。每个列表都有 list (一页), iterate (每一页)和,除了 activity, stats 上面的数字 相同的过滤器)。的游标 answers, indexing 和 activity 不透明的: 迭代器通过 next_cursor 回来找你。

日志读取需要保持
logs.conversations工作区外的人问的是:小部件访问者、通过API密钥或MCP访问产品的用户。成员自己的聊天记录不在其中。assistants:write,而一个人的代币则是编辑助手的权利最后一条信息发出后的90天
logs.answers任何渠道的每个答案(chat, lookio_ai, api, mcp, widget),仅提供元数据,不提供问答文本usage:read使用历史
logs.indexing读取和索引的每个文件、页面或文本,以及其状态和失败原因resources:read有了资源
logs.activity谁改变了什么,从哪扇门app, api, cli, mcp, agent, system)admin,通过个人连接(绝不是API密钥)一年
// Conversations
for await (const chat of lookio.logs.conversations.iterate({ rating: "down", channel: "widget,api" })) {
  console.log(chat.channel, chat.end_user, chat.title, chat.thumbs_down);
}
const full = await lookio.logs.conversations.get("conversation_id"); // messages, citations, cost, thumbs, comments
const stats = await lookio.logs.conversations.stats({ from: "2026-10-01" }); // conversations, questions, people, credits, thumbs, by_channel

// Answers: the questions the resources could not answer, and the conversation of a kept one
for await (const answer of lookio.logs.answers.iterate({ channel: "widget,api" })) {
  console.log(answer.channel, answer.mode, answer.credits, answer.conversation_id);
}
const answerStats = await lookio.logs.answers.stats({ from: "2026-10-01" }); // answers, credits, tokens, by_channel

// Indexing: what failed, and why
const failed = await lookio.logs.indexing.list({ status: "failed", limit: 20 });
for (const line of failed.data) console.log(line.resource.title, line.name, line.error);
const indexingStats = await lookio.logs.indexing.stats({ resource_id: "resource_id" }); // total, indexed, failed, in_progress, words_indexed

// Activity (admins)
for await (const change of lookio.logs.activity.iterate({ origin: "cli,mcp", action: "assistant" })) {
  console.log(change.created_at, change.actor.name, change.action, change.summary);
}

过滤器(全部可选):

  • conversations: channel (逗号分隔 widget, api, mcp), widget_id, api_key_id, assistant_id, rating (up, down, rated, unrated), end_user, q, from, to.
  • answers: channel (逗号分隔 chat, lookio_ai, api, mcp, widget), assistant_id, widget_id, api_key_id, member_id (管理员) mode, from, to.
  • indexing: resource_id, status (逗号分隔 queued, processing, indexed, replaced, unchanged, skipped, failed), source_type (file, url, site, text), q, include_unchanged ("true" 或者 "false"(默认情况下,网站同步未更改的页面会被忽略), from, to.
  • activity: actor_id, origin (逗号分隔) target_type (resource, assistant, widget, tag, member), target_id, action (assistant.updated,或者 assistant 对于一种类型上的每一个动作, q, from, to.

类型

公共类型(Resource, Assistant, Answer, Citation, Conversation, ConversationSummary, LogConversation, LogStats, LogAnswer, LogAnswerStats, LogIndexing, LogIndexingStats, LogActivity, Widget, WidgetSettings, WidgetLimits, WidgetSnippets, WidgetConversation, CreateWidgetParams, Member, Usage, Account, Credits, TagSummary, SitePages, SitePreview, StreamEvent)都是从生成的 OpenAPI类型和导出 lookio,就像 components, operations 和 paths 他们自己。它们是由 ../api-worker/openapi.json:

npm run generate   # rewrites src/generated/openapi.ts; never edit that file by hand

npm test, npm run typecheck 和 npm run build 先运行它,这样就提交了 文件不能过期。

开发

npm install
npm test            # vitest, with a mocked fetch: no test calls a live API
npm run typecheck
npm run build       # dist/index.js (ESM), dist/index.cjs (CJS), dist/index.d.ts

src/coverage.test.ts 读取OpenAPI文档,当一个操作有 没有SDK方法,当一个方法发送一个规范没有描述的请求时,或者当 这个README提到了API没有的端点、范围或错误代码。

安全

API密钥永远不能发送给浏览器。 任何打开这一页的人都能读到 然后花掉你的信用。从服务器(Worker, API路由)调用Lookio 将结果发送到页面。在浏览器中,客户端记录一次警告;通过 dangerouslyAllowBrowser: true 让它安静下来,如果你知道你在做什么 在内部工具上实例一个限制为只读范围的键)。永远不要犯错误。 关键:读它 LOOKIO_API_KEY.

许可证

麻省理工学院Duv公司

暂停一个小部件的每月上限 client.widgets.update(id, { limits: { monthly_credits_enabled: false } }). 将其设置为 true 恢复储蓄金额;当月早些时候的支出仍有影响。

版本与发布记录

@lookio/sdk 共发布 2 个版本,首次发布于 2026/11/02;过去 12 个月发布了 2 个版本。

版本发布日期距今
1.0.0latest2026/11/021 天前
0.0.0-stage2026/11/021 天前

关于 @lookio/sdk 的常见问题

@lookio/sdk 是什么?

官方的Lookio TypeScript SDK:来自Node、Workers、Deno或服务器端应用的资源、助手和问题。

如何安装 @lookio/sdk?

在项目目录运行 npm install @lookio/sdk,或使用 pnpm add / yarn add / bun add。

@lookio/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@lookio/sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@lookio/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@lookio/sdk 可以商用吗?

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

@lookio/sdk 还在维护吗?

最新版本 1.0.0 发布于 2026/11/02(1 天前);至今共发布 2 个版本,其中过去 12 个月发布了 2 个;首次发布于 2026/11/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。