Skip to main content

SocketIO Real-Time Events

AiderDesk uses SocketIO to provide real-time event streaming, allowing external applications to receive live updates about project activities, AI responses, and system events.

Overview​

The SocketIO server runs on the same port as the REST API (default: 24337, configurable via AIDER_DESK_PORT). Clients can connect and subscribe to specific event types to receive real-time updates.

Connection Setup​

import io from 'socket.io-client';

// Connect to AiderDesk
const socket = io('http://localhost:24337', {
autoConnect: true,
forceNew: true,
});

// Subscribe to events
socket.on('connect', () => {
socket.emit('message', {
action: 'subscribe-events',
eventTypes: ['response-chunk', 'response-completed', 'log', 'context-files-updated']
});
});

Event Filtering​

Events can be filtered by project directory and task ID when applicable. The system compares base directories and task IDs to ensure events are only sent to relevant subscribers.

Project-level filtering: Events are filtered by baseDir to match the project directory. Task-level filtering: Task-specific events are also filtered by taskId for granular control.

Event Types​

Response Events​

response-chunk​

Emitted during AI response streaming for real-time updates.

Data Structure:

{
"messageId": "unique-message-id",
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"chunk": "AI response text chunk",
"reflectedMessage": "optional reflected message",
"promptContext": {
"id": "context-uuid",
"group": {
"id": "group-uuid",
"name": "optional group name",
"color": "optional group color",
"finished": false
}
}
}

response-completed​

Emitted when an AI response is fully completed.

Data Structure:

{
"type": "response-completed",
"messageId": "unique-message-id",
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"content": "Complete AI response",
"reflectedMessage": "optional reflected message",
"editedFiles": ["file1.ts", "file2.ts"],
"commitHash": "abc123",
"commitMessage": "Changes committed",
"diff": "diff content",
"usageReport": {
"model": "gpt-4",
"sentTokens": 100,
"receivedTokens": 50,
"messageCost": 0.0023,
"cacheWriteTokens": 10,
"cacheReadTokens": 5,
"aiderTotalCost": 0.002,
"agentTotalCost": 0.0003
},
"sequenceNumber": 1,
"promptContext": {
"id": "context-uuid",
"group": {
"id": "group-uuid",
"name": "optional group name",
"color": "optional group color",
"finished": false
}
},
"timestamp": 1716123456789
}

Context Events​

context-files-updated​

Emitted when the project's context files are modified.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"files": [
{
"path": "src/main.ts",
"readOnly": false
},
{
"path": "src/utils.ts",
"readOnly": true
}
]
}

commands-updated​

Emitted when commands are updated.

Data Structure:

{
"baseDir": "/path/to/project",
"customCommands": [
{
"name": "format-code",
"description": "Format code using prettier",
"arguments": [
{
"description": "File to format",
"required": false
}
],
"template": "prettier --write {{file}}",
"includeContext": false,
"autonomyMode": "guided"
}
],
"extensionCommands": []
}

AI and Model Events​

ask-question​

Emitted when the AI needs to ask the user a question.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"text": "What framework would you like to use?",
"subject": "Framework Selection",
"isGroupQuestion": false,
"answers": [
{
"text": "React",
"shortkey": "r"
},
{
"text": "Vue",
"shortkey": "v"
}
],
"defaultAnswer": "React",
"internal": false,
"key": "framework-choice"
}

update-aider-models​

Emitted when AI model information is updated.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"mainModel": "gpt-4",
"weakModel": "gpt-3.5-turbo",
"architectModel": "gpt-4-turbo",
"reasoningEffort": "medium",
"thinkingTokens": "1000",
"editFormat": "diff",
"info": {
"max_input_tokens": 128000,
"max_output_tokens": 4096,
"input_cost_per_token": 0.000003,
"output_cost_per_token": 0.000015,
"supports_function_calling": true,
"supports_tool_choice": true,
"litellm_provider": "openai"
},
"error": "Optional error message"
}

Tool and Command Events​

tool​

Emitted during tool execution.

Data Structure:

{
"type": "tool",
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"id": "tool-execution-id",
"serverName": "server-name",
"toolName": "run_terminal_cmd",
"args": ["npm", "install"],
"response": "Installing dependencies...",
"usageReport": {
"model": "gpt-4",
"sentTokens": 50,
"receivedTokens": 25,
"messageCost": 0.001,
"cacheWriteTokens": 5,
"cacheReadTokens": 2,
"aiderTotalCost": 0.0008,
"agentTotalCost": 0.0002
},
"promptContext": {
"id": "context-uuid",
"group": {
"id": "group-uuid",
"name": "optional group name",
"color": "optional group color",
"finished": false
}
},
"timestamp": 1716123456789
}

