Deuz SDK 2.0 is out — stores, guardrails, handoffs, and zero-config MCP. What is new in 2.0
Deuz SDK

Installation

Install @deuz-sdk/core, check runtime requirements, and pick the optional peers and subpath exports you need.

@deuz-sdk/core is a single package with zero runtime dependencies. Install it, and the chat core, the agentic tool loop, streaming, and the canonical UI wire are all available out of the box. Heavier or stateful capabilities (schema-typed objects, MCP, document parsing, real databases) pull in optional peers only when you actually use them.

Install

npm
npm install @deuz-sdk/core
pnpm
pnpm add @deuz-sdk/core
yarn
yarn add @deuz-sdk/core
bun
bun add @deuz-sdk/core

Runtime requirements

The core is pure and web-first: it touches only Web APIs (fetch, Web Streams, TextDecoder, WebCrypto, atob/btoa). Anything stateful or non-deterministic — HTTP, clock, logging, metering, circuit-breaker, API keys, id generation — is injected through a single Dependencies seam, with no-op/in-memory defaults applied for you. As a result the same build runs unchanged on any runtime that has fetch plus Web Streams.

RuntimeCore + tool loopNode-only subpathsNotes
Node.js ≥ 22Enforced via engines. Native fetch + Web Streams. The reference runtime — every test runs here.
Deno⚠️ depends on its node: compatWeb APIs available by default. The …/node subpaths reach Node built-ins through a lazy import('node:…'), so they work exactly as far as Deno's compatibility layer does. Verify the one you need.
Bun⚠️ depends on its node: compatSame reasoning as Deno.
Cloudflare WorkersImport @deuz-sdk/core/edge for the guaranteed-safe subset.
Vercel EdgeSame — use the /edge entry.
BrowsersWorks, but never ship provider API keys to the client. Put the model call on a server route and use the UI wire to reach the browser.

The browser guarantee is checked, not asserted: a release-gate step bundles the root entry, the /edge entry and the provider factories for platform: 'browser' and fails if a single node: builtin — or a Node-only module — makes it into the graph.

Two version floors that are not `engines`

@deuz-sdk/core/stores/sqlite needs node:sqlite, which ships unflagged only from Node 22.13 / 23.4. On an older Node 22 the store throws an explicit "node:sqlite is unavailable" error on the first call rather than at import time — you can pass your own better-sqlite3-shaped handle instead. And running a .ts file directly with node --experimental-strip-types needs Node 22.6+; below that, use tsx or a build step.

Node-only capabilities (filesystem skill sources, document parsers, the markdown memory vault, MCP stdio transport, file workspace, compute sandbox, Playwright browser, JSONL run store, the SQLite/Redis/Postgres store packs) live behind dedicated …/node subpaths and never leak node:* imports into the edge-safe core.

Optional peer dependencies

The package ships nothing in dependencies. The chat core, resilience, metering, the four provider wires, the agentic loop and the UI wire all run on Web APIs alone. Everything below is declared optional in peerDependenciesMeta, so your package manager will not nag you for the ones you skip.

Install a peer only when you reach for the feature in its row. The last column is the part worth reading before you ship: skipping a peer is never silent, but the quality of the failure differs.

PeerNeeded forIf it is missing
zod (or any Standard Schema lib) + @standard-community/standard-jsongenerateObject / streamObject / typed tool parameters with a schema objectActionable throw: "Converting it to JSON Schema needs the optional peer @standard-community/standard-json — install it, or pass a raw JSON Schema instead." Raw JSON Schema needs neither peer.
@modelcontextprotocol/sdk/mcp, /mcp/stdio, /mcp/nodeActionable throw naming the package and the install command. Loaded lazily, so importing the module is fine — only connecting fails.
@opentelemetry/api/otelcreateOtelTracer / createOtelObserverActionable throw naming the package, plus the escape hatch: createOtelTracer({ tracer }) with a tracer you already have.
playwright/browser/nodeActionable throw: "requires the optional peer playwright. Install it with npm i playwright && npx playwright install chromium."
redis/stores/redis via createRedisStores({ url })Actionable throw, with the alternative spelled out: pass a client you connected yourself, createRedisStores({ client }).
pg/stores/postgres via createPostgresStores({ connectionString })Actionable throw naming pg. Passing your own pool skips the peer.
unpdfPDF parsing in /rag/nodeRaw module-resolution error (ERR_MODULE_NOT_FOUND) at first parse — the parsers import the peer directly, so the message is your runtime's, not ours.
mammothDOCX parsing in /rag/nodeSame — raw ERR_MODULE_NOT_FOUND.
xlsxXLSX parsing in /rag/nodeSame — raw ERR_MODULE_NOT_FOUND.
react@deuz-sdk/core/react (frozen legacy hooks)You would not import it without React. Prefer the separate @deuz-sdk/react package for new work.
schema-typed generateObject
npm install zod @standard-community/standard-json
MCP client
npm install @modelcontextprotocol/sdk
rag/node document parsers (install only the formats you need)
npm install unpdf mammoth xlsx
browser/node (Playwright)
npm install playwright && npx playwright install chromium

