Eloquent

Documentation

AI Agents

Build intelligent AI agents that can execute tools, integrate with chat, and stream responses using SSE.

Overview

Eloquent AI Agents provide:

  • Tool Execution: Call APIs, query databases, execute code
  • Chat Integration: Conversational interfaces with history
  • SSE Streaming: Real-time response streaming
  • Multi-turn Context: Maintain conversation state

Agent Definition

interface Agent {
  id: string;
  name: string;
  description: string;
  systemPrompt: string;
  model: "gpt-4" | "gpt-3.5-turbo" | "claude-3";
  tools: AgentTool[];
  settings: AgentSettings;
}

interface AgentTool {
  id: string;
  name: string;
  description: string;
  type: "api_call" | "entity_query" | "kg_search" | "code_exec";
  config: ToolConfig;
}

interface AgentSettings {
  temperature: number;
  maxTokens: number;
  streaming: boolean;
}

Creating an Agent

Agent Configuration

const supportAgent: Agent = {
  name: "Customer Support Agent",
  description: "Handles customer inquiries and support tickets",
  systemPrompt: `You are a helpful customer support agent.
    Use the available tools to look up customer information,
    check order status, and resolve issues.
    Be professional and empathetic.`,
  model: "gpt-4",
  tools: [
    {
      name: "lookup_customer",
      description: "Look up customer by email or ID",
      type: "entity_query",
      config: {
        entityName: "customer",
        queryFields: ["email", "id"],
      },
    },
    {
      name: "check_order_status",
      description: "Check the status of an order",
      type: "api_call",
      config: {
        endpoint: "/api/v1/orders/{orderId}",
        method: "GET",
      },
    },
    {
      name: "create_ticket",
      description: "Create a support ticket",
      type: "entity_query",
      config: {
        entityName: "ticket",
        operation: "create",
      },
    },
  ],
  settings: {
    temperature: 0.7,
    maxTokens: 1000,
    streaming: true,
  },
};

Chat Integration

Starting a Chat Session

import { useAgentChat } from "@/hooks/use-agent-chat";

function ChatInterface({ agentId }: { agentId: string }) {
  const {
    messages,
    sendMessage,
    isStreaming,
    toolCalls,
  } = useAgentChat(agentId);

  const handleSend = async (content: string) => {
    await sendMessage({ content });
  };

  return (
    <div className="chat-container">
      <MessageList messages={messages} />
      {toolCalls.length > 0 && (
        <ToolCallIndicator calls={toolCalls} />
      )}
      <ChatInput onSend={handleSend} disabled={isStreaming} />
    </div>
  );
}

Message Types

interface ChatMessage {
  id: string;
  role: "user" | "assistant" | "system" | "tool";
  content: string;
  toolCalls?: ToolCall[];
  toolResult?: ToolResult;
  createdAt: string;
}

interface ToolCall {
  id: string;
  name: string;
  arguments: Record<string, any>;
  status: "pending" | "executing" | "completed" | "failed";
}

interface ToolResult {
  toolCallId: string;
  result: any;
  error?: string;
}

SSE Streaming

Streaming Response

function useAgentStream(agentId: string) {
  const [chunks, setChunks] = useState<string[]>([]);

  const streamMessage = async (content: string) => {
    const eventSource = new EventSource(
      `/api/v1/agents/${agentId}/chat/stream?message=${encodeURIComponent(content)}`
    );

    eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);

      if (data.type === "token") {
        setChunks((prev) => [...prev, data.content]);
      }

      if (data.type === "tool_call") {
        // Handle tool call
      }

      if (data.type === "done") {
        eventSource.close();
      }
    };

    eventSource.onerror = () => {
      eventSource.close();
    };
  };

  return { chunks, streamMessage };
}

Tool Execution

Tool Types

TypeDescriptionConfig
api_callCall external APIendpoint, method, headers
entity_queryQuery/create entitiesentityName, operation
kg_searchSemantic search in KGgraphId, labels
code_execExecute code snippetsruntime, timeout

Backend Tool Handler

func (h *Handler) ExecuteTool(ctx context.Context, call ToolCall) (*ToolResult, error) {
    tool := h.tools[call.Name]

    switch tool.Type {
    case "api_call":
        return h.executeAPICall(ctx, tool.Config, call.Arguments)

    case "entity_query":
        return h.executeEntityQuery(ctx, tool.Config, call.Arguments)

    case "kg_search":
        return h.executeKGSearch(ctx, tool.Config, call.Arguments)

    default:
        return nil, fmt.Errorf("unknown tool type: %s", tool.Type)
    }
}

API Endpoints

MethodPathDescription
GET/api/v1/agentsList agents
POST/api/v1/agentsCreate agent
GET/api/v1/agents/{id}Get agent
PUT/api/v1/agents/{id}Update agent
POST/api/v1/agents/{id}/chatSend message
GET/api/v1/agents/{id}/chat/streamStream response (SSE)
GET/api/v1/chats/{chatId}/historyGet chat history

Best Practices

  1. Clear system prompts - Define agent personality and capabilities
  2. Descriptive tool names - Help the model choose the right tool
  3. Handle tool failures - Graceful error handling
  4. Use streaming - Better UX for long responses
  5. Limit context - Keep conversation history manageable

Next Steps