Event Protocol
Complete specification for the application-level event contract between HUMA clients and the HUMA server.
Overview
HUMA uses a bidirectional event protocol over WebSocket. Clients send events to inform the agent about state changes and tool results. The server sends events when the agent wants to take action or communicate.
Client Events (3 types)
context-update— push new statetool-result— return tool outputaddon-tool-event— in-flight addon data
Server Events (4 types)
tool-call— request tool executioncancel-tool-call— abort pending toolmessaging— typing & message deliveryerror— validation or server error
Transport
All communication uses Socket.IO over WebSocket.
Sending to Server
socket.emit('message', ) Receiving from Server
socket.on('event', handler) // tool-call, messaging
socket.on('error', handler) // error eventsClient Events
Every client event is a JSON object sent via socket.emit('message', event). There are exactly three event types.
type field set to one of: context-update, tool-result, addon-tool-event. Any Record field is recursively checked for dangerous keys (__proto__, constructor, prototype).context-update
Pushes new context to the HUMA agent. This is the primary way to inform the agent about what is happening in the client application.
socket.emit('message', {
type: 'context-update',
triggering: true,
name: 'new-message',
context: {
group: { id: 'group-123', name: 'Movie Night' },
members: [
{ name: 'Alice', id: 'user-1' },
{ name: 'Bob', id: 'user-2' }
],
conversationHistory: '[14:30] Alice: What movie should we watch?'
},
description: 'Alice sent a message: "What movie should we watch?"'
})| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Always "context-update" |
| triggering | boolean | Yes | Whether this event should trigger the agent to respond |
| name | string | Yes | Event name identifying what happened (1–128 chars) |
| context | object | Yes | Arbitrary key-value data representing current state |
| description | string | Yes | Human-readable description of what triggered this event |
The triggering Field
triggering: trueThe agent SHOULD respond. Use for new input that warrants a reaction (e.g., user sent a message). Also activates emotion and reflection processes.
triggering: falseInformational only. Context is received but no response generated. Use for background state sync, initial hydration, or events where the agent hasn't spoken yet.
Examples
User message (agent should respond):
{
type: 'context-update',
triggering: true,
name: 'new-message',
context: {
group: { id: 'group-123', name: 'Movie Night' },
conversationHistory: '[14:30] Alice: What movie?\n[14:31] Bob: Something fun'
},
description: 'Bob sent a message: "Something fun"'
}Initial context hydration (no response needed):
{
type: 'context-update',
triggering: false,
name: 'new-message',
context: {
group: { id: 'group-123', name: 'Movie Night' },
conversationHistory: '[14:30] Alice: What movie should we watch?'
},
description: 'You joined the group'
}tool-result
Returns the result of a tool call that the agent previously requested via a tool-call server event.
socket.emit('message', {
type: 'tool-result',
triggering: true,
toolCallId: '550e8400-e29b-41d4-a716-446655440000',
toolName: 'lookup_movie',
outcome: 'success',
result: { title: 'Inception', year: 2010, rating: 8.8 }
})| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Always "tool-result" |
| triggering | boolean | Yes | Whether to trigger further agent action |
| toolCallId | string | Yes | The toolCallId from the original tool-call event |
| toolName | string | Yes | The tool name from the original tool-call event |
| outcome | string | Yes | "success", "failure", or "canceled" |
| result | any | No | Return value on success. Must be JSON-serializable, max 65,536 chars. |
| error | string | No | Error message on failure |
The outcome Field
| Outcome | Meaning |
|---|---|
| success | Tool executed successfully. result may contain the return value. |
| failure | Tool failed. error should contain the error message. |
| canceled | Tool was canceled in response to a cancel-tool-call from the server. |
The triggering Field in Tool Results
triggering: trueThe agent should process this result and potentially continue its action. This is the typical value for successful tool calls.
triggering: falseResult is recorded but doesn't trigger further action. Use for canceled results or side-effect-only tools (e.g., update_preferences).
Examples
Success:
{
type: 'tool-result',
triggering: true,
toolCallId: '550e8400-e29b-41d4-a716-446655440000',
toolName: 'lookup_movie',
outcome: 'success',
result: '{"title":"Inception","year":2010,"rating":8.8}'
}Failure:
{
type: 'tool-result',
triggering: true,
toolCallId: '550e8400-e29b-41d4-a716-446655440000',
toolName: 'lookup_movie',
outcome: 'failure',
error: 'Movie not found: Nonexistent Movie'
}Canceled (response to cancel-tool-call):
{
type: 'tool-result',
triggering: false,
toolCallId: '550e8400-e29b-41d4-a716-446655440000',
toolName: 'lookup_movie',
outcome: 'canceled'
}Non-triggering (side-effect only):
{
type: 'tool-result',
triggering: false,
toolCallId: '660e8400-e29b-41d4-a716-446655440001',
toolName: 'update_preferences',
outcome: 'success',
result: 'Preferences updated for Alice'
}addon-tool-event
Sends data back to a server-side addon tool during its execution. This is not a final result — it is an in-flight data exchange. The most common use case is confirming message delivery from the messaging addon.
socket.emit('message', {
type: 'addon-tool-event',
toolCallId: '770e8400-e29b-41d4-a716-446655440002',
data: {
messageIndex: 0,
success: true,
context: {
conversationHistory: '[14:30] Alice: What movie?\n[14:31] Agent: How about Inception?'
}
}
})| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Always "addon-tool-event" |
| toolCallId | string | Yes | The toolCallId from the addon's originating event |
| data | object | Yes | Payload for the addon (structure depends on the addon) |
Messaging Addon Confirmation
When confirming message delivery from the messaging addon, the data field contains:
| data Field | Type | Description |
|---|---|---|
| messageIndex | number | Zero-based index echoed from message_sent |
| success | boolean | Whether the message was delivered successfully |
| context | object? | Updated conversation context (on success), to keep agent state synchronized |
| error | string? | Error message (on failure) |
Success confirmation:
{
type: 'addon-tool-event',
toolCallId: '' ,
data: {
messageIndex: 0,
success: true,
context: {
conversationHistory: '...'
}
}
}Failure confirmation:
{
type: 'addon-tool-event',
toolCallId: '' ,
data: {
messageIndex: 0,
success: false,
error: 'Failed to send: rate limited'
}
}Server Events
All server events arrive on the "event" Socket.IO channel: socket.on('event', handler). Each event is a JSON object with a type field.
tool-call
The agent is requesting the client to execute a tool.
{
type: 'tool-call',
toolCallId: '550e8400-e29b-41d4-a716-446655440000',
toolName: 'lookup_movie',
arguments: {
title: 'Inception',
year: 2010
}
}| Field | Type | Description |
|---|---|---|
| type | string | Always "tool-call" |
| toolCallId | string | Unique identifier (UUID). Use this in the tool-result response. |
| toolName | string | Name of the tool to execute. Must match a registered tool. |
| arguments | object | Arguments for the tool, as determined by the agent. |
Client Responsibility
1. Look up the tool by toolName.
2. Execute the tool with the provided arguments.
3. Send back a tool-result event with the matching toolCallId and toolName.
If the tool is unknown, send a failed result:
{
type: 'tool-result',
triggering: true,
toolCallId: '' ,
toolName: '' ,
outcome: 'failure',
error: 'Unknown tool: '
}cancel-tool-call
The agent is requesting cancellation of a previously issued tool call. This happens when the agent is interrupted (e.g., a new triggering event arrives while a tool is still executing).
{
type: 'cancel-tool-call',
toolCallId: '550e8400-e29b-41d4-a716-446655440000',
toolName: 'lookup_movie',
reason: 'canceled by agent'
}| Field | Type | Description |
|---|---|---|
| type | string | Always "cancel-tool-call" |
| toolCallId | string | The toolCallId of the tool call to cancel |
| toolName | string | Name of the tool being canceled |
| reason | string? | Human-readable reason for cancellation |
Client Responsibility
Abort the in-flight tool execution if possible, then send a canceled result:
{
type: 'tool-result',
triggering: false,
toolCallId: '' ,
toolName: '' ,
outcome: 'canceled'
}messaging
Events from the messaging addon. This addon handles the agent's message-sending lifecycle with realistic typing delays.
| Field | Type | Description |
|---|---|---|
| type | string | Always "messaging" |
| event | string | "typing_start", "message_sent", or "typing_end" |
| toolCallId | string? | Tool call ID for the send_message invocation |
| message | string? | Message text (present on message_sent) |
| messageIndex | number? | Zero-based index in the burst (present on message_sent) |
| messageCount | number? | Total messages in the burst (present on message_sent) |
| reason | string? | Reason for typing_end (e.g., "canceled") |
| extra_args | object? | Additional parameters passed through from the agent |
Messaging Lifecycle
The full lifecycle for a burst of N messages:
Client Responsibilities
typing_start
Show a typing/composing indicator on the platform.
message_sent
Deliver the message to the platform, then send an addon-tool-event confirmation back to the server.
socket.emit('message', {
type: 'addon-tool-event',
toolCallId: data.toolCallId,
data: {
messageIndex: data.messageIndex,
success: true,
context: { conversationHistory: '...' }
}
})typing_end
Hide the typing indicator. reason: "canceled" means the messaging burst was aborted.
error
Server-side error. Arrives on the "error" Socket.IO channel: socket.on('error', handler).
{
type: 'error',
message: 'context-update requires boolean "triggering"',
code: 'INVALID_EVENT'
}| Field | Type | Description |
|---|---|---|
| type | string | Always "error" |
| message | string | Human-readable error description |
| code | string? | Error code (e.g., "INVALID_EVENT") |
Validation Limits
| Constraint | Value |
|---|---|
Maximum name length (context-update) | 128 characters |
Maximum result size (tool-result) | 65,536 characters (JSON-serialized) |
Allowed outcome values (tool-result) | "success", "failure", "canceled" |
Forbidden keys (recursive, in context and data fields) | __proto__, constructor, prototype |
| Messaging addon confirmation timeout | 30 seconds |