Repository: heboai/hebo-eval
Pull request #10: add agent interface and hebo implementation
Author: login: turisanapo
Created: 2025-04-07T11:05:02Z | Merged: 2025-04-09T07:11:04Z

# Implement Agent Interaction System

## Description
This PR implements a flexible and type-safe agent interaction system for Hebo Eval, enabling support for multiple agent types with a focus on the Hebo agent implementation.

## Changes
- Created abstract interfaces and base classes for agent interactions
- Implemented type-safe message handling with support for multiple messages
- Added Hebo agent implementation with conversation history management
- Integrated with Hebo's `/response` endpoint
- Added comprehensive error handling and type safety

## Key Features
- **Modular Design**: Abstract interfaces (`IAgent`, `BaseAgent`) for easy extension
- **Type Safety**: Comprehensive TypeScript types for all components
- **Message Management**: Support for multiple messages with different roles
- **Authentication**: API key-based authentication with configurable headers
- **Error Handling**: Robust error handling at all levels

## Implementation Details
- Created new `agents` directory structure:
  - `types/`: Core type definitions
  - `interfaces/`: Abstract interfaces and base classes
  - `implementations/`: Concrete agent implementations
- Implemented Hebo agent with:
  - Conversation history tracking
  - System message support
  - Message role conversion
  - API integration

## Testing
Added unit tests

## Related Issue
Closes #3

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced the `HeboAgent` class for enhanced interaction with the Hebo API, featuring robust error handling and message management.
  - Added a new interface `IAgent` to standardize agent implementations and interactions.
  - Launched a `RoleMapper` class for improved mapping between different role systems, enhancing message role handling.

- **Chores**
  - Updated dependency versioning for increased flexibility and improved future compatibility, ensuring a smoother upgrade path.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Linked issue #3: Hebo Eval: Develop an Abstract Agent Configuration Interface
#### Description
As a user, I want an abstract and flexible way to configure agent interactions within Hebo Eval, enabling me to adapt to various agents regardless of their implementation specifics.

#### Tasks
- Define an abstract interface that clearly specifies the methods required for agent interactions:
  - Handle authentication with the Agent
  - Sending inputs (e.g., messages and additional context).
  - Receiving and handling outputs (e.g., formatting responses).
- Ensure the abstract class provides sufficient documentation detailing the purpose and expected behavior of each method.
- Implement clear guidelines and examples to assist users in creating concrete implementations tailored to their specific agents.
- Support extensibility, allowing multiple agent configurations to coexist, facilitating comparative or varied testing scenarios.
- Implement the concrete agent configuration for Hebo agents.

#### Technical Implementation Details
- Abstract interface specification:
  - Define required methods clearly and precisely.
  - Provide method signatures for input handling, output retrieval, and error handling.
- Documentation should include examples of typical implementations to clarify the interface’s usage.
- The interface should not enforce specific technology or communication protocols, maintaining flexibility for various agent technologies.
- Provide an implementation for Hebo Agents

