The AI Manager is a general-purpose completion layer that wraps every LLM call on the platform. Beyond basic chat completions, it provides two optional capabilities that make it particularly useful for applications that need persistent context: supplementary data injection and automatic fact extraction.
Basic completion
At its simplest, POST /v1/ai/complete runs a chat completion using whichever AI provider is configured for your workspace (OpenAI or a local Ollama model).
Run a chat completion. Returns the assistant's response text, token usage, and any facts extracted from the conversation.
Request body
Name
Type
Required
Description
systemPrompt
string
required
Instructions for the model — sets tone, role, and constraints
messages
Message[]
required
Conversation history. Each item: { role: "user" | "assistant" | "system", content: string }
json
boolean
optional
When true, instructs the model to respond with a valid JSON object
temperature
number
optional
Sampling temperature 0–2. Lower = more deterministic (default: model default)
max_tokens
number
optional
Maximum tokens in the completion
supplementary
SupplementaryItem[]
optional
Structured data blocks injected after the system prompt. See Supplementary Data.
extraction
ExtractionConfig
optional
Fact extraction config. See Extraction.
Response
{
"content": "Based on your runway of 14 months, hiring now makes sense if...",
"usage": {
"promptTokens": 312,
"completionTokens": 189,
"totalTokens": 501
},
"extracted": [] // populated when extraction is enabled
}
curl -X POST http://localhost:3001/v1/ai/complete \
-H "x-api-key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"systemPrompt": "You are a strategic business advisor.",
"messages": [
{ "role": "user", "content": "Should we expand into the EU market?" }
]
}'
Supplementary data
Supplementary data lets you attach structured context to any completion call — company financials, user profiles, CRM data, live metrics — without manually formatting it into your system prompt. Each item is categorized and injected automatically between the system prompt and the conversation.
How it works
Items are sorted by priority (high first) and appended to your system prompt inside a clearly delimited block:
categorystringrequiredIdentifies the type of data (e.g. company-financials, user-profile, crm-data). Used as the section heading.
dataobject | stringrequiredThe context payload. Objects are JSON-formatted; strings are inserted verbatim.
labelstringoptionalCustom heading shown in the injected block. Defaults to category if omitted.
priority"high" | "medium" | "low"optionalSorting order within the block. High-priority items appear first. Defaults to medium.
✓
Supplementary data is ideal for data your application already has — you retrieved it from your database, not from the user. For information you want to learn from the user's messages, use extraction below.
When extraction is set, PulseLABS runs a secondary LLM call after the main completion to parse structured facts out of the user's message. Extracted facts are returned in the response and, when persist: true, saved to your account for retrieval via GET /v1/ai/extracted-data.
How it works
The extractor is a fast, low-temperature model call (pinned to gpt-4o-mini when using OpenAI). It reads the user message and returns a list of typed key-value pairs filtered to only the categories you allow. Facts are upserted by (source, category, key) — re-running on the same user always updates rather than duplicates.
The extraction config
sourcestringrequiredLogical namespace for these facts (e.g. "onboarding-chat", "support-ticket"). Enables filtering later.
categoriesstring[]requiredWhitelist of categories the extractor is allowed to emit. Only matching facts are returned and persisted.
persistbooleanoptionalWhen true, extracted facts are upserted to the database. When false (default), they are returned in the response but not stored.
ℹ
Extraction never throws — if the secondary model call fails, the main completion is unaffected and extracted returns an empty array.
const res = await fetch('/v1/ai/complete', {
method: 'POST',
headers: {
'x-api-key': 'sk_live_xxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({
systemPrompt: 'You are a helpful assistant.',
messages: [
{
role: 'user',
content: 'My name is Sarah, I run a SaaS company in Berlin with 12 employees and €40k MRR.',
},
],
extraction: {
source: 'onboarding-chat',
categories: ['person', 'company', 'financials'],
persist: true,
},
}),
})
const { content, extracted } = await res.json()
// extracted = [
// { category: 'person', key: 'name', value: 'Sarah', confidence: 0.98 },
// { category: 'company', key: 'location', value: 'Berlin', confidence: 0.95 },
// { category: 'company', key: 'employees', value: '12', confidence: 0.93 },
// { category: 'financials', key: 'mrr', value: '40000', confidence: 0.91 },
// ]
Using both together
Supplementary data and extraction are designed to work together in a feedback loop. You inject what you already know, extract what you learn, and on the next call inject the freshly-learned facts:
1
First message
User sends their first message. Extraction runs and persists facts about them.
2
Retrieve facts
Your app calls GET /v1/ai/extracted-data?source=onboarding-chat to load saved facts.
3
Next completion
Facts from step 2 are passed as supplementary data — the model now knows the user's context without it being in the conversation history.
4
Repeat
Each turn enriches the fact store. Context grows automatically without bloating the message history.
const res = await fetch('/v1/ai/complete', {
method: 'POST',
headers: {
'x-api-key': 'sk_live_xxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({
systemPrompt: 'You are a strategic business advisor.',
messages: [
{ role: 'user', content: 'We have 14 months of runway. Should we hire now?' },
],
// Inject structured context into the prompt
supplementary: [
{
category: 'company-financials',
priority: 'high',
data: { mrr: 85000, runway_months: 14, burn_rate: 42000 },
},
{
category: 'hiring-pipeline',
data: { open_roles: ['Senior Engineer', 'Head of Sales'], avg_ramp_weeks: 8 },
},
],
// Extract facts from the user's message and persist them
extraction: {
source: 'strategy-chat',
categories: ['financials', 'intent'],
persist: true,
},
temperature: 0.4,
max_tokens: 800,
}),
})
const { content, usage, extracted } = await res.json()
console.log('Answer:', content)
console.log('Tokens used:', usage.totalTokens)
console.log('Facts learned:', extracted)
Managing extracted facts
List facts extracted and persisted across all AI completions. Filterable by source and category.