Tool Handler Logic

Understanding the flexibility and capabilities of DAIN tool handlers

Tool Handler Overview

The handler function in a DAIN tool is where you implement your core business logic. It receives the parsed input parameters and authenticated agent information, allowing you to perform any operations needed to fulfill the tool's purpose.

import { DainResponse, CardUIBuilder } from "@dainprotocol/utils";

handler: async (inputs: InputType, agentInfo: AgentInfo) => {
  // Your custom logic here
  return new DainResponse({
    text: string,      // Message for the AI agent
    data: OutputType,  // Structured data matching output schema
    ui?: UIComponent   // Optional UI built with UIBuilders
  });
}

Authentication and Identity

Every tool handler receives an agentInfo parameter that provides authenticated identity information:

interface AgentInfo {
  id: string;  // Unique identifier linked to DAIN ID
  // ... other agent properties
}

The id is uniquely tied to either:

  • A human user's DAIN ID smart account (id.dain.org)
  • An AI agent's unique identifier

You can use this ID to:

  • Authenticate users against your own systems
  • Maintain user-specific state or preferences
  • Track usage and implement rate limiting
  • Link actions to specific DAIN identities

Handler Capabilities

Inside your handler, you can implement any logic your tool requires:

import { DainResponse, CardUIBuilder, AlertUIBuilder } from "@dainprotocol/utils";

handler: async ({ query }, agentInfo) => {
  try {
    // Database operations
    const userPreferences = await db.getUserPreferences(agentInfo.id);

    // External API calls
    const apiResponse = await axios.get('https://api.example.com/data');

    // Custom business logic
    const processedData = await processData(apiResponse.data);

    // Authentication with external services
    const userToken = await getUserAuthToken(agentInfo.id);

    // File operations
    const fileContent = await fs.readFile('template.json');

    // Machine learning models
    const prediction = await mlModel.predict(query);

    const cardUI = new CardUIBuilder()
      .title("Results")
      .content(`Processed data for user ${agentInfo.id}`)
      .build();

    return new DainResponse({
      text: `Processed request for user ${agentInfo.id}`,
      data: processedData,
      ui: cardUI
    });
  } catch (error) {
    console.error(`Error processing request for ${agentInfo.id}:`, error);

    const errorUI = new AlertUIBuilder()
      .variant("error")
      .title("Error")
      .message("Unable to complete request")
      .build();

    return new DainResponse({
      text: `Error occurred: ${error.message}. Consider suggesting an alternative approach.`,
      data: { error: error.message },
      ui: errorUI
    });
  }
}

Error Handling

import { DainResponse, AlertUIBuilder, CardUIBuilder } from "@dainprotocol/utils";

handler: async (inputs, agentInfo) => {
  try {
    const results = await processData(inputs);
    
    const successUI = new CardUIBuilder()
      .title("Success")
      .content("Operation completed successfully")
      .variant("default")
      .build();

    return new DainResponse({
      text: "Successfully processed the request",
      data: results,
      ui: successUI
    });

  } catch (error) {
    console.error(`Error processing request for ${agentInfo.id}:`, error);

    const errorUI = new AlertUIBuilder()
      .variant("error")
      .title("Operation Failed")
      .message(error.message)
      .icon(true)
      .build();

    return new DainResponse({
      text: `Error occurred: ${error.message}. Consider suggesting an alternative approach.`,
      data: { error: error.message },
      ui: errorUI
    });
  }
}

Example with Multiple UI Components

import { 
  DainResponse, 
  CardUIBuilder, 
  TableUIBuilder,
  ChartUIBuilder 
} from "@dainprotocol/utils";

handler: async (inputs, agentInfo) => {
  const data = await fetchAnalytics(agentInfo.id);

  const chartUI = new ChartUIBuilder()
    .type("line")
    .title("Usage Trends")
    .chartData(data.trends)
    .dataKeys({ x: "date", y: "value" })
    .build();

  const tableUI = new TableUIBuilder()
    .addColumns([
      { key: "metric", header: "Metric" },
      { key: "value", header: "Value" }
    ])
    .rows(data.metrics)
    .build();

  const cardUI = new CardUIBuilder()
    .title("Analytics Dashboard")
    .addChild(chartUI)
    .addChild(tableUI)
    .build();

  return new DainResponse({
    text: "Generated analytics dashboard",
    data: data,
    ui: cardUI
  });
}

Type Safety

interface AnalyticsData {
  trends: Array<{
    date: string;
    value: number;
  }>;
  metrics: Array<{
    metric: string;
    value: number;
  }>;
}

interface HandlerResponse {
  text: string;
  data: AnalyticsData;
  ui?: UIComponent;
}

handler: async (inputs, agentInfo): Promise<HandlerResponse> => {
  // Implementation
}