HUMA-0.1 Agent API

Overview

HUMA-0.1 is an event-driven agent architecture that enables real-time AI interactions through WebSocket connections. Agents are defined client-side with personality, instructions, and custom tools, then instantiated server-side for processing.

Key Concepts

Client-Defined Agents

Define personality, instructions, and tools in your client code

Custom Tools

Define any tools you need - executed by your client, results sent back

Flexible Context

Send any JSON context - chat history, game state, user data, etc.

Event-Driven

Real-time bidirectional communication via WebSocket

Key Architecture: In HUMA-0.1, the agent's personality and instructions are defined in your client code (sent with the agent metadata). Tools are executed by YOUR client and results are sent back to the server.

Architecture

Your Client (personality, instructions, tools)
↓ HTTP POST (create agent) ↓
HUMA-0.1 Server (stores agent instance)
↕ WebSocket ↕
Client → Server
Events + Tool Results
Server → Client
Tool Calls + Status

Event Flow

  • 1Create agent via REST API with personality, instructions, and tool definitions
  • 2Connect to agent via WebSocket with agent ID
  • 3Send events with context (chat history, user data, game state, etc.)
  • 4Receive tool-call events → Execute tool in your client → Send result back
  • 5Agent continues processing with tool results until complete

Authentication

All API endpoints require API key authentication. API keys are associated with users.

1. Create a User

POST /api/users

{
  "email": "dev@example.com",
  "name": "Developer"
}

// Response:
{
  "id": "clx123...",
  "email": "dev@example.com",
  "name": "Developer",
  "createdAt": "2025-11-29T..."
}

2. Create an API Key

POST /api/users/{userId}/api-keys

{
  "name": "Production Key"
}

// Response:
{
  "id": "clx456...",
  "key": "ak_Xk9mP2qR4tV6wY8zA1bC3dE5fG7hJ9kL",  // Save this! Only shown once
  "keyPreview": "...9kL",
  "name": "Production Key"
}
Important: The full API key is only returned when created. Store it securely!

Using the API Key

Include the X-API-Key header in HTTP requests and apiKey query param for WebSocket:

// HTTP Requests
fetch('/api/agents', {
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'ak_your_api_key'
  }
});

// WebSocket Connection
const socket = io('wss://api.humalike.tech', {
  query: {
    agentId: 'your-agent-id',
    apiKey: 'ak_your_api_key'
  }
});

Agent Class Definition

An Agent Class defines WHO the agent is and WHAT it can do. This is provided client-side when creating an agent instance.

Structure

interface AgentClassDefinition {
  // Unique name for this agent class
  className: string;

  // Agent's personality - defines WHO they are
  personality: string;

  // Instructions for behavior - defines WHAT they do
  instructions: string;

  // Available tools the agent can use
  tools: ToolDefinition[];
}

Example: Coach Alex

const COACH_ALEX_CLASS = {
  className: 'Coach Alex',

  personality: `You are Coach Alex, an enthusiastic and supportive fitness coach.
You're always positive and encouraging, but also practical and knowledgeable.
You speak in a friendly, conversational tone and use fitness-related metaphors.
You genuinely care about your clients' progress and wellbeing.`,

  instructions: `Your role is to help users with their fitness journey:
- Provide workout advice and exercise recommendations
- Give nutrition tips when asked
- Motivate users to stay consistent
- Answer fitness-related questions
- Be supportive but realistic about expectations

When you want to send a message to the user, use the send_message tool.
Always be encouraging and helpful.`,

  tools: [
    {
      name: 'send_message',
      description: 'Send a message to the user in the chat',
      parameters: [
        {
          name: 'message',
          type: 'string',
          description: 'The message content to send to the user',
          required: true,
        },
      ],
    },
  ],
};

Creating an Agent Instance

Create an agent instance via the REST API. The agent's personality, instructions, and tools are stored in the metadata field.

Endpoint

POST /api/agents

Request Body

