Architecture Decisions
Key architectural decisions in the Amigo API design and their rationale.
Key architectural decisions in the Amigo AI API design and their rationale.
ADR-001: NDJSON for Classic API Streaming
Status: Accepted
Context: Conversation creation and interaction endpoints stream multiple events back to the client. The HTTP streaming protocol had to be chosen from Server-Sent Events (SSE), WebSocket, and Newline-Delimited JSON (NDJSON).
Decision: Use NDJSON (newline-delimited JSON) for Classic API conversation streaming endpoints (create conversation and interact). The Platform API made a different choice: its conversation turns endpoints stream Server-Sent Events (SSE, text/event-stream) - see the note below.
Platform API uses SSE for turns. The Platform API conversation turns endpoints stream SSE, not NDJSON. POST /turns returns an SSE stream when the request sends Accept: text/event-stream (and the synchronous JSON response otherwise), while POST /turns/stream always returns text/event-stream. Each frame is a typed TurnStreamEvent. New Platform API integrations should prefer POST /turns/stream.
Rationale:
Parsing complexity
Parse each line as JSON
Event ID management, retry logic, type field parsing
Full duplex protocol, framing
Client support
Works with any HTTP client
Requires EventSource API or polyfill
Requires WebSocket API
Content types
Standard application/x-ndjson
text/event-stream
Binary frames
Proxy compatibility
Passes through standard HTTP proxies
Some proxies buffer SSE streams
Requires upgrade
Error handling
Standard HTTP status codes
Limited to stream reconnection
Close codes
Binary data
Base64 in JSON fields
Text only
Native binary support
Key advantages for this use case:
Simplicity. Each line is a self-contained JSON object. No event ID tracking or reconnection logic needed.
Language agnostic. Works with any language that can read lines from an HTTP response body.
Discriminated unions. Each event has a
typefield that maps directly to a typed discriminated union in both SDKs.Progressive parsing. Clients can process events as they arrive without buffering the entire response.
Consequences:
Clients must handle newline-delimited parsing (both SDKs provide this via async generators).
No built-in reconnection semantics (clients implement retry via the SDK retry middleware).
WebSocket is used separately for the real-time voice endpoint where bidirectional streaming is required.
ADR-002: JWT over Session Tokens
Status: Accepted
Context: The API needs an authentication mechanism that works across multiple services, supports token refresh, and can be verified without database lookups.
Decision: Use JWT (JSON Web Token) bearer tokens obtained via API key exchange.
Authentication flow:
Client exchanges API key + API key ID for a JWT via
POST /user/signin_with_api_key.JWT is sent as
Authorization: Bearer {token}on subsequent requests.SDKs proactively refresh tokens 5 minutes before expiry.
Rationale:
Stateless verification
Yes (signature check)
No (DB lookup)
No (DB lookup)
Cross-service
Yes (signature verification)
No (service-specific)
Yes
Expiration
Built-in exp claim
Manual tracking
Never expires
Revocation
Requires token blacklist
Delete from DB
Requires rotation
Payload
Standard claims (sub, exp)
Opaque identifier
Opaque identifier
Token size
Larger (~1KB)
Small (~32 bytes)
Small (~64 bytes)
Key advantages:
Stateless. API servers verify tokens without hitting a session store, which enables horizontal scaling.
Standard claims.
sub(user ID) andexp(expiration) are standard JWT fields that any JWT library can validate.Proactive refresh. The 5-minute refresh window in both SDKs keeps operation uninterrupted without 401 retry overhead.
Separation of concerns. Long-lived API keys never travel over the wire after initial exchange. Short-lived JWTs limit exposure if intercepted.
Consequences:
Tokens are larger than session IDs, which increases request overhead slightly.
SDKs must implement token refresh logic (both SDKs implement safe concurrent token refresh).
Token revocation requires additional infrastructure (not currently needed for API key-based auth).
ADR-003: service_hierarchical_state_machine Naming
Status: Accepted
Context: The platform documentation refers to "Context Graphs," the state-based architecture that structures agent reasoning and conversation flow. The API needs a field name for this entity.
Decision: Use service_hierarchical_state_machine as the API resource name.
Rationale:
The name was chosen to be technically precise about what the entity represents:
service. Scoped to a service (the deployment unit that combines agent, state machine, and tools).hierarchical. States can be nested hierarchically (parent states containing child states).state_machine. The fundamental computational model: a finite set of states with defined transitions.
Why not context_graph?
Disambiguation
"Graph" is overloaded and could be confused with knowledge graphs, graph databases, or dependency graphs. "State machine" is unambiguous in computer science.
Implementation fidelity
The implementation IS a hierarchical state machine. Exit conditions define transitions. States have types (Action, Annotation, Decision, Recall, Reflection, ToolCall).
API stability
Technical names are less likely to change than marketing names. The platform docs can rename "Context Graph" without breaking the API.
Self-documenting
A developer seeing service_hierarchical_state_machine in a payload immediately understands the data structure without needing to read documentation.
Consequences:
Verbose field name increases payload sizes slightly.
Developers must learn the mapping between platform terminology ("Context Graph") and API names.
The terminology mapping page bridges this gap. See Terminology Mapping.
See also: Terminology Mapping for the complete mapping between platform concepts and API names.
Last updated
Was this helpful?