command-output​

Emitted when a command is executed.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"command": "npm install",
"output": "Installing dependencies...\nDone.",
"timestamp": 1716123456789
}

terminal-data​

Emitted when terminal data is received.

Data Structure:

{
"terminalId": "term-123",
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"data": "npm install"
}

terminal-exit​

Emitted when a terminal process exits.

Data Structure:

{
"terminalId": "term-123",
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"exitCode": 0,
"signal": 15
}

System Events​

log​

Emitted for logging information.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"level": "info",
"message": "Project initialized successfully",
"finished": true,
"promptContext": {
"id": "context-uuid",
"group": {
"id": "group-uuid",
"name": "optional group name",
"color": "optional group color",
"finished": false
}
},
"timestamp": 1716123456789
}

update-autocompletion​

Emitted when autocompletion data is updated.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"words": [
"/api/",
"/src/",
"/tests/"
],
"allFiles": [
"src/main.ts",
"src/utils.ts"
],
"models": [
"gpt-4",
"gpt-3.5-turbo"
]
}

versions-info-updated​

Emitted when version information is updated.

Data Structure:

{
"aiderDeskCurrentVersion": "1.0.0",
"aiderCurrentVersion": "0.45.0",
"aiderDeskAvailableVersion": "1.1.0",
"aiderAvailableVersion": "0.46.0",
"aiderDeskDownloadProgress": 0.75,
"aiderDeskNewVersionReady": false,
"releaseNotes": "New features and bug fixes..."
}

Session and Message Events​

user-message​

Emitted when a user sends a message.

Data Structure:

{
"type": "user",
"id": "message-uuid",
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"content": "Implement user authentication",
"promptContext": {
"id": "context-uuid",
"group": {
"id": "group-uuid",
"name": "optional group name",
"color": "optional group color",
"finished": false
}
},
"timestamp": 1716123456789
}

input-history-updated​

Emitted when input history is updated.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"inputHistory": [
"Create login component",
"Add user validation",
"Implement authentication"
]
}

Project Management Events​

clear-task​

Emitted when a task is cleared.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"clearMessages": true,
"clearSession": false
}

project-started​

Emitted when a project is started.

Data Structure:

{
"baseDir": "/path/to/project"
}

Task Lifecycle Events​

task-created​

Emitted when a new task is created.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T00:00:00.000Z",
"aiderTotalCost": 0.0,
"agentTotalCost": 0.0
}

task-initialized​

Emitted when a task is initialized with context.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T00:00:00.000Z",
"aiderTotalCost": 0.0,
"agentTotalCost": 0.0
}

task-updated​

Emitted when task metadata is updated.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Updated Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T01:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T00:00:00.000Z",
"aiderTotalCost": 0.0,
"agentTotalCost": 0.0
}

task-started​

Emitted when a task is started.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T00:00:00.000Z",
"aiderTotalCost": 0.0,
"agentTotalCost": 0.0
}

task-completed​

Emitted when a task is completed.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T01:00:00.000Z",
"aiderTotalCost": 0.025,
"agentTotalCost": 0.005
}

task-cancelled​

Emitted when a task is cancelled.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T00:30:00.000Z",
"aiderTotalCost": 0.015,
"agentTotalCost": 0.003
}

task-deleted​

Emitted when a task is deleted.

Data Structure:

{
"id": "task-uuid",
"baseDir": "/path/to/project",
"name": "Task Name",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"startedAt": "2024-01-01T00:00:00.000Z",
"completedAt": "2024-01-01T00:00:00.000Z",
"aiderTotalCost": 0.0,
"agentTotalCost": 0.0
}

Settings and Provider Events​

settings-updated​

Emitted when application settings are updated.

Data Structure:

