AppSDK
Application SDK
Lightweight SDK for invoking healthcare AI agents in your medical applications and EHR systems.HIPAA-ready, fast, and production-ready with streaming responses for clinical workflows and session support for patient consultations.
Installation
Using pip
pip install hikigai-appsdkQuick Start
from hikigai.appsdk import AppClient
# Initialize client (or set HIKIGAI_API_KEY / HIKIGAI_PROJECT_ID)
client = AppClient(
api_key="your-api-key",
project_id="your-project-id"
)
# Get an agent
agent = client.agent("medical-coder")
# Invoke the agent
response = agent.invoke("Patient presents with fever and cough...")
print(response.content)
# Stream responses
for chunk in agent.stream("Tell me about diabetes"):
print(chunk, end="", flush=True)
# Session-based conversations
session_agent = agent.with_session("user-123")
session_agent.invoke("What is hypertension?")
session_agent.invoke("How is it treated?") # Remembers context
# Live WebSocket session
import asyncio
async def live():
async with agent.live_session() as session:
await session.connect()
await session.send_text("Hello")
async for event in session:
print(event)
asyncio.run(live())Client Reference
class AppClient
AppClientCoreMain client for invoking AI agents. Manages authentication, HTTP connections, and provides access to deployed agents.
Constructor
client = AppClient(
api_key: Optional[str] = None, # API key (or HIKIGAI_API_KEY env var)
project_id: Optional[str] = None, # Project ID (or HIKIGAI_PROJECT_ID env var)
base_url: Optional[str] = None, # API endpoint (defaults to production)
timeout: float = 30.0, # Request timeout in seconds
sona_url: Optional[str] = None, # Optional SONA service URL
sona_api_key: Optional[str] = None, # Optional SONA API key
)Methods
| Method | Returns | Description |
|---|---|---|
agent(agent_id: str) | RuntimeAgent | Get agent by ID or slug for invocation |
list_agents(category=None, tags=None, search=None) | List[RuntimeAgent] | List available agents with optional filters |
invoke(agent_id, input, session_id=None, provider=None, model=None, connectors=None, plugin_context=None) | InvokeResponse | Invoke an agent without fetching RuntimeAgent first |
live(agent_id, session_id=None, user_id='sdk-user', context=None) | StreamSession | Open a live WebSocket session for an agent |
create_session(external_user_ref=None, ttl_seconds=None, app_id='_', metadata=None) | SessionContext | Create a server-side session context store |
session(session_id, app_id='_') | SessionContext | Attach to an existing session context |
list_sessions(user_ref=None, limit=50, cursor=None) | Dict | List session contexts |
get_auth_token() | Dict[str, Any] | Exchange API key for a short-lived access token |
Properties
identity() | IdentityClient | End-user auth (Cognito, MFA, QR, SSO) |
sona() | SONAClient | SONA personalization (edits, preferences, suggestions) |
storage() | StorageClient | App object storage |
Context Manager
with AppClient() as client:
agent = client.agent("my-agent")
response = agent.invoke("Hello")
# Resources automatically releasedAgent Reference
class RuntimeAgent
RuntimeAgentModelRepresents a deployed agent ready for invocation. Provides methods for synchronous invocation, streaming, and session management.
Properties
| Property | Type | Description |
|---|---|---|
id | str | Unique agent ID |
name | str | Agent name |
slug | str | URL-friendly slug |
version | str | Agent version |
description | str | None | Agent description |
status | str | Deployment status ('active', 'pending', etc.) |
endpoint | str | None | Invocation endpoint URL |
Methods
| Method | Returns | Description |
|---|---|---|
invoke(input, session_id=None, provider=None, model=None, timeout=None, connectors=None, plugin_context=None) | InvokeResponse | Invoke agent synchronously with optional session, MCP connectors, and plugins |
stream(input, session_id=None, provider=None, model=None, connectors=None) | Iterator[str] | Stream agent response chunks in real-time (SSE) |
with_session(session_id: str) | RuntimeAgent | Create agent instance with persistent session |
live_session(session_id=None) | StreamSession | Open a bidirectional WebSocket live session |
Basic Usage
agent = client.agent("medical-coder")
# Synchronous invocation
response = agent.invoke("Patient has diabetes...")
print(response.content)
# With MCP connectors + SONA plugin context
response = agent.invoke(
"Prepare patient chart",
connectors={"epic-ehr": {"headers": {"Authorization": "Bearer ..."}}},
plugin_context={"sona": {"user_id": "dr-smith-uuid"}},
)
# Streaming
for chunk in agent.stream("Explain hypertension"):
print(chunk, end="")
# With session
response = agent.invoke("My name is Alice", session_id="user-123")
response = agent.invoke("What's my name?", session_id="user-123") # Remembers "Alice"Response Types
class InvokeResponse
InvokeResponsePydantic ModelResponse from a synchronous agent invocation containing output content and metadata.
| Property | Type | Description |
|---|---|---|
content* | str | Agent output content |
agent_id | str | ID of the agent that responded |
agent_version | str | None | Version of the agent |
session_id | str | None | Session ID if used |
status | str | Status (success, requires_human_review, etc.) |
output | Dict | None | Structured agent output when available |
confidence | ClinicalConfidence | None | Clinical confidence score (0–1) |
safety_flags | List[SafetyFlag] | Safety flags (severity: low|medium|high|critical) |
citations | List[ClinicalCitation] | Evidence-based clinical citations |
metadata | InvocationMetadata | Invocation metadata (latency, tokens, etc.) |
message | str | None | Optional warning or info message |
plugins | Dict | None | Plugin metadata (e.g. plugins['sona']) |
Example
response = agent.invoke("Hello")
print(response.content) # "Hi! How can I help you?"
print(response.status) # "success"
print(response.metadata.latency_ms) # 234
print(response.metadata.tokens_used) # 156
print(response.metadata.tools_called) # ["web_search"]
print(response.plugins) # {"sona": {"output_id": "..."}}class InvocationMetadata
InvocationMetadataPydantic ModelMetadata about an agent invocation including performance metrics and execution details.
invocation_id | str | Unique invocation ID |
latency_ms | int | None | Response latency in milliseconds |
timestamp | datetime | Invocation timestamp |
status | str | Status ('success', 'error', etc.) |
tokens_used | int | None | Total tokens consumed |
tools_called | List[str] | List of tools used by agent |
phi_redacted | bool | Whether PHI was redacted |
trace_id | str | None | Trace ID for troubleshooting |
Live WebSocket Sessions
Bidirectional realtime sessions via StreamSession. Requires the optional websockets dependency.
import asyncio
from hikigai.appsdk import AppClient
async def main():
client = AppClient(api_key="...", project_id="...")
agent = client.agent("live-scribe")
async with agent.live_session() as session:
await session.connect()
await session.start(modality="text") # or "audio"
await session.send_text("Patient presents with fever")
# await session.send_audio(pcm_bytes, mime_type="audio/pcm;rate=16000")
async for event in session:
print(event)
if event.get("type") == "turn_complete":
break
await session.end()
await session.close()
asyncio.run(main())Session Context Store
Server-side key/value context for apps (SessionContext), separate from conversation session_id memory on invoke.
# Create a context store
ctx = client.create_session(external_user_ref="dr-smith", ttl_seconds=3600)
ctx.set("patient_id", "MRN-12345")
ctx.set("visit_id", "V-99", if_match=None)
print(ctx.get("patient_id"))
print(ctx.get_all())
print(ctx.metadata())
# Attach later
ctx = client.session(ctx.session_id)
ctx.update({"chief_complaint": "chest pain"})
ctx.touch(ttl_seconds=7200)
ctx.delete("visit_id")
ctx.clear()Session Management
Maintain conversation context across multiple invocations using sessions. Sessions enable multi-turn conversations where the agent remembers previous interactions.
Per-Invocation Sessions
Pass a session_id to each invocation to maintain context.
agent = client.agent("chatbot")
# First message
response1 = agent.invoke(
"My name is Alice",
session_id="user-123"
)
# Follow-up - agent remembers the name
response2 = agent.invoke(
"What's my name?",
session_id="user-123"
)
print(response2.content) # "Your name is Alice"Persistent Session Agent
Create a session-bound agent using with_session(). All invocations automatically use the same session.
agent = client.agent("assistant")
# Create session-bound agent
session_agent = agent.with_session("user-456")
# All invocations share the same session
session_agent.invoke("I live in New York")
session_agent.invoke("What's the weather like here?") # Knows "here" = NYC
# Streaming works too
for chunk in session_agent.stream("Tell me more about my city"):
print(chunk, end="")Multiple Users
Maintain separate contexts for different users with different session IDs.
agent = client.agent("support-bot")
# User 1's conversation
user1 = agent.with_session("user-001")
user1.invoke("I'm having trouble logging in")
# User 2's isolated conversation
user2 = agent.with_session("user-002")
user2.invoke("How do I reset my password?")
# Contexts are completely separate
# User 1's issues don't affect User 2's conversationRooms
Multi-party realtime rooms via RoomSession(presence, publish, sequence tracking).
import asyncio
from hikigai.appsdk import RoomSession
async def main():
room = RoomSession(
base_url="https://api.hikigai.com",
api_key="your-api-key",
project_id="your-project-id",
)
async with room:
await room.join("care-team-7")
await room.publish("care-team-7", "note", {"text": "Labs ready"})
await room.who("care-team-7")
async for frame in room:
print(frame)
asyncio.run(main())Multi-Cloud Deployment
client.cloud exposes the deployment catalog and BYOC credentials. Apps, agents, and MCP servers deploy to GCP or AWS targets from the same catalog.
from hikigai.appsdk import AppClient
client = AppClient(api_key=..., project_id=...)
catalog = client.cloud.catalog(workload="app")
for service in catalog.services:
print(service.id, service.display_name, service.regions[0].id)
result = client.cloud.validate_target(
workload="app",
service_id="gcp-cloud-run",
region="europe-west1",
config={"cpu": "2", "memory": "1Gi"},
)Events & Webhooks
client.events is the SDK surface for the platform event bus — HMAC-signed webhooks (at-least-once) andevents.stream() (at-most-once).
sub = client.events.create_webhook(
url="https://ci.example.com/hooks/hikigai",
event_types=["agent.deployed", "agent.deleted"],
description="deploy notifications",
)
print(sub.secret) # shown once — store it
# Live stream
async with client.events.stream(patterns=["job.*", "agent.deployed"]) as stream:
async for event in stream:
print(event.type, event.data)Storage
uploaded = client.storage.upload(
app_id="app_123",
file=open("audio.wav", "rb"),
filename="audio.wav",
content_type="audio/wav",
)
url = client.storage.signed_url("app_123", uploaded.object_id, ttl=3600)
client.storage.list("app_123")
client.storage.delete("app_123", uploaded.object_id)SONA Personalization
Access via client.sona. Invoke with plugin_context={"sona": {"user_id": "..."}}to receive SONA metadata on response.plugins.
response = agent.invoke(
"Draft discharge summary",
plugin_context={"sona": {"user_id": "dr-smith-uuid"}},
)
output_id = response.plugins["sona"]["output_id"]
client.sona.submit_edit(output_id, "User-edited note text...")
client.sona.approve_output(output_id, user_id="dr-smith-uuid")
prefs = client.sona.get_preferences("dr-smith-uuid", agent_id=agent.id)
suggestions = client.sona.get_suggestions("dr-smith-uuid")End-User Identity
Add signup, login, MFA, QR badge login, and SSO for your app's end users — clinicians, patients, staff. Each app is backed by a dedicated AWS Cognito user pool the platform provisions for you; login returns standard OIDC tokens. Everything is reached through client.identity.
class IdentityClient
client.identityCoreEnd-user authentication and account management for the app's Cognito pool, plus QR/PIN badge credentials. Access it as a property on AppClient.
Account & auth methods
| Method | Returns | Description |
|---|---|---|
signup(app_id, email, password, first_name=None, last_name=None, role=None, attributes=None, metadata=None) | dict | Register a new end user. attributes = Cognito fields (e.g. phone_number); metadata = opaque app JSON on EndUser. |
confirm(app_id, email, code) | dict | Confirm a signup with the emailed code |
login(app_id, email, password) | dict | Authenticate — returns OIDC tokens or an MFA challenge |
refresh(app_id, refresh_token) | dict | Exchange a refresh token for fresh tokens |
logout(app_id, email) | dict | Globally sign the user out |
forgot_password(app_id, email) | dict | Request a password-reset code (emailed by Cognito) |
reset_password(app_id, email, code, new_password) | dict | Set a new password with the emailed code |
change_password(app_id, access_token, current_password, new_password) | dict | Change password for a logged-in user |
update_user(user_id, **fields) | dict | Update end-user profile (role, name, metadata, is_active). Email cannot be changed. |
list_app_users(app_id, limit=50, offset=0) | list[dict] | List the app's end users |
delete_app_user(app_id, email) | None | Delete a user from the pool |
MFA, QR & SSO
| Method | Returns | Description |
|---|---|---|
mfa_associate(app_id, access_token) | dict | Begin TOTP enrollment — returns secret for a QR code |
mfa_verify(app_id, access_token, code, device_name=None) | dict | Verify the first code to finish enrollment |
mfa_set_preference(app_id, access_token, enabled=True) | dict | Turn TOTP MFA on or off |
mfa_respond(app_id, email, session, code) | dict | Complete a login that returned an MFA challenge |
issue_qr_login(app_id, email) | dict | Issue a QR badge credential for a user |
qr_login(app_id, qr_payload) | dict | Exchange a scanned QR payload for tokens |
configure_sso(app_id, provider_name, provider_type, …) | dict | Add a Google/Okta/SAML/OIDC provider |
sso_authorize_url(app_id, redirect_uri, provider=None) | dict | Build the hosted-UI authorize URL |
sso_exchange(app_id, code, redirect_uri) | dict | Exchange the callback code for tokens |
Setup (one-time, per app)
enable_identity(app_id, mode='managed', enabled_methods=…) | dict | Provision the app's Cognito pool |
get_identity_config(app_id) | dict | Get config + provisioning status |
byo_setup() | dict | CloudFormation params for bring-your-own Cognito |
byo_test(role_arn, region=None) | dict | Verify a cross-account role before enabling BYO |
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.
from hikigai.appsdk import AppClient
client = AppClient(api_key="hikigai_...", project_id="proj_123")
# 1. Register the end user
client.identity.signup(
app_id="app_123",
email="clinician@hospital.com",
password="Temp#Pass2026",
first_name="Asha",
last_name="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)
client.identity.confirm("app_123", "clinician@hospital.com", code="123456")
# 3. Log in -> OIDC tokens
tokens = client.identity.login("app_123", "clinician@hospital.com", "Temp#Pass2026")
print(tokens["access_token"])
# 4. Refresh later
fresh = client.identity.refresh("app_123", tokens["refresh_token"])Forgot password
# 1. Request reset code (Cognito emails it)
client.identity.forgot_password("app_123", "clinician@hospital.com")
# 2. User enters code + new password
client.identity.reset_password(
"app_123", "clinician@hospital.com", code="123456", new_password="NewTemp#Pass2026"
)Change password (logged in)
tokens = client.identity.login("app_123", "clinician@hospital.com", "Temp#Pass2026")
client.identity.change_password(
"app_123",
access_token=tokens["access_token"],
current_password="Temp#Pass2026",
new_password="NewTemp#Pass2026",
)Update role / profile
# user_id from signup response or list_app_users()
client.identity.update_user("eu_abc123", role="doctor", first_name="Asha", last_name="Mehta")Multi-factor login
# Login may return an MFA challenge instead of tokens
result = client.identity.login("app_123", "clinician@hospital.com", "Temp#Pass2026")
if result.get("status") == "challenge":
code = input("Enter your authenticator code: ")
tokens = client.identity.mfa_respond(
app_id="app_123",
email="clinician@hospital.com",
session=result["session"],
code=code,
)
print(tokens["access_token"])QR badge login
# Admin: issue a badge for the user (payload shown once)
badge = client.identity.issue_qr_login("app_123", "clinician@hospital.com")
print(badge["qr_payload"]) # encode into the printed badge
# Kiosk: scan the badge, exchange it for tokens
tokens = client.identity.qr_login("app_123", scanned_payload)signup vs create_user
Use identity.signup() for real Cognito accounts (password, MFA, SSO). Use identity.create_user() only for the lightweight QR/PIN badge flow (no password), paired with verify_qr() / verify_pin().
Complete Examples
Basic Agent Invocation
from hikigai.appsdk import AppClient
client = AppClient()
# Get agent
agent = client.agent("customer-support")
# Invoke
response = agent.invoke("How do I reset my password?")
print(response.content)
print(f"Latency: {response.metadata.latency_ms}ms")Streaming Responses
agent = client.agent("content-writer")
# Stream in real-time
print("Agent response: ", end="")
for chunk in agent.stream("Write a paragraph about AI"):
print(chunk, end="", flush=True)
print() # New lineSession-Based Chat Application
import uuid
from hikigai.appsdk import AppClient
def chat_session(user_id: str):
"""Start a chat session for a user."""
client = AppClient()
agent = client.agent("chatbot")
# Create session-bound agent
session = agent.with_session(user_id)
print("Chat started. Type 'exit' to quit.")
while True:
user_input = input("You: ")
if user_input.lower() == "exit":
break
# Invoke with session context
response = session.invoke(user_input)
print(f"Bot: {response.content}")
# Start chat for a user
chat_session(f"user-{uuid.uuid4()}")Listing and Filtering Agents
client = AppClient()
# List all agents
agents = client.list_agents()
for agent in agents:
print(f"{agent.name} (v{agent.version}): {agent.status}")
# Filter by category
medical_agents = client.list_agents(category="Medical Coding")
# Search
search_results = client.list_agents(search="diagnosis")Error Handling
from hikigai.appsdk import (
AppClient,
AgentNotFoundError,
InvocationError,
RateLimitError
)
client = AppClient()
try:
agent = client.agent("my-agent")
response = agent.invoke("Hello")
print(response.content)
except AgentNotFoundError:
print("Agent not found. Check the agent ID.")
except InvocationError as e:
print(f"Invocation failed: {e}")
except RateLimitError:
print("Rate limit exceeded. Please wait.")
except Exception as e:
print(f"Unexpected error: {e}")Error Handling
AgentNotFoundError
Raised when the requested agent doesn't exist
from hikigai.appsdk import AgentNotFoundError
try:
agent = client.agent("nonexistent-agent")
except AgentNotFoundError as e:
print(f"Agent not found: {e}")InvocationError
Raised when agent invocation fails
from hikigai.appsdk import InvocationError
try:
response = agent.invoke("Complex query...")
except InvocationError as e:
print(f"Invocation failed: {e}")AuthenticationError
Raised when the API key is invalid or missing
from hikigai.appsdk import AuthenticationError, ConfigurationError
try:
client = AppClient(api_key="invalid-key", project_id="proj_123")
except (AuthenticationError, ConfigurationError) as e:
print(f"Auth/config failed: {e}")RateLimitError
Raised when API rate limit is exceeded
from hikigai.appsdk import RateLimitError
import time
try:
response = agent.invoke("Query")
except RateLimitError as e:
print(f"Rate limit hit. Retry after: {e.retry_after}s")
time.sleep(e.retry_after)
response = agent.invoke("Query") # Retry