- **For Hebo agents specifically**, the implementation must:
  - Integrate with the new `/response` endpoint described in [hebo #52](https://github.com/heboai/hebo/issues/52)

#### Acceptance Criteria
- Users can easily implement the abstract interface according to their agents’ unique APIs or interaction protocols.
- Implementations of this abstract interface seamlessly integrate with Hebo Eval, facilitating straightforward execution of tests.
- A concrete, working implementation for Hebo agents is included and validated.
- Comprehensive documentation and examples available to aid users in implementing their configurations.

#### Definition of Done
- Abstract interface clearly defined, documented, and validated.
- Sample implementations provided for demonstration purposes.
- Interface integration with Hebo Eval fully tested and operational.
- Hebo-specific agent integration confirmed working through at least one end-to-end test case.



Diff:
diff --git a/package-lock.json b/package-lock.json
index 661087e..fd66960 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,7 +27,7 @@
         "jest": "^29.7.0",
         "prettier": "^3.5.3",
         "ts-jest": "^29.3.1",
-        "typescript": "^5.3.3"
+        "typescript": "^5"
       },
       "engines": {
         "node": ">=18.0.0"
@@ -4776,9 +4776,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.8.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
-      "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
+      "version": "5.8.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
diff --git a/package.json b/package.json
index c97c92f..6617e6c 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
     "jest": "^29.7.0",
     "prettier": "^3.5.3",
     "ts-jest": "^29.3.1",
-    "typescript": "^5.3.3"
+    "typescript": "^5"
   },
   "engines": {
     "node": ">=18.0.0"
diff --git a/src/agents/implementations/hebo-agent.ts b/src/agents/implementations/hebo-agent.ts
new file mode 100644
index 0000000..e32253e
--- /dev/null
+++ b/src/agents/implementations/hebo-agent.ts
@@ -0,0 +1,159 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
+}
+
+/**
+ * Implementation of the Hebo agent
+ */
+export class HeboAgent extends BaseAgent {
+  private baseUrl: string;
+  private store: boolean;
+  private previousResponseId?: string;
+  private messageHistory: OpenAIMessage[] = [];
+
+  constructor(config: HeboAgentConfig) {
+    super(config);
+    this.baseUrl = config.baseUrl || 'https://api.hebo.ai';
+    this.store = config.store ?? true;
+    this.messageHistory = [];
+  }
+
+  /**
+   * Validates the Hebo-specific configuration
+   */
+  public override validateConfig(): Promise<boolean> {
+    if (!this.config.model) {
+      throw new Error('Model is required for Hebo agent');
+    }
+    return super.validateConfig();
+  }
+
+  /**
+   * Processes the input and returns the agent's response
+   */
+  protected async processInput(input: AgentInput): Promise<AgentOutput> {
+    // Add new messages to history
+    this.messageHistory.push(...input.messages);
+
+    const request: ResponseRequest = {
+      model: this.config.model,
+      store: this.store,
+      previous_response_id: this.previousResponseId,
+      messages: this.messageHistory,
+    };
+
+    try {
+      const response = await this.makeRequest(request);
+      this.previousResponseId = response.id;
+
+      // Add assistant's response to history
+      if (response.choices.length > 0 && response.choices[0].message) {
+        const message = response.choices[0].message;
+        this.messageHistory.push({
+          role: roleMapper.toRole(message.role),
+          content: message.content || '',
+          toolUsages: message.toolUsages || [],
+          toolResponses: message.toolResponses || [],
+        });
+      }
+
+      if (response.error) {
+        return {
+          response: '',
+          error: {
+            message: response.error.message,
+            code: response.error.code,
+            details: response.error,
+          },
+        };
+      }
+
+      return {
+        response: response.choices[0].message.content || '',
+        metadata: {
+          id: response.id,
+          model: response.model,
+          usage: response.usage,
+        },
+      };
+    } catch (error) {
+      return {
+        response: '',
+        error: {
+          message:
+            error instanceof Error ? error.message : 'Unknown error occurred',
+          details: error,
+        },
+      };
+    }
+  }
+
+  /**
+   * Makes a request to the Hebo API
+   */
+  private async makeRequest(request: ResponseRequest): Promise<Response> {
+    const headers = {
+      ...this.getAuthHeaders(),
+      'Content-Type': 'application/json',
+    };
+
+    const response = await fetch(`${this.baseUrl}/response`, {
+      method: 'POST',
+      headers,
+      body: JSON.stringify(request),
+    });
+
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    }
+
+    return response.json() as Promise<Response>;
+  }
+
+  /**
+   * Gets the authentication headers for the Hebo API
+   * @returns Record containing the authentication headers
+   * @throws Error if authentication configuration is invalid
+   */
+  protected override getAuthHeaders(): Record<string, string> {
+    if (!this.authConfig) {
+      throw new Error('Authentication configuration not found');
+    }
+
+    const { apiKey } = this.authConfig;
+
+    return {
+      'X-API-Key': apiKey,
+    };
+  }
+
+  /**
+   * Cleans up the agent's resources and message history
+   */
+  public override async cleanup(): Promise<void> {
+    await super.cleanup();
+    this.messageHistory = [];
+  }
+}
diff --git a/src/agents/index.ts b/src/agents/index.ts
new file mode 100644
index 0000000..cbe3e9c
--- /dev/null
+++ b/src/agents/index.ts
@@ -0,0 +1,8 @@
+/**
+ * Agent-related types and interfaces for Hebo Eval
+ * @module agents
+ */
+
+export * from './types/agent.types';
+export * from './interfaces/agent.interface';
+export * from './interfaces/base-agent';
diff --git a/src/agents/interfaces/agent.interface.ts b/src/agents/interfaces/agent.interface.ts
new file mode 100644
index 0000000..f2bb66b
--- /dev/null
+++ b/src/agents/interfaces/agent.interface.ts
@@ -0,0 +1,54 @@
+import {
+  AgentConfig,
+  AgentInput,
+  AgentOutput,
+  AgentAuthConfig,
+} from '../types/agent.types';
+
+/**
+ * Abstract interface for agent interactions
+ *
+ * This interface defines the contract that all agent implementations must follow,
+ * providing a consistent way to interact with different types of agents.
+ */
+export interface IAgent {
+  /**
+   * Gets the configuration of the agent
+   * @returns The agent's configuration
+   */
+  getConfig(): AgentConfig;
+
+  /**
+   * Initializes the agent with the provided configuration
+   * @param config The agent configuration
+   * @returns Promise that resolves when initialization is complete
+   */
+  initialize(config: AgentConfig): Promise<void>;
+
+  /**
+   * Authenticates the agent with the provided credentials
+   * @param authConfig Authentication configuration
+   * @returns Promise that resolves when authentication is complete
+   */
+  authenticate(authConfig: AgentAuthConfig): Promise<void>;
+
+  /**
+   * Sends input to the agent and receives its response
+   * @param input The input to send to the agent
+   * @returns Promise that resolves with the agent's output
+   */
+  sendInput(input: AgentInput): Promise<AgentOutput>;
+
+  /**
+   * Validates the agent's configuration
+   * @returns Promise that resolves with true if the configuration is valid
+   * @throws Error if the configuration is invalid
+   */
+  validateConfig(): Promise<boolean>;
+
+  /**
+   * Cleans up any resources used by the agent
+   * @returns Promise that resolves when cleanup is complete
+   */
+  cleanup(): Promise<void>;
+}
diff --git a/src/agents/interfaces/base-agent.ts b/src/agents/interfaces/base-agent.ts
new file mode 100644
index 0000000..ac1e40a
--- /dev/null
+++ b/src/agents/interfaces/base-agent.ts
@@ -0,0 +1,152 @@
+import { IAgent } from './agent.interface';
+import {
+  AgentConfig,
+  AgentInput,
+  AgentOutput,
+  AgentAuthConfig,
+} from '../types/agent.types';
+
+/**
+ * Abstract base class for agent implementations
+ *
+ * This class provides a foundation for implementing the IAgent interface,
+ * including common functionality and error handling.
+ *
+ * @remarks
+ * Agents are designed to be initialized once during their lifecycle. Reinitialization
+ * is not supported as it could lead to inconsistent state. If you need to change
+ * the agent's configuration, create a new instance instead.
+ */
+export abstract class BaseAgent implements IAgent {
+  protected config: AgentConfig;
+  protected isInitialized: boolean = false;
+  protected isAuthenticated: boolean = false;
+  protected authConfig?: AgentAuthConfig;
+
+  constructor(config: AgentConfig) {
+    this.config = config;
+  }
+
+  /**
+   * Gets the current configuration of the agent
+   * @returns The agent's configuration
+   */
+  getConfig(): AgentConfig {
+    return this.config;
+  }
+
+  /**
+   * Initializes the agent with the provided configuration
+   * @param config The agent configuration
+   * @returns Promise that resolves when initialization is complete
+   * @throws Error if the agent is already initialized
+   */
+  async initialize(config: AgentConfig): Promise<void> {
+    if (this.isInitialized) {
+      throw new Error(
+        'Agent is already initialized. Create a new instance to use different configuration.',
+      );
+    }
+    this.config = config;
+    await this.validateConfig();
+    this.isInitialized = true;
+  }
+
+  /**
+   * Authenticates the agent with the provided API key
+   * @param authConfig Authentication configuration containing the API key
+   * @returns Promise that resolves when authentication is complete
+   */
+  async authenticate(authConfig: AgentAuthConfig): Promise<void> {
+    if (!this.isInitialized) {
+      throw new Error('Agent must be initialized before authentication');
+    }
+    await this.validateAuthConfig(authConfig);
+    this.authConfig = authConfig;
+    this.isAuthenticated = true;
+  }
+
+  /**
+   * Sends input to the agent and receives its response
+   * @param input The input to send to the agent
+   * @returns Promise that resolves with the agent's output
+   */
+  async sendInput(input: AgentInput): Promise<AgentOutput> {
+    if (!this.isInitialized) {
+      throw new Error('Agent must be initialized before sending input');
+    }
+    if (!this.isAuthenticated) {
+      throw new Error('Agent must be authenticated before sending input');
+    }
+    return this.processInput(input);
+  }
+
+  /**
+   * Validates the agent's configuration
+   * @returns Promise that resolves with true if the configuration is valid
+   * @throws Error if the configuration is invalid
+   */
+  validateConfig(): Promise<boolean> {
+    if (!this.config.model) {
+      throw new Error('Agent model is required');
+    }
+    return Promise.resolve(true);
+  }
+
+  /**
+   * Cleans up any resources used by the agent
+   * @returns Promise that resolves when cleanup is complete
+   */
+  cleanup(): Promise<void> {
+    this.isInitialized = false;
+    this.isAuthenticated = false;
+    this.authConfig = undefined;
+    return Promise.resolve();
+  }
+
+  /**
+   * Gets the authentication headers for the request
+   * @returns Record containing the authentication headers
+   * @throws Error if authentication configuration is invalid or headerFormat is missing the {apiKey} placeholder
+   */
+  protected getAuthHeaders(): Record<string, string> {
+    if (!this.authConfig) {
+      throw new Error('Authentication configuration not found');
+    }
+
+    const {
+      apiKey,
+      headerName = 'Authorization',
+      headerFormat = 'Bearer {apiKey}',
+    } = this.authConfig;
+
+    if (!headerFormat.includes('{apiKey}')) {
+      throw new Error('headerFormat must contain the {apiKey} placeholder');
+    }
+
+    const headerValue = headerFormat.replace('{apiKey}', apiKey);
+
+    return {
+      [headerName]: headerValue,
+    };
+  }
+
+  /**
+   * Validates the authentication configuration
+   * @param authConfig Authentication configuration to validate
+   * @throws Error if the authentication configuration is invalid
+   */
+  protected validateAuthConfig(authConfig: AgentAuthConfig): Promise<void> {
+    if (!authConfig.apiKey) {
+      throw new Error('API key is required for authentication');
+    }
+    return Promise.resolve();
+  }
+
+  /**
+   * Processes the input and returns the agent's response
+   * @param input The input to process
+   * @returns Promise that resolves with the agent's output
+   */
+  protected abstract processInput(input: AgentInput): Promise<AgentOutput>;
+}
diff --git a/src/agents/types/agent.types.ts b/src/agents/types/agent.types.ts
new file mode 100644
index 0000000..2e250a0
--- /dev/null
+++ b/src/agents/types/agent.types.ts
@@ -0,0 +1,73 @@
+import { BaseMessage } from '../../core/types/message.types';
+
+/**
+ * Represents the base configuration for an agent
+ */
+export interface AgentConfig {
+  /**
+   * The model to use for the agent
+   * @example "myfirstagent:next", "myfirstagent:v1"
+   */
+  model: string;
+}
+
+/**
+ * Represents the input that can be sent to an agent
+ */
+export interface AgentInput {
+  /**
+   * List of messages to send to the agent
+   */
+  messages: BaseMessage[];
+}
+
+/**
+ * Represents the output received from an agent
+ */
+export interface AgentOutput {
+  /**
+   * The main response from the agent
+   */
+  response: string;
+
+  /**
+   * Optional metadata about the response
+   */
+  metadata?: Record<string, unknown>;
+
+  /**
+   * Optional error information if the request failed
+   */
+  error?: {
+    message: string;
+    code?: string;
+    details?: unknown;
+  };
+}
+
+/**
+ * Configuration for API key authentication
+ */
+export interface ApiKeyAuthConfig {
+  /**
+   * The API key to be used for authentication
+   */
+  apiKey: string;
+
+  /**
+   * The header name where the API key should be sent
+   * @default 'Authorization'
+   */
+  headerName?: string;
+
+  /**
+   * The format of the API key in the header
+   * @default 'Bearer {apiKey}'
+   */
+  headerFormat?: string;
+}
+
+/**
+ * Represents the authentication configuration for an agent
+ */
+export type AgentAuthConfig = ApiKeyAuthConfig;
diff --git a/src/agents/types/openai.types.ts b/src/agents/types/openai.types.ts
new file mode 100644
index 0000000..66607e2
--- /dev/null
+++ b/src/agents/types/openai.types.ts
@@ -0,0 +1,131 @@
+import { BaseMessage } from '../../core/types/message.types';
+
+/**
+ * Types for OpenAI Response API interactions
+ */
+
+/**
+ * OpenAI/Hebo specific message format
+ */
+export interface OpenAIMessage extends BaseMessage {
+  name?: string;
+  function_call?: {
+    name: string;
+    arguments: string;
+  };
+}
+
+/**
+ * Represents a request to the OpenAI Response API
+ */
+export interface ResponseRequest {
+  /**
+   * The model to use for the response
+   */
+  model: string;
+
+  /**
+   * The messages to send to the API
+   */
+  messages: OpenAIMessage[];
+
+  /**
+   * Whether to store the conversation
+   */
+  store?: boolean;
+
+  /**
+   * The ID of the previous response
+   */
+  previous_response_id?: string;
+}
+
+/**
+ * Represents a response from the OpenAI Response API
+ */
+export interface Response {
+  /**
+   * The ID of the response
+   */
+  id: string;
+
+  /**
+   * The type of the response
+   */
+  object: string;
+
+  /**
+   * The timestamp when the response was created
+   */
+  created: number;
+
+  /**
+   * The model used for the response
+   */
+  model: string;
+
+  /**
+   * The ID of the previous response
+   */
+  previous_response_id?: string;
+
+  /**
+   * The choices returned by the API
+   */
+  choices: {
+    /**
+     * The index of the choice
+     */
+    index: number;
+
+    /**
+     * The message returned by the API
+     */
+    message: OpenAIMessage;
+
+    /**
+     * The reason why the response finished
+     */
+    finish_reason?: string;
+  }[];
+
+  /**
+   * The token usage information
+   */
+  usage?: {
+    /**
+     * The number of tokens used in the prompt
+     */
+    prompt_tokens: number;
+
+    /**
+     * The number of tokens used in the completion
+     */
+    completion_tokens: number;
+
+    /**
+     * The total number of tokens used
+     */
+    total_tokens: number;
+  };
+
+  /**
+   * Optional error information
+   */
+  error?: {
+    /**
+     * The error message
+     */
+    message: string;
+
+    /**
+     * The type of error
+     */
+    type: string;
+
+    /**
+     * The error code
+     */
+    code?: string;
+  };
+}
diff --git a/src/core/types/message.types.ts b/src/core/types/message.types.ts
new file mode 100644
index 0000000..21eeb0d
--- /dev/null
+++ b/src/core/types/message.types.ts
@@ -0,0 +1,71 @@
+/**
+ * Base role types for messages
+ *
+ * These roles represent different actors in a conversation:
+ * - USER: The end-user interacting with the system
+ * - ASSISTANT: The AI assistant responding to the user
+ * - SYSTEM: System-level instructions and configurations
+ * - HUMAN_AGENT: A human operator who can temporarily take over the assistant's role
+ * - TOOL: Messages from tool executions
+ * - FUNCTION: Messages from function calls
+ * - DEVELOPER: Messages from developers for testing or debugging
+ */
+export enum MessageRole {
+  /** The end-user who initiates the conversation and interacts with the system */
+  USER = 'user',
+
+  /** The AI assistant that processes and responds to user queries */
+  ASSISTANT = 'assistant',
+
+  /** System-level messages that provide context, instructions, or configuration */
+  SYSTEM = 'system',
+
+  /**
+   * A human operator who can temporarily take over the assistant's role.
+   * This role is distinct from USER as it represents a third party that can
+   * intervene in the conversation between the user and assistant.
+   */
+  HUMAN_AGENT = 'human_agent',
+
+  /** Messages generated by tool executions */
+  TOOL = 'tool',
+
+  /** Messages from function calls within the system */
+  FUNCTION = 'function',
+
+  /** Messages from developers, typically used for testing or debugging purposes */
+  DEVELOPER = 'developer',
+}
+
+/**
+ * Base tool usage type
+ */
+export interface ToolUsage {
+  name: string;
+  args: Record<string, unknown>;
+}
+
+/**
+ * Base tool response type
+ */
+export interface ToolResponse {
+  content: string;
+}
+
+/**
+ * Base message interface that can be extended
+ */
+export interface BaseMessage {
+  role: MessageRole;
+  content: string;
+  toolUsages?: ToolUsage[];
+  toolResponses?: ToolResponse[];
+}
+
+/**
+ * Test case definition
+ */
+export interface TestCase {
+  name: string;
+  messageBlocks: BaseMessage[];
+}
diff --git a/src/core/utils/role-mapper.ts b/src/core/utils/role-mapper.ts
new file mode 100644
index 0000000..0547ea6
--- /dev/null
+++ b/src/core/utils/role-mapper.ts
@@ -0,0 +1,57 @@
+import { MessageRole } from '../types/message.types';
+
+/**
+ * Maps between different role systems
+ */
+export class RoleMapper {
+  /**
+   * Maps a role to OpenAI format
+   */
+  public toOpenAI(role: MessageRole): string {
+    switch (role) {
+      case MessageRole.USER:
+        return 'user';
+      case MessageRole.ASSISTANT:
+      case MessageRole.HUMAN_AGENT:
+        return 'assistant';
+      case MessageRole.DEVELOPER:
+        return 'developer';
+      case MessageRole.SYSTEM:
+        return 'system';
+      case MessageRole.TOOL:
+      case MessageRole.FUNCTION:
+        return 'function';
+      default:
+        console.warn(
+          `Unrecognized role: ${role as string}, defaulting to USER`,
+        );
+        return 'user';
+    }
+  }
+
+  /**
+   * Maps an OpenAI role to our role system
+   */
+  public toRole(role: string): MessageRole {
+    switch (role.toLowerCase()) {
+      case 'user':
+        return MessageRole.USER;
+      case 'assistant':
+        return MessageRole.ASSISTANT;
+      case 'system':
+        return MessageRole.SYSTEM;
+      case 'function':
+        return MessageRole.TOOL;
+      case 'developer':
+        return MessageRole.DEVELOPER;
+      default:
+        console.warn(`Unrecognized role: ${role}, defaulting to USER`);
+        return MessageRole.USER;
+    }
+  }
+}
+
+/**
+ * Singleton instance
+ */
+export const roleMapper = new RoleMapper();
diff --git a/src/tests/agent.test.ts b/src/tests/agent.test.ts
new file mode 100644
index 0000000..c9c1fb8
--- /dev/null
+++ b/src/tests/agent.test.ts
@@ -0,0 +1,287 @@
+import { describe, it, expect, beforeEach, jest } from '@jest/globals';
+import { BaseAgent } from '../agents/interfaces/base-agent';
+import {
+  AgentConfig,
+  AgentInput,
+  AgentOutput,
+} from '../agents/types/agent.types';
+import { HeboAgent } from '../agents/implementations/hebo-agent';
+import { BaseMessage, MessageRole } from '../core/types/message.types';
+import { roleMapper } from '../core/utils/role-mapper';
+
+/**
+ * Test implementation of BaseAgent for testing abstract functionality
+ */
+class TestAgent extends BaseAgent {
+  protected processInput(_: AgentInput): Promise<AgentOutput> {
+    return Promise.resolve({
+      response: 'test response',
+      metadata: { test: true },
+    });
+  }
+}
+
+describe('Agent Types and Interfaces', () => {
+  describe('BaseMessage', () => {
+    it('should create a valid user message', () => {
+      const message: BaseMessage = {
+        role: MessageRole.USER,
+        content: 'Hello',
+      };
+      expect(message.role).toBe(MessageRole.USER);
+      expect(message.content).toBe('Hello');
+    });
+  });
+
+  describe('AgentInput', () => {
+    it('should create input with multiple messages', () => {
+      const input: AgentInput = {
+        messages: [
+          { role: MessageRole.USER, content: 'Hello' },
+          { role: MessageRole.ASSISTANT, content: 'Hi there' },
+        ],
+      };
+      expect(input.messages).toHaveLength(2);
+    });
+  });
+});
+
+describe('BaseAgent', () => {
+  let agent: TestAgent;
+  const config: AgentConfig = {
+    model: 'gpt-4o',
+  };
+
+  beforeEach(() => {
+    agent = new TestAgent(config);
+  });
+
+  describe('Initialization', () => {
+    it('should initialize with valid config', async () => {
+      await agent.initialize(config);
+      expect(agent.getConfig()).toEqual(config);
+    });
+
+    it('should throw error for invalid config', async () => {
+      const invalidConfig = { ...config, model: '' };
+      await expect(agent.initialize(invalidConfig)).rejects.toThrow();
+    });
+  });
+
+  describe('Authentication', () => {
+    it('should authenticate with valid API key', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+      // No error means success
+    });
+
+    it('should throw error if not initialized before authentication', async () => {
+      await expect(
+        agent.authenticate({ apiKey: 'test-key' }),
+      ).rejects.toThrow();
+    });
+  });
+
+  describe('Input Processing', () => {
+    it('should process input after initialization and authentication', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+
+      const input: AgentInput = {
+        messages: [{ role: MessageRole.USER, content: 'Hello' }],
+      };
+
+      const output = await agent.sendInput(input);
+      expect(output.response).toBe('test response');
+    });
+
+    it('should throw error if not authenticated before sending input', async () => {
+      await agent.initialize(config);
+      const input: AgentInput = {
+        messages: [{ role: MessageRole.USER, content: 'Hello' }],
+      };
+      await expect(agent.sendInput(input)).rejects.toThrow();
+    });
+  });
+});
+
+describe('HeboAgent', () => {
+  let agent: HeboAgent;
+  const config = {
+    model: 'gpt-4o',
+  };
+
+  beforeEach(() => {
+    agent = new HeboAgent(config);
+  });
+
+  describe('Network Error Handling', () => {
+    it('should handle network failure gracefully', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+
+      // Mock fetch to simulate network errors
+      const originalFetch = global.fetch;
+      global.fetch = jest.fn().mockImplementation(() => {
+        throw new Error('Network error: Failed to fetch');
+      }) as jest.MockedFunction<typeof fetch>;
+
+      const input: AgentInput = {
+        messages: [{ role: MessageRole.USER, content: 'Hello' }],
+      };
+
+      const output = await agent.sendInput(input);
+
+      // Verify error handling
+      expect(output).toBeDefined();
+      expect(output.response).toBe('');
+      expect(output.error).toBeDefined();
+      expect(output.error?.message).toBe('Network error: Failed to fetch');
+      expect(output.error?.details).toBeDefined();
+
+      // Restore original fetch
+      global.fetch = originalFetch;
+    });
+
+    it('should handle HTTP error responses gracefully', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+
+      // Mock fetch to simulate HTTP error
+      const originalFetch = global.fetch;
+      global.fetch = jest.fn().mockImplementation(() => {
+        return Promise.resolve({
+          ok: false,
+          status: 500,
+          statusText: 'Internal Server Error',
+          json: () => Promise.resolve({ error: { message: 'Server error' } }),
+        } as Response);
+      }) as jest.MockedFunction<typeof fetch>;
+
+      const input: AgentInput = {
+        messages: [{ role: MessageRole.USER, content: 'Hello' }],
+      };
+
+      const output = await agent.sendInput(input);
+
+      // Verify error handling
+      expect(output).toBeDefined();
+      expect(output.response).toBe('');
+      expect(output.error).toBeDefined();
+      expect(output.error?.message).toContain('HTTP error! status: 500');
+      expect(output.error?.details).toBeDefined();
+
+      // Restore original fetch
+      global.fetch = originalFetch;
+    });
+  });
+
+  describe('Message History', () => {
+    it('should maintain conversation history', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+
+      const input: AgentInput = {
+        messages: [
+          { role: MessageRole.USER, content: 'Hello' },
+          { role: MessageRole.ASSISTANT, content: 'Hi there' },
+        ],
+      };
+
+      await agent.sendInput(input);
+      expect(agent['messageHistory']).toHaveLength(2);
+    });
+  });
+
+  describe('Message Conversion', () => {
+    it('should handle role conversion correctly', () => {
+      expect(roleMapper.toOpenAI(MessageRole.USER)).toBe('user');
+      expect(roleMapper.toOpenAI(MessageRole.ASSISTANT)).toBe('assistant');
+      expect(roleMapper.toOpenAI(MessageRole.SYSTEM)).toBe('system');
+    });
+  });
+
+  describe('Memory Management', () => {
+    it('should handle multiple consecutive inputs without performance degradation', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+
+      // Mock fetch to simulate API responses
+      const originalFetch = global.fetch;
+      global.fetch = jest.fn().mockImplementation(() => {
+        return Promise.resolve({
+          ok: true,
+          status: 200,
+          json: () =>
+            Promise.resolve({
+              id: 'test-id',
+              model: config.model,
+              choices: [
+                {
+                  message: {
+                    role: 'assistant',
+                    content: 'Test response',
+                  },
+                },
+              ],
+              usage: {
+                prompt_tokens: 10,
+                completion_tokens: 5,
+                total_tokens: 15,
+              },
+            }),
+        } as Response);
+      }) as jest.MockedFunction<typeof fetch>;
+
+      // Simulate a conversation with multiple messages
+      const conversationRounds = 10;
+      const messagesPerRound = 3;
+
+      for (let round = 0; round < conversationRounds; round++) {
+        const input: AgentInput = {
+          messages: Array.from({ length: messagesPerRound }, (_, i) => ({
+            role: i % 2 === 0 ? MessageRole.USER : MessageRole.ASSISTANT,
+            content: `Message ${round * messagesPerRound + i + 1}`,
+          })),
+        };
+
+        const startTime = performance.now();
+        const output = await agent.sendInput(input);
+        const endTime = performance.now();
+        const executionTime = endTime - startTime;
+
+        // Verify response is received
+        expect(output).toBeDefined();
+        expect(output.response).toBe('Test response');
+
+        // Log performance metrics for monitoring
+        console.log(`Round ${round + 1} execution time: ${executionTime}ms`);
+
+        // Verify message history is maintained correctly
+        expect(agent['messageHistory']).toHaveLength(
+          (round + 1) * messagesPerRound + (round + 1), // Add one for each assistant response
+        );
+      }
+
+      // Final verification of message history
+      const finalHistory = agent['messageHistory'];
+      expect(finalHistory).toHaveLength(
+        conversationRounds * messagesPerRound + conversationRounds,
+      );
+
+      // Verify message order and content
+      finalHistory.forEach((message, index) => {
+        // Calculate the expected role based on the index
+        // Even indices are user messages, odd indices are assistant messages
+        const expectedRole =
+          index % 2 === 0 ? MessageRole.USER : MessageRole.ASSISTANT;
+        expect(roleMapper.toOpenAI(message.role)).toBe(
+          roleMapper.toOpenAI(expectedRole),
+        );
+      });
+
+      // Restore original fetch
+      global.fetch = originalFetch;
+    });
+  });
+});