{
"onboardingFinished": true,
"language": "en",
"startupMode": "last",
"zoomLevel": 1.0,
"notificationsEnabled": true,
"theme": "dark",
"font": "Inter",
"fontSize": 14,
"renderMarkdown": true,
"virtualizedRendering": true,
"aiderDeskAutoUpdate": true,
"aider": {
"options": "--auto-commits",
"environmentVariables": "",
"addRuleFiles": true,
"autoCommits": true,
"cachingEnabled": true,
"watchFiles": true,
"confirmBeforeEdit": false
},
"preferredModels": ["gpt-4", "claude-3-sonnet"],
"agentProfiles": [],
"llmProviders": {},
"telemetryEnabled": true,
"telemetryInformed": true,
"promptBehavior": {
"suggestionMode": "automatically",
"suggestionDelay": 500,
"requireCommandConfirmation": {
"add": false,
"readOnly": false,
"model": true,
"modeSwitching": true
},
"useVimBindings": false
},
"server": {
"enabled": false,
"basicAuth": {
"enabled": false,
"username": "",
"password": ""
}
}
}

providers-updated​

Emitted when provider profiles are updated.

Data Structure:

{
"providers": [
{
"id": "openai-default",
"name": "OpenAI",
"provider": "openai",
"headers": {}
},
{
"id": "anthropic-default",
"name": "Anthropic",
"provider": "anthropic",
"headers": {}
}
]
}

provider-models-updated​

Emitted when provider models are updated.

Data Structure:

{
"models": [
{
"id": "gpt-4",
"providerId": "openai-default",
"maxInputTokens": 128000,
"maxOutputTokens": 4096,
"inputCostPerToken": 0.000003,
"outputCostPerToken": 0.000015,
"cacheWriteInputTokenCost": 0.00000375,
"cacheReadInputTokenCost": 0.000000375,
"supportsTools": true,
"isCustom": false,
"isHidden": false,
"hasModelOverrides": false,
"providerOverrides": {}
}
],
"loading": false,
"errors": {}
}

mcp-servers-updated​

Emitted when MCP server configurations change (added, updated, removed, or reloaded from file).

Data Structure:

{
"global": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
},
"projectServers": {
"/path/to/project": {}
}
}

extensions-updated​

Emitted when the extension set changes (extensions loaded, enabled, or disabled).

Data Structure:

{
"projectDir": "/path/to/project"
}

projectDir is optional; it scopes the event to a project when provided.

Token and Usage Events​

update-tokens-info​

Emitted when token usage information is updated.

Data Structure:

{
"baseDir": "/path/to/project",
"taskId": "task-uuid",
"chatHistory": {
"tokens": 500,
"tokensEstimated": false,
"cost": 0.01
},
"files": {
"src/main.ts": {
"tokens": 200,
"tokensEstimated": false,
"cost": 0.004
}
},
"repoMap": {
"tokens": 150,
"tokensEstimated": false,
"cost": 0.003
},
"systemMessages": {
"tokens": 100,
"tokensEstimated": false,
"cost": 0.002
},
"agent": {
"tokens": 300,
"tokensEstimated": false,
"cost": 0.006
}
}

Usage Examples​

Complete Client Implementation​

import io from 'socket.io-client';

class AiderDeskClient {
constructor(port = 24337) {
this.socket = io(`http://localhost:${port}`);
this.setupEventHandlers();
}

connect() {
this.socket.on('connect', () => {
console.log('Connected to AiderDesk');
this.subscribeToEvents([
'response-chunk',
'response-completed',
'log',
'context-files-updated',
'task-completed',
'settings-updated'
]);
});
}

subscribeToEvents(eventTypes) {
this.socket.emit('message', {
action: 'subscribe-events',
eventTypes: eventTypes
});
}

setupEventHandlers() {
// Handle response streaming
this.socket.on('response-chunk', (data) => {
console.log(`AI Response chunk for task ${data.taskId}:`, data.chunk);
process.stdout.write(data.chunk);
});

// Handle completion
this.socket.on('response-completed', (data) => {
console.log(`Response completed for task ${data.taskId} in ${data.baseDir}`);
if (data.usageReport) {
console.log(`Tokens: ${data.usageReport.sentTokens + data.usageReport.receivedTokens}, Cost: ${data.usageReport.messageCost}`);
}
});

// Handle context updates
this.socket.on('context-files-updated', (data) => {
console.log(`Context updated for task ${data.taskId} in ${data.baseDir}`);
console.log(`Files in context: ${data.files.length}`);
});

// Handle task lifecycle
this.socket.on('task-completed', (data) => {
console.log(`Task ${data.name} completed in ${data.baseDir}`);
console.log(`Total cost: ${data.aiderTotalCost + data.agentTotalCost}`);
});

// Handle settings updates
this.socket.on('settings-updated', (data) => {
console.log('Settings updated:', data);
});

// Handle logs
this.socket.on('log', (data) => {
console.log(`[${data.level.toUpperCase()}] ${data.baseDir} [${data.taskId}]: ${data.message}`);
});
}

disconnect() {
this.socket.disconnect();
}
}