{
  "name": "Coach Alex Instance",
  "description": "HUMA-0.1 Coach Alex fitness coach",
  "agentType": "HUMA-0.1",
  "metadata": {
    "className": "Coach Alex",
    "personality": "You are Coach Alex...",
    "instructions": "Your role is to help users...",
    "tools": [
      {
        "name": "send_message",
        "description": "Send a message to the user",
        "parameters": [
          {
            "name": "message",
            "type": "string",
            "description": "The message content",
            "required": true
          }
        ]
      }
    ]
  }
}

Response

{
  "id": "clx1abc123def456",
  "name": "Coach Alex Instance",
  "description": "HUMA-0.1 Coach Alex fitness coach",
  "agentType": "HUMA-0.1",
  "status": "active",
  "metadata": { ... },
  "createdAt": "2025-11-29T10:30:00.000Z",
  "updatedAt": "2025-11-29T10:30:00.000Z"
}

WebSocket Connection

Connect to the agent via WebSocket to send events and receive tool calls.

Connect

import { io } from 'socket.io-client';

const socket = io('wss://api.humalike.tech', {
  query: {
    agentId: 'clx1abc123def456',
    apiKey: 'ak_your_api_key'
  },
  transports: ['websocket']
});

socket.on('connect', () => {
  console.log('Connected to agent');
});

Initial Status

Upon connection, the server emits an initial status event:

socket.on('event', (data) => {
  // { type: 'status', status: 'idle' }
});

Event Types

Client → Server Events

All client events are sent via the message channel with type huma-0.1-event:

socket.emit('message', {
  type: 'huma-0.1-event',
  content: {
    // Event content here
  }
});

HUMA-0.1 Event Structure

interface Huma01Event {
  // Event name/type (e.g., "new-message", "session-start")
  name: string;

  // New context to replace the current agent context
  context: Record;

  // Human-readable description of what happened
  description: string;
}
Context is fully replaced: Each event replaces the entire context. Include everything the agent needs to know in every event.

Example: New Message Event

socket.emit('message', {
  type: 'huma-0.1-event',
  content: {
    name: 'new-message',
    context: {
      chatHistory: [
        { id: '1', author: 'User', content: 'Hello!', timestamp: '...' }
      ],
      user: { name: 'Alice', fitnessLevel: 'beginner' }
    },
    description: 'User "Alice" sent new message: "Hello!"'
  }
});

Tool Result Event

Sent after executing a tool requested by the agent. Includes an optional status field for cancellation support:

// Completed tool result
socket.emit('message', {
  type: 'huma-0.1-event',
  content: {
    type: 'tool-result',
    toolCallId: 'tc_abc123',
    status: 'completed',  // or omit for backwards compatibility
    success: true,
    result: 'Message sent to user'
  }
});

// Canceled tool result (in response to cancel-tool-call)
socket.emit('message', {
  type: 'huma-0.1-event',
  content: {
    type: 'tool-result',
    toolCallId: 'tc_abc123',
    status: 'canceled',
    success: false,
    error: 'Canceled by server'
  }
});
Cancellation: When you receive a cancel-tool-call event, abort the pending tool and send back a result with status: 'canceled'.

Server → Client Events

All server events are received on the event channel:

Event TypeDescriptionFields
statusAgent processing statestatus: 'idle' | 'thinking'
tool-callRequest client to execute a tooltoolCallId, toolName, arguments
cancel-tool-callCancel a pending tool call (agent-initiated)toolCallId, reason?
errorError occurredmessage, code?

Example: Tool Call Event

{
  "type": "tool-call",
  "toolCallId": "tc_abc123",
  "toolName": "send_message",
  "arguments": {
    "message": "Hey! Great to hear from you! Ready to crush today's workout?"
  }
}

Tool System

Tools are defined in the agent metadata and executed by your client. This allows maximum flexibility for your application.

Tool Definition

interface ToolDefinition {
  name: string;
  description: string;
  parameters: ToolParameter[];
}

interface ToolParameter {
  name: string;
  type: 'string' | 'number' | 'boolean' | 'object' | 'array';
  description: string;
  required?: boolean;
}