Reviews:
user: login: sandyandi
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-04-08T13:04:19Z
user: login: turisanapo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:11:46Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>♻️ Duplicate comments (2)</summary><blockquote>

<details>
<summary>package.json (1)</summary><blockquote>

`48-48`: **TypeScript version specification update looks good.**

Setting the dependency to `"^5"` will allow for minor and patch version updates while staying within major version 5, which is a common and recommended practice for dependencies.

</blockquote></details>
<details>
<summary>src/agents/implementations/hebo-agent.ts (1)</summary><blockquote>

`39-39`: **Document behavior for `store = false`.**  
By default, `store` is set to `true` if not provided. Confirm whether setting `store = false` is intended to skip storing conversation data on the server. Ensure there are no side effects or unexpected usage if the user explicitly sets it to false.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (11)</summary><blockquote>

<details>
<summary>src/core/utils/role-mapper.ts (2)</summary><blockquote>

`6-26`: **Consider handling MessageRole.FUNCTION in the toOpenAI method.**

The `toOpenAI` method correctly maps most role types, but MessageRole.FUNCTION is not explicitly handled, although it might be related to the TOOL case that returns 'function'. For completeness and clarity, consider adding a specific case for FUNCTION.


```diff
public toOpenAI(role: MessageRole): string {
  switch (role) {
    case MessageRole.USER:
      return 'user';
    case MessageRole.ASSISTANT:
    case MessageRole.HUMAN_AGENT:
      return 'assistant';
    case MessageRole.DEVELOPER:
      return 'developer';
    case MessageRole.SYSTEM:
      return 'system';
    case MessageRole.TOOL:
      return 'function';
+   case MessageRole.FUNCTION:
+     return 'function';
    default:
      return 'user';
  }
}
```

