@cognicloud/sdk

中文文档
0.18.0发布于 2026/11/01UNLICENSEDTypeScriptES Module零依赖构建来源已验证

CogniCloud SDK: call AI Gateway endpoints and manage them.

原始使用文档
文档目录14 节
  1. Install
  2. Call an endpoint
  3. Responses with tools
  4. Embeddings
  5. Stream a response
  6. Send a PDF or an image
  7. Manage endpoints
  8. Browser sessions
  9. Mail
  10. Database
  11. Errors
  12. Configuration
  13. Changes
  14. Development

@cognicloud/sdk

Call CogniCloud AI Gateway endpoints and manage them from Node.js, Bun, Deno and edge runtimes.

Preview. The first version covers AI Gateway endpoints. Browser sessions are included; agents, scraping, vault and activity are not included yet.

Install

npm install @cognicloud/sdk

ESM, typed, uses the platform fetch, no runtime dependencies.

Call an endpoint

import { EndpointClient } from "@cognicloud/sdk"

const endpoint = new EndpointClient({
  endpointId: process.env.COGNICLOUD_ENDPOINT_ID!,
  credential: process.env.COGNICLOUD_KEY!,
})

const { output, finishReason, usage } = await endpoint.invoke({
  input: [
    { role: "system", content: "Answer in one sentence." },
    { role: "user", content: "Summarise this ticket." },
  ],
  max_output_tokens: 256,
})

The invoke address is <baseUrl>/invoke/<tenant>/<endpointId>. The endpoint belongs to the platform tenant, cognicloud, unless you pass tenant. You can also pass the address CogniCloud issued for the endpoint (endpoint.url) as url instead of endpointId.

Without a request mapping the body goes to the provider as it is, and only plain-text messages are accepted:

  • An endpoint without a deployment uses the Responses API: input (a string or system/developer/user/assistant messages), max_output_tokens, temperature, top_p.
  • An endpoint with an Azure deployment uses Chat Completions: messages, max_completion_tokens (or max_tokens), temperature, top_p.

store and text.format (structured outputs) are refused with 400 invalid_request. For instructions, MCP tools and chaining use responses; for streaming use stream. Some models refuse temperature; the gateway then answers 502 provider_refused. The endpoint always chooses the model.

Every model answers in the same shape: output (text), finishReason (stop, length, content_filter, other, or null) and usage (token counts).

invoke is never retried, because a retried call can be billed twice.

Responses with tools

responses takes a Responses body with optional instructions, MCP tools and previous_response_id. An MCP tool names its server with server_url and its bearer token with headers, as { Authorization: "Bearer <token>" }. The gateway checks the address (https, with no credentials or fragment), sets approval to never, and passes both to the provider. A tool with only server_label names a server the gateway is configured with.

const answer = await endpoint.responses({
  input: "Is this invoice valid?",
  instructions: "Check invoices.",
  tools: [{ type: "mcp", server_label: "ksef", allowed_tools: ["validate_invoice_xml"] }],
  tool_choice: "required",
})

const next = await endpoint.responses({ input: "And this one?", previous_response_id: answer.responseId })

The answer adds responseId (for chaining on the same endpoint) and outputItems (the tool calls and messages the provider returned).

Embeddings

const { data } = await endpoint.embeddings({ input: ["first text", "second text"], dimensions: 256 })
const first = data[0].embedding

The endpoint must point at an embedding deployment. data has one item per input, in input order, and each call is billed as prompt tokens.

Stream a response

stream sets stream: true and yields events as the answer is written:

for await (const event of await endpoint.stream({ messages: [{ role: "user", content: "Write a haiku." }] })) {
  if (event.type === "delta") process.stdout.write(event.text)
  if (event.type === "done") console.log(`\n${event.answer.usage.totalTokens} tokens`)
  if (event.type === "error") console.error(`${event.code}: ${event.message}`)
}

Each event is delta (text), then one done (answer, the same shape as invoke), or one error (code, message). A refused call rejects with a CogniCloudError before any event. Streams are not retried and have no total timeout; the gateway ends them at five minutes. Stopping early with break closes the connection, and the gateway still settles the call.

Send a PDF or an image

import { EndpointClient, pdfPart, textPart } from "@cognicloud/sdk"
import { readFile } from "node:fs/promises"

const endpoint = new EndpointClient({ url: process.env.COGNICLOUD_ENDPOINT_URL!, credential: process.env.COGNICLOUD_KEY! })
const cv = await readFile("cv.pdf")

