# ElizaOS Developer Update - July 24, 2025

## Core Framework

The ElizaOS core framework has undergone significant architectural changes this week:

- **EventTarget Migration**: Completed migration from Node.js `EventEmitter` to Bun's native `EventTarget` API for improved runtime performance and compatibility. This affects the `InternalMessageBus` and `SimpleMigrationAgent` classes with full backward compatibility achieved [(#5609)](https://github.com/elizaOS/eliza/pull/5609).

- **ModuleLoader Enhancement**: Implemented a comprehensive ModuleLoader system with local-first guarantees, ensuring consistent module resolution across all ElizaOS commands. This fixes critical edge cases where plugins would load from global paths instead of local project directories [(#5629)](https://github.com/elizaOS/eliza/pull/5629).

- **Plugin Export Fix**: Resolved critical issue where plugin actions weren't being received by the runtime in NPM-deployed versions, ensuring consistent behavior between development and production environments [(#5624)](https://github.com/elizaOS/eliza/pull/5624).

- **Action Chaining**: Fixed critical issues in action chaining implementation, allowing actions to store state and communicate sequential results through the runtime [(#5490)](https://github.com/elizaOS/eliza/pull/5490).

## New Features

### Service Types System

A new standardized service interfaces system has been implemented with the `getServicesByType()` method, enabling better service discovery and interoperability:

```typescript
// Get all email services registered in the system
const emailServices = runtime.getServicesByType(ServiceType.EMAIL);

// Example using the first available email service
if (emailServices.length > 0) {
  const emailService = emailServices[0];
  await emailService.sendEmail({
    to: "user@example.com",
    subject: "Hello from ElizaOS",
    body: "This is a message sent via the standardized email service interface"
  });
}
```

### Plugin Quick Starter

Added a new `plugin-quick-starter` template for creating backend-only plugins without frontend overhead:

```bash
elizaos create my-backend-plugin --type plugin-quick-starter
```

The template provides a streamlined development experience focused on backend functionality, removing unnecessary UI components and tooling.

### Auto-Resizing Chat Input

The ChatInput component now features dynamic resizing based on content length:

```typescript
// In ChatInput.tsx
const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
  resizeTextarea(e.target);
  // Additional input handling...
};

// Automatically adjusts height while typing, with max height constraints
const resizeTextarea = (textarea: HTMLTextAreaElement) => {
  textarea.style.height = "auto";
  textarea.style.height = Math.min(textarea.scrollHeight, MAX_HEIGHT) + "px";
};
```

## Bug Fixes

A critical fix was implemented for plugin loading on Windows systems, addressing a persistent issue that prevented proper plugin initialization [(#5416)](https://github.com/elizaOS/eliza/pull/5416):

```typescript
// Before: Path handling incompatible with Windows
const pluginPath = path.join(projectDir, 'node_modules', pluginName);

// After: Cross-platform path normalization
const pluginPath = path.normalize(
  path.join(projectDir, 'node_modules', pluginName)
);
```

Additional notable fixes:

- Fixed SQL plugin advisory lock acquisition bug that could cause database migration failures [(#5572)](https://github.com/elizaOS/eliza/pull/5572)
- Corrected prompt handling in bootstrap plugin to enforce proper code block formatting in LLM replies [(#5525)](https://github.com/elizaOS/eliza/pull/5525)
- Addressed improper JSON string handling in the SQL base plugin that could cause data corruption [(#5628)](https://github.com/elizaOS/eliza/pull/5628)
- Fixed client path resolution for globally installed CLI to prevent "Client application not found" errors [(#5472)](https://github.com/elizaOS/eliza/pull/5472)

## API Changes

### 1. Service Type Interface

New standardized service type interfaces have been added to the core API:

```typescript
// New service type enums and interfaces
export enum ServiceType {
  EMAIL = 'email',
  WEB_SEARCH = 'web-search',
  PDF = 'pdf',
  BROWSER = 'browser',
  VIDEO = 'video',
  TRANSCRIPTION = 'transcription',
  POST = 'post',
  MESSAGE = 'message'
  // Additional service types...
}

// Example of the Email service interface
export interface EmailService extends Service {
  serviceType: ServiceType.EMAIL;
  sendEmail(params: EmailParams): Promise<EmailResult>;
}

// Example usage in a plugin
@service(ServiceType.EMAIL)
export class MyEmailService implements EmailService {
  serviceType = ServiceType.EMAIL;
  
  static async start() {
    // Service initialization
    return new MyEmailService();
  }
  
  async sendEmail(params: EmailParams): Promise<EmailResult> {
    // Implementation
  }
}
```

### 2. Action Chaining API

The action chaining system now supports sequential execution with state retention:

```typescript
// Action with chaining support
export const myFirstAction = async (
  state: State,
  params: ActionParams
): Promise<ActionResult> => {
  // Store data for next action in chain
  state.actionState.set('myData', { value: 42 });
  
  return {
    success: true,
    next: 'mySecondAction', // Chain to next action
    data: { initialStep: 'completed' }
  };
};

export const mySecondAction = async (
  state: State,
  params: ActionParams
): Promise<ActionResult> => {
  // Retrieve data from previous action
  const myData = state.actionState.get('myData');
  
  // Optionally send intermediate message to user
  state.callback(`Processing step 2 with value: ${myData.value}`);
  
  return {
    success: true,
    data: { result: 'complete' }
  };
};
```

## Social Media Integrations

### Twitter Plugin Updates

The Twitter plugin documentation has been updated to clarify API tier requirements. Users reported challenges with the Twitter API integration due to rate limits:

- The free tier allows only ~17 posts per day
- Full functionality requires the $200/month tier API credentials
- Fixed an issue where creating a DM channel would return a "Not implemented" error when missing a static start method

A new example for the default Eliza character has been added to support Twitter posting functionality via the `POST` service type [(#5652)](https://github.com/elizaOS/eliza/pull/5652).

For detailed Twitter integration guidance, see the updated [Twitter plugin documentation](https://github.com/elizaOS/eliza/blob/main/packages/docs/packages/plugins/twitter.md).

## Model Provider Updates

### Ollama Integration Improvements

The Ollama plugin integration has been refactored to be conditionally included based on the `OLLAMA_API_ENDPOINT` environment variable, instead of being a universal fallback:

```typescript
// Before: Always included Ollama plugin
plugins.push("@elizaos/plugin-ollama");

// After: Conditional inclusion based on environment
if (process.env.OLLAMA_API_ENDPOINT) {
  plugins.push("@elizaos/plugin-ollama");
}
```

This change improves performance and reduces unnecessary dependencies when Ollama is not in use.

### Model Selection Improvements

The CLI now provides clearer model selection options during project creation, with better handling of local model resolution. When selecting "Local" as the model type, the system properly installs the Ollama plugin rather than attempting to find a generic "local" plugin.

## Breaking Changes

### V1 to V2 Migration

A significant improvement for V1 to V2 character conversion has been added, automatically handling legacy format during import:

- The new `useConvertCharacter` hook automatically detects V1 character files and converts them to V2 format
- Plugin mapping has been updated to translate legacy v1 plugin names to their v2 equivalents (e.g., `llama_local` → `@elizaos/plugin-ollama`)
- If you're manually converting characters, be aware that plugins and prompt formats have changed

```typescript
// V1 to V2 plugin name mapping example
const LEGACY_PLUGIN_MAPPING: Record<string, string> = {
  'llama_local': '@elizaos/plugin-ollama',
  'openai': '@elizaos/plugin-openai',
  'anthropic': '@elizaos/plugin-anthropic',
  // ...additional mappings
};
```

### EventEmitter to EventTarget Migration

All internal event systems now use `EventTarget` instead of `EventEmitter`. If you've built custom components that extend ElizaOS internal messaging:

```typescript
// Before (EventEmitter pattern)
bus.on('message', (data) => {
  // Handle event
}).on('error', (err) => {
  // Handle error
});

// After (EventTarget pattern)
bus.on('message', (event) => {
  const data = event.detail;
  // Handle event
});
bus.on('error', (event) => {
  const err = event.detail;
  // Handle error
});
```