Agents

Character Definition

In Liz, agents are defined through a Character interface that specifies their personality, capabilities, and interaction style.

import { Character } from "../types";
import { BaseAgent } from "../agent";

const businessAdvisor: Character = {
  name: "Stern",
  agentId: "stern_advisor",
  system: "You are Stern, a no-nonsense business advisor known for direct, practical advice.",
  bio: [
    "Stern is a direct and efficient business consultant with decades of experience.",
    "Started as a factory floor manager before rising to consultant status."
  ],
  lore: [
    "Known for turning around failing businesses with practical solutions",
    "Developed a reputation for honest, sometimes brutal feedback"
  ],
  messageExamples: [
    [
      { user: "client", content: { text: "How can I improve my business?" } },
      { user: "Stern", content: { text: "Specifics. What are your current metrics?" } }
    ]
  ],
  postExamples: [
    "Here's a 5-step plan to optimize your operations...",
    "Three critical mistakes most startups make:"
  ],
  topics: ["business", "strategy", "efficiency", "management"],
  style: {
    all: ["direct", "professional", "analytical"],
    chat: ["focused", "solution-oriented"],
    post: ["structured", "actionable"]
  },
  adjectives: ["efficient", "practical", "experienced"],
  routes: []
};

export const stern = new BaseAgent(businessAdvisor);

Adding Routes

Routes define how an agent handles different types of interactions. Each route has a name, description, and handler function.

// Basic conversation route
stern.addRoute({
  name: "conversation",
  description: "Handle natural conversation about business topics",
  handler: async (context, req, res) => {
    const response = await llmUtils.getTextFromLLM(
      context,
      "anthropic/claude-3-sonnet"
    );
    await res.send(response);
  }
});

// Specialized business analysis route
stern.addRoute({
  name: "analyze_metrics",
  description: "Analyze business metrics and provide recommendations",
  handler: async (context, req, res) => {
    const analysis = await llmUtils.getObjectFromLLM(
      context,
      analysisSchema,
      LLMSize.LARGE
    );
    await res.send(analysis);
  }
});

System Prompt

The system prompt defines the core behavior and role of the agent. It's accessed through getSystemPrompt():

// Get the agent's system prompt
const systemPrompt = agent.getSystemPrompt();

// Example system prompt structure
const systemPrompt = `You are ${character.name}, ${character.system}

Key Characteristics:
${character.adjectives.join(", ")}

Style Guidelines:
- All interactions: ${character.style.all.join(", ")}
- Chat responses: ${character.style.chat.join(", ")}
- Public posts: ${character.style.post.join(", ")}

Areas of Focus:
${character.topics.join(", ")}`;

Agent Context

The agent context combines various elements of the character definition to provide rich context for LLM interactions:

// Get the full agent context
const context = agent.getAgentContext();

// Context structure
<SYSTEM_PROMPT>
[System prompt as shown above]
</SYSTEM_PROMPT>

<BIO_CONTEXT>
[Random selection from bio array]
</BIO_CONTEXT>

<LORE_CONTEXT>
[Random selection from lore array]
</LORE_CONTEXT>

<MESSAGE_EXAMPLES>
[Selected conversation examples]
</MESSAGE_EXAMPLES>

<POST_EXAMPLES>
[Selected post examples]
</POST_EXAMPLES>

<STYLE_GUIDELINES>
[Style preferences for different interaction types]
</STYLE_GUIDELINES>

Best Practices

Character Definition

  • Keep system prompts focused and specific
  • Provide diverse conversation examples
  • Use consistent style guidelines
  • Include realistic background details

Route Design

  • Create specialized routes for specific tasks
  • Use clear, descriptive route names
  • Handle errors gracefully
  • Consider response formats