The RAG core (MIME sniffing, chunkers, retrieve/rerank, BM25, RRF) is edge-safe and needs no peers; only the Node document parsers do. Likewise the store seams are dependency-free — only the concrete Redis/Postgres packs want a driver, and SQLite wants a Node built-in rather than a package.

Subpath exports

There are 52 deep subpaths plus the root. That is not API sprawl — it is the tree-shaking contract. Every subpath is a separate build artifact with its own .d.ts, so a Cloudflare Worker that imports @deuz-sdk/core and @deuz-sdk/core/anthropic never pulls in Playwright glue, a Postgres schema or a 7 KB HTML report template. Three rules cover almost every case:

  1. Free functions and types come from the root. streamChat, generateText, generateObject, streamObject, embed, createClient, the error classes, tool(), the stop conditions, and every canonical type.
  2. One provider = one subpath. Import only the factories you actually call.
  3. A …/node suffix means Node built-ins. If you are on an edge runtime and reaching for one, you want the seam (the plain subpath) plus your own implementation instead.

Core surface

ImportReach for it when
@deuz-sdk/coreAlways. Free functions, createClient, the error taxonomy, stop conditions, tool(), filePart/imagePart, all types
@deuz-sdk/core/edgeYour bundle must be provably free of Node APIs — see below
@deuz-sdk/core/agentYou want a reusable agent as a frozen value: createAgent (1.9)
@deuz-sdk/core/testingYou are writing tests: createMockModel, runEval, golden-replay SSE fixtures
@deuz-sdk/core/middlewareYou need wrapModel + logging / simpleCache / redactPII / promptInjectionGuard / withFallback
@deuz-sdk/core/guardrailsYou want the ready-made promptInjectionGuardrail / maxOutputLength (2.0)
@deuz-sdk/core/pricingYou want token → USD: the 2026 cost table + createPriceProvider

Providers

ImportReach for it when
@deuz-sdk/core/anthropicClaude via the Messages API (createAnthropic)
@deuz-sdk/core/openaiOpenAI Chat Completions + Responses (createOpenAI, createOpenAIResponses) + openaiEmbedding
@deuz-sdk/core/xaixAI Grok (createXai)
@deuz-sdk/core/googleGemini — compat (createGoogle), native generateContent (createGoogleNative), googleEmbedding
@deuz-sdk/core/google/extrasGemini explicit caching + Files API (createGeminiCache, uploadFile)
@deuz-sdk/core/vertexClaude or Gemini on Vertex AI with OAuth2 Bearer auth
@deuz-sdk/core/vertex/nodeApplication Default Credentials for Vertex (createAdcKeyProvider) — the one documented env-var/filesystem exception in the package
@deuz-sdk/core/azureAzure OpenAI / Foundry (createAzure) — deployment URL, api-key or Entra
@deuz-sdk/core/bedrockAmazon Bedrock Mantle (createBedrock) — Bearer API key, no SigV4 SDK
@deuz-sdk/core/voyageVoyage AI embeddings (createVoyage)
@deuz-sdk/core/yunwuThe Yunwu unified relay + the 2026 YUNWU_MODELS catalog
@deuz-sdk/core/providersAny OpenAI-shaped host: 19 named factories, the keyless Ollama / LM Studio, createOpenAICompatible for anything unlisted, and createProviderRegistry

Agents and long-running work

ImportReach for it when
@deuz-sdk/core/mcpMCP over HTTP/SSE, edge-safe (createMcpClient)
@deuz-sdk/core/mcp/stdioMCP over stdio — a local process (Node only)
@deuz-sdk/core/mcp/nodeMCP OAuth on Node: createFileTokenStore, createLoopbackRedirect (2.0)
@deuz-sdk/core/durableRuns must survive a process restart: checkpoint/resume, signed approvals
@deuz-sdk/core/autonomyPlanner → executor → verifier: planTasks, bestOfN, selfConsistency, parallelAgents
@deuz-sdk/core/runtimeBackground runs with a live plan/activity feed + steering (RunStore, createRunManager)
@deuz-sdk/core/runtime/nodeThe JSONL run store + pollStaleRuns
@deuz-sdk/core/workspace · /workspace/nodePath-addressed external memory; the Node half is a sandboxed directory
@deuz-sdk/core/compute · /compute/nodeCodeAct / shell tools; the Node half is a child_process reference sandbox
@deuz-sdk/core/browser · /browser/nodeBrowser control seam; the Node half is the Playwright adapter
@deuz-sdk/core/skills · /skills/nodeSKILL.md progressive disclosure; the Node half reads them off disk