---

`31-46`: **Consider more explicit error handling for unrecognized roles.**

Currently, unrecognized roles default to `MessageRole.USER`, which is a reasonable fallback but might mask errors. Consider adding logging or a more explicit indication that an unrecognized role was encountered.


```diff
public toRole(role: string): MessageRole {
  switch (role.toLowerCase()) {
    case 'user':
      return MessageRole.USER;
    case 'assistant':
      return MessageRole.ASSISTANT;
    case 'system':
      return MessageRole.SYSTEM;
    case 'function':
      return MessageRole.TOOL;
    case 'developer':
      return MessageRole.DEVELOPER;
    default:
+     console.warn(`Unrecognized role: ${role}, defaulting to USER`);
      return MessageRole.USER;
  }
}
```

</blockquote></details>
<details>
<summary>src/agents/types/agent.types.ts (1)</summary><blockquote>

`6-11`: **Consider adding more specific typing or documentation for model property.**

The `model` property in `AgentConfig` is very generic. It would be helpful to provide more specific documentation about expected values or patterns for this property, especially if specific model identifiers are required for the Hebo agent.


```diff
/**
 * The model to use for the agent
+ * @example "hebo-chat-1.5", "hebo-instructional-beta"
 */
model: string;
```

</blockquote></details>
<details>
<summary>src/core/types/message.types.ts (2)</summary><blockquote>

`1-12`: **Enum definitions are comprehensive.**  
The roles capture a wide range of potential message contexts. If there's any potential overlap (e.g., `human_agent` vs. `user`), consider adding a brief comment clarifying their differences.

---

