feat: Add intelligent auto-router and enhanced integrations

- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
admin
2026-01-28 00:27:56 +04:00
Unverified
parent 3b128ba3bd
commit b52318eeae
1724 changed files with 351216 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
{
"label": "API Reference",
"position": 3,
"link": {
"type": "generated-index",
"title": "Dexto API Reference",
"description": "Welcome to the Dexto API documentation. Here you will find detailed information about using Dexto as a Library, and about our REST and SSE streaming APIs. To use the REST or SSE API, you must first start the Dexto server by running the following command in your terminal:\n\n```bash\ndexto --mode server\n```\n\nBy default, the server will start on `http://localhost:3001`."
}
}

View File

@@ -0,0 +1,54 @@
---
slug: /
sidebar_position: 1
---
# Getting Started
Welcome to the Dexto API. This guide will walk you through the essential first steps to begin interacting with your Dexto agent programmatically.
## 1. Starting the API Server
Before you can make any API calls, you must start the Dexto server. This single command enables both the REST and SSE streaming APIs.
Run the following command in your terminal:
```bash
dexto --mode server
```
By default, the server will run on port `3001`. You should see a confirmation message in your terminal indicating that the server has started successfully.
**Customize the port:**
```bash
dexto --mode server --port 8080
```
This starts the API server on port 8080 instead of the default 3001.
## 2. Choosing Your API
Dexto offers two distinct APIs to suit different use cases. Understanding when to use each is key to building your application effectively.
### When to use the REST API?
Use the **REST API** for synchronous, request-response actions where you want to perform a task and get a result immediately. It's ideal for:
- Managing resources (e.g., listing or adding MCP servers).
- Retrieving configuration or session data.
- Triggering a single, non-streamed agent response.
**Base URL**: `http://localhost:3001`
### When to use Server-Sent Events (SSE)?
Use **Server-Sent Events (SSE)** for building interactive, real-time applications. It's the best choice for:
- Streaming agent responses (`chunk` events) as they are generated.
- Receiving real-time events from the agent's core, such as `toolCall` and `toolResult`.
- Creating chat-like user interfaces.
**Stream URL**: `http://localhost:3001/api/message-stream`
## 3. What's Next?
Now that your server is running and you know which API to use, you can dive into the specifics:
- Explore the **[REST API Reference](/api/rest)** - comprehensive documentation of all HTTP endpoints.
- Learn about the **[SDK Events Reference](/api/sdk/events)**.

View File

@@ -0,0 +1,9 @@
{
"label": "Dexto SDK",
"position": 4,
"link": {
"type": "generated-index",
"title": "Dexto SDK API Reference",
"description": "Complete technical API reference for the Dexto SDK for TypeScript/JavaScript."
}
}

View File

@@ -0,0 +1,324 @@
---
sidebar_position: 7
---
# AgentFactory API
The `AgentFactory` namespace provides static methods for agent creation, installation, and management. Use these functions to create agents from inline configs, install agents from the bundled registry, install custom agents, and manage installed agents.
```typescript
import { AgentFactory } from '@dexto/agent-management';
```
---
## createAgent
Creates a `DextoAgent` from an inline configuration object. Use this when you have a config from a database, API, or constructed programmatically and don't need a registry file.
```typescript
async function AgentFactory.createAgent(
config: AgentConfig,
options?: CreateAgentOptions
): Promise<DextoAgent>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `config` | `AgentConfig` | Agent configuration object |
| `options.agentId` | `string` | (Optional) Override agent ID (affects log/storage paths) |
| `options.isInteractiveCli` | `boolean` | (Optional) If true, disables console logging |
**Returns:** `Promise<DextoAgent>` - Agent instance (not started)
**Example:**
```typescript
import { AgentFactory } from '@dexto/agent-management';
// Create from inline config
const agent = await AgentFactory.createAgent({
llm: {
provider: 'openai',
model: 'gpt-4o',
apiKey: process.env.OPENAI_API_KEY
},
systemPrompt: 'You are a helpful assistant.'
});
await agent.start();
// With custom agent ID (affects log/storage paths)
const agent = await AgentFactory.createAgent(config, { agentId: 'my-custom-agent' });
// From database
const configFromDb = await db.getAgentConfig(userId);
const agent = await AgentFactory.createAgent(configFromDb, { agentId: `user-${userId}` });
await agent.start();
```
---
## listAgents
Lists all installed and available agents from the bundled registry.
```typescript
async function AgentFactory.listAgents(): Promise<{
installed: AgentInfo[];
available: AgentInfo[];
}>
```
**Returns:** Object with `installed` and `available` agent arrays
```typescript
interface AgentInfo {
id: string; // Unique identifier
name: string; // Display name
description: string; // What the agent does
author: string; // Creator
tags: string[]; // Categorization tags
type: 'builtin' | 'custom';
}
```
**Example:**
```typescript
import { AgentFactory } from '@dexto/agent-management';
const { installed, available } = await AgentFactory.listAgents();
console.log('Installed agents:');
installed.forEach(agent => {
console.log(` - ${agent.name} (${agent.id})`);
});
console.log('\nAvailable to install:');
available.forEach(agent => {
console.log(` - ${agent.name}: ${agent.description}`);
});
```
---
## installAgent
Installs an agent from the bundled registry to the local agents directory (`~/.dexto/agents/`).
```typescript
async function AgentFactory.installAgent(
agentId: string,
options?: InstallOptions
): Promise<string>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agentId` | `string` | Agent ID from bundled registry |
| `options.agentsDir` | `string` | (Optional) Custom agents directory |
**Returns:** `Promise<string>` - Path to installed agent's main config file
**Throws:** `DextoRuntimeError` if agent not found or installation fails
**Example:**
```typescript
import { AgentFactory } from '@dexto/agent-management';
// Install a bundled agent
const configPath = await AgentFactory.installAgent('coding-agent');
console.log(`Installed to: ${configPath}`);
```
### What Happens During Installation
1. Agent files are copied from bundled location to `~/.dexto/agents/{agentId}/`
2. Agent is added to the user's registry (`~/.dexto/agents/registry.json`)
3. User preferences are applied at runtime for the bundled coding-agent only
---
## installCustomAgent
Installs a custom agent from a local file or directory path.
```typescript
async function AgentFactory.installCustomAgent(
agentId: string,
sourcePath: string,
metadata: {
name?: string;
description: string;
author: string;
tags: string[];
},
options?: InstallOptions
): Promise<string>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agentId` | `string` | Unique ID for the custom agent |
| `sourcePath` | `string` | Absolute path to agent YAML file or directory |
| `metadata.name` | `string` | (Optional) Display name (defaults to agentId) |
| `metadata.description` | `string` | Description of what the agent does |
| `metadata.author` | `string` | Creator of the agent |
| `metadata.tags` | `string[]` | Categorization tags |
| `options.agentsDir` | `string` | (Optional) Custom agents directory |
**Returns:** `Promise<string>` - Path to installed agent's main config file
**Throws:**
- `DextoRuntimeError` if agent ID conflicts with bundled agent
- `DextoRuntimeError` if agent ID already exists
- `DextoRuntimeError` if source path doesn't exist
**Example:**
```typescript
import { AgentFactory } from '@dexto/agent-management';
// Install from a single YAML file
const configPath = await AgentFactory.installCustomAgent(
'my-support-agent',
'/path/to/support-agent.yml',
{
description: 'Custom support agent for our product',
author: 'My Team',
tags: ['support', 'custom']
}
);
// Install from a directory (for agents with multiple files)
const configPath = await AgentFactory.installCustomAgent(
'my-complex-agent',
'/path/to/agent-directory/',
{
name: 'Complex Agent',
description: 'Agent with knowledge files and multiple configs',
author: 'My Team',
tags: ['complex', 'custom']
}
);
```
### Directory Structure for Multi-File Agents
When installing from a directory:
```
my-agent/
├── agent.yml # Main config (required, or specify custom name)
├── knowledge/
│ ├── docs.md
│ └── faq.md
└── prompts/
└── system.txt
```
---
## uninstallAgent
Removes an installed agent from disk and the user registry.
```typescript
async function AgentFactory.uninstallAgent(agentId: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agentId` | `string` | Agent ID to uninstall |
**Throws:** `DextoRuntimeError` if agent is not installed
**Example:**
```typescript
import { AgentFactory } from '@dexto/agent-management';
// Uninstall an agent
await AgentFactory.uninstallAgent('my-custom-agent');
console.log('Agent uninstalled');
```
### What Happens During Uninstallation
1. Agent directory is removed from `~/.dexto/agents/{agentId}/`
2. Agent entry is removed from user registry (`~/.dexto/agents/registry.json`)
:::caution
Uninstallation is permanent. All agent files including conversation history (if stored locally) will be deleted.
:::
---
## InstallOptions
Options for installation functions:
```typescript
interface InstallOptions {
/** Directory where agents are stored (default: ~/.dexto/agents) */
agentsDir?: string;
}
```
---
## Complete Example
```typescript
import { AgentFactory } from '@dexto/agent-management';
import { AgentManager } from '@dexto/agent-management';
async function setupAgents() {
// List what's available
const { installed, available } = await AgentFactory.listAgents();
console.log(`${installed.length} installed, ${available.length} available`);
// Install a bundled agent if not already installed
if (!installed.some(a => a.id === 'coding-agent')) {
await AgentFactory.installAgent('coding-agent');
console.log('Installed coding-agent');
}
// Install a custom agent
await AgentFactory.installCustomAgent(
'team-agent',
'./my-agents/team-agent.yml',
{
description: 'Our team\'s custom agent',
author: 'Engineering Team',
tags: ['internal', 'custom']
}
);
// Now use AgentManager to work with installed agents
const manager = new AgentManager('~/.dexto/agents/registry.json');
await manager.loadRegistry();
const agent = await manager.loadAgent('team-agent');
await agent.start();
// ... use the agent ...
await agent.stop();
}
```
---
## File Locations
| Resource | Path |
| :--- | :--- |
| Agents directory | `~/.dexto/agents/` |
| User registry | `~/.dexto/agents/registry.json` |
| Per-agent configs | `~/.dexto/agents/{agentId}/` |
| Bundled registry | Bundled with `@dexto/agent-management` package |
---
## See Also
- [AgentManager API](./agent-manager.md) - Registry-based agent lifecycle management
- [Config Utilities](./config-utilities.md) - Lower-level config loading functions
- [Agent Orchestration Tutorial](/docs/tutorials/sdk/orchestration) - Step-by-step guide

View File

@@ -0,0 +1,263 @@
---
sidebar_position: 5
---
# AgentManager API
The `AgentManager` class provides registry-based agent lifecycle management. It loads agent configurations from a registry file and creates agent instances programmatically.
```typescript
import { AgentManager } from '@dexto/agent-management';
```
:::note When to use AgentManager
**`AgentManager`** - Registry-based. Use when you have a `registry.json` with multiple predefined agents.
:::
---
## Constructor
### `constructor`
Creates a new AgentManager instance pointing to a registry file.
```typescript
constructor(registryPath: string)
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `registryPath` | `string` | Path to registry.json file (absolute or relative) |
**Example:**
```typescript
// Project-local registry
const manager = new AgentManager('./agents/registry.json');
// Absolute path
const manager = new AgentManager('/path/to/registry.json');
```
---
## Methods
### `loadRegistry`
Loads the registry from file. Must be called before using sync methods like `listAgents()` or `hasAgent()`.
```typescript
async loadRegistry(): Promise<Registry>
```
**Returns:** `Promise<Registry>` - The loaded registry object
**Example:**
```typescript
const manager = new AgentManager('./registry.json');
await manager.loadRegistry();
// Now sync methods work
const agents = manager.listAgents();
```
:::note
`loadAgent()` automatically calls `loadRegistry()` if not already loaded.
:::
---
### `listAgents`
Returns metadata for all agents in the registry.
```typescript
listAgents(): AgentMetadata[]
```
**Returns:** `AgentMetadata[]` - Array of agent metadata objects
```typescript
interface AgentMetadata {
id: string; // Unique identifier
name: string; // Display name
description: string; // What the agent does
author?: string; // Creator
tags?: string[]; // Categorization tags
}
```
**Example:**
```typescript
const manager = new AgentManager('./registry.json');
await manager.loadRegistry();
const agents = manager.listAgents();
console.log(agents);
// [
// { id: 'coding-agent', name: 'Coding Assistant', description: '...', tags: ['coding'] },
// { id: 'support-agent', name: 'Support Assistant', description: '...', tags: ['support'] }
// ]
// Filter by tag
const codingAgents = agents.filter(a => a.tags?.includes('coding'));
```
---
### `hasAgent`
Checks if an agent exists in the registry.
```typescript
hasAgent(id: string): boolean
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `id` | `string` | Agent ID to check |
**Returns:** `boolean` - True if agent exists
**Example:**
```typescript
const manager = new AgentManager('./registry.json');
await manager.loadRegistry();
if (manager.hasAgent('coding-agent')) {
const agent = await manager.loadAgent('coding-agent');
}
```
---
### `loadAgent`
Loads a `DextoAgent` instance from the registry. Loads the agent's YAML config, enriches it with runtime paths, and returns an unstarted agent.
```typescript
async loadAgent(id: string): Promise<DextoAgent>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `id` | `string` | Agent ID from registry |
**Returns:** `Promise<DextoAgent>` - Agent instance (not started)
**Throws:**
- `DextoRuntimeError` if agent not found or config loading fails
- `DextoValidationError` if agent config validation fails
**Example:**
```typescript
const manager = new AgentManager('./registry.json');
const agent = await manager.loadAgent('coding-agent');
await agent.start();
// Use the agent
const session = await agent.createSession();
const response = await agent.generate('Write a function to reverse a string', session.id);
console.log(response.content);
await agent.stop();
```
---
## Registry Format
The registry file is a JSON file that describes available agents:
```json
{
"agents": [
{
"id": "coding-agent",
"name": "Coding Assistant",
"description": "Expert coding assistant for development tasks",
"configPath": "./coding-agent.yml",
"author": "Your Team",
"tags": ["coding", "development"]
},
{
"id": "support-agent",
"name": "Support Assistant",
"description": "Friendly customer support agent",
"configPath": "./support-agent.yml",
"tags": ["support", "customer-service"]
}
]
}
```
| Field | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `id` | `string` | Yes | Unique identifier (used in `loadAgent()`) |
| `name` | `string` | Yes | Human-readable display name |
| `description` | `string` | Yes | What this agent does |
| `configPath` | `string` | Yes | Path to YAML config (relative to registry.json) |
| `author` | `string` | No | Creator of the agent |
| `tags` | `string[]` | No | Categorization tags |
---
## Complete Example
```typescript
import { AgentManager } from '@dexto/agent-management';
async function main() {
// Initialize manager
const manager = new AgentManager('./agents/registry.json');
await manager.loadRegistry();
// List available agents
console.log('Available agents:');
for (const agent of manager.listAgents()) {
console.log(` - ${agent.name} (${agent.id}): ${agent.description}`);
}
// Create and use an agent
if (manager.hasAgent('coding-agent')) {
const agent = await manager.loadAgent('coding-agent');
await agent.start();
const session = await agent.createSession();
const response = await agent.generate('Hello!', session.id);
console.log(response.content);
await agent.stop();
}
}
main();
```
---
## Error Handling
```typescript
import { AgentManager } from '@dexto/agent-management';
try {
const manager = new AgentManager('./registry.json');
const agent = await manager.loadAgent('non-existent-agent');
} catch (error) {
if (error.code === 'AGENT_NOT_FOUND') {
console.log('Agent not found in registry');
} else if (error.name === 'DextoValidationError') {
console.log('Agent config validation failed:', error.issues);
}
}
```
---
## See Also
- [Config Utilities](./config-utilities.md) - Lower-level config loading functions
- [AgentFactory API](./agent-factory.md) - Agent installation and management
- [Agent Orchestration Tutorial](/docs/tutorials/sdk/orchestration) - Step-by-step guide

View File

@@ -0,0 +1,209 @@
---
sidebar_position: 6
---
# Config Utilities
Utilities for loading and enriching agent configurations from YAML files. These functions are the building blocks for programmatic agent management.
```typescript
import { loadAgentConfig, enrichAgentConfig } from '@dexto/agent-management';
```
---
## loadAgentConfig
Loads and processes an agent configuration from a YAML file. Handles file reading, YAML parsing, and template variable expansion.
```typescript
async function loadAgentConfig(
configPath: string,
logger?: IDextoLogger
): Promise<AgentConfig>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `configPath` | `string` | Path to the YAML config file (absolute or relative) |
| `logger` | `IDextoLogger` | (Optional) Logger instance for debug output |
**Returns:** `Promise<AgentConfig>` - Parsed configuration object
**Throws:**
- `ConfigError` with `FILE_NOT_FOUND` if file doesn't exist
- `ConfigError` with `FILE_READ_ERROR` if file read fails
- `ConfigError` with `PARSE_ERROR` if YAML is invalid
### What It Does
1. **Reads the YAML file** from disk
2. **Parses YAML** into a JavaScript object
3. **Expands template variables** like `${{dexto.agent_dir}}`
4. **Expands environment variables** like `$OPENAI_API_KEY`
### Example
```typescript
import { loadAgentConfig } from '@dexto/agent-management';
// Load a config file
const config = await loadAgentConfig('./agents/my-agent.yml');
console.log(config.llm.provider); // 'openai'
console.log(config.llm.model); // 'gpt-4o'
```
### Template Variables
Config files can use template variables that are expanded at load time:
```yaml
# my-agent.yml
systemPrompt:
contributors:
- id: knowledge
type: file
files:
- ${{dexto.agent_dir}}/knowledge/docs.md
```
| Variable | Expands To |
| :--- | :--- |
| `${{dexto.agent_dir}}` | Directory containing the config file |
### Environment Variables
Environment variables are expanded during schema validation:
```yaml
llm:
provider: openai
model: gpt-4o
apiKey: $OPENAI_API_KEY # Expanded from environment
```
---
## enrichAgentConfig
Enriches a loaded configuration with per-agent runtime paths for logs, database, and blob storage. This function should be called after `loadAgentConfig` and before creating a `DextoAgent`.
```typescript
function enrichAgentConfig(
config: AgentConfig,
configPath?: string,
isInteractiveCli?: boolean
): AgentConfig
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `config` | `AgentConfig` | Configuration from `loadAgentConfig` |
| `configPath` | `string` | (Optional) Path to config file (used for agent ID derivation) |
| `isInteractiveCli` | `boolean` | (Optional) If true, disables console logging (default: false) |
**Returns:** `AgentConfig` - Enriched configuration with explicit paths
### What It Adds
Each agent gets isolated paths based on its ID:
| Resource | Path |
| :--- | :--- |
| Logs | `~/.dexto/agents/{agentId}/logs/{agentId}.log` |
| Database | `~/.dexto/agents/{agentId}/db/{agentId}.db` |
| Blob Storage | `~/.dexto/agents/{agentId}/blobs/` |
### Agent ID Derivation
The agent ID is derived in priority order:
1. `agentCard.name` from config (sanitized)
2. Config filename (without extension)
3. Fallback: `coding-agent`
### Example
```typescript
import { loadAgentConfig, enrichAgentConfig } from '@dexto/agent-management';
import { DextoAgent } from '@dexto/core';
// Load raw config
const config = await loadAgentConfig('./agents/coding-agent.yml');
// Enrich with runtime paths
const enrichedConfig = enrichAgentConfig(config, './agents/coding-agent.yml');
// Create agent with enriched config
const agent = new DextoAgent(enrichedConfig, './agents/coding-agent.yml');
await agent.start();
```
### Default Storage Configuration
If no storage is specified in the config, enrichment adds:
```typescript
{
storage: {
cache: { type: 'in-memory' },
database: { type: 'sqlite', path: '~/.dexto/agents/{agentId}/db/{agentId}.db' },
blob: { type: 'local', storePath: '~/.dexto/agents/{agentId}/blobs/' }
}
}
```
---
## Complete Usage Pattern
```typescript
import { loadAgentConfig, enrichAgentConfig } from '@dexto/agent-management';
import { DextoAgent } from '@dexto/core';
async function createAgentFromConfig(configPath: string): Promise<DextoAgent> {
// 1. Load the YAML config
const config = await loadAgentConfig(configPath);
// 2. Enrich with runtime paths
const enrichedConfig = enrichAgentConfig(config, configPath);
// 3. Create and start the agent
const agent = new DextoAgent(enrichedConfig, configPath);
await agent.start();
return agent;
}
// Usage
const agent = await createAgentFromConfig('./agents/my-agent.yml');
const session = await agent.createSession();
const response = await agent.generate('Hello!', session.id);
```
---
## Error Handling
```typescript
import { loadAgentConfig, enrichAgentConfig } from '@dexto/agent-management';
try {
const config = await loadAgentConfig('./agents/my-agent.yml');
const enriched = enrichAgentConfig(config, './agents/my-agent.yml');
} catch (error) {
if (error.code === 'FILE_NOT_FOUND') {
console.error('Config file not found:', error.path);
} else if (error.code === 'PARSE_ERROR') {
console.error('Invalid YAML:', error.message);
}
}
```
---
## See Also
- [AgentManager API](./agent-manager.md) - Higher-level registry-based management
- [AgentFactory API](./agent-factory.md) - Agent installation functions
- [Loading Agent Configs Tutorial](/docs/tutorials/sdk/config-files) - Step-by-step guide

View File

@@ -0,0 +1,596 @@
---
sidebar_position: 1
---
# DextoAgent API
Complete API reference for the main `DextoAgent` class. This is the core interface for the Dexto Agent SDK.
## Constructor and Lifecycle
### `constructor`
Creates a new Dexto agent instance with the provided configuration.
```typescript
constructor(config: AgentConfig)
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `config` | `AgentConfig` | Agent configuration object |
### `start`
Initializes and starts the agent with all required services.
```typescript
async start(): Promise<void>
```
**Parameters:** None
**Example:**
```typescript
const agent = new DextoAgent(config);
await agent.start();
```
### `stop`
Stops the agent and cleans up all resources.
```typescript
async stop(): Promise<void>
```
**Example:**
```typescript
await agent.stop();
```
---
## Core Methods
The Dexto Agent SDK provides three methods for processing messages:
- **`generate()`** - Recommended for most use cases. Returns a complete response.
- **`stream()`** - For real-time streaming UIs. Yields events as they arrive.
- **`run()`** - Lower-level method for direct control.
### `generate`
**Recommended method** for processing user input. Waits for complete response.
```typescript
async generate(
content: ContentInput,
sessionId: string,
options?: GenerateOptions
): Promise<GenerateResponse>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `content` | `string \| ContentPart[]` | User message (string) or multimodal content (array) |
| `sessionId` | `string` | **Required.** Session ID for the conversation |
| `options.signal` | `AbortSignal` | (Optional) For cancellation |
**Content Types:**
```typescript
// Simple string content
type ContentInput = string | ContentPart[];
// For multimodal content, use ContentPart array:
type ContentPart = TextPart | ImagePart | FilePart;
interface TextPart { type: 'text'; text: string; }
interface ImagePart { type: 'image'; image: string; mimeType?: string; }
interface FilePart { type: 'file'; data: string; mimeType: string; filename?: string; }
```
**Returns:** `Promise<GenerateResponse>`
```typescript
interface GenerateResponse {
content: string; // The AI's text response
reasoning?: string; // Extended thinking (o1/o3 models)
usage: TokenUsage; // Token usage statistics
toolCalls: AgentToolCall[]; // Tools that were called
sessionId: string;
messageId: string;
}
```
**Example:**
```typescript
const agent = new DextoAgent(config);
await agent.start();
const session = await agent.createSession();
// Simple text message
const response = await agent.generate('What is 2+2?', session.id);
console.log(response.content); // "4"
console.log(response.usage.totalTokens); // Token count
// With image URL (auto-detected)
const response = await agent.generate([
{ type: 'text', text: 'Describe this image' },
{ type: 'image', image: 'https://example.com/photo.jpg' }
], session.id);
// With image base64
const response = await agent.generate([
{ type: 'text', text: 'Describe this image' },
{ type: 'image', image: base64Image, mimeType: 'image/png' }
], session.id);
// With file URL
const response = await agent.generate([
{ type: 'text', text: 'Summarize this document' },
{ type: 'file', data: 'https://example.com/doc.pdf', mimeType: 'application/pdf' }
], session.id);
// With file base64
const response = await agent.generate([
{ type: 'text', text: 'Summarize this document' },
{ type: 'file', data: base64Pdf, mimeType: 'application/pdf', filename: 'doc.pdf' }
], session.id);
// With cancellation support
const controller = new AbortController();
const response = await agent.generate('Long task...', session.id, { signal: controller.signal });
await agent.stop();
```
### `stream`
For real-time streaming UIs. Yields events as they arrive.
```typescript
async stream(
content: ContentInput,
sessionId: string,
options?: StreamOptions
): Promise<AsyncIterableIterator<StreamingEvent>>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `content` | `string \| ContentPart[]` | User message (string) or multimodal content (array) |
| `sessionId` | `string` | **Required.** Session ID |
| `options.signal` | `AbortSignal` | (Optional) For cancellation |
**Returns:** `Promise<AsyncIterableIterator<StreamingEvent>>`
**Example:**
```typescript
const session = await agent.createSession();
// Simple text streaming
for await (const event of await agent.stream('Write a poem', session.id)) {
if (event.name === 'llm:chunk') {
process.stdout.write(event.content);
}
if (event.name === 'llm:tool-call') {
console.log(`\n[Using ${event.toolName}]\n`);
}
}
// Streaming with image
for await (const event of await agent.stream([
{ type: 'text', text: 'Describe this image' },
{ type: 'image', image: base64Image, mimeType: 'image/png' }
], session.id)) {
if (event.name === 'llm:chunk') {
process.stdout.write(event.content);
}
}
```
### `run`
Lower-level method for direct control. Prefer `generate()` for most use cases.
```typescript
async run(
textInput: string,
imageDataInput: { image: string; mimeType: string } | undefined,
fileDataInput: { data: string; mimeType: string; filename?: string } | undefined,
sessionId: string,
stream?: boolean
): Promise<string>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `textInput` | `string` | User message or query |
| `imageDataInput` | `{ image: string; mimeType: string } \| undefined` | Image data or undefined |
| `fileDataInput` | `{ data: string; mimeType: string; filename?: string } \| undefined` | File data or undefined |
| `sessionId` | `string` | **Required.** Session ID |
| `stream` | `boolean` | (Optional) Enable streaming (default: false) |
**Returns:** `Promise<string>` - AI response text
**Example:**
```typescript
const agent = new DextoAgent(config);
await agent.start();
const session = await agent.createSession();
// Recommended: Use generate() for most use cases
const response = await agent.generate(
"Explain quantum computing",
session.id
);
console.log(response.content);
// Lower-level run() method (returns just the text)
const responseText = await agent.run(
"Explain quantum computing",
undefined, // no image
undefined, // no file
session.id
);
await agent.stop();
```
### `cancel`
Cancels the currently running turn for a session.
```typescript
async cancel(sessionId: string): Promise<boolean>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | **Required.** Session ID to cancel |
**Returns:** `Promise<boolean>` - true if a run was in progress and cancelled
---
## Session Management
:::note Architectural Pattern
DextoAgent's core is **stateless** and does not track a "current" or "default" session. All session-specific operations require an explicit `sessionId` parameter. Application layers (CLI, WebUI, API servers) are responsible for managing which session is active in their own context.
:::
### `createSession`
Creates a new conversation session with optional custom ID.
```typescript
async createSession(sessionId?: string): Promise<ChatSession>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | (Optional) Custom session ID |
**Returns:** `Promise<ChatSession>`
**Example:**
```typescript
// Create a new session (auto-generated ID)
const session = await agent.createSession();
console.log(`Created session: ${session.id}`);
// Create a session with custom ID
const userSession = await agent.createSession('user-123');
// Use the session for conversations
await agent.generate("Hello!", session.id);
```
### `getSession`
Retrieves an existing session by its ID.
```typescript
async getSession(sessionId: string): Promise<ChatSession | undefined>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | Session ID to retrieve |
**Returns:** `Promise<ChatSession | undefined>`
### `listSessions`
Returns an array of all active session IDs.
```typescript
async listSessions(): Promise<string[]>
```
**Returns:** `Promise<string[]>` - Array of session IDs
### `deleteSession`
Permanently deletes a session and all its conversation history. This action cannot be undone.
```typescript
async deleteSession(sessionId: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | Session ID to delete |
**Note:** This completely removes the session and all associated conversation data from storage.
### `resetConversation`
Clears the conversation history of a session while keeping the session active.
```typescript
async resetConversation(sessionId: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | Session ID to reset |
### `getSessionMetadata`
Retrieves metadata for a session including creation time and message count.
```typescript
async getSessionMetadata(sessionId: string): Promise<SessionMetadata | undefined>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | Session ID |
**Returns:** `Promise<SessionMetadata | undefined>`
### `getSessionHistory`
Gets the complete conversation history for a session.
```typescript
async getSessionHistory(sessionId: string): Promise<ConversationHistory>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | Session ID |
**Returns:** `Promise<ConversationHistory>`
---
## Configuration
### `switchLLM`
Dynamically changes the LLM configuration for the agent or a specific session.
```typescript
async switchLLM(
llmUpdates: LLMUpdates,
sessionId?: string
): Promise<ValidatedLLMConfig>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `llmUpdates` | `LLMUpdates` | LLM configuration updates (model, provider, apiKey, etc.) |
| `sessionId` | `string` | (Optional) Target session ID |
**Returns:** `Promise<ValidatedLLMConfig>` the fully validated, effective LLM configuration.
```typescript
const config = await agent.switchLLM({
provider: 'anthropic',
model: 'claude-sonnet-4-5-20250929'
});
console.log(config.model);
```
### `getCurrentLLMConfig`
Returns the base LLM configuration from the agent's initialization config.
```typescript
getCurrentLLMConfig(): LLMConfig
```
**Returns:** `LLMConfig` - The base LLM configuration (does not include session-specific overrides)
### `getEffectiveConfig`
Gets the complete effective configuration for a session or the default configuration.
```typescript
getEffectiveConfig(sessionId?: string): Readonly<AgentConfig>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `sessionId` | `string` | (Optional) Session ID |
**Returns:** `Readonly<AgentConfig>`
---
## MCP Server Management
### `addMcpServer`
Adds and connects to a new MCP server, making its tools available to the agent.
```typescript
async addMcpServer(name: string, config: McpServerConfig): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `name` | `string` | Server name |
| `config` | `McpServerConfig` | Server configuration |
### `removeMcpServer`
Disconnects from an MCP server and removes it completely from the agent.
```typescript
async removeMcpServer(name: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `name` | `string` | Server name to remove |
### `enableMcpServer`
Enables a disabled MCP server and connects it.
```typescript
async enableMcpServer(name: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `name` | `string` | Server name to enable |
### `disableMcpServer`
Disables an MCP server and disconnects it. The server remains registered but inactive.
```typescript
async disableMcpServer(name: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `name` | `string` | Server name to disable |
### `restartMcpServer`
Restarts an MCP server by disconnecting and reconnecting with its original configuration.
```typescript
async restartMcpServer(name: string): Promise<void>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `name` | `string` | Server name to restart |
### `executeTool`
Executes a tool from any source (MCP servers, custom tools, or internal tools). This is the unified interface for tool execution.
```typescript
async executeTool(toolName: string, args: any): Promise<any>
```
| Parameter | Type | Description |
| :--- | :--- | :--- |
| `toolName` | `string` | Tool name |
| `args` | `any` | Tool arguments |
**Returns:** `Promise<any>` - Tool execution result
### `getAllMcpTools`
Returns a map of all available tools from all connected MCP servers.
```typescript
async getAllMcpTools(): Promise<Record<string, ToolDefinition>>
```
**Returns:** `Promise<Record<string, ToolDefinition>>`
### `getAllTools`
Returns a map of all available tools from all sources (MCP servers, custom tools, and internal tools). This is the unified interface for tool discovery.
```typescript
async getAllTools(): Promise<Record<string, ToolDefinition>>
```
**Returns:** `Promise<Record<string, ToolDefinition>>`
### `getMcpClients`
Returns a map of all connected MCP client instances.
```typescript
getMcpClients(): Map<string, IMCPClient>
```
**Returns:** `Map<string, IMCPClient>`
### `getMcpFailedConnections`
Returns a record of failed MCP server connections and their error messages.
```typescript
getMcpFailedConnections(): Record<string, string>
```
**Returns:** `Record<string, string>` - Failed connection names to error messages
---
## Model & Provider Introspection
### `getSupportedProviders`
Returns the list of supported LLM providers.
```typescript
getSupportedProviders(): LLMProvider[]
```
### `getSupportedModels`
Returns supported models grouped by provider, including a flag for the default model per provider.
```typescript
getSupportedModels(): Record<LLMProvider, Array<ModelInfo & { isDefault: boolean }>>
```
### `getSupportedModelsForProvider`
Returns supported models for a specific provider.
```typescript
getSupportedModelsForProvider(provider: LLMProvider): Array<ModelInfo & { isDefault: boolean }>
```
### `inferProviderFromModel`
Infers the provider from a model name or returns `null` if unknown.
```typescript
inferProviderFromModel(modelName: string): LLMProvider | null
```
---
## Search
### `searchMessages`
Search for messages across all sessions or within a specific session.
```typescript
async searchMessages(query: string, options?: SearchOptions): Promise<SearchResponse>
```
### `searchSessions`
Search for sessions that contain the specified query.
```typescript
async searchSessions(query: string): Promise<SessionSearchResponse>
```

View File

@@ -0,0 +1,658 @@
---
sidebar_position: 3
---
# Events Reference
Complete event system documentation for monitoring and integrating with Dexto agents.
## Overview
The Dexto SDK provides a comprehensive event system through two main event buses:
- **AgentEventBus**: Agent-level events that occur across the entire agent instance
- **SessionEventBus**: Session-specific events that occur within individual conversation sessions
### Event Naming Convention
All events follow the `namespace:kebab-case` format:
- **LLM events**: `llm:thinking`, `llm:chunk`, `llm:response`, `llm:tool-call`
- **Session events**: `session:created`, `session:reset`, `session:title-updated`
- **MCP events**: `mcp:server-connected`, `mcp:resource-updated`
- **Approval events**: `approval:request`, `approval:response`
- **State events**: `state:changed`, `state:exported`
- **Tool events**: `tools:available-updated`
### Event Visibility Tiers
Events are organized into three tiers based on their intended audience:
#### **Tier 1: Streaming Events** (`STREAMING_EVENTS`)
Exposed via `DextoAgent.stream()` for real-time chat UIs. These are the most commonly used events for building interactive applications.
**LLM Events:** `llm:thinking`, `llm:chunk`, `llm:response`, `llm:tool-call`, `llm:tool-result`, `llm:error`, `llm:unsupported-input`
**Tool Events:** `tool:running`
**Context Events:** `context:compressed`, `context:pruned`
**Message Queue Events:** `message:queued`, `message:dequeued`
**Run Lifecycle Events:** `run:complete`
**Session Events:** `session:title-updated`
**Approval Events:** `approval:request`, `approval:response`
**Use cases:**
- Real-time chat interfaces
- Progress indicators
- Streaming responses
- Tool execution tracking
- User approval flows
#### **Tier 2: Integration Events** (`INTEGRATION_EVENTS`)
Exposed via webhooks, A2A subscriptions, and monitoring systems. Includes all streaming events plus lifecycle and state management events.
**Additional events:** `session:created`, `session:reset`, `mcp:server-connected`, `mcp:server-restarted`, `mcp:tools-list-changed`, `mcp:prompts-list-changed`, `tools:available-updated`, `llm:switched`, `state:changed`
**Use cases:**
- External system integrations
- Monitoring and observability
- Analytics and logging
- Multi-agent coordination (A2A)
#### **Tier 3: Internal Events**
Only available via direct `AgentEventBus` access for advanced use cases. These are implementation details that may change between versions.
**Examples:** `resource:cache-invalidated`, `state:exported`, `state:reset`, `mcp:server-added`, `mcp:server-removed`, `session:override-set`
---
## Agent-Level Events
These events are emitted by the `AgentEventBus` and provide insight into agent-wide operations.
### Session Events
#### `session:reset`
Fired when a conversation history is reset for a session.
```typescript
{
sessionId: string;
}
```
#### `session:created`
Fired when a new session is created and should become active.
```typescript
{
sessionId: string;
switchTo: boolean; // Whether UI should switch to this session
}
```
#### `session:title-updated`
Fired when a session's human-friendly title is updated.
```typescript
{
sessionId: string;
title: string;
}
```
#### `session:override-set`
Fired when session-specific configuration is set.
```typescript
{
sessionId: string;
override: SessionOverride;
}
```
#### `session:override-cleared`
Fired when session-specific configuration is cleared.
```typescript
{
sessionId: string;
}
```
### MCP Server Events
#### `mcp:server-connected`
Fired when an MCP server connection attempt completes (success or failure).
```typescript
{
name: string;
success: boolean;
error?: string;
}
```
#### `mcp:server-added`
Fired when an MCP server is added to the runtime state.
```typescript
{
serverName: string;
config: McpServerConfig;
}
```
#### `mcp:server-removed`
Fired when an MCP server is removed from the runtime state.
```typescript
{
serverName: string;
}
```
#### `mcp:server-updated`
Fired when an MCP server configuration is updated.
```typescript
{
serverName: string;
config: McpServerConfig;
}
```
#### `mcp:server-restarted`
Fired when an MCP server is restarted.
```typescript
{
serverName: string;
}
```
#### `mcp:resource-updated`
Fired when an MCP server resource is updated.
```typescript
{
serverName: string;
resourceUri: string;
}
```
#### `mcp:prompts-list-changed`
Fired when available prompts from MCP servers change.
```typescript
{
serverName: string;
prompts: string[];
}
```
#### `mcp:tools-list-changed`
Fired when available tools from MCP servers change.
```typescript
{
serverName: string;
tools: string[];
}
```
#### `resource:cache-invalidated`
Fired when resource cache is invalidated.
```typescript
{
resourceUri?: string;
serverName: string;
action: 'updated' | 'server_connected' | 'server_removed' | 'blob_stored';
}
```
#### `tools:available-updated`
Fired when the available tools list is updated.
```typescript
{
tools: string[];
source: 'mcp' | 'builtin';
}
```
### Configuration Events
#### `llm:switched`
Fired when the LLM configuration is changed.
```typescript
{
newConfig: LLMConfig;
historyRetained?: boolean;
sessionIds: string[]; // Array of affected session IDs
}
```
#### `state:changed`
Fired when agent runtime state changes.
```typescript
{
field: string; // keyof AgentRuntimeState
oldValue: any;
newValue: any;
sessionId?: string;
}
```
#### `state:exported`
Fired when agent state is exported as configuration.
```typescript
{
config: AgentConfig;
}
```
#### `state:reset`
Fired when agent state is reset to baseline.
```typescript
{
toConfig: AgentConfig;
}
```
### User Approval Events
Dexto's generalized approval system handles various types of user input requests, including tool confirmations and form-based input (elicitation). These events are included in `STREAMING_EVENTS` and are available via `DextoAgent.stream()`.
:::tip Custom Approval Handlers
For direct `DextoAgent` usage without SSE streaming, you can implement a custom approval handler via `agent.setApprovalHandler()` to intercept approval requests programmatically.
:::
#### `approval:request`
Fired when user approval or input is requested. This event supports multiple approval types through a discriminated union based on the `type` field.
```typescript
{
approvalId: string; // Unique identifier for this approval request
type: string; // 'tool_confirmation' | 'command_confirmation' | 'elicitation'
sessionId?: string; // Optional session scope
timeout?: number; // Request timeout in milliseconds
timestamp: Date; // When the request was created
metadata: Record<string, any>; // Type-specific approval data
}
```
**Approval Types:**
- **`tool_confirmation`**: Binary approval for tool execution
- `metadata.toolName`: Name of the tool requiring confirmation
- `metadata.args`: Tool arguments
- `metadata.description`: Optional tool description
- **`command_confirmation`**: Binary approval for command execution (e.g., bash commands)
- `metadata.command`: Command requiring confirmation
- `metadata.args`: Command arguments
- **`elicitation`**: Schema-based form input (typically from MCP servers or ask_user tool)
- `metadata.schema`: JSON Schema defining expected input structure
- `metadata.prompt`: Prompt text to display to user
- `metadata.serverName`: Name of requesting entity (MCP server or 'Dexto Agent')
- `metadata.context`: Optional additional context
#### `approval:response`
Fired when a user approval response is received from the UI layer.
```typescript
{
approvalId: string; // Must match the request approvalId
status: 'approved' | 'denied' | 'cancelled'; // Approval status
reason?: DenialReason; // Reason for denial/cancellation
message?: string; // Optional user message
sessionId?: string; // Session identifier (if scoped)
data?: Record<string, any>; // Type-specific response data
}
```
**Response Data by Type:**
- **Tool confirmation**: `{ rememberChoice?: boolean }`
- **Command confirmation**: `{ rememberChoice?: boolean }`
- **Elicitation**: `{ formData: Record<string, unknown> }`
**Usage Notes:**
- Agent-initiated forms use `ask_user` tool → triggers elicitation request
- MCP server input requests trigger elicitation automatically
- Tool confirmations can be remembered per session via `rememberChoice`
- Approval requests timeout based on configuration (default: 2 minutes)
- Cancelled status indicates timeout or explicit cancellation
---
## Session-Level Events
These events are emitted by the `SessionEventBus` and provide insight into LLM service operations within sessions. They are automatically forwarded to the `AgentEventBus` with a `sessionId` property.
### LLM Processing Events
#### `llm:thinking`
Fired when the LLM service starts processing a request.
```typescript
{
sessionId: string;
}
```
#### `llm:response`
Fired when the LLM service completes a response.
```typescript
{
content: string;
reasoning?: string; // Extended thinking output for reasoning models
provider?: string;
model?: string;
tokenUsage?: {
inputTokens?: number;
outputTokens?: number;
reasoningTokens?: number; // Additional tokens used for reasoning
totalTokens?: number;
};
sessionId: string;
}
```
**Note:** The `reasoning` field contains extended thinking output for models that support reasoning (e.g., o1, o3-mini). This is separate from the main `content` response.
#### `llm:chunk`
Fired when a streaming response chunk is received.
```typescript
{
chunkType: 'text' | 'reasoning'; // Indicates whether chunk is reasoning or main response
content: string;
isComplete?: boolean;
sessionId: string;
}
```
**Note:** The `chunkType` field distinguishes between reasoning output (`reasoning`) and the main response text (`text`). For reasoning models, you'll receive reasoning chunks followed by text chunks.
#### `llm:error`
Fired when the LLM service encounters an error.
```typescript
{
error: Error;
context?: string;
recoverable?: boolean;
sessionId: string;
}
```
#### `llm:switched`
Fired when session LLM configuration is changed.
```typescript
{
newConfig: LLMConfig;
historyRetained?: boolean;
sessionIds: string[]; // Array of affected session IDs
}
```
#### `llm:unsupported-input`
Fired when the LLM service receives unsupported input.
```typescript
{
errors: string[];
provider: LLMProvider;
model?: string;
fileType?: string;
details?: any;
sessionId: string;
}
```
### Tool Execution Events
#### `llm:tool-call`
Fired when the LLM service requests a tool execution.
```typescript
{
toolName: string;
args: Record<string, any>;
callId?: string;
sessionId: string;
}
```
#### `tool:running`
Fired when a tool actually starts executing (after approval if required). This allows UIs to distinguish between tools pending approval and tools actively running.
```typescript
{
toolName: string;
toolCallId: string;
sessionId: string;
}
```
#### `llm:tool-result`
Fired when a tool execution completes.
```typescript
{
toolName: string;
sanitized: SanitizedToolResult;
rawResult?: unknown; // only present when DEXTO_DEBUG_TOOL_RESULT_RAW=true
callId?: string;
success: boolean;
sessionId: string;
}
```
### Context Management Events
#### `context:compressed`
Fired when conversation context is compressed to stay within token limits.
```typescript
{
originalTokens: number; // Actual input tokens that triggered compression
compressedTokens: number; // Estimated tokens after compression
originalMessages: number;
compressedMessages: number;
strategy: string;
reason: 'overflow' | 'token_limit' | 'message_limit';
sessionId: string;
}
```
#### `context:pruned`
Fired when old messages are pruned from context.
```typescript
{
prunedCount: number;
savedTokens: number;
sessionId: string;
}
```
### Message Queue Events
These events track the message queue system, which allows users to queue additional messages while the agent is processing.
#### `message:queued`
Fired when a user message is queued during agent execution.
```typescript
{
position: number; // Position in the queue
id: string; // Unique message ID
sessionId: string;
}
```
#### `message:dequeued`
Fired when queued messages are dequeued and injected into context.
```typescript
{
count: number; // Number of messages dequeued
ids: string[]; // IDs of dequeued messages
coalesced: boolean; // Whether messages were combined
content: ContentPart[]; // Combined content for UI display
sessionId: string;
}
```
### Run Lifecycle Events
#### `run:complete`
Fired when an agent run completes, providing summary information about the execution.
```typescript
{
finishReason: LLMFinishReason; // How the run ended
stepCount: number; // Number of steps executed
durationMs: number; // Wall-clock duration in milliseconds
error?: Error; // Error if finishReason === 'error'
sessionId: string;
}
```
**Finish Reasons:**
- `stop` - Normal completion
- `tool-calls` - Stopped to execute tool calls (more steps coming)
- `length` - Hit token/length limit
- `content-filter` - Content filter violation
- `error` - Error occurred
- `cancelled` - User cancelled
- `max-steps` - Hit max steps limit
---
## Usage Examples
### Listening to Streaming Events
```typescript
import { DextoAgent } from '@dexto/core';
const agent = new DextoAgent(config);
await agent.start();
// Use the stream() API to get streaming events
for await (const event of await agent.stream('Hello!', 'session-1')) {
switch (event.name) {
case 'llm:thinking':
console.log('Agent is thinking...');
break;
case 'llm:chunk':
process.stdout.write(event.content);
break;
case 'llm:response':
console.log('\nFull response:', event.content);
console.log('Tokens used:', event.tokenUsage);
break;
case 'llm:tool-call':
console.log(`Calling tool: ${event.toolName}`);
break;
case 'tool:running':
console.log(`Tool ${event.toolName} is now running`);
break;
case 'run:complete':
console.log(`Run completed: ${event.finishReason} (${event.stepCount} steps, ${event.durationMs}ms)`);
break;
case 'approval:request':
console.log(`Approval needed: ${event.type}`);
// Handle approval UI...
break;
}
}
```
### Listening to Integration Events
```typescript
import { DextoAgent, INTEGRATION_EVENTS } from '@dexto/core';
const agent = new DextoAgent(config);
await agent.start();
// Listen to all integration events via the event bus
INTEGRATION_EVENTS.forEach((eventName) => {
agent.agentEventBus.on(eventName, (payload) => {
console.log(`[${eventName}]`, payload);
// Send to your monitoring/analytics system
sendToMonitoring(eventName, payload);
});
});
```
### Listening to Internal Events
```typescript
import { DextoAgent } from '@dexto/core';
const agent = new DextoAgent(config);
await agent.start();
// Listen to internal events for advanced debugging
agent.agentEventBus.on('resource:cache-invalidated', (payload) => {
console.log('Cache invalidated:', payload);
});
agent.agentEventBus.on('state:exported', (payload) => {
console.log('State exported:', payload.config);
});
```

View File

@@ -0,0 +1,415 @@
---
sidebar_position: 2
title: "MCPManager"
---
# MCPManager
The `MCPManager` is a powerful, standalone utility for managing [Model Context Protocol (MCP)](/docs/mcp/overview) servers. It allows you to connect, manage, and interact with multiple MCP servers in your own applications without needing the full Dexto agent framework.
This class provides a unified interface for accessing tools, resources, and prompts from all connected servers, making it an essential component for building complex, multi-server workflows.
## Constructor
```typescript
constructor(confirmationProvider?: ToolConfirmationProvider)
```
Creates a new `MCPManager` instance for managing MCP server connections.
**Parameters:**
- `confirmationProvider` (optional): A custom tool confirmation provider. If not provided, a default CLI-based confirmation is used.
**Example:**
```typescript
import { MCPManager } from '@dexto/core';
// Basic manager
const manager = new MCPManager();
// With a custom confirmation provider
const customProvider = new CustomConfirmationProvider();
const managerWithProvider = new MCPManager(customProvider);
```
## Connection Management Methods
#### `connectServer`
Connects to a new MCP server.
```typescript
async connectServer(name: string, config: McpServerConfig): Promise<void>
```
**Parameters:**
- `name`: Unique identifier for the server connection
- `config`: Server configuration object
**Server Configuration Types:**
```typescript
// stdio server (most common)
{
type: 'stdio',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '.'],
env?: { [key: string]: string }
}
// HTTP server (recommended for remote)
{
type: 'http',
url: 'http://localhost:3001/mcp',
headers?: { [key: string]: string },
timeout?: number,
connectionMode?: 'strict' | 'lenient'
}
// SSE (Server-Sent Events) server - DEPRECATED, use http instead
{
type: 'sse',
url: 'http://localhost:3001/sse',
headers?: { [key: string]: string },
timeout?: number,
connectionMode?: 'strict' | 'lenient'
}
```
**Examples:**
```typescript
// File system server
await manager.connectServer('filesystem', {
type: 'stdio',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '.']
});
// Web search server with API key
await manager.connectServer('tavily-search', {
type: 'stdio',
command: 'npx',
args: ['-y', 'tavily-mcp@0.1.2'],
env: {
TAVILY_API_KEY: process.env.TAVILY_API_KEY
}
});
// HTTP MCP server
await manager.connectServer('remote-agent', {
type: 'http',
baseUrl: 'http://localhost:3001/mcp',
timeout: 30000
});
```
#### `initializeFromConfig`
Initialize multiple servers from configuration.
```typescript
async initializeFromConfig(
serverConfigs: ServerConfigs,
connectionMode: 'strict' | 'lenient' = 'lenient'
): Promise<void>
```
**Parameters:**
- `serverConfigs`: Object mapping server names to configurations
- `connectionMode`:
- `'strict'`: All servers must connect successfully
- `'lenient'`: At least one server must connect successfully
**Example:**
```typescript
const serverConfigs = {
filesystem: {
type: 'stdio',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '.']
},
search: {
type: 'stdio',
command: 'npx',
args: ['-y', 'tavily-mcp@0.1.2'],
env: { TAVILY_API_KEY: process.env.TAVILY_API_KEY }
}
};
await manager.initializeFromConfig(serverConfigs, 'lenient');
```
#### `removeClient`
Disconnects and removes a specific MCP server.
```typescript
async removeClient(name: string): Promise<void>
```
**Example:**
```typescript
await manager.removeClient('filesystem');
```
#### `disconnectAll`
Disconnect all servers and clear caches.
```typescript
async disconnectAll(): Promise<void>
```
**Example:**
```typescript
await manager.disconnectAll();
```
#### `restartServer`
Restart a specific MCP server by disconnecting and reconnecting with its original configuration.
```typescript
async restartServer(name: string): Promise<void>
```
**Parameters:**
- `name`: The name of the server to restart
**Example:**
```typescript
// Restart a server after it becomes unresponsive
await manager.restartServer('filesystem');
```
#### `refresh`
Refresh all tool, resource, and prompt caches from connected servers.
```typescript
async refresh(): Promise<void>
```
**Example:**
```typescript
// Force refresh all caches after external changes
await manager.refresh();
```
## Tool Management Methods
#### `getAllTools`
Gets all available tools from connected servers.
```typescript
async getAllTools(): Promise<ToolSet>
```
**Returns:** Object mapping tool names to tool definitions
**Example:**
```typescript
const tools = await manager.getAllTools();
console.log('Available tools:', Object.keys(tools));
// Inspect a specific tool
const readFileTool = tools.readFile;
console.log('Tool schema:', readFileTool.inputSchema);
```
#### `getToolClient`
Get the client that provides a specific tool.
```typescript
getToolClient(toolName: string): IMCPClient | undefined
```
#### `executeTool`
Executes a specific tool with arguments.
```typescript
async executeTool(toolName: string, args: any): Promise<any>
```
**Example:**
```typescript
// Read a file
const content = await manager.executeTool('readFile', {
path: './package.json'
});
// Search the web
const searchResults = await manager.executeTool('search', {
query: 'latest AI developments',
max_results: 5
});
// Write a file
await manager.executeTool('writeFile', {
path: './output.txt',
content: 'Hello from MCP!'
});
```
## Resource Management Methods
#### `listAllResources`
Gets all cached MCP resources from connected servers.
```typescript
async listAllResources(): Promise<MCPResolvedResource[]>
```
**Returns:** Array of resolved resources with metadata:
```typescript
interface MCPResolvedResource {
key: string; // Qualified resource key
serverName: string; // Server that provides this resource
summary: MCPResourceSummary;
}
```
#### `getResource`
Get cached resource metadata by qualified key.
```typescript
getResource(resourceKey: string): MCPResolvedResource | undefined
```
#### `readResource`
Reads a specific resource by URI.
```typescript
async readResource(uri: string): Promise<ReadResourceResult>
```
**Example:**
```typescript
const resource = await manager.readResource('file:///project/README.md');
console.log('Resource content:', resource.contents);
```
## Prompt Management Methods
#### `listAllPrompts`
Gets all available prompt names from connected servers.
```typescript
async listAllPrompts(): Promise<string[]>
```
#### `getPromptClient`
Get the client that provides a specific prompt.
```typescript
getPromptClient(promptName: string): IMCPClient | undefined
```
#### `getPrompt`
Gets a specific prompt by name.
```typescript
async getPrompt(name: string, args?: any): Promise<GetPromptResult>
```
**Example:**
```typescript
const prompt = await manager.getPrompt('code-review', {
language: 'typescript',
file: 'src/index.ts'
});
console.log('Prompt:', prompt.messages);
```
#### `getPromptMetadata`
Get cached metadata for a specific prompt (no network calls).
```typescript
getPromptMetadata(promptName: string): PromptDefinition | undefined
```
#### `getAllPromptMetadata`
Get all cached prompt metadata (no network calls).
```typescript
getAllPromptMetadata(): Array<{
promptName: string;
serverName: string;
definition: PromptDefinition;
}>
```
## Status and Monitoring Methods
#### `getClients`
Returns all registered MCP client instances.
```typescript
getClients(): Map<string, IMCPClient>
```
**Example:**
```typescript
const clients = manager.getClients();
console.log('Connected servers:', Array.from(clients.keys()));
for (const [name, client] of clients) {
console.log(`Server: ${name}, Tools available: ${Object.keys(await client.getTools()).length}`);
}
```
#### `getFailedConnections`
Returns failed connection error messages.
```typescript
getFailedConnections(): Record<string, string>
```
**Example:**
```typescript
const errors = manager.getFailedConnections();
if (Object.keys(errors).length > 0) {
console.log('Failed connections:', errors);
}
```
### Complete Example
```typescript
import { MCPManager } from '@dexto/core';
const manager = new MCPManager();
// Connect to servers
await manager.connectServer('filesystem', {
type: 'stdio',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '.']
});
// Execute tools directly
const result = await manager.executeTool('readFile', { path: './README.md' });
console.log('Read file result:', result);
// Get all available tools
const tools = await manager.getAllTools();
console.log('Available tools:', Object.keys(tools));
// Clean up
await manager.disconnectAll();
```

685
dexto/docs/api/sdk/types.md Normal file
View File

@@ -0,0 +1,685 @@
---
sidebar_position: 4
---
# SDK Types for TypeScript
Type definitions and interfaces for the Dexto Agent SDK for TypeScript.
## Core Imports
```typescript
import {
// Main classes
DextoAgent,
// Standalone utilities
MCPManager,
Logger,
AgentEventBus,
SessionEventBus,
createStorageBackends,
createAgentServices,
// Configuration types
AgentConfig,
LLMConfig,
McpServerConfig,
StorageConfig,
// Session types
ChatSession,
SessionMetadata,
ConversationHistory,
// Result types
ValidatedLLMConfig,
// Event types
AgentEventMap,
SessionEventMap,
// Storage types
StorageBackends,
CacheBackend,
DatabaseBackend,
// Service types
AgentServices,
} from '@dexto/core';
```
---
## Configuration Types
### `AgentConfig`
Main configuration object for creating Dexto agents.
```typescript
interface AgentConfig {
llm: LLMConfig;
mcpServers?: Record<string, McpServerConfig>;
storage?: StorageConfig;
sessions?: SessionConfig;
systemPrompt?: string;
}
```
### `LLMConfig`
Configuration for Large Language Model providers.
```typescript
interface LLMConfig {
provider: 'openai' | 'anthropic' | 'google' | 'groq' | 'xai' | 'cohere' | 'openai-compatible';
model: string;
apiKey?: string;
baseURL?: string;
temperature?: number;
maxOutputTokens?: number;
maxInputTokens?: number;
maxIterations?: number;
systemPrompt?: string;
}
```
### `McpServerConfig`
Configuration for Model Context Protocol servers.
```typescript
interface McpServerConfig {
type: 'stdio' | 'sse' | 'http';
command?: string; // Required for stdio
args?: string[]; // For stdio
env?: Record<string, string>; // For stdio
url?: string; // Required for sse/http
headers?: Record<string, string>; // For sse/http
timeout?: number; // Default: 30000
connectionMode?: 'strict' | 'lenient'; // Default: 'lenient'
}
```
### `StorageConfig`
Configuration for storage backends.
```typescript
interface StorageConfig {
cache: CacheBackendConfig;
database: DatabaseBackendConfig;
}
interface CacheBackendConfig {
type: 'in-memory' | 'redis';
url?: string;
options?: Record<string, any>;
}
interface DatabaseBackendConfig {
type: 'in-memory' | 'sqlite' | 'postgresql';
url?: string;
options?: Record<string, any>;
}
```
---
## Session Types
### `ChatSession`
Represents an individual conversation session.
```typescript
interface ChatSession {
id: string;
createdAt: Date;
lastActivity: Date;
// Session methods
run(userInput: string, imageData?: ImageData): Promise<string>;
getHistory(): Promise<ConversationHistory>;
reset(): Promise<void>;
getLLMService(): VercelLLMService;
}
```
### `SessionMetadata`
Metadata information about a session.
```typescript
interface SessionMetadata {
id: string;
createdAt: Date;
lastActivity: Date;
messageCount: number;
tokenCount?: number;
}
```
### `ConversationHistory`
Complete conversation history for a session.
```typescript
interface ConversationHistory {
sessionId: string;
messages: ConversationMessage[];
totalTokens?: number;
}
interface ConversationMessage {
role: 'user' | 'assistant' | 'system' | 'tool';
content: string;
timestamp: Date;
tokenCount?: number;
toolCall?: ToolCall;
toolResult?: ToolResult;
}
```
---
## Result Types
### `ValidatedLLMConfig`
Validated LLM configuration returned by `switchLLM`.
```typescript
type ValidatedLLMConfig = LLMConfig & {
maxInputTokens?: number;
};
```
---
## Event Types
:::info Event Naming Convention
All events use the `namespace:kebab-case` format. For detailed event documentation and usage examples, see the [Events Reference](./events.md).
:::
### `AgentEventMap`
Type map for agent-level events. All event names follow the `namespace:kebab-case` convention.
```typescript
interface AgentEventMap {
// Session events
'session:reset': {
sessionId: string;
};
'session:created': {
sessionId: string;
switchTo: boolean; // Whether UI should switch to this session
};
'session:title-updated': {
sessionId: string;
title: string;
};
'session:override-set': {
sessionId: string;
override: SessionOverride;
};
'session:override-cleared': {
sessionId: string;
};
// MCP server events
'mcp:server-connected': {
name: string;
success: boolean;
error?: string;
};
'mcp:server-added': {
serverName: string;
config: McpServerConfig;
};
'mcp:server-removed': {
serverName: string;
};
'mcp:server-updated': {
serverName: string;
config: McpServerConfig;
};
'mcp:server-restarted': {
serverName: string;
};
'mcp:resource-updated': {
serverName: string;
resourceUri: string;
};
'mcp:prompts-list-changed': {
serverName: string;
prompts: string[];
};
'mcp:tools-list-changed': {
serverName: string;
tools: string[];
};
'resource:cache-invalidated': {
resourceUri?: string;
serverName: string;
action: 'updated' | 'server_connected' | 'server_removed' | 'blob_stored';
};
'tools:available-updated': {
tools: string[];
source: 'mcp' | 'builtin';
};
// Configuration events
'llm:switched': {
newConfig: ValidatedLLMConfig;
historyRetained?: boolean;
sessionIds: string[]; // Array of affected session IDs
};
'state:changed': {
field: string;
oldValue: any;
newValue: any;
sessionId?: string;
};
'state:exported': {
config: AgentConfig;
};
'state:reset': {
toConfig: AgentConfig;
};
// Approval events
'approval:request': {
approvalId: string;
approvalType: 'tool_confirmation' | 'elicitation' | 'custom';
sessionId?: string;
timeout?: number;
timestamp: Date;
metadata: Record<string, any>;
};
'approval:response': {
approvalId: string;
status: 'approved' | 'denied' | 'cancelled';
reason?: DenialReason;
message?: string;
sessionId?: string;
data?: Record<string, any>;
};
// LLM service events (forwarded from sessions with sessionId)
'llm:thinking': {
sessionId: string;
};
'llm:response': {
content: string;
reasoning?: string;
provider?: string;
model?: string;
tokenUsage?: {
inputTokens?: number;
outputTokens?: number;
reasoningTokens?: number;
totalTokens?: number;
};
sessionId: string;
};
'llm:chunk': {
chunkType: 'text' | 'reasoning'; // Note: renamed from 'type' to avoid conflicts
content: string;
isComplete?: boolean;
sessionId: string;
};
'llm:tool-call': {
toolName: string;
args: Record<string, any>;
callId?: string;
sessionId: string;
};
'llm:tool-result': {
toolName: string;
sanitized: SanitizedToolResult;
rawResult?: unknown;
callId?: string;
success: boolean;
sessionId: string;
};
'llm:error': {
error: Error;
context?: string;
recoverable?: boolean;
sessionId: string;
};
'llm:unsupported-input': {
errors: string[];
provider: LLMProvider;
model?: string;
fileType?: string;
details?: any;
sessionId: string;
};
}
```
### `SessionEventMap`
Type map for session-level events. These events are emitted within individual chat sessions and are automatically forwarded to the `AgentEventBus` with a `sessionId` property.
```typescript
interface SessionEventMap {
'llm:thinking': void;
'llm:response': {
content: string;
reasoning?: string;
provider?: string;
model?: string;
tokenUsage?: {
inputTokens?: number;
outputTokens?: number;
reasoningTokens?: number;
totalTokens?: number;
};
};
'llm:chunk': {
chunkType: 'text' | 'reasoning';
content: string;
isComplete?: boolean;
};
'llm:tool-call': {
toolName: string;
args: Record<string, any>;
callId?: string;
};
'llm:tool-result': {
toolName: string;
sanitized: SanitizedToolResult;
rawResult?: unknown;
callId?: string;
success: boolean;
};
'llm:error': {
error: Error;
context?: string;
recoverable?: boolean;
};
'llm:switched': {
newConfig: ValidatedLLMConfig;
historyRetained?: boolean;
sessionIds: string[];
};
'llm:unsupported-input': {
errors: string[];
provider: LLMProvider;
model?: string;
fileType?: string;
details?: any;
};
}
```
### Event Tier Types
```typescript
// Tier 1: Events exposed via DextoAgent.stream()
export type StreamingEventName =
| 'llm:thinking'
| 'llm:chunk'
| 'llm:response'
| 'llm:tool-call'
| 'llm:tool-result'
| 'llm:error'
| 'llm:unsupported-input'
| 'approval:request'
| 'approval:response'
| 'session:title-updated';
// Tier 2: Events exposed via webhooks, A2A, and monitoring
export type IntegrationEventName = StreamingEventName
| 'session:created'
| 'session:reset'
| 'mcp:server-connected'
| 'mcp:server-restarted'
| 'mcp:tools-list-changed'
| 'mcp:prompts-list-changed'
| 'tools:available-updated'
| 'llm:switched'
| 'state:changed';
// Union types with payloads
// Note: Uses 'name' (not 'type') to avoid collision with ApprovalRequest.type payload field
export type StreamingEvent = {
[K in StreamingEventName]: { name: K } & AgentEventMap[K];
}[StreamingEventName];
```
---
## Storage Types
### `StorageBackends`
Container for storage backend instances.
```typescript
interface StorageBackends {
cache: CacheBackend;
database: DatabaseBackend;
}
```
### `CacheBackend`
Interface for cache storage operations.
```typescript
interface CacheBackend {
get(key: string): Promise<any>;
set(key: string, value: any, ttl?: number): Promise<void>;
delete(key: string): Promise<void>;
clear(): Promise<void>;
disconnect?(): Promise<void>;
}
```
### `DatabaseBackend`
Interface for database storage operations.
```typescript
interface DatabaseBackend {
get(key: string): Promise<any>;
set(key: string, value: any): Promise<void>;
delete(key: string): Promise<void>;
append(key: string, value: any): Promise<void>;
getRange(key: string, start: number, end: number): Promise<any[]>;
disconnect?(): Promise<void>;
}
```
---
## Service Types
### `AgentServices`
Container for all agent service instances.
```typescript
interface AgentServices {
mcpManager: MCPManager;
systemPromptManager: SystemPromptManager;
agentEventBus: AgentEventBus;
stateManager: AgentStateManager;
sessionManager: SessionManager;
storage: StorageBackends;
}
```
---
## Tool Types
### `ToolSet`
Map of tool names to tool definitions.
```typescript
type ToolSet = Record<string, ToolDefinition>;
interface ToolDefinition {
name: string;
description: string;
inputSchema: {
type: 'object';
properties: Record<string, any>;
required?: string[];
};
}
```
### `ToolCall`
Represents a tool execution request.
```typescript
interface ToolCall {
id: string;
name: string;
arguments: Record<string, any>;
}
```
### `ToolResult`
Represents a tool execution result.
```typescript
interface ToolResult {
callId: string;
toolName: string;
result: any;
success: boolean;
error?: string;
}
```
---
## Utility Types
### `ImageData`
Type for image data in conversations.
```typescript
interface ImageData {
base64: string; // Base64 encoded image
mimeType: string; // e.g., 'image/jpeg', 'image/png'
}
```
### `FileData`
Type for file data in conversations.
```typescript
interface FileData {
base64: string; // Base64 encoded file data
mimeType: string; // e.g., 'application/pdf', 'audio/wav'
filename?: string; // Optional filename
}
```
**Supported File Types:**
- **PDF files** (`application/pdf`) - Most widely supported
- **Audio files** (`audio/mp3`, `audio/wav`) - With OpenAI `gpt-4o-audio-preview` and Google Gemini models
**Unsupported File Types:**
- Text files (`.txt`, `.md`)
- CSV files (`.csv`)
- Word documents (`.doc`, `.docx`)
- Excel files (`.xls`, `.xlsx`)
- PowerPoint files (`.ppt`, `.pptx`)
- JSON files (`.json`)
- XML files (`.xml`)
- HTML files (`.html`)
For unsupported file types, consider:
1. Converting to text and sending as regular messages
2. Using specialized MCP servers for file processing
3. Using dedicated file processing tools
### `LoggerOptions`
Configuration options for the Logger class.
```typescript
interface LoggerOptions {
level?: 'error' | 'warn' | 'info' | 'http' | 'verbose' | 'debug' | 'silly';
silent?: boolean;
}
```
### `ChalkColor`
Available colors for logger output.
```typescript
type ChalkColor =
| 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white'
| 'gray' | 'grey' | 'blackBright' | 'redBright' | 'greenBright' | 'yellowBright'
| 'blueBright' | 'magentaBright' | 'cyanBright' | 'whiteBright';
```
---
## Generic Types
### `EventListener`
Generic event listener function type.
```typescript
type EventListener<T> = (data: T) => void;
```
### `EventEmitterOptions`
Options for event emitter methods.
```typescript
interface EventEmitterOptions {
signal?: AbortSignal;
}