State, retrieval and media

ImportReach for it when
@deuz-sdk/core/chat · /chat/nodeFramework-neutral chat state/reducers + the ChatStore seam; the Node half is a JSONL store
@deuz-sdk/core/memory · /memory/markdownmem0-style extract/reconcile/recall; the markdown half is an Obsidian-style vault
@deuz-sdk/core/rag · /rag/nodeMIME sniff, chunkers, BM25 + RRF hybrid retrieval; the Node half adds PDF/DOCX/XLSX
@deuz-sdk/core/stores/sqlite · /stores/redis · /stores/postgresYou want memory / chats / sessions / runs in a real database instead of memory (2.0)
@deuz-sdk/core/uiThe versioned Deuz UI wire: toDeuzStreamResponse (server) + readDeuzStream (client)
@deuz-sdk/core/reactFrozen legacy React hooks — prefer @deuz-sdk/react for new work
@deuz-sdk/core/observe · /observe/nodeLocal observers, run summaries; the Node half is a bounded JSONL sink
@deuz-sdk/core/otelYou already run OpenTelemetry and want spans + events to land there
@deuz-sdk/core/image · /midjourneySynchronous OpenAI-compatible image generation; Midjourney's async submit/poll/action
@deuz-sdk/core/speech · /transcription · /videoText-to-speech, speech-to-text, async video jobs (2.0)

Verify it works

API keys are read from the environment at your app layer and passed into the provider factory — the SDK core never reads process.env itself.

verify.ts
import { streamChat } from '@deuz-sdk/core';
import { createAnthropic } from '@deuz-sdk/core/anthropic';

const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });

// streamChat returns synchronously; the request starts lazily on first access.
const res = streamChat({
  model: anthropic('claude-opus-4-8'),
  messages: [{ role: 'user', content: 'Say hello in one word.' }],
});

for await (const chunk of res.textStream) process.stdout.write(chunk);

const usage = await res.usage; // resolves when the stream finishes
console.log(`\n${usage.inputTokens} in / ${usage.outputTokens} out`);

res.textStream is an AsyncIterable<string> and res.usage is a Promise<Usage> — both are explained in streamChat.

Nothing printed and no error?

That is the lazy pump doing its job. streamChat sends no request until something reads an output. If you return the result without iterating it — or await nothing — the call is a no-op. See consume().

Edge-safe subset

When you target Cloudflare Workers or Vercel Edge and want a build that is provably free of any Node API, import from the /edge entry. It re-exports streamChat / generateText / generateObject / streamObject, the stop conditions, createClient, tool(), createAgent, the durable-session helpers, the chat reducers, request validation, the observers, the OTel bridge, and all types.

app/api/chat/route.ts (Edge runtime)
import { streamChat, validateChatRequest } from '@deuz-sdk/core/edge';
import { createAnthropic } from '@deuz-sdk/core/anthropic';
import { toDeuzStreamResponse } from '@deuz-sdk/core/ui';

export const runtime = 'edge';

const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY! });

export async function POST(req: Request): Promise<Response> {
  const parsed = validateChatRequest(await req.json());
  if (!parsed.ok) return Response.json({ issues: parsed.issues }, { status: 400 });

  const res = streamChat({ model: anthropic('claude-opus-4-8'), messages: parsed.request.messages });
  return toDeuzStreamResponse(res); // versioned Deuz UI wire
}

Two things /edge deliberately does not re-export, so do not go looking:

  • The full error taxonomy. Only DeuzError, isDeuzError, NoObjectGeneratedError and BreakerOpenError are there. RateLimitError, AuthenticationError and friends come from the package root — which is itself edge-safe, so importing them costs you nothing.
  • renderRunReport. It is pure and would be legal, but it carries roughly 7 KB gzip of inline HTML/CSS/JS for a local debugging workflow. Reach it from @deuz-sdk/core/observe instead.

The provider factories (/anthropic, /openai, …) are edge-safe too and are imported normally — /edge is about the orchestration surface, not the providers.

ESM and CJS

Every subpath ships both an ESM (import) and a CommonJS (require) build with matching .d.ts / .d.cts declarations, so the package resolves correctly under "moduleResolution": "Bundler", "Node16", or "NodeNext". It is authored against TypeScript strict mode (including noUncheckedIndexedAccess), so the public types are strict-ready in your project with no extra configuration.

ESM (recommended)
import { generateText } from '@deuz-sdk/core';
CommonJS
const { generateText } = require('@deuz-sdk/core');

Next steps

  • streamChat — the synchronous, never-throws streaming entry point.
  • generateText — buffered text plus the agentic tool loop.
  • generateObject — schema-typed structured output.
  • Providers — Anthropic, OpenAI, xAI, Gemini, Vertex, Azure, Bedrock, Yunwu, Voyage.

On this page