@context-server/sdk
v0.1.0
Published
Context SDK
Downloads
92
Readme
@context/sdk
TypeScript/JavaScript client for the Context API.
- ✅ Node 18+ (built-in
fetch, ESM/CJS) - ✅ First-class TypeScript types
- ✅ Works in browsers (uses
fetch/FormData) - ✅ Simple, promise-based API
Installation
# npm
npm i @context/sdk
# pnpm
pnpm add @context/sdk
# yarn
yarn add @context/sdkNode version: 18 or newer.
Quick start
import { Context } from '@context/sdk'
const context = new Context({
apiKey: process.env.CONTEXT_API_KEY!, // required
// baseUrl is optional; see "Configuration"
// baseUrl: 'http://localhost:4600',
})
const server = await context.getServer('ctx.ai')
const chat = await server.startChat('Hello 👋')
console.log(chat.answer)
await chat.send('Tell me more.')
console.log(chat.answer)The SDK throws on non-2xx responses. Wrap calls in
try/catchif you want to handle errors explicitly.
Configuration
new Context({
apiKey: string; // required
baseUrl?: string; // optional
})Base URL tips
- If you’re talking to a local Developer API:
new Context({ apiKey: '…', baseUrl: 'http://localhost:4600' }) - Or use an env var (recommended):
export DEVELOPER_API_URL=http://localhost:4600 export NO_PROXY=localhost,127.0.0.1,::1 # avoids proxies hijacking localhost - In the SDK,
baseUrlcan default to production; passingbaseUrlor settingDEVELOPER_API_URLoverrides it.
ESM, CJS & TypeScript
ESM / TypeScript (preferred)
import { Context } from '@context/sdk'CommonJS
const { Context } = require('@context/sdk')If your runner compiles to CJS, avoid top-level
await(wrap in an async IIFE).
Servers
const server = await context.getServer('ctx.ai')Chat
// Start a chat
const chat = await server.startChat('What is your expertise?')
console.log(chat.answer)
// Continue the chat
await chat.send('And what can you help me with today?')
console.log(chat.answer)Knowledge Base (Documents)
Add a document (text)
const doc = await server.knowledge.add({
name: 'Product Overview',
content: 'Our product helps teams collaborate…',
collection: 'public', // or 'private'
})
console.log('Document ID:', doc.id)
console.log('Status:', doc.status)
console.log('Is processing?', doc.isProcessing)Upload a file (Node)
import fs from 'node:fs'
// Buffer or Readable stream are both supported
const uploaded = await server.knowledge.add({
name: 'my-document.pdf',
file: fs.readFileSync('./my-document.pdf'), // or fs.createReadStream(...)
collection: 'public',
})
console.log(uploaded.id, uploaded.status)Upload a file (browser)
const input = document.querySelector('input[type="file"]') as HTMLInputElement
const file = input.files?.[0]
if (!file) throw new Error('Pick a file first')
await server.knowledge.add({
name: file.name,
file, // File/Blob
collection: 'public',
})Refresh & access documents
// Refresh the cache from the server
await server.knowledge.load()
// Snapshot of all docs (from local cache)
const all = server.knowledge.documents
console.log('Total:', all.length)
// Get by ID (from cache)
const one = server.knowledge.get('doc-id-123')
if (one) {
console.log(one.name, one.status)
}
// Find by name (from cache)
const found = server.knowledge.find('Product Overview')
console.log('Found?', !!found)Filter by status / counts
const pending = server.knowledge.getByStatus('pending')
const running = server.knowledge.getByStatus('running')
const completed = server.knowledge.getByStatus('completed')
const failed = server.knowledge.getByStatus('failed')
console.log('Counts:', {
pending: pending.length,
running: running.length,
completed: completed.length,
failed: failed.length,
})
console.log('Total docs:', server.knowledge.count)Track processing until done (polling example)
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
let doc = await server.knowledge.add({
name: 'Large Report',
content: 'Long content…',
collection: 'public',
})
// Poll until terminal state
while (!doc.isComplete && !doc.isFailed) {
await sleep(2000)
await server.knowledge.load() // refresh cache from server
const refreshed = server.knowledge.get(doc.id)
if (!refreshed) throw new Error('Document disappeared from cache')
doc = refreshed
console.log('Status:', doc.status)
}
if (doc.isComplete) console.log('✓ Processing complete!')
else console.log('✗ Processing failed')Delete documents
// By ID
await server.knowledge.del('doc-id-123')
// By Document instance
const doc = server.knowledge.get('doc-id-456')
if (doc) await server.knowledge.del(doc)
// Many at once
await server.knowledge.deleteMany(['id1', 'id2', 'id3'])API surface (selected)
Context
constructor(options: { apiKey: string; baseUrl?: string })getServer(name: string): Promise<Server>
Server
startChat(prompt: string): Promise<Chat>knowledge: Knowledge
Knowledge
add(options: { name: string; content?: string; file?: File|Buffer; sourceUrl?: string; collection?: 'public'|'private' }): Promise<Document>del(documentOrId: string | Document): Promise<void>deleteMany(ids: string[]): Promise<void>load(): Promise<Document[]>get(documentId: string): Document | undefinedfind(name: string): Document | undefinedgetByStatus(s: 'pending' | 'running' | 'completed' | 'failed'): Document[]documents: Document[](getter, cache snapshot)count: number(getter)
Document
- Properties:
id,name,status,sourceType,collectionType,task? - Helpers:
isProcessing,isComplete,isFailed - Methods:
update(options: { name?: string; content?: string }): Promise<void>
Chat
- Properties:
answer(last assistant message) - Methods:
send(message: string): Promise<void>
Note: Some fields can be snake_case from the API; the SDK normalizes them to camelCase on the
Document/Serverobjects.
Error handling
The SDK throws an Error on non-2xx responses and on network failures:
try {
const server = await context.getServer('ctx.ai')
const chat = await server.startChat('Hello')
console.log(chat.answer)
} catch (err) {
console.error('Request failed:', err instanceof Error ? err.message : String(err))
}If you want a result-style helper:
async function result<T>(fn: () => Promise<T>) {
try {
return { ok: true as const, data: await fn() }
} catch (e) {
return { ok: false as const, error: e as Error }
}
}Browser notes
- Use
<input type="file">to obtain aFileobject; the SDK will POSTmultipart/form-data. - Ensure your API has CORS headers allowing the origin where your app runs.
Local development tips
- Use
baseUrl: 'http://localhost:4600'or setDEVELOPER_API_URL. - If you run behind corporate proxies, set:
export NO_PROXY=localhost,127.0.0.1,::1
License
MIT © Context
