@hasura/promptql
v2.0.0-alpha.42
Published
A Typescript SDK allows you to interact with PromptQL API
Readme
PromptQL TypeScript SDK
The PromptQL TypeScript SDK is a general-purpose SDK that interacts with the PromptQL API by Hasura. PromptQL is a multiplayer AI agent — think Claude or ChatGPT, but with shared threads and a shared brain.
[!NOTE] This SDK supports PromptQL v2. Please install @hasura/[email protected] if you wants to integrate PromptQL v1.
Requirements
- Node.js >= 24
- TypeScript >= 5.9.2
Installation
npm install @hasura/promptql@latestOr with your preferred package manager:
# Yarn
yarn add @hasura/promptql@latest
# pnpm
pnpm add @hasura/promptql@latest
# Bun
bun add @hasura/promptql@latestQuick Start
Getting PromptQL access token
- Visit your PromptQL project
- Navigate to User Directory
- Use your account or create a bot account.
- Create a personal access token with
MCPscope. - Copy the token and use it in your SDK configuration
Basic Usage
Start a PromptQL thread
import { PromptQLSdk } from '@hasura/promptql';
// Initialize the SDK
const sdk = new PromptQLSdk({
baseUrl: 'https://your-data-plane-url',
accessToken: 'personal-access-token',
});
// Start a new thread
const thread = await sdk.thread.start({
message: 'What are the top 10 customers by revenue?',
});
console.log('Thread ID:', thread.thread_id);
// Stream events from the thread
sdk.thread.streamEvents(thread.thread_id).subscribe({
next: (events) => {
events.forEach(event => {
console.log('Event:', event);
});
},
error: (err) => console.error('Error:', err),
complete: () => console.log('Interaction complete'),
});Continue a Conversation
// Send a follow-up message to an existing thread
const result = await sdk.thread.sendMessage({
threadId: 'existing-thread-id',
message: 'Now show me their average order value',
});
// Stream the response
sdk.streamEvents(result.thread_id, result.thread_event_id)
.subscribe({
next: (events) => console.log('New events:', events),
});Wait until the final response only
Use the lastValueFrom function to wrap the subscription.
import { PromptQLSdk } from '@hasura/promptql';
import { lastValueFrom } from "rxjs";
// Initialize the SDK
const sdk = new PromptQLSdk({
serviceAccountToken: 'your-service-account-token',
});
// Start a new thread
const thread = await sdk.thread.start({
message: 'What are the top 10 customers by revenue?',
});
console.log('Thread ID:', thread.thread_id);
const events = await lastValueFrom(
sdk.thread.streamEvents(
result.thread_id,
),
);
events.forEach(event => {
console.log('Event:', event);
});Print new events only
import { PromptQLSdk, diffThreadEvents } from '@hasura/promptql';
import { pairwise, map } from 'rxjs';
// Initialize the SDK
const sdk = new PromptQLSdk({
baseUrl: 'https://your-data-plane-url',
accessToken: 'personal-access-token',
});
// Start a new thread
const thread = await sdk.thread.start({
message: 'What are the top 10 customers by revenue?',
});
console.log('Thread ID:', thread.thread_id);
// Stream events from the thread
sdk.streamEvents(thread.thread_id)
.pipe(
pairwise(),
map(([prev, curr]) => diffThreadEvents(prev, curr)),
)
.subscribe({
next: (events) => {
events.forEach(event => {
console.log('Event:', event);
});
},
error: (err) => console.error('Error:', err),
complete: () => console.log('Interaction complete'),
});Listing Threads
const threads = await sdk.thread.list({
limit: 20,
offset: 0,
order_by: [{ created_at: 'desc' }],
where: {
// Optional filters
},
});
threads.forEach(thread => {
console.log(`Thread ${thread.id}:`, thread.title);
});Get a Specific Thread
const thread = await sdk.thread.get('thread-id');
console.log('Thread:', thread);Event Handling
Basics
The data structure of event data is the union of many event type. Each event type contains a different payload. You can go to the definition of ThreadEventData type to view the full data structure details.
The SDK also provides utility functions to parse different event types, for example, the following example catches and prints the query plan event and the final generated response:
import {
getAgentPlanGenerationStartedEvent,
getAgentPlanStepGeneratedEvent,
getAgentGeneratedResponse,
getUserMessageEvent,
} from '@hasura/promptql';
sdk.thread.streamEvents(threadId).subscribe({
next: (events) => {
events.forEach(event => {
// Check for plan generation start
const planStart = getAgentPlanGenerationStartedEvent(event.event_data);
if (planStart) {
console.log('Query Plan:\n');
return;
}
// Check for plan steps
const planStep = getAgentPlanStepGeneratedEvent(event.event_data);
if (planStep) {
console.log(` - Step ${planStep.step_index}: ${planStep.step_title}\n`);
return;
}
// Check for final response
const response = getAgentGeneratedResponse(event.event_data);
if (response) {
const xmlRegex = /<\w+.*\/>/gm;
console.log('Response:', source.replaceAll(xmlRegex, response.response.message));
if (response.response.modified_artifacts) {
console.log('Artifacts:', response.response.modified_artifacts);
}
return;
}
});
},
});Handle XML tags in generated response message
The generated message may contains XML tags. They represents custom UI elements that the markdown text doesn't support. You should parse or remove them if they aren't required.
Common XML tags are:
<artifact type="table" identifier="last_5_products" />: the identifier of the artifact block.<user_mention id="user_id" />: mentioned user in the chat message.<user_group_mention id="group_id" />: mentioned group in the chat message.<promptql_mention />: represents a@promptqltag in the chat message.
You can remove them using regular expressions or parse the message to XML elements for advanced format.
const xmlRegex = /<\w+.*\/>/gm;
console.log(source.replaceAll(xmlRegex, ""));Configuration Options
export type PromptQLSdkOptions = {
/**
* Base URL of the PromptQL API.
*/
baseUrl?: string;
/**
* Access token of the PromptQL project.
*/
accessToken: string;
/**
* A function to use instead of calling the Fetch API directly when sending HTTP requests to your GraphQL endpoint. The function must conform to the signature of fetch.
* By default, the Fetch API is used unless it isn't available in your runtime environment.
*/
fetch?: typeof fetch;
/**
* An object representing headers to include in every HTTP request.
*/
headers?: Record<string, string>;
/**
* An [IANA timezone](https://data.iana.org/time-zones/tzdb-2021a/zone1970.tab) for interpreting time-based queries. Default is the timezone from the client config.
*/
timezone?: string;
};Links
Support
For support, please:
- Join the Hasura Discord community