// Usage
const client = new AiderDeskClient();
client.connect();

React Hook for Real-Time Updates​

import { useEffect, useState } from 'react';
import io from 'socket.io-client';

export function useAiderDeskEvents(projectDir, taskId = null, eventTypes = []) {
const [isConnected, setIsConnected] = useState(false);
const [events, setEvents] = useState([]);

useEffect(() => {
const socket = io('http://localhost:24337');

socket.on('connect', () => {
setIsConnected(true);
socket.emit('message', {
action: 'subscribe-events',
eventTypes: eventTypes
});
});

socket.on('disconnect', () => {
setIsConnected(false);
});

// Listen to all subscribed events
eventTypes.forEach(eventType => {
socket.on(eventType, (data) => {
// Filter by project directory
if (data.baseDir !== projectDir) {
return;
}

// Filter by task ID if specified
if (taskId && data.taskId && data.taskId !== taskId) {
return;
}

setEvents(prev => [...prev, { type: eventType, data, timestamp: Date.now() }]);
});
});

return () => {
socket.disconnect();
};
}, [projectDir, taskId, eventTypes]);

return { isConnected, events };
}

// Usage example
function TaskComponent({ projectDir, taskId }) {
const { isConnected, events } = useAiderDeskEvents(
projectDir,
taskId,
['response-chunk', 'response-completed', 'task-completed']
);

return (
<div>
<div>Connected: {isConnected ? 'Yes' : 'No'}</div>
<div>Events: {events.length}</div>
</div>
);
}

Task-Specific Event Filtering​

// Listen to events for a specific task
socket.on('connect', () => {
socket.emit('message', {
action: 'subscribe-events',
eventTypes: ['response-chunk', 'response-completed', 'tool', 'log']
});
});

// Filter events by task ID
socket.on('response-chunk', (data) => {
if (data.taskId === 'my-specific-task-id') {
console.log('Response for my task:', data.chunk);
}
});

socket.on('tool', (data) => {
if (data.taskId === 'my-specific-task-id') {
console.log(`Tool ${data.toolName} executed:`, data.response);
}
});

Error Handling​

Handle connection errors and disconnections gracefully:

socket.on('connect_error', (error) => {
console.error('SocketIO connection error:', error);
// Implement retry logic or show error message to user
});

socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason);
if (reason === 'io server disconnect') {
// Server disconnected, manual reconnection needed
socket.connect();
} else if (reason === 'ping timeout' || reason === 'transport close') {
// Network issues, socket will try to reconnect automatically
console.log('Network issue detected, attempting to reconnect...');
}
});

// Handle connection timeout
socket.on('connect_timeout', () => {
console.error('Connection timeout');
});

Best Practices​

  1. Event Filtering: Always filter events by baseDir and taskId to only process relevant updates
  2. Connection Management: Implement proper connection lifecycle management with reconnection logic
  3. Error Handling: Handle network errors and connection drops gracefully with user feedback
  4. Resource Cleanup: Always disconnect when the component/application unmounts
  5. Selective Subscriptions: Only subscribe to the events you need to minimize network traffic
  6. Task-Level Filtering: Use taskId filtering for granular event handling in multi-task scenarios
  7. Type Safety: Use TypeScript interfaces for event data structures when possible
  8. Event Ordering: Handle sequenceNumber in response events for proper message ordering
  9. Usage Tracking: Monitor usageReport data for cost tracking and optimization
  10. Context Awareness: Use promptContext to understand the context of events

Event Subscription Patterns​

Project-Level Events​

// Subscribe to project-wide events
socket.emit('message', {
action: 'subscribe-events',
eventTypes: ['project-started', 'settings-updated', 'providers-updated']
});

Task-Level Events​

// Subscribe to task-specific events
socket.emit('message', {
action: 'subscribe-events',
eventTypes: ['response-chunk', 'response-completed', 'tool', 'task-completed']
});

// Filter by taskId in event handlers
socket.on('response-chunk', (data) => {
if (data.taskId === currentTaskId) {
handleResponseChunk(data);
}
});

System-Level Events​

// Subscribe to system-wide events
socket.emit('message', {
action: 'subscribe-events',
eventTypes: ['versions-info-updated', 'log']
});