The official Node.js SDK for the Subconscious API
v1.0 — If you're upgrading from
0.x, read the Migration Guide.
pnpm add subconscious
# or
npm install subconscious
# or
yarn add subconsciousimport { Subconscious } from 'subconscious';
const client = new Subconscious({
apiKey: process.env.SUBCONSCIOUS_API_KEY!,
});
const run = await client.run({
engine: 'tim',
input: {
instructions: 'Search for the latest AI news and summarize the top 3 stories',
tools: [{ type: 'platform', id: 'web_search' }],
},
options: { awaitCompletion: true },
});
console.log(run.result?.answer);Create an API key in the Subconscious dashboard.
const run = await client.run({
engine: 'tim',
input: {
instructions: 'Analyze the latest trends in renewable energy',
tools: [{ type: 'platform', id: 'web_search' }],
},
options: { awaitCompletion: true },
});
console.log(run.result?.answer);
console.log(run.result?.reasoning); // ReasoningTask[]const run = await client.run({
engine: 'tim',
input: {
instructions: 'Generate a comprehensive report',
tools: [],
},
});
console.log(`Run started: ${run.runId}`);
// Check status later
const status = await client.get(run.runId);
console.log(status.status); // 'queued' | 'running' | 'succeeded' | 'failed' | 'canceled' | 'timed_out'const run = await client.run({
engine: 'tim',
input: {
instructions: 'Complex task',
tools: [{ type: 'platform', id: 'web_search' }],
},
});
const result = await client.wait(run.runId, {
intervalMs: 2000,
maxAttempts: 60,
});const stream = client.stream({
engine: 'tim',
input: {
instructions: 'Write a short essay about space exploration',
tools: [{ type: 'platform', id: 'web_search' }],
},
});
for await (const event of stream) {
if (event.type === 'delta') {
process.stdout.write(event.content);
} else if (event.type === 'done') {
console.log('\n\nRun completed:', event.runId);
} else if (event.type === 'error') {
console.error('Error:', event.message);
}
}Note: Rich streaming events (reasoning steps, tool calls) are coming soon. The stream currently provides text deltas as they're generated.
Pass images alongside instructions using the content field:
import { Subconscious, Image } from 'subconscious';
const client = new Subconscious();
const run = await client.run({
engine: 'tim-claude',
input: {
instructions: 'What is in this image?',
content: [Image.fromPath('shot.png')],
},
options: { awaitCompletion: true },
});Image factory constructors:
| Constructor | When to use |
|---|---|
Image.fromPath(path) |
Read a local file from disk |
Image.fromBytes(buf, mime?) |
Wrap raw bytes you already have in memory |
Image.fromUrl(url) |
Reference a public URL (server fetches on your behalf) |
Image.fromUrl(url, {fetch:1}) |
Download client-side and embed as base64 |
Image.fromBlobRef(key, mime) |
Reference an asset already in Subconscious storage |
Supported MIME types: image/png, image/jpeg, image/gif, image/webp. Requests larger than 5MB throw RequestTooLargeError — upload via /v1/internal/attachments first, then pass Image.fromBlobRef(...).
Attach lifecycle-managed services (sandboxes, browsers, memory stores) to your run via resources:
const run = await client.run({
engine: 'tim',
input: {
instructions: 'Analyze data.csv and output a chart',
resources: ['sandbox'], // E2B sandbox
},
options: { awaitCompletion: true },
});Attach reusable knowledge packages to your runs. Skills inject custom instructions into the agent's system prompt at request time.
const run = await client.run({
engine: 'tim',
input: {
instructions: 'Build a REST API following our team standards',
tools: [{ type: 'platform', id: 'web_search' }],
skills: ['api-design', 'error-handling'],
},
options: { awaitCompletion: true },
});Skills are resolved by name. Browse and create skills at subconscious.dev/platform/skills.
Platform Tools — built-in tools hosted by Subconscious:
| Tool Name | API Name | Description |
|---|---|---|
| Fast Search | fast_search |
Extremely fast search for simple factual lookups |
| Web Search | web_search |
Comprehensive web search for detailed research |
| Fresh Search | fresh_search |
Search the web for content from the last 7 days |
| Page Reader | page_reader |
Extract content from a specific webpage URL |
| Find Similar | find_similar |
Find similar links to a given URL |
| People Search | people_search |
Search for people, profiles, and bios |
| Company Search | company_search |
Search for companies, funding info, and business details |
| News Search | news_search |
Search for news articles and press coverage |
| Tweet Search | tweet_search |
Search for tweets and Twitter/X discussions |
| Research Paper Search | research_paper_search |
Search for academic research papers and studies |
| Google Search | google_search |
Search the web using Google |
// Platform tool (hosted by Subconscious)
const fastSearch = { type: 'platform', id: 'fast_search' };
// Function tool (your own HTTP endpoint)
const customFunction = {
type: 'function',
name: 'get_weather',
description: 'Get current weather for a location',
url: 'https://api.example.com/weather',
method: 'GET',
timeout: 30,
parameters: {
type: 'object',
properties: {
location: { type: 'string', description: 'City name' },
},
required: ['location'],
},
};
// MCP tool (any MCP-compatible server)
const mcpTool = {
type: 'mcp',
url: 'https://mcp.example.com',
allowedTools: ['search', 'get_page'],
};Function tools support two features for injecting data at call time:
headers: HTTP headers sent with the request to your tool endpointdefaults: Parameter values hidden from the model and injected automatically
const toolWithHeadersAndDefaults = {
type: 'function',
name: 'search_database',
description: 'Search the database',
url: 'https://api.example.com/search',
method: 'POST',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
sessionId: { type: 'string' },
apiKey: { type: 'string' },
},
required: ['query'],
},
headers: {
'x-custom-auth': 'my-secret-token',
},
defaults: {
sessionId: 'user-session-abc123',
apiKey: 'secret-api-key',
},
};Connect to any Model Context Protocol server. Subconscious discovers tools from the server, filters by your allowedTools list, and proxies calls automatically.
MCP servers requiring authentication accept an auth object:
| Method | When to use | Header sent |
|---|---|---|
| Bearer | OAuth tokens, JWTs — most common | Authorization: Bearer <token> |
| API key | Service-specific API keys | <header>: <token> (typically X-Api-Key) |
// Bearer auth (most common)
{ type: 'mcp', url: 'https://mcp.google.com/v1',
auth: { type: 'bearer', token: 'your-oauth-token' } }
// API key auth
{ type: 'mcp', url: 'https://mcp.example.com',
auth: { type: 'api_key', token: 'key123', header: 'X-Api-Key' } }allowedTools filtering:
| Value | Behavior |
|---|---|
Omitted / undefined |
All tools from the server are enabled |
["*"] |
All tools enabled (explicit wildcard) |
["search", "fetch"] |
Only these tools (case-insensitive) |
[] |
No tools (blocks all) |
Get structured responses using JSON Schema. We recommend using Zod and converting with zodToJsonSchema():
import { z } from 'zod';
import { Subconscious, zodToJsonSchema } from 'subconscious';
const client = new Subconscious();
const AnalysisSchema = z.object({
summary: z.string().describe('A brief summary of the findings'),
keyPoints: z.array(z.string()).describe('Main takeaways'),
sentiment: z.enum(['positive', 'neutral', 'negative']),
confidence: z.number().describe('Confidence score from 0 to 1'),
});
const run = await client.run({
engine: 'tim',
input: {
instructions: 'Analyze the latest news about electric vehicles',
tools: [{ type: 'platform', id: 'web_search' }],
answerFormat: zodToJsonSchema(AnalysisSchema, 'Analysis'),
},
options: { awaitCompletion: true },
});
const result = run.result?.answer as z.infer<typeof AnalysisSchema>;
console.log(result.summary);Pass reasoningFormat to also structure the agent's reasoning trace:
const ReasoningSchema = z.object({
steps: z.array(z.object({ thought: z.string(), action: z.string() })),
conclusion: z.string(),
});
const run = await client.run({
engine: 'tim',
input: {
instructions: 'Research and explain quantum computing',
tools: [{ type: 'platform', id: 'web_search' }],
answerFormat: zodToJsonSchema(AnalysisSchema, 'Analysis'),
reasoningFormat: zodToJsonSchema(ReasoningSchema, 'Reasoning'),
},
options: { awaitCompletion: true },
});import {
SubconsciousError,
AuthenticationError,
RateLimitError,
RequestTooLargeError,
} from 'subconscious';
try {
const run = await client.run({
/* ... */
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof RateLimitError) {
console.error('Rate limited, retry later');
} else if (error instanceof RequestTooLargeError) {
console.error('Payload over 5MB — split images across turns or upload via /v1/internal/attachments');
} else if (error instanceof SubconsciousError) {
console.error(`API error: ${error.code} - ${error.message}`);
}
}// Cancel via AbortController
const controller = new AbortController();
const stream = client.stream(params, { signal: controller.signal });
setTimeout(() => controller.abort(), 30000);
// Or cancel a running run
await client.cancel(run.runId);Control how results are delivered via options.output.
Per-run webhook — receive a POST to your server when the run reaches a terminal state:
const run = await client.run({
engine: 'tim',
input: { instructions: 'Generate a report', tools: [] },
options: {
output: { callbackUrl: 'https://your-server.com/webhook' },
},
});Response shape — return only the final answer instead of the full reasoning tree:
options: {
output: { responseContent: 'answer_only' }, // 'full' (default) | 'answer_only'
}The main client class.
| Option | Type | Required | Default |
|---|---|---|---|
apiKey |
string |
No* | — |
baseUrl |
string |
No | https://api-legacy.subconscious.dev/v1 |
* If not passed, resolved from SUBCONSCIOUS_API_KEY env var or ~/.subcon/config.json.
| Method | Description |
|---|---|
run(params) |
Create a new run |
stream(params, options?) |
Stream text deltas |
get(runId) |
Get run status |
wait(runId, options?) |
Poll until completion |
cancel(runId) |
Cancel a running run |
| Engine | Type | Description |
|---|---|---|
tim |
Unified | Flagship unified agent engine for a wide range of tasks |
tim-edge |
Unified | Highly efficient engine tuned for performance with search tools |
tim-claude |
Compound | Complex reasoning engine backed by Anthropic Claude Sonnet |
tim-claude-heavy |
Compound | Complex reasoning engine backed by Anthropic Claude Opus |
tim-oss-local |
Compound | Tool-calling engine for TIM-trained OSS models |
tim-1.5 |
Compound | Tool-calling engine for large OSS models v1.5 |
| Status | Description |
|---|---|
queued |
Waiting to start |
running |
Currently executing |
succeeded |
Completed successfully |
failed |
Encountered an error |
canceled |
Manually canceled |
timed_out |
Exceeded time limit |
- Node.js ≥ 18
- ESM only
Contributions are welcome! Please feel free to submit a pull request.
Apache-2.0
- Documentation: https://docs.subconscious.dev
- Email: {hongyin,jack,dana,wei}@subconscious.dev