HUMA-0.1 Agent API

Event-driven agent architecture with client-defined tools and flexible context.

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 Difference from HUMA-1: In HUMA-0.1, the agent's personality and instructions are defined in your client code (sent with the agent metadata), not stored server-side. 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:

socket.emit('message', {
  type: 'huma-0.1-event',
  content: {
    type: 'tool-result',
    toolCallId: 'tc_abc123',
    success: true,
    result: 'Message sent to user'
  }
});

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
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

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
const chatHistory = [];

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 '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
function handleToolCall(socket, data) {
  if (data.toolName === 'send_message') {
    const message = data.arguments.message;

    // 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 back to server
    socket.emit('message', {
      type: 'huma-0.1-event',
      content: {
        type: 'tool-result',
        toolCallId: data.toolCallId,
        success: true,
        result: 'Message displayed'
      }
    });
  }
}

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

  // Send event to agent with full context
  socket.emit('message', {
    type: 'huma-0.1-event',
    content: {
      name: 'new-message',
      context: {
        chatHistory: chatHistory.slice(-50), // Last 50 messages
        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

Error Handling

  • Always listen for error events
  • Implement reconnection logic
  • Handle tool execution failures
  • Log errors for debugging
Humalike | Infra for Humanlike Agents