const { output } = await endpoint.invoke({
  messages: [{ role: "user", content: [textPart("Match this CV to the job."), pdfPart(cv, "cv.pdf")] }],
})

Files go up to 10 MB. The gateway reserves a quarter of a file's size in tokens before the call, so an endpoint's monthly limit must cover it.

Manage endpoints

Calls act as the account of token, the signed-in person's Amadeus session token or a browser key for browser calls, sent as Authorization: Bearer. A missing, empty or blank token throws CogniCloudError with code missing_token when the client is created. The workspace (tenant, default cognicloud) is sent as the tenant_id header.

import { CogniCloud } from "@cognicloud/sdk"

const cc = new CogniCloud({ token: amadeusToken, locale: "en" })

const { endpoint, credential } = await cc.endpoints.create({
  name: "Support bot",
  providerId: "azure-openai",
  model: "gpt-5-mini",
  tokenLimit: 1_000_000,
})

await cc.endpoints.update(endpoint.id, { tokenLimit: 2_000_000 })
await cc.endpoints.update(endpoint.id, { status: "paused" })
const usage = await cc.endpoints.usage(endpoint.id)
const days = await cc.endpoints.dailyUsage(endpoint.id, { from: "2026-10-01", to: "2026-10-20" })
const { secret } = await cc.endpoints.rotateCredential(endpoint.id)
await cc.endpoints.delete(endpoint.id)

Also available: cc.endpoints.list() and cc.endpoints.get(id).

Browser sessions

Browser calls accept the signed-in person's token, or a browser key. Create a key in the dashboard under Browser → API keys and pass it as the token. A key keeps working after its owner signs out. Keys cannot be created through the SDK or the API.

Use the browser product with a browser key alone. The key names its workspace, so no Amadeus token or tenant is needed:

import { CogniCloudBrowser } from "@cognicloud/sdk"

const browser = new CogniCloudBrowser({ key: process.env.COGNICLOUD_BROWSER_KEY! })
const session = await browser.browser.sessions.create({ timeoutMinutes: 15 })

Upload a profile folder packed as a .tar.gz (see the app docs for how to pack it), then start a session from it:

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

const profile = await browser.browser.importProfile("Shop account", await readFile("shop-profile.tar.gz"))
const session = await browser.browser.sessions.create({ profileId: profile.id })

A browser session is a Chrome that your agent drives over the Chrome DevTools Protocol. Start one, connect your automation library to its cdpUrl, and stop it when you are done:

import { CogniCloud } from "@cognicloud/sdk"
import { chromium } from "playwright"

const cc = new CogniCloud({ token: amadeusToken })

const session = await cc.browser.sessions.create({ timeoutMinutes: 15 })
const browser = await chromium.connectOverCDP(session.cdpUrl!)
const page = browser.contexts()[0].pages()[0] ?? (await browser.contexts()[0].newPage())
await page.goto("https://example.com")

await browser.close()
await cc.browser.sessions.stop(session.id)
  • timeoutMinutes is 1 to 240 and defaults to 15. The session stops by itself when the timeout passes.
  • Closing the CDP connection does not stop the session. Call stop as above.
  • status is active or stopped. cdpUrl and liveUrl are null once the session has stopped. liveUrl is a page where a person can watch and take over the browser.
  • sessions.list() returns the workspace's sessions, newest first, with concurrency: { active, limit }. A start beyond the limit fails with 429 and code concurrency_limit.
  • Proxy countries, profiles, screen sizes, captcha solving and recording are not available yet. countries() and profiles() return empty lists, and a start that asks for one of those options fails with 422.

Mail

Mailboxes on the Flippico mail server. token is a signed-in person's token or a mail key (cgm_...). The password is returned once; store it.

const { mailbox, password } = await cc.mail.create("support")
const settings = await cc.mail.connectionSettings() // IMAP and SMTP hosts, and defaultDomain

// Your own domain: add it, publish domain.records at your DNS provider, then verify.
const domain = await cc.mail.domains.add("yourcompany.com")
await cc.mail.domains.verify(domain.id)
await cc.mail.create("ceo", { domain: "yourcompany.com" })

mail.list, get, rotatePassword and delete manage mailboxes; mail.domains.list, get and delete manage domains. Adding, verifying and deleting domains need a signed-in person's token.

Database