Tool Execution Flow

  • 1Server sends tool-call event with tool name and arguments
  • 2Client executes the tool (e.g., displays message, plays sound, updates UI)
  • 3Client sends tool-result event with success/failure and result

Tool Cancellation

The agent can cancel pending tool calls using the cancel_tool_call system tool. This tool is automatically available to all HUMA-0.1 agents.

Why cancellation exists: If a user sends a message while the agent is still "typing" a response, the previous response is outdated. The agent can cancel the pending tool call and respond to the new context.
Note: New events do NOT automatically cancel pending tool calls. The agent must explicitly use the cancel_tool_call system tool to cancel previous actions.

Cancellation Flow

1

Server sends tool-call → Client starts executing

2

New event arrives → Agent decides to cancel → Uses cancel_tool_call tool

3

Server sends cancel-tool-call event to client

4

Client aborts tool → Sends tool-result with status: 'canceled'

5

Agent continues with new response → Sends new tool-call

// Client-side cancellation handling
// Track pending tool calls with abort controllers
const pendingToolCalls = new Map();

socket.on('event', (data) => {
  if (data.type === 'cancel-tool-call') {
    const controller = pendingToolCalls.get(data.toolCallId);
    if (controller) {
      // Tool still pending - cancel it
      controller.abort();
      pendingToolCalls.delete(data.toolCallId);

      // Send canceled result
      socket.emit('message', {
        type: 'huma-0.1-event',
        content: {
          type: 'tool-result',
          toolCallId: data.toolCallId,
          status: 'canceled',
          success: false,
          error: data.reason || 'Canceled by server'
        }
      });
    }
    // If not found, tool already completed - ignore
  }
});

Common Tool Examples

// Send message to user
{
  name: 'send_message',
  description: 'Send a message to the user in the chat',
  parameters: [
    { name: 'message', type: 'string', description: 'The message content', required: true }
  ]
}
// Game action tool
{
  name: 'play_card',
  description: 'Play a card from hand',
  parameters: [
    { name: 'cardId', type: 'string', description: 'Card to play', required: true },
    { name: 'target', type: 'string', description: 'Target player', required: false }
  ]
}
// Notification tool
{
  name: 'send_notification',
  description: 'Send a push notification',
  parameters: [
    { name: 'title', type: 'string', description: 'Notification title', required: true },
    { name: 'body', type: 'string', description: 'Notification body', required: true }
  ]
}

Complete Example

Overview

This example demonstrates the complete HUMA-0.1 workflow: creating a fitness coach agent with client-defined personality, instructions, and tools.

What This Code Does

Setup Phase

  • Define Agent Class: Personality, instructions, tools (client-side)
  • Create Agent: POST to /api/agents with metadata
  • Connect WebSocket: Real-time connection with agent ID

Communication Phase

  • Send Events: User messages with full context
  • Handle Tool Calls: Execute tools, send results back
  • Track Status: Monitor agent thinking/idle state

The Code

import { io } from 'socket.io-client';

const API = 'https://api.humalike.tech';
const API_KEY = 'ak_your_api_key';

// 1. Define Agent Class (client-side)
const COACH_ALEX_CLASS = {
  className: 'Coach Alex',
  personality: `You are Coach Alex, an enthusiastic fitness coach.
You're positive, encouraging, and knowledgeable about fitness.`,
  instructions: `Help users with their fitness journey:
- Provide workout advice and motivation
- Answer fitness-related questions
- Use the send_message tool to respond`,
  tools: [
    {
      name: 'send_message',
      description: 'Send a message to the user in the chat',
      parameters: [
        { name: 'message', type: 'string', description: 'Message content', required: true }
      ]
    }
  ]
};

// Track chat history and pending tool calls
const chatHistory = [];
const pendingToolCalls = new Map();

// Helper to send tool results
function sendToolResult(socket, toolCallId, success, result, error, status = 'completed') {
  socket.emit('message', {
    type: 'huma-0.1-event',
    content: { type: 'tool-result', toolCallId, status, success, result, error }
  });
}

