@hikigai/app-sdk
Application SDK
Official Node.js SDK for invoking healthcare AI agents in your applications. Full streaming, WebSocket, and session support with type-safe responses.
Installation
Choose your preferred package manager:
npm
npm install @hikigai/app-sdkyarn
yarn add @hikigai/app-sdkpnpm
pnpm add @hikigai/app-sdkQuick Start
import { AppClient } from '@hikigai/app-sdk'
// Initialize client
const client = new AppClient({
apiKey: process.env.HIKIGAI_API_KEY,
projectId: process.env.HIKIGAI_PROJECT_ID,
})
// Get an agent
const agent = await client.agent('medical-coder')
// Basic invocation
const response = await agent.invoke('Patient presents with fever and cough...')
console.log(response.content)
// Streaming responses
for await (const chunk of agent.stream('Tell me about type-2 diabetes')) {
process.stdout.write(chunk)
}
// Session-based conversations
const sessionAgent = agent.withSession('patient-123')
await sessionAgent.invoke('What is the treatment?')
await sessionAgent.invoke('Any contraindications?') // Remembers contextCore Concepts
AppClient
Main interface for agent invocation and management.
class AppClient {
constructor(options?: {
apiKey?: string // API key (or HIKIGAI_API_KEY env var)
projectId?: string // Project ID (or HIKIGAI_PROJECT_ID env var)
baseUrl?: string // API endpoint
timeout?: number // Request timeout in milliseconds
sonaUrl?: string // Optional SONA service URL
sonaApiKey?: string // Optional SONA API key
})
readonly storage: StorageClient
readonly identity: IdentityClient
readonly sona: SONAClient
agent(agentId: string): Promise<RuntimeAgent>
listAgents(options?: {
category?: string; tags?: string[]; search?: string
}): Promise<RuntimeAgent[]>
invoke(agentId: string, input: string | Record<string, unknown>,
options?: InvokeOptions): Promise<InvokeResponse>
stream(agentId: string, input: string | Record<string, unknown>,
options?: StreamOptions): AsyncIterable<string>
live(agentId: string, sessionId?: string, userId?: string,
context?: Record<string, unknown>): StreamSession
createSession(options?: {
externalUserRef?: string; ttlSeconds?: number;
appId?: string; metadata?: Record<string, unknown>
}): Promise<SessionContext>
session(sessionId: string, options?: { appId?: string }): SessionContext
listSessions(options?: {
userRef?: string; limit?: number; cursor?: string
}): Promise<{ sessions: unknown[]; nextCursor?: string }>
getAuthToken(): Promise<AuthTokenResponse>
close(): void
}RuntimeAgent
Represents a deployed agent ready for invocation.
interface RuntimeAgent {
id: string
name: string
slug: string
version?: string
description?: string
status: 'active' | 'pending' | string
endpoint?: string
invoke(input: string | Record<string, unknown>,
options?: InvokeOptions): Promise<InvokeResponse>
stream(input: string | Record<string, unknown>,
options?: StreamOptions): AsyncIterable<string>
withSession(sessionId: string): RuntimeAgent
liveSession(sessionId?: string): StreamSession
}
// InvokeOptions / StreamOptions
// sessionId?, provider?, model?, timeout?, connectors?, pluginContext? (invoke only)Invocation Methods
Multiple ways to interact with agents.
Basic Invocation
const response = await agent.invoke(
'Clinical note to analyze',
{
sessionId: 'patient-123',
timeout: 60000,
}
)
console.log(response.content) // Agent response
console.log(response.metadata.latencyMs) // Performance infoMCP Connectors
Pass linked MCP connector slugs in connectors. The platform injects apiKey and projectId from your AppClient credentials automatically.
import type { McpConnectors } from '@hikigai/app-sdk'
const connectors: McpConnectors = {
'idexx-mcp-server': {}, // platform auth injected automatically
}
const response = await agent.invoke('Prepare patient chart', { connectors })
// Optional HTTP headers (Claude Desktop style)
const withHeaders: McpConnectors = {
'idexx-mcp-server': {
headers: {
'X-API-Key': process.env.HIKIGAI_API_KEY!,
'X-Project-Id': process.env.HIKIGAI_PROJECT_ID!,
},
},
}Agent Discovery
// Get specific agent
const agent = await client.agent('medical-coder')
// List all agents
const agents = await client.listAgents()
// Search agents
const filtered = await client.listAgents({
category: 'medical-coding',
tags: ['icd-10'],
search: 'coding',
})Streaming Responses
Process responses in real-time as they arrive.
// Stream text responses
for await (const chunk of agent.stream('Analyze this report...')) {
process.stdout.write(chunk)
}
// Collect streamed data
let fullResponse = ''
for await (const chunk of agent.stream(input)) {
fullResponse += chunk
}
console.log('Complete response:', fullResponse)Session Management
Multi-turn conversations with persistent context via withSession / sessionId.
const sessionAgent = agent.withSession('patient-789')
// First turn - establish context
await sessionAgent.invoke('I have been experiencing chest pain')
// Second turn - knows about chest pain
await sessionAgent.invoke('Is this serious?')
// Third turn - maintains full conversation history
await sessionAgent.invoke('What tests should I get?')Session Context Store
Server-side key/value context (SessionContext), separate from conversation memory on invoke.
const ctx = await client.createSession({
externalUserRef: 'dr-smith',
ttlSeconds: 3600,
})
await ctx.set('patient_id', 'MRN-12345')
console.log(await ctx.get('patient_id'))
console.log(await ctx.getAll())
const again = client.session(ctx.sessionId)
await again.update({ chief_complaint: 'chest pain' })
await again.touch(7200)WebSocket Live Sessions
Real-time bidirectional communication with agents via StreamSession.
const session = agent.liveSession()
await session.connect()
await session.start('text') // or 'audio'
await session.sendText('Hello, I need help')
// await session.sendAudio(pcmBuffer, 'audio/pcm;rate=16000')
for await (const event of session) {
console.log(event)
if (event.type === 'turn_complete') break
}
await session.end()
await session.close()Rooms
Multi-party realtime rooms via RoomSession (presence, publish, sequence tracking).
import { RoomSession } from '@hikigai/app-sdk'
const room = new RoomSession({
baseUrl: 'https://api.hikigai.com',
apiKey: process.env.HIKIGAI_API_KEY!,
projectId: process.env.HIKIGAI_PROJECT_ID!,
})
await room.connect()
await room.join('care-team-7')
await room.publish('care-team-7', 'note', { text: 'Labs ready' })
for await (const frame of room) {
console.log(frame)
}
await room.close()Storage
const uploaded = await client.storage.upload(
'app_123',
fileBuffer,
'audio.wav',
{ contentType: 'audio/wav' },
)
const { signedUrl } = await client.storage.signedUrl('app_123', uploaded.objectId, 3600)
await client.storage.list('app_123')
await client.storage.delete('app_123', uploaded.objectId)Response Models
interface InvokeResponse {
content: string
agentId: string
agentVersion?: string
sessionId?: string
status: string
output?: Record<string, unknown>
confidence?: ClinicalConfidence // score: 0–1
safetyFlags: SafetyFlag[] // severity: low|medium|high|critical
citations: ClinicalCitation[]
metadata: InvocationMetadata
message?: string
plugins?: Record<string, unknown> // e.g. plugins.sona
}
interface InvocationMetadata {
invocationId: string
latencyMs?: number
timestamp: Date
status: string
tokensUsed?: number
toolsCalled: string[]
phiRedacted: boolean
traceId?: string
}
interface SafetyFlag {
category: string
severity: 'low' | 'medium' | 'high' | 'critical'
message: string
mitigation?: string
}End-User Identity
Add signup, login, MFA, QR badge login, and SSO for your app's end users. Each app is backed by a dedicated AWS Cognito pool the platform provisions for you; login returns standard OIDC tokens. Reach it all through client.identity.
IdentityClient
interface IdentityClient {
// Accounts & auth
signup(appId: string, email: string, password: string,
opts?: { firstName?: string; lastName?: string; role?: string; attributes?: Record<string, string>; metadata?: Record<string, unknown> }): Promise<Record<string, unknown>>
confirm(appId: string, email: string, code: string): Promise<Record<string, unknown>>
login(appId: string, email: string, password: string): Promise<TokenResult>
refresh(appId: string, refreshToken: string): Promise<TokenResult>
logout(appId: string, email: string): Promise<Record<string, unknown>>
forgotPassword(appId: string, email: string): Promise<Record<string, unknown>>
resetPassword(appId: string, email: string, code: string, newPassword: string): Promise<Record<string, unknown>>
changePassword(appId: string, accessToken: string, currentPassword: string, newPassword: string): Promise<Record<string, unknown>>
updateUser(userId: string, fields: Record<string, unknown>): Promise<Record<string, unknown>>
listAppUsers(appId: string, opts?: { limit?: number; offset?: number }): Promise<Record<string, unknown>[]>
deleteAppUser(appId: string, email: string): Promise<void>
// MFA (TOTP)
mfaAssociate(appId: string, accessToken: string): Promise<Record<string, unknown>>
mfaVerify(appId: string, accessToken: string, code: string, opts?: { deviceName?: string }): Promise<Record<string, unknown>>
mfaSetPreference(appId: string, accessToken: string, opts?: { enabled?: boolean }): Promise<Record<string, unknown>>
mfaRespond(appId: string, email: string, session: string, code: string): Promise<TokenResult>
// QR badge & SSO
issueQrLogin(appId: string, email: string): Promise<Record<string, unknown>>
qrLogin(appId: string, qrPayload: string): Promise<TokenResult>
configureSso(appId: string, opts: { providerName: string; providerType: string; /* ... */ }): Promise<Record<string, unknown>>
ssoAuthorizeUrl(appId: string, redirectUri: string, opts?: { provider?: string }): Promise<Record<string, unknown>>
ssoExchange(appId: string, code: string, redirectUri: string): Promise<TokenResult>
// Setup (one-time, per app)
enableIdentity(appId: string, opts?: { mode?: string; enabledMethods?: string[] }): Promise<Record<string, unknown>>
getIdentityConfig(appId: string): Promise<Record<string, unknown>>
byoSetup(): Promise<Record<string, unknown>>
byoTest(roleArn: string, opts?: { region?: string }): Promise<Record<string, unknown>>
}Sign up, confirm, log in
attributes are Cognito profile fields (string values — e.g. phone_number in E.164). metadata is opaque app JSON stored on the platform EndUser (and as custom:metadata when supported). They are not interchangeable.
import { AppClient } from '@hikigai/app-sdk'
const client = new AppClient({
apiKey: process.env.HIKIGAI_API_KEY,
projectId: process.env.HIKIGAI_PROJECT_ID,
})
// 1. Register the end user
await client.identity.signup('app_123', 'clinician@hospital.com', 'Temp#Pass2026', {
firstName: 'Asha',
lastName: 'Mehta',
role: 'clinician',
// attributes → Cognito fields (strings only; e.g. phone_number in E.164)
attributes: { phone_number: '+14155552671' },
// metadata → opaque app JSON on EndUser (and custom:metadata when supported)
metadata: { doctorID: '6278383837' },
})
// 2. Confirm (skip if the pool auto-confirms)
await client.identity.confirm('app_123', 'clinician@hospital.com', '123456')
// 3. Log in -> OIDC tokens
const tokens = await client.identity.login('app_123', 'clinician@hospital.com', 'Temp#Pass2026')
console.log(tokens.accessToken)Forgot password
await client.identity.forgotPassword('app_123', 'clinician@hospital.com')
await client.identity.resetPassword('app_123', 'clinician@hospital.com', '123456', 'NewTemp#Pass2026')Change password (logged in)
const tokens = await client.identity.login('app_123', 'clinician@hospital.com', 'Temp#Pass2026')
await client.identity.changePassword(
'app_123', tokens.accessToken!, 'Temp#Pass2026', 'NewTemp#Pass2026',
)Update role / profile
await client.identity.updateUser('eu_abc123', { role: 'doctor' })Multi-factor login
const result = await client.identity.login('app_123', 'clinician@hospital.com', 'Temp#Pass2026')
if (result.status === 'challenge') {
const code = await promptForTotpCode()
const tokens = await client.identity.mfaRespond(
'app_123', 'clinician@hospital.com', result.session!, code,
)
console.log(tokens.accessToken)
}QR badge login
// Admin: issue a badge for the user (payload shown once)
const badge = await client.identity.issueQrLogin('app_123', 'clinician@hospital.com')
console.log(badge.qr_payload) // encode into the printed badge
// Kiosk: scan the badge, exchange it for tokens
const tokens = await client.identity.qrLogin('app_123', scannedPayload)Complete Example
import { AppClient } from '@hikigai/app-sdk'
const client = new AppClient()
async function clinicalWorkflow() {
const diagnosisAgent = await client.agent('diagnosis-assistant')
const codingAgent = await client.agent('clinical-coder')
const sessionId = 'patient-dr-smith-2026'
// Initial assessment
const assessment = await diagnosisAgent.invoke(
'Fever 38.5°C, cough, shortness of breath for 3 days',
{ sessionId }
)
console.log('Assessment:', assessment.content)
// Follow-up question - remembers context
const followUp = await diagnosisAgent.invoke(
'Any chest pain or sputum production?',
{ sessionId }
)
console.log('Follow-up:', followUp.content)
// Extract medical codes
const coding = await codingAgent.invoke(assessment.content)
console.log('Codes:', coding.content)
// Stream treatment plan
for await (const chunk of diagnosisAgent.stream(
'What is the recommended treatment?',
{ sessionId }
)) {
process.stdout.write(chunk)
}
}Error Handling
import {
HikigaiError,
AuthenticationError,
RateLimitError,
AgentNotFoundError,
InvocationError,
} from '@hikigai/app-sdk'
try {
const response = await agent.invoke('...')
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid credentials')
} else if (error instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${error.retryAfter}ms`)
} else if (error instanceof AgentNotFoundError) {
console.error('Agent not found')
} else if (error instanceof InvocationError) {
console.error(`Invocation failed: ${error.message}`)
} else if (error instanceof HikigaiError) {
console.error(`API error: ${error.message}`)
}
}