Hosted Postgres. A signed-in person creates databases; a database key (cgd_...) from the dashboard queries one of them and needs nothing else. A read key can only read. A write key runs as the database owner.

import { CogniCloud, CogniCloudDatabase } from "@cognicloud/sdk"

const cc = new CogniCloud({ token: sessionToken })
const database = await cc.database.create("Orders")

const db = new CogniCloudDatabase({ key: process.env.COGNICLOUD_DATABASE_KEY! })

await db.query("CREATE TABLE orders (id serial PRIMARY KEY, email text, total numeric)")
const { rows } = await db.query("SELECT * FROM orders WHERE total > $1", [100])

await db.table("orders").insert({ email: "[email protected]", total: "19.90" })
const paid = await db.table("orders").select("id", "email").gt("total", 10).order("id", { desc: true }).limit(20)
await db.table("orders").update({ total: "0" }).eq("id", 1)
await db.table("orders").delete().eq("id", 1)

await db.transaction([
  { sql: "UPDATE accounts SET balance = balance - $1 WHERE id = $2", params: [10, 1] },
  { sql: "UPDATE accounts SET balance = balance + $1 WHERE id = $2", params: [10, 2] },
])
const tables = await db.tables()
  • Filters are eq, neq, gt, gte, lt, lte, like, ilike, is and in. update and delete need at least one; to change every row, use query.
  • select, update and delete run when awaited. insert runs at once.
  • A result has rows, columns, rowCount and truncated. One request stops after 15 seconds and returns at most 1,000 rows and 5 MB.
  • numeric values, and bigint values beyond 2^53, come back as strings, so nothing is rounded. bytea comes back as base64.
  • A failed statement throws CogniCloudError with code query_failed and queryCode: a Postgres SQLSTATE such as 23505, or query_timeout.
  • query and transaction, inserts, updates and deletes are never retried, because they may change data.

Pass values as params, never inside the SQL. They need no quotes and cannot break the statement:

await db.query("INSERT INTO members (id, user_id) VALUES ($1, $2)", [id, userId])

A signed-in person can run SQL in their own database without a key: cc.database.query(database.id, sql, params) and cc.database.tables(database.id).

cc.database.list, get and delete manage databases, cc.database.keys.list and revoke manage keys, and cc.database.actions lists what was done. Keys are created in the dashboard.

Errors

import { CogniCloudError } from "@cognicloud/sdk"

try {
  await endpoint.invoke({ input: "Hi" })
} catch (error) {
  if (error instanceof CogniCloudError && error.code === "credits_exhausted") {
    // top up credits
  }
  throw error
}

status is the HTTP status (0 when the request never got an answer); code is CogniCloud's stable error code.

Configuration

OptionDefault
baseUrlhttps://cognicloud.dev/api/v1/ai-gatewayPoint at another environment.
locale"en"Accept-Language for localised responses.
timeoutMs30000Per request.
maxRetries2For 429 and 5xx, on calls that are safe to repeat.
fetchglobalThis.fetchSupply your own, e.g. for proxies or tests.

The CogniCloud client also takes token (the signed-in person's Amadeus session token), tenant (the workspace, sent as the tenant_id header; default "cognicloud", the platform workspace), browserBaseUrl (default https://cognicloud.dev/api/v1/browser) mailBaseUrl (default https://cognicloud.dev/api/v1/mail) and databaseBaseUrl (default https://cognicloud.dev/api/v1/database).

Changes

See CHANGELOG.md. Agents, scraping, vault and activity are planned for later versions.

Source: https://github.com/Flippico/cognicloud-js-sdk

Development

npm install
npm test
npm run build

版本与发布记录

@cognicloud/sdk 共发布 15 个版本,首次发布于 2026/10/20;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.18.0latest2026/11/012 天前
0.17.02026/10/303 天前
0.16.02026/10/304 天前
0.15.02026/10/304 天前
0.14.02026/10/304 天前
0.13.02026/10/277 天前

关于 @cognicloud/sdk 的常见问题

@cognicloud/sdk 是什么?

CogniCloud SDK:调用AI网关端点并管理它们。

如何安装 @cognicloud/sdk?

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

@cognicloud/sdk 支持 TypeScript 吗?

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

@cognicloud/sdk 支持 ESM 还是 CommonJS?

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

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

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

@cognicloud/sdk 可以商用吗?

@cognicloud/sdk 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@cognicloud/sdk 还在维护吗?

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