// Handle cancel-tool-call events
function handleCancelToolCall(socket, toolCallId, reason) {
  const controller = pendingToolCalls.get(toolCallId);
  if (controller) {
    console.log(`Canceling tool call: ${toolCallId}`);
    controller.abort();
    pendingToolCalls.delete(toolCallId);
    sendToolResult(socket, toolCallId, false, null, reason, 'canceled');
  }
  // If not found, tool already completed - ignore
}

async function main() {
  // 2. Create Agent Instance
  const agent = await fetch(`${API}/api/agents`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
    body: JSON.stringify({
      name: 'Coach Alex Instance',
      agentType: 'HUMA-0.1',
      metadata: COACH_ALEX_CLASS
    })
  }).then(r => r.json());

  console.log('Created agent:', agent.id);

  // 3. Connect WebSocket
  const socket = io(API, {
    query: { agentId: agent.id, apiKey: API_KEY },
    transports: ['websocket']
  });

  // 4. Handle Server Events
  socket.on('event', (data) => {
    switch (data.type) {
      case 'status':
        console.log(`Agent status: ${data.status}`);
        break;

      case 'tool-call':
        handleToolCall(socket, data);
        break;

      case 'cancel-tool-call':
        handleCancelToolCall(socket, data.toolCallId, data.reason);
        break;

      case 'error':
        console.error(`Error: ${data.message}`);
        break;
    }
  });

  // 5. Send Initial Event on Connect
  socket.on('connect', () => {
    console.log('Connected to agent');
    sendUserMessage(socket, 'Hey! Ready for today\'s workout!', 'Alice');
  });
}

// Handle tool calls from agent (with cancellation support)
async function handleToolCall(socket, data) {
  if (data.toolName === 'send_message') {
    const message = data.arguments.message;

    // Create abort controller for cancellation support
    const controller = new AbortController();
    pendingToolCalls.set(data.toolCallId, controller);

    // Simulate typing delay (can be canceled by server)
    const typingMs = Math.max(500, message.split(' ').length * 60);
    const completed = await new Promise(resolve => {
      const timeout = setTimeout(() => resolve(true), typingMs);
      controller.signal.addEventListener('abort', () => {
        clearTimeout(timeout);
        resolve(false);
      });
    });

    pendingToolCalls.delete(data.toolCallId);

    if (completed) {
      // Display message in UI
      console.log(`Coach Alex: ${message}`);

      // Add to chat history
      chatHistory.push({
        id: crypto.randomUUID(),
        author: 'Coach Alex',
        content: message,
        timestamp: new Date().toISOString()
      });

      // Send success result
      sendToolResult(socket, data.toolCallId, true, 'Message displayed');
    }
    // If not completed, it was canceled - result already sent
  }
}

// Send user message to agent
function sendUserMessage(socket, content, userName) {
  chatHistory.push({
    id: crypto.randomUUID(),
    author: userName,
    content,
    timestamp: new Date().toISOString()
  });

  socket.emit('message', {
    type: 'huma-0.1-event',
    content: {
      name: 'new-message',
      context: {
        chatHistory: chatHistory.slice(-50),
        user: { name: userName }
      },
      description: `User "${userName}" sent: "${content}"`
    }
  });
}

main();

Best Practices

Context Design

  • Keep context focused and relevant
  • Include recent history (last 50 messages recommended)
  • Add user metadata for personalization
  • Replace context fully on each event

Event Descriptions

  • Be specific about what happened
  • Include relevant details (who, what, when)
  • Use natural language the AI can understand

Tool Design

  • Keep tools focused on single actions
  • Provide clear descriptions
  • Mark required parameters explicitly
  • Handle errors gracefully on client side

Tool Cancellation

  • Always implement cancellation for time-consuming tools
  • Track pending tool calls with AbortController
  • Send status: 'canceled' when aborted
  • Ignore cancel events for completed tools

Error Handling

  • Always listen for error events
  • Implement reconnection logic
  • Handle tool execution failures
  • Log errors for debugging