Skip to main content

Examples, practices, troubleshooting

Code examples

8.1 JavaScript / TypeScript — reusable AI client

type AiQueryOptions = {
promptId?: number;
provider?: string;
providerId?: number;
stream?: boolean;
externalId?: string;
externalUser?: string;
noLog?: boolean;
knowledgeBaseIds?: number[];
agentDefinitionId?: number;
};

class KroovClient {
constructor(
private readonly baseUrl: string,
private readonly apiKey: string
) {}

async query(prompt: string, projectId: number, options: AiQueryOptions = {}) {
const response = await fetch(`${this.baseUrl}/api/ai/query`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ prompt, projectId, stream: false, ...options })
});
if (!response.ok) {
const err = await response.json().catch(() => ({}));
throw new Error(err.errorMessage || `HTTP ${response.status}`);
}
return response.json();
}

async chat(
messageUser: string,
projectId: number,
options: AiQueryOptions & { chatId?: string | null; delegation?: object } = {}
) {
const response = await fetch(`${this.baseUrl}/api/ai/chat`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ messageUser, projectId, stream: false, ...options })
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
return response.json();
}

async *streamChat(messageUser: string, projectId: number, options: Record<string, unknown> = {}) {
const response = await fetch(`${this.baseUrl}/api/ai/chat`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json',
Accept: 'text/event-stream'
},
body: JSON.stringify({ messageUser, projectId, stream: true, ...options })
});
if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`);

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.startsWith('data:')) continue;
const data = line.slice(5).trim();
if (data === '[DONE]') return;
try { yield JSON.parse(data); } catch { /* keep-alive */ }
}
}
}
}

// Usage
const client = new KroovClient('https://your-kroov-host', process.env.AINEXUS_API_KEY!);
const result = await client.query('Summarize the key points', 1, { providerId: 12 });
console.log(result.content);

8.2 Python — chat with knowledge bases + streaming

import json
import requests

BASE = "https://your-kroov-host"

def chat(api_key: str, message: str, project_id: int, kb_ids: list[int], chat_id: str | None = None):
r = requests.post(
f"{BASE}/api/ai/chat",
headers={"x-api-key": api_key, "Content-Type": "application/json"},
json={
"messageUser": message,
"projectId": project_id,
"chatId": chat_id,
"knowledgeBaseIds": kb_ids,
"stream": False,
},
timeout=120,
)
r.raise_for_status()
return r.json()

def stream_query(api_key: str, prompt: str, project_id: int, provider_id: int | None = None):
with requests.post(
f"{BASE}/api/ai/query",
headers={"x-api-key": api_key, "Content-Type": "application/json"},
json={"prompt": prompt, "projectId": project_id, "providerId": provider_id, "stream": True},
stream=True,
timeout=300,
) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if not line or not line.startswith("data:"):
continue
data = line[5:].strip()
if data == "[DONE]":
break
try:
evt = json.loads(data)
except json.JSONDecodeError:
continue
if content := evt.get("content"):
print(content, end="", flush=True)

8.3 C# — OpenAI-compatible client

using var http = new HttpClient { BaseAddress = new Uri("https://your-kroov-host") };
http.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");

var payload = new {
model = "gpt-4o",
messages = new[] { new { role = "user", content = "Summarize the key guidance" } },
extension = new { noLog = false }
};

var res = await http.PostAsJsonAsync("/v1/chat/completions", payload);
res.EnsureSuccessStatusCode();
var json = await res.Content.ReadAsStringAsync();

8.4 cURL — automation happy path (dev)

TOKEN=$(curl -s -X POST https://localhost:7003/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}' | jq -r .token)
AUTH="Authorization: Bearer $TOKEN"

# 1) Agent
AGENT_ID=$(curl -s -X POST https://localhost:7003/api/agents \
-H "$AUTH" -H 'Content-Type: application/json' \
-d '{"projectId":1,"name":"Support agent","systemPrompt":"Draft replies."}' | jq -r .id)

# 2) After Pipedream Connect UI records a connection:
# curl -s -X POST https://localhost:7003/api/automations -H "$AUTH" -H 'Content-Type: application/json' -d '{...}'
# curl -s -X POST https://localhost:7003/api/automations/$ID/grants -H "$AUTH" ...
# curl -s -X POST https://localhost:7003/api/automations/$ID/toggle -H "$AUTH" -d '{"isActive":true}'
# curl -s -X POST https://localhost:7003/api/automation-events/test -H "$AUTH" -d '{...}'
# Full walkthrough available in the automations guides

8.5 cURL — create interactive session (empty workspace)

curl -s -X POST https://localhost:7003/api/sessions \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"projectId": 1,
"providerId": 12,
"title": "Scratch workspace",
"firstMessage": "Create a short project plan markdown file"
}'

8.6 cURL — knowledge base upload + chat grounding

# Admin JWT required for KB admin APIs
curl -s -X POST https://localhost:7003/api/knowledge-bases \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"projectId": 1,
"name": "Protocols",
"embeddingProviderId": 3,
"embeddingModel": "text-embedding-3-small",
"chunkSize": 1000,
"chunkOverlap": 100,
"isActive": true
}'

curl -s -X POST https://localhost:7003/api/knowledge-bases/1/documents \
-H "Authorization: Bearer $TOKEN" \
-F "files=@protocol.pdf"

# Inference uses API key + knowledgeBaseIds (after documents reach Indexed)
curl -s -X POST https://localhost:7003/api/ai/chat \
-H "x-api-key: $API_KEY" -H 'Content-Type: application/json' \
-d '{
"messageUser": "What does the protocol say about escalation?",
"projectId": 1,
"providerId": 12,
"knowledgeBaseIds": [1]
}'

Best practices

9.1 API Key & JWT Management

  • Prefer API keys for service-to-service AI calls; JWT for user-context admin/agent operations
  • Scope keys to a project when possible
  • Rotate keys; revoke immediately on compromise
  • Use refresh tokens; never embed long-lived JWTs in mobile binaries without a refresh flow

9.2 Provider Routing

  • Prefer providerId for deterministic routing and cost attribution
  • Check capability flags (text/image/audio/embeddings/agentTools/realtime) before calling
  • Keep a fallback provider strategy client-side for 502 responses

9.3 Chat & MCP

  • Use stream: true for tool-using chats
  • Constrain tools with project MCP assignments + per-user credentials + grants
  • For multi-MCP, set delegation.mcpServerIds explicitly; use [] only when you intentionally want grants-only tools
  • Never put long-lived vendor secrets in client-side code — use the vault (/api/integrations) or managed instances

9.4 Knowledge Bases

  • Chunk size / overlap defaults are fine for most corpora; reindex after embedding model changes
  • Share bases across projects via PUT .../projects instead of duplicating uploads
  • Use knowledgeBaseIds on chat for ad-hoc grounding without a dedicated KB provider

9.5 Agents, Sessions & Tasks

  • Start autonomous work in Plan or Ask mode before enabling write tools
  • Set budgets (maxTokens, maxEstimatedCostUsd, tool/model call caps) on sessions and scheduled tasks
  • Prefer overlapPolicy: Skip for scheduled tasks unless concurrent work is intentional
  • Export session artifacts (/export) before DELETE if you need the files

9.6 Automations

  • Create automations paused, add grants, then toggle active
  • Prefer ApproveWrites for anything that sends external messages
  • Treat webhook secrets like passwords; rotate with /rotate-secret
  • Rely on platform dedupe — still design handlers to be safe under at-least-once delivery

9.7 Performance & Resilience

  • Reuse chatId instead of resending full history via messageHistory when possible
  • Use resumable SSE (after=) for long agent runs
  • Apply exponential backoff on 502/503
  • Watch cost endpoints in production integrations

Security considerations

10.1 Input Validation

  • Enforce max prompt / attachment sizes client-side as well as server-side
  • Sanitize filenames on uploads
  • Treat model output as untrusted when displaying in HTML (XSS)

10.2 Data Minimization & Sensitive Data

  • Send the minimum sensitive data required for the task
  • Prefer externalId opaque tokens over raw personal identifiers when feasible
  • Use noLog only when the project explicitly allows it — metrics still remain
  • Follow your organisation's Acceptable Use and retention policies

10.3 Secrets

SecretStorage
API keysSecrets manager / env
JWT / refreshHttpOnly secure storage / memory
Pipedream webhookSecretSecrets manager (shown once)
MCP OAuth client secretsServer-side only (never in API responses)
Jwt:SecretKey / Encryption:MasterKeyEnvironment / K8s Secret — never committed

10.4 Webhook authenticity

  • Verify signatures with the connection’s secret
  • Reject unsigned bodies
  • Do not distinguish “unknown connection” from “bad signature” in client logs exposed to untrusted parties

10.5 Network

  • Production APIs are often internal-only
  • Public webhook base URLs (automations) must be HTTPS in production and tightly scoped
  • Hosted MCP / agent pods run with restricted Pod Security; do not inject host credentials into workspaces

Troubleshooting

11.1 Common Issues

401 Unauthorized

  • Missing/invalid x-api-key or JWT
  • Expired API key or access token — refresh or renew
  • Webhook: wrong signature or connection id
  • /api/ai/* called with JWT only — use an API key

403 Forbidden

  • API key project mismatch
  • Non-admin calling AdminOnly route
  • Member trying to edit a development agent (repository-backed)

400 Bad Request

  • Missing prompt / messageUser / multipart file
  • Invalid cron / time zone on scheduled tasks
  • KB / MCP ids not visible to the project

409 Conflict

  • Duplicate knowledge-base name in project
  • Second automation approval
  • Unique constraint (idempotency)

502 Bad Gateway

  • Upstream model provider outage or quota
  • Retry with backoff; fail over providerId

503 Service Unavailable

  • Feature flag off — check GET /api/features
  • Internal KB on non-PostgreSQL
  • Hosted MCP / agents without Kubernetes
  • Automations disabled

Slow responses / stuck sessions

  • Check /api/sessions/{id}/diagnostics for pod provisioning
  • Confirm kubeconfig / cluster capacity
  • Review budgets and tool-loop limits

11.2 Debugging Tips

# Capability matrix
curl -s https://localhost:7003/api/features | jq

# Auth modes
curl -s https://localhost:7003/api/auth/options | jq

# Health
curl -s https://localhost:7003/health

# AI smoke (API key)
curl -s -X POST https://localhost:7003/api/ai/query \
-H "x-api-key: $API_KEY" -H 'Content-Type: application/json' \
-d '{"prompt":"ping","projectId":1}'

# Swagger (Development)
open https://localhost:7003/swagger

Correlate failures with Dashboard logs (requestId) and, for agents/sessions, SSE event streams.

11.3 Getting Help

Include: environment (prod/dev/local), endpoint, HTTP status, requestId, project id, feature-flag snapshot (/api/features), redacted request body, and timestamp. Contact your platform administrator or operations team.