`32-45`: **Potential duplication with single vs. multiple tool usage.**  
You have both `toolUsage?: ToolUsage` in `BaseMessage` and `toolUsages?: ToolUsage[]` in `MessageBlock`. Consider consolidating if multiple tool usages are always required, or clarify the reason for having both.

</blockquote></details>
<details>
<summary>src/agents/interfaces/base-agent.ts (2)</summary><blockquote>

`38-42`: **Re-initialization behavior may benefit from safeguards.**  
If the agent is not meant to be reconfigured at runtime, consider throwing an error when `initialize` is called again or clarifying the intended usage in the documentation.

---

`100-115`: **Consider stricter checks in `headerFormat`.**  
Currently, `headerFormat.replace('{apiKey}', apiKey)` proceeds silently if `'{apiKey}'` is missing. For enhanced reliability, you might ensure the placeholder is present or throw an error if not found.

</blockquote></details>
<details>
<summary>src/agents/types/openai.types.ts (2)</summary><blockquote>

`10-16`: **Consider refining the `function_call.arguments` type.**  
Currently, `arguments` is typed as a string. If the call arguments are structured data (e.g., JSON), using a more explicit type such as `Record<string, unknown>` or a generic type parameter could help minimize runtime parsing errors.  

```diff
 export interface OpenAIMessage extends BaseMessage {
   name?: string;
-  function_call?: {
+  function_call?: {
     name: string;
-    arguments: string;
+    arguments: Record<string, unknown>;
   };
 }
```

---

`46-131`: **Confirm that `usage` is always returned by the API.**  
OpenAI-like APIs typically supply usage information, but if there are scenarios where usage is not returned (e.g., for certain endpoints, errors, or billing modes), consider making the `usage` property optional to avoid potential runtime issues.

</blockquote></details>
<details>
<summary>src/tests/agent.test.ts (1)</summary><blockquote>

`109-133`: **Test large conversation history.**  
When messages accumulate, memory usage grows, and this may affect performance. Adding a test that simulates multiple consecutive user inputs can validate that the agent still behaves as expected.

</blockquote></details>
<details>
<summary>src/agents/implementations/hebo-agent.ts (1)</summary><blockquote>

`134-141`: **Consider bounding the conversation history.**  
Appending messages indefinitely may cause memory issues in long-running sessions. Introduce a cap or an LRU mechanism if your use case can safely discard older messages.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 456e9af8ac977a6d9145902b40d1b864aa850abc and 3528fe1e31a9aba3eef464de6c7f0730219d2b8e.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `package-lock.json` is excluded by `!**/package-lock.json`

</details>

<details>
<summary>📒 Files selected for processing (10)</summary>

* `package.json` (1 hunks)
* `src/agents/implementations/hebo-agent.ts` (1 hunks)
* `src/agents/index.ts` (1 hunks)
* `src/agents/interfaces/agent.interface.ts` (1 hunks)
* `src/agents/interfaces/base-agent.ts` (1 hunks)
* `src/agents/types/agent.types.ts` (1 hunks)
* `src/agents/types/openai.types.ts` (1 hunks)
* `src/core/types/message.types.ts` (1 hunks)
* `src/core/utils/role-mapper.ts` (1 hunks)
* `src/tests/agent.test.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (6)</summary>

<details>
<summary>src/agents/types/agent.types.ts (1)</summary><blockquote>

<details>
<summary>src/core/types/message.types.ts (1)</summary>

* `BaseMessage` (32-37)

</details>

</blockquote></details>
<details>
<summary>src/tests/agent.test.ts (3)</summary><blockquote>

<details>
<summary>src/agents/types/agent.types.ts (4)</summary>

* `AgentInput` (31-36)
* `AgentOutput` (41-60)
* `AgentMessage` (16-26)
* `AgentConfig` (6-11)

</details>
<details>
<summary>src/agents/implementations/hebo-agent.ts (1)</summary>

* `HeboAgent` (30-142)

</details>
<details>
<summary>src/core/utils/role-mapper.ts (1)</summary>

* `roleMapper` (52-52)

</details>

</blockquote></details>
<details>
<summary>src/agents/interfaces/agent.interface.ts (1)</summary><blockquote>

<details>
<summary>src/agents/types/agent.types.ts (4)</summary>

* `AgentConfig` (6-11)
* `AgentAuthConfig` (87-87)
* `AgentInput` (31-36)
* `AgentOutput` (41-60)

</details>

</blockquote></details>
<details>
<summary>src/agents/interfaces/base-agent.ts (2)</summary><blockquote>

<details>
<summary>src/agents/interfaces/agent.interface.ts (1)</summary>

* `IAgent` (14-54)

</details>
<details>
<summary>src/agents/types/agent.types.ts (4)</summary>

* `AgentConfig` (6-11)
* `AgentAuthConfig` (87-87)
* `AgentInput` (31-36)
* `AgentOutput` (41-60)

</details>

</blockquote></details>
<details>
<summary>src/agents/types/openai.types.ts (1)</summary><blockquote>

<details>
<summary>src/core/types/message.types.ts (1)</summary>

* `BaseMessage` (32-37)

</details>

</blockquote></details>
<details>
<summary>src/agents/implementations/hebo-agent.ts (3)</summary><blockquote>

<details>
<summary>src/agents/types/agent.types.ts (3)</summary>

* `AgentConfig` (6-11)
* `AgentInput` (31-36)
* `AgentOutput` (41-60)

</details>
<details>
<summary>src/agents/types/openai.types.ts (3)</summary>

* `OpenAIMessage` (10-16)
* `ResponseRequest` (21-41)
* `Response` (46-131)

</details>
<details>
<summary>src/core/utils/role-mapper.ts (1)</summary>

* `roleMapper` (52-52)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>src/agents/index.ts (1)</summary>

`1-8`: **Well-structured code exports module.**

This file provides a clean centralized export for agent-related types and interfaces, which aligns well with the PR objectives of creating a modular design. The module structure with separate directories for types, interfaces, and implementations (as referenced in the exports) promotes good code organization.

</details>
<details>
<summary>src/core/utils/role-mapper.ts (1)</summary>

`49-52`: **Good use of the singleton pattern.**

The singleton instance export is clean and well-documented, making it easy for other modules to use the mapper without instantiating it.

</details>
<details>
<summary>src/agents/types/agent.types.ts (2)</summary>

`41-60`: **Comprehensive error handling in AgentOutput.**

The `AgentOutput` interface includes a well-structured error object with message, code, and details fields. This provides a robust way to handle and communicate errors that might occur during agent processing.

---

`84-87`: **Type alias provides good extensibility.**

Using a type alias for `AgentAuthConfig` is a good approach as it allows for future expansion to support additional authentication methods beyond API keys without breaking changes to the interface.

</details>
<details>
<summary>src/agents/interfaces/agent.interface.ts (2)</summary>

`1-6`: **Imports look good.**  
No issues found with the path references or usage of imported types.

---

`14-54`: **Interface design is clear and thorough.**  
The method signatures are consistent and well-documented. The asynchronous design for validation and initialization appears appropriate for potential network or remote checks.

</details>
<details>
<summary>src/agents/interfaces/base-agent.ts (1)</summary>

`16-19`: **Property naming and scope are appropriate.**  
The naming is intuitive and reflects each property’s usage.

</details>
<details>
<summary>src/agents/types/openai.types.ts (1)</summary>

`21-41`: **Double-check necessity of making `store` optional.**  
By default, it’s optional here and set to `true` in the Hebo agent. If storing the conversation is always desired in your use case, you could mark it as required or remove the option altogether. If not, ensure all downstream usage handles both states properly.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T05:53:39Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>src/agents/types/agent.types.ts (1)</summary><blockquote>

`51-68`: **Defaults alignment with previous review comment.**

This portion previously prompted implementing default values for `headerName` and `headerFormat`. The current approach of documenting defaults via JSDoc aligns well with the usage in `BaseAgent`, thereby resolving the earlier concern.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/agents/interfaces/base-agent.ts (1)</summary><blockquote>

`26-29`: **Optional early validation for constructor usage.**

Currently, the constructor sets `this.config` without immediate validation. This is a consistent design choice, deferring checks to `initialize()`. However, consider throwing an error earlier for misconfigured agents to catch errors sooner.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3528fe1e31a9aba3eef464de6c7f0730219d2b8e and b0573f85fe0bcce65a5e497a31bff14565564f96.

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `src/agents/implementations/hebo-agent.ts` (1 hunks)
* `src/agents/interfaces/base-agent.ts` (1 hunks)
* `src/agents/types/agent.types.ts` (1 hunks)
* `src/agents/types/openai.types.ts` (1 hunks)
* `src/core/types/message.types.ts` (1 hunks)
* `src/core/utils/role-mapper.ts` (1 hunks)
* `src/tests/agent.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary>

* src/core/utils/role-mapper.ts
* src/core/types/message.types.ts
* src/tests/agent.test.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (3)</summary>

<details>
<summary>src/agents/interfaces/base-agent.ts (2)</summary><blockquote>

<details>
<summary>src/agents/interfaces/agent.interface.ts (1)</summary>

* `IAgent` (14-54)

</details>
<details>
<summary>src/agents/types/agent.types.ts (4)</summary>

* `AgentConfig` (6-11)
* `AgentAuthConfig` (87-87)
* `AgentInput` (31-36)
* `AgentOutput` (41-60)

</details>

</blockquote></details>
<details>
<summary>src/agents/types/openai.types.ts (1)</summary><blockquote>

<details>
<summary>src/core/types/message.types.ts (1)</summary>

* `BaseMessage` (32-37)

</details>

</blockquote></details>
<details>
<summary>src/agents/implementations/hebo-agent.ts (3)</summary><blockquote>

<details>
<summary>src/agents/types/agent.types.ts (3)</summary>

* `AgentConfig` (6-11)
* `AgentInput` (31-36)
* `AgentOutput` (41-60)

</details>
<details>
<summary>src/agents/types/openai.types.ts (3)</summary>

* `OpenAIMessage` (10-16)
* `ResponseRequest` (21-41)
* `Response` (46-131)

</details>
<details>
<summary>src/core/utils/role-mapper.ts (1)</summary>

* `roleMapper` (52-52)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (9)</summary><blockquote>

<details>
<summary>src/agents/types/agent.types.ts (1)</summary>

`1-22`: **Interfaces look good and are clearly documented.**

No obvious issues with correctness or security. It's helpful that `AgentConfig` and `AgentInput` are minimal and straightforward.

</details>
<details>
<summary>src/agents/types/openai.types.ts (3)</summary>

`10-16`: **OpenAIMessage interface extension is consistent.**

The extension from `BaseMessage` and optional `function_call` fields are sensible and flexible for future expansions.

---

`21-41`: **Naming consistency for 'store' field.**

Retaining the `store` name (as per OpenAI-like specs) is acceptable. No major design concerns here.

---

`46-131`: **Structures are comprehensive and well-organized.**

The large `Response` interface thoroughly represents the potential API response objects. The usage of optional fields is clear. This aligns with the actual usage in the `HeboAgent`.

</details>
<details>
<summary>src/agents/interfaces/base-agent.ts (1)</summary>

`112-132`: **Authentication headers implement documented defaults correctly.**

The logic for `headerName` and `headerFormat` usage is properly enforced. The placeholder validation ensures a valid format string. No issues here.

</details>
<details>
<summary>src/agents/implementations/hebo-agent.ts (4)</summary>

`30-40`: **Agent-specific properties look well-defined.**

The use of `previousResponseId` and `messageHistory` tracks conversation context effectively. Defaulting `store` to `true` matches Hebo usage patterns.

---

`116-133`: **Network request logic looks sound.**

The `fetch` call includes error handling for non-OK status. The error is propagated and caught in `processInput`. This guard is sufficient for the current scope.

---

`140-150`: **Hebo-specific authentication header is valid.**

Using `X-API-Key` is consistent with certain API standards. It's also clearly separated from the generic `Authorization` header approach in the base class.

---

`155-158`: **Cleanup method neatly resets agent state.**

Clearing `messageHistory` alongside the base cleanup approach is a proper extension of the lifecycle management.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T06:46:05Z
user: login: turisanapo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T07:07:00Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T07:07:42Z

Review comments:
diff_hunk: @@ -45,7 +45,7 @@
     "jest": "^29.7.0",
     "prettier": "^3.5.3",
     "ts-jest": "^29.3.1",
-    "typescript": "^5.3.3"
+    "typescript": "^5.8.3"
path: package.json
user: login: sandyandi
body: Setting this to just `^5` will update the minor and patch versions which looks like the intent here.
created_at: 2025-04-08T12:46:21Z
author_association: NONE
diff_hunk: @@ -0,0 +1,142 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
path: src/agents/implementations/hebo-agent.ts
user: login: sandyandi
body: Common convention to name boolean properties begin with `is`, `has`, `can` or `should`. In this case it should be a `shouldStore` unless `store` here is common convention in AI that is always related to messages.
created_at: 2025-04-08T12:57:14Z
author_association: NONE
diff_hunk: @@ -0,0 +1,142 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
path: src/agents/implementations/hebo-agent.ts
user: login: turisanapo
body: I'm using the same naming `store` as per openai request api specs. Changing it may cause some confusion. What do you think?
created_at: 2025-04-08T13:11:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import { BaseMessage, MessageRole } from '../../core/types/message.types';
+
+/**
+ * Represents the base configuration for an agent
+ */
+export interface AgentConfig {
+  /**
+   * The model to use for the agent
+   */
+  model: string;
+}
+
+/**
+ * Represents a single message in a conversation
+ */
+export interface AgentMessage {
+  /**
+   * The content of the message
+   */
+  content: string;
+
+  /**
+   * The role of the message sender
+   */
+  role: MessageRole;
+}
+
+/**
+ * Represents the input that can be sent to an agent
+ */
+export interface AgentInput {
+  /**
+   * List of messages to send to the agent
+   */
+  messages: BaseMessage[];
+}
+
+/**
+ * Represents the output received from an agent
+ */
+export interface AgentOutput {
+  /**
+   * The main response from the agent
+   */
+  response: string;
+
+  /**
+   * Optional metadata about the response
+   */
+  metadata?: Record<string, unknown>;
+
+  /**
+   * Optional error information if the request failed
+   */
+  error?: {
+    message: string;
+    code?: string;
+    details?: unknown;
+  };
+}
+
+/**
+ * Configuration for API key authentication
+ */
+export interface ApiKeyAuthConfig {
+  /**
+   * The API key to be used for authentication
+   */
+  apiKey: string;
+
+  /**
+   * The header name where the API key should be sent
+   * @default 'Authorization'
+   */
+  headerName?: string;
+
+  /**
+   * The format of the API key in the header
+   * @default 'Bearer {apiKey}'
+   */
+  headerFormat?: string;
+}
path: src/agents/types/agent.types.ts
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Consider implementing default values for auth config options.**

The JSDoc comments indicate default values for `headerName` and `headerFormat`, but it's not clear how these defaults are applied in the implementation. Consider documenting how these defaults are handled in the agent implementations.

---

🏁 Script executed:

```shell
#!/bin/bash
# Search for implementations that use ApiKeyAuthConfig to see how defaults are handled
grep -r "ApiKeyAuthConfig" --include="*.ts" src/
```

Length of output: 196

---



</details>

**Action Required: Clarify and Implement Default Values for API Key Authentication**

The JSDoc for `ApiKeyAuthConfig` specifies default values for both `headerName` and `headerFormat`, yet a search of the codebase only reveals the interface definition (and its alias) without any implementation enforcing these defaults. Please either:

- **Implement default logic**: Modify the agent initialization or configuration processing code so that, when these options are not provided, `headerName` defaults to `'Authorization'` and `headerFormat` defaults to `'Bearer {apiKey}'`.
- **Update the documentation**: If default value application occurs elsewhere (or is intended to be handled by the consumer), clearly document where and how these defaults are applied in the agent implementations.

Review and adjust the appropriate files to ensure consistency between the documentation and actual behavior.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-09T05:53:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import { BaseMessage, MessageRole } from '../../core/types/message.types';
+
+/**
+ * Represents the base configuration for an agent
+ */
+export interface AgentConfig {
+  /**
+   * The model to use for the agent
+   */
+  model: string;
+}
+
+/**
+ * Represents a single message in a conversation
+ */
+export interface AgentMessage {
+  /**
+   * The content of the message
+   */
+  content: string;
+
+  /**
+   * The role of the message sender
+   */
+  role: MessageRole;
+}
path: src/agents/types/agent.types.ts
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Clarify relationship between AgentMessage and BaseMessage.**

There seems to be overlap between `AgentMessage` and the imported `BaseMessage`, but `AgentInput` uses `BaseMessage[]` rather than `AgentMessage[]`. Consider documenting the relationship between these interfaces or potentially refactoring to reduce duplication.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check the definition of BaseMessage to understand its relationship with AgentMessage
cat src/core/types/message.types.ts | grep -A 15 "export interface BaseMessage"
```

Length of output: 376

---



</details>

**Action: Clarify and Refactor Agent and Base Message Interfaces**

In `src/agents/types/agent.types.ts` (lines 16–26), the `AgentMessage` interface duplicates the `content` and `role` properties already defined in `BaseMessage` (see `src/core/types/message.types.ts`), but omits the additional optional properties like `toolUsage` and `toolResponse`. Since `AgentInput` uses `BaseMessage[]`, it's unclear whether `AgentMessage` is intended as a specialized subset or if the separation is unnecessary.

**Recommendations:**
- **Document the Relationship:** Clearly explain the intended use case and differences between `AgentMessage` and `BaseMessage` in the code documentation.
- **Refactor if Appropriate:** Consider having `AgentMessage` extend `BaseMessage` (if the extra properties aren’t required) or refactor to use a unified interface to reduce duplication.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-09T05:53:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+import { describe, it, expect, beforeEach } from '@jest/globals';
+import { BaseAgent } from '../agents/interfaces/base-agent';
+import {
+  AgentConfig,
+  AgentInput,
+  AgentMessage,
+  AgentOutput,
+} from '../agents/types/agent.types';
+import { HeboAgent } from '../agents/implementations/hebo-agent';
+import { MessageRole } from '../core/types/message.types';
+import { roleMapper } from '../core/utils/role-mapper';
+
+/**
+ * Test implementation of BaseAgent for testing abstract functionality
+ */
+class TestAgent extends BaseAgent {
+  protected processInput(_: AgentInput): Promise<AgentOutput> {
+    return Promise.resolve({
+      response: 'test response',
+      metadata: { test: true },
+    });
+  }
+}
+
+describe('Agent Types and Interfaces', () => {
+  describe('AgentMessage', () => {
+    it('should create a valid user message', () => {
+      const message: AgentMessage = {
+        role: MessageRole.USER,
+        content: 'Hello',
+      };
+      expect(message.role).toBe(MessageRole.USER);
+      expect(message.content).toBe('Hello');
+    });
+  });
+
+  describe('AgentInput', () => {
+    it('should create input with multiple messages', () => {
+      const input: AgentInput = {
+        messages: [
+          { role: MessageRole.USER, content: 'Hello' },
+          { role: MessageRole.ASSISTANT, content: 'Hi there' },
+        ],
+      };
+      expect(input.messages).toHaveLength(2);
+    });
+  });
+});
+
+describe('BaseAgent', () => {
+  let agent: TestAgent;
+  const config: AgentConfig = {
+    model: 'gpt-4o',
+  };
+
+  beforeEach(() => {
+    agent = new TestAgent(config);
+  });
+
+  describe('Initialization', () => {
+    it('should initialize with valid config', async () => {
+      await agent.initialize(config);
+      expect(agent.getConfig()).toEqual(config);
+    });
+
+    it('should throw error for invalid config', async () => {
+      const invalidConfig = { ...config, model: '' };
+      await expect(agent.initialize(invalidConfig)).rejects.toThrow();
+    });
+  });
+
+  describe('Authentication', () => {
+    it('should authenticate with valid API key', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+      // No error means success
+    });
+
+    it('should throw error if not initialized before authentication', async () => {
+      await expect(
+        agent.authenticate({ apiKey: 'test-key' }),
+      ).rejects.toThrow();
+    });
+  });
+
+  describe('Input Processing', () => {
+    it('should process input after initialization and authentication', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+
+      const input: AgentInput = {
+        messages: [{ role: MessageRole.USER, content: 'Hello' }],
+      };
+
+      const output = await agent.sendInput(input);
+      expect(output.response).toBe('test response');
+    });
+
path: src/tests/agent.test.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add tests for network failure scenarios.**  
All current tests assume successful request/response flows. Consider testing how the agent behaves if a network request fails, e.g., non-200 response from the server or a parsing error, to ensure robust error handling.  

```diff
 describe('BaseAgent', () => {
   ...
   describe('Input Processing', () => {
     ...
+    it('should handle network failure gracefully', async () => {
+      await agent.initialize(config);
+      await agent.authenticate({ apiKey: 'test-key' });
+      // Mock fetch or the method that triggers the request to simulate network error
+      // Ensure error is returned or handled as expected
+    });
   });
 });
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  describe('Input Processing', () => {
    it('should process input after initialization and authentication', async () => {
      await agent.initialize(config);
      await agent.authenticate({ apiKey: 'test-key' });

      const input: AgentInput = {
        messages: [{ role: MessageRole.USER, content: 'Hello' }],
      };

      const output = await agent.sendInput(input);
      expect(output.response).toBe('test response');
    });

    it('should handle network failure gracefully', async () => {
      await agent.initialize(config);
      await agent.authenticate({ apiKey: 'test-key' });
      // Mock fetch or the method that triggers the request to simulate network error
      // Ensure error is returned or handled as expected
    });
  });
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commit b0573f8
created_at: 2025-04-09T05:53:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,142 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
+}
+
+/**
+ * Implementation of the Hebo agent
+ */
+export class HeboAgent extends BaseAgent {
+  private baseUrl: string;
+  private store: boolean;
+  private previousResponseId?: string;
+  private messageHistory: OpenAIMessage[] = [];
+
+  constructor(config: HeboAgentConfig) {
+    super(config);
+    this.baseUrl = config.baseUrl || 'https://api.hebo.ai';
+    this.store = config.store || true;
+    this.messageHistory = [];
+  }
+
+  /**
+   * Validates the Hebo-specific configuration
+   */
+  public override validateConfig(): Promise<boolean> {
+    if (!this.config.model) {
+      throw new Error('Model is required for Hebo agent');
+    }
+    return super.validateConfig();
+  }
+
+  /**
+   * Processes the input and returns the agent's response
+   */
+  protected async processInput(input: AgentInput): Promise<AgentOutput> {
+    // Add new messages to history
+    this.messageHistory.push(...input.messages);
+
+    const request: ResponseRequest = {
+      model: this.config.model,
+      store: this.store,
+      previous_response_id: this.previousResponseId,
+      messages: this.messageHistory,
+    };
+
+    try {
+      const response = await this.makeRequest(request);
+      this.previousResponseId = response.id;
+
+      // Add assistant's response to history
+      if (response.choices[0]?.message) {
+        const message = response.choices[0].message;
+        this.messageHistory.push({
+          role: roleMapper.toRole(message.role),
+          content: message.content || '',
+          toolUsage: message.toolUsage,
+          toolResponse: message.toolResponse,
+        });
+      }
path: src/agents/implementations/hebo-agent.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Handle absent response choices more gracefully.**  
The code accesses `response.choices[0]?.message` without checking if `response.choices` is empty. Though you use optional chaining for the first element’s message, it would be safer to verify `response.choices` has length ≥ 1 to avoid potential undefined indexing.  

```diff
     // Add assistant's response to history
-    if (response.choices[0]?.message) {
-      const message = response.choices[0].message;
+    if (response.choices.length > 0 && response.choices[0].message) {
+      const message = response.choices[0]?.message;
       this.messageHistory.push({
         role: roleMapper.toRole(message.role),
         content: message.content || '',
         toolUsage: message.toolUsage,
         toolResponse: message.toolResponse,
       });
     }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      // Add assistant's response to history
      if (response.choices.length > 0 && response.choices[0].message) {
        const message = response.choices[0]?.message;
        this.messageHistory.push({
          role: roleMapper.toRole(message.role),
          content: message.content || '',
          toolUsage: message.toolUsage,
          toolResponse: message.toolResponse,
        });
      }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commit b0573f8
created_at: 2025-04-09T05:53:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,159 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
+}
+
+/**
+ * Implementation of the Hebo agent
+ */
+export class HeboAgent extends BaseAgent {
+  private baseUrl: string;
+  private store: boolean;
+  private previousResponseId?: string;
+  private messageHistory: OpenAIMessage[] = [];
+
+  constructor(config: HeboAgentConfig) {
+    super(config);
+    this.baseUrl = config.baseUrl || 'https://api.hebo.ai';
+    this.store = config.store ?? true;
+    this.messageHistory = [];
+  }
+
+  /**
+   * Validates the Hebo-specific configuration
+   */
+  public override validateConfig(): Promise<boolean> {
+    if (!this.config.model) {
+      throw new Error('Model is required for Hebo agent');
+    }
+    return super.validateConfig();
+  }
+
+  /**
+   * Processes the input and returns the agent's response
+   */
+  protected async processInput(input: AgentInput): Promise<AgentOutput> {
+    // Add new messages to history
+    this.messageHistory.push(...input.messages);
+
+    const request: ResponseRequest = {
+      model: this.config.model,
+      store: this.store,
+      previous_response_id: this.previousResponseId,
+      messages: this.messageHistory,
+    };
+
+    try {
+      const response = await this.makeRequest(request);
+      this.previousResponseId = response.id;
+
+      // Add assistant's response to history
+      if (response.choices.length > 0 && response.choices[0].message) {
+        const message = response.choices[0].message;
+        this.messageHistory.push({
+          role: roleMapper.toRole(message.role),
+          content: message.content || '',
+          toolUsages: message.toolUsages || [],
+          toolResponses: message.toolResponses || [],
path: src/agents/implementations/hebo-agent.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Potential mismatch with base message properties.**

`toolUsages` and `toolResponses` differ from `toolUsage` and `toolResponse` in `BaseMessage`. Ensure the extended message interface accommodates these arrays to prevent TypeScript errors or runtime mismatches.  

```diff
- toolUsages: message.toolUsages || [],
- toolResponses: message.toolResponses || [],
+ toolUsage: message.toolUsage || null,
+ toolResponse: message.toolResponse || null,
```
Or update corresponding definitions to align with multiple usage/responses if intended.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
          toolUsage: message.toolUsage || null,
          toolResponse: message.toolResponse || null,
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-09T06:46:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,159 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
+}
+
+/**
+ * Implementation of the Hebo agent
+ */
+export class HeboAgent extends BaseAgent {
+  private baseUrl: string;
+  private store: boolean;
+  private previousResponseId?: string;
+  private messageHistory: OpenAIMessage[] = [];
+
+  constructor(config: HeboAgentConfig) {
+    super(config);
+    this.baseUrl = config.baseUrl || 'https://api.hebo.ai';
+    this.store = config.store ?? true;
+    this.messageHistory = [];
+  }
+
+  /**
+   * Validates the Hebo-specific configuration
+   */
+  public override validateConfig(): Promise<boolean> {
+    if (!this.config.model) {
+      throw new Error('Model is required for Hebo agent');
+    }
+    return super.validateConfig();
+  }
+
+  /**
+   * Processes the input and returns the agent's response
+   */
+  protected async processInput(input: AgentInput): Promise<AgentOutput> {
+    // Add new messages to history
+    this.messageHistory.push(...input.messages);
+
+    const request: ResponseRequest = {
+      model: this.config.model,
+      store: this.store,
+      previous_response_id: this.previousResponseId,
+      messages: this.messageHistory,
+    };
+
+    try {
+      const response = await this.makeRequest(request);
+      this.previousResponseId = response.id;
+
+      // Add assistant's response to history
+      if (response.choices.length > 0 && response.choices[0].message) {
+        const message = response.choices[0].message;
+        this.messageHistory.push({
+          role: roleMapper.toRole(message.role),
+          content: message.content || '',
+          toolUsages: message.toolUsages || [],
+          toolResponses: message.toolResponses || [],
path: src/agents/implementations/hebo-agent.ts
user: login: turisanapo
body: `BaseMessage` exposes `toolUsages` not `toolUsage`. Same for `ToolResponse`. Not sure I understand your comment here.
created_at: 2025-04-09T07:06:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,159 @@
+import { BaseAgent } from '../interfaces/base-agent';
+import { AgentConfig, AgentInput, AgentOutput } from '../types/agent.types';
+import {
+  Response,
+  ResponseRequest,
+  OpenAIMessage,
+} from '../types/openai.types';
+import { roleMapper } from '../../core/utils/role-mapper';
+
+/**
+ * Configuration specific to Hebo agent
+ */
+export interface HeboAgentConfig extends AgentConfig {
+  /**
+   * The base URL for the Hebo API
+   * @default 'https://api.hebo.ai'
+   */
+  baseUrl?: string;
+
+  /**
+   * Whether to store the conversation
+   * @default true
+   */
+  store?: boolean;
+}
+
+/**
+ * Implementation of the Hebo agent
+ */
+export class HeboAgent extends BaseAgent {
+  private baseUrl: string;
+  private store: boolean;
+  private previousResponseId?: string;
+  private messageHistory: OpenAIMessage[] = [];
+
+  constructor(config: HeboAgentConfig) {
+    super(config);
+    this.baseUrl = config.baseUrl || 'https://api.hebo.ai';
+    this.store = config.store ?? true;
+    this.messageHistory = [];
+  }
+
+  /**
+   * Validates the Hebo-specific configuration
+   */
+  public override validateConfig(): Promise<boolean> {
+    if (!this.config.model) {
+      throw new Error('Model is required for Hebo agent');
+    }
+    return super.validateConfig();
+  }
+
+  /**
+   * Processes the input and returns the agent's response
+   */
+  protected async processInput(input: AgentInput): Promise<AgentOutput> {
+    // Add new messages to history
+    this.messageHistory.push(...input.messages);
+
+    const request: ResponseRequest = {
+      model: this.config.model,
+      store: this.store,
+      previous_response_id: this.previousResponseId,
+      messages: this.messageHistory,
+    };
+
+    try {
+      const response = await this.makeRequest(request);
+      this.previousResponseId = response.id;
+
+      // Add assistant's response to history
+      if (response.choices.length > 0 && response.choices[0].message) {
+        const message = response.choices[0].message;
+        this.messageHistory.push({
+          role: roleMapper.toRole(message.role),
+          content: message.content || '',
+          toolUsages: message.toolUsages || [],
+          toolResponses: message.toolResponses || [],
path: src/agents/implementations/hebo-agent.ts
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

Let me check the definition of `BaseMessage` to verify the property names.

---

🏁 Script executed:
```
#!/bin/bash
# Check the definition of BaseMessage in the file
cat src/core/types/message.types.ts
```

Length of output: 1901

---



</details>

@turisanapo You're absolutely right, and I apologize for the confusion in my automated review. After checking the `BaseMessage` interface definition in `src/core/types/message.types.ts`, I can confirm that the properties are indeed defined as `toolUsages` and `toolResponses` (plural form), and they are arrays:

```typescript
export interface BaseMessage {
  role: MessageRole;
  content: string;
  toolUsages?: ToolUsage[];
  toolResponses?: ToolResponse[];
}
```

Your implementation is correct as is. Thank you for pointing out this error in my review.
---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: turisanapo
PR: heboai/hebo-eval#10
File: src/agents/implementations/hebo-agent.ts:77-78
Timestamp: 2025-04-09T07:07:41.023Z
Learning: The BaseMessage interface in src/core/types/message.types.ts defines properties as `toolUsages?: ToolUsage[]` and `toolResponses?: ToolResponse[]` (plural form), which are optional arrays of ToolUsage and ToolResponse objects, not singular properties.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-04-09T07:07:41Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-09T05:48:25Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This pull request updates the TypeScript dependency in the project and introduces a suite of new agent-related modules. A concrete implementation for the Hebo agent is added via a new `HeboAgent` class, extending an abstract `BaseAgent` and conforming to the newly defined `IAgent` interface. Centralized exports, various type definitions for agents and messaging, and a role mapping utility are also provided. Comprehensive Jest tests validate the framework's behavior covering initialization, authentication, input processing, and role conversion.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `package.json` | Updated the TypeScript dependency version from `"^5.3.3"` to `"^5"`. |
| `src/agents/implementations/hebo-agent.ts` | Added new `HeboAgent` class extending `BaseAgent`; includes configuration (`HeboAgentConfig`), methods `validateConfig`, `processInput`, `makeRequest`, and `cleanup` to interact with the Hebo API. |
| `src/agents/index.ts`, `src/agents/interfaces/agent.interface.ts`, `src/agents/interfaces/base-agent.ts` | Introduced centralized exports for agent modules, a new `IAgent` interface, and an abstract `BaseAgent` class that implements common agent functionalities and error handling. |
| `src/agents/types/agent.types.ts`, `src/agents/types/openai.types.ts` | Added various interfaces and type aliases for agent configurations, messaging structures, and OpenAI API request/response types. |
| `src/core/types/message.types.ts`, `src/core/utils/role-mapper.ts` | Introduced messaging types such as `MessageRole`, `ToolUsage`, and a `RoleMapper` utility class to map roles between internal and OpenAI-compatible formats. |
| `src/tests/agent.test.ts` | Added a comprehensive Jest test suite for both `BaseAgent` and `HeboAgent`, validating configuration, authentication, input processing, message history management, and role mapping. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant HeboAgent
    participant HeboAPI
    Client->>HeboAgent: sendInput(message)
    HeboAgent->>HeboAgent: validateConfig()
    HeboAgent->>HeboAgent: processInput(message)
    HeboAgent->>HeboAPI: makeRequest(apiPayload)
    HeboAPI-->>HeboAgent: API response
    HeboAgent->>Client: return response or error
```

## Assessment against linked issues

| Objective                                                                                         | Addressed | Explanation                                                                        |
|---------------------------------------------------------------------------------------------------|:---------:|------------------------------------------------------------------------------------|
| Abstract interface and required method signatures for agent interactions (#3)                     | ✅        |                                                                                    |
| Concrete HeboAgent implementation with authentication, input/output handling (#3)                | ✅        |                                                                                    |
| Integration with Hebo-specific API (/response endpoint) and inclusion of documentation/examples (#3) | ❓        | The API endpoint target and documentation guidelines are not explicitly defined.   |

## Poem
> I'm a rabbit leaping through the code,  
> Hopping on changes down the innovation road.  
> New agents and tests in a garden so bright,  
> With carrots of logic and bytes taking flight.  
> Enjoy the burrow of code—it's pure delight!

<!-- walkthrough_end -->
<!-- internal state start -->


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

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=heboai/hebo-eval&utm_content=10):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-09T05:56:10Z
body: > [!CAUTION]
> No docstrings were generated.
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-09T05:57:15Z
body: > [!CAUTION]
> No docstrings were generated.
author_association: CONTRIBUTOR