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,305 @@
import { OpenAPIHono } from '@hono/zod-openapi';
import type { Context } from 'hono';
import type { DextoAgent, AgentCard } from '@dexto/core';
import { logger } from '@dexto/core';
import { createHealthRouter } from './routes/health.js';
import { createGreetingRouter } from './routes/greeting.js';
import { createMessagesRouter } from './routes/messages.js';
import { createLlmRouter } from './routes/llm.js';
import { createSessionsRouter } from './routes/sessions.js';
import { createSearchRouter } from './routes/search.js';
import { createMcpRouter } from './routes/mcp.js';
import { createA2aRouter } from './routes/a2a.js';
import { createA2AJsonRpcRouter } from './routes/a2a-jsonrpc.js';
import { createA2ATasksRouter } from './routes/a2a-tasks.js';
import { createWebhooksRouter } from './routes/webhooks.js';
import { createPromptsRouter } from './routes/prompts.js';
import { createResourcesRouter } from './routes/resources.js';
import { createMemoryRouter } from './routes/memory.js';
import { createAgentsRouter, type AgentsRouterContext } from './routes/agents.js';
import { createApprovalsRouter } from './routes/approvals.js';
import { createQueueRouter } from './routes/queue.js';
import { createOpenRouterRouter } from './routes/openrouter.js';
import { createKeyRouter } from './routes/key.js';
import { createToolsRouter } from './routes/tools.js';
import { createDiscoveryRouter } from './routes/discovery.js';
import { createModelsRouter } from './routes/models.js';
import { createDextoAuthRouter } from './routes/dexto-auth.js';
import {
createStaticRouter,
createSpaFallbackHandler,
type WebUIRuntimeConfig,
} from './routes/static.js';
import { WebhookEventSubscriber } from '../events/webhook-subscriber.js';
import { A2ASseEventSubscriber } from '../events/a2a-sse-subscriber.js';
import { handleHonoError } from './middleware/error.js';
import { prettyJsonMiddleware, redactionMiddleware } from './middleware/redaction.js';
import { createCorsMiddleware } from './middleware/cors.js';
import { createAuthMiddleware } from './middleware/auth.js';
import { ApprovalCoordinator } from '../approval/approval-coordinator.js';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8')) as {
version: string;
};
// Dummy context for type inference and runtime fallback
// Used when running in single-agent mode (CLI, Docker, etc.) where multi-agent
// features aren't available. Agents router is always mounted for consistent API
// structure, but will return clear errors if multi-agent endpoints are called.
// This ensures type safety across different deployment modes.
const dummyAgentsContext: AgentsRouterContext = {
switchAgentById: async () => {
throw new Error('Multi-agent features not available in single-agent mode');
},
switchAgentByPath: async () => {
throw new Error('Multi-agent features not available in single-agent mode');
},
resolveAgentInfo: async () => {
throw new Error('Multi-agent features not available in single-agent mode');
},
ensureAgentAvailable: () => {},
getActiveAgentId: () => undefined,
};
// Type for async getAgent with context support
export type GetAgentFn = (ctx: Context) => DextoAgent | Promise<DextoAgent>;
export type CreateDextoAppOptions = {
/**
* Prefix for API routes. Defaults to '/api'.
*/
apiPrefix?: string;
getAgent: GetAgentFn;
getAgentCard: () => AgentCard;
approvalCoordinator: ApprovalCoordinator;
webhookSubscriber: WebhookEventSubscriber;
sseSubscriber: A2ASseEventSubscriber;
agentsContext?: AgentsRouterContext;
/** Absolute path to WebUI build output. If provided, static files will be served. */
webRoot?: string;
/** Runtime configuration to inject into WebUI (analytics, etc.) */
webUIConfig?: WebUIRuntimeConfig;
/** Disable built-in auth middleware. Use when you have your own auth layer. */
disableAuth?: boolean;
};
// Default API prefix as a const literal for type inference
const DEFAULT_API_PREFIX = '/api' as const;
export function createDextoApp(options: CreateDextoAppOptions) {
const {
apiPrefix,
getAgent,
getAgentCard,
approvalCoordinator,
webhookSubscriber,
sseSubscriber,
agentsContext,
webRoot,
webUIConfig,
disableAuth = false,
} = options;
// Security check: Warn when auth is disabled
if (disableAuth) {
logger.warn(
`⚠️ Authentication disabled (disableAuth=true). createAuthMiddleware() skipped. Ensure external auth is in place.`
);
}
const app = new OpenAPIHono({ strict: false });
// Global CORS middleware for cross-origin requests (must be first)
app.use('*', createCorsMiddleware());
// Global authentication middleware (after CORS, before routes)
// Can be disabled when using an external auth layer
if (!disableAuth) {
app.use('*', createAuthMiddleware());
}
// Global error handling for all routes
app.onError((err, ctx) => handleHonoError(ctx, err));
// Normalize prefix: strip trailing slashes, treat '' as '/'
const rawPrefix = apiPrefix ?? DEFAULT_API_PREFIX;
const normalizedPrefix = rawPrefix === '' ? '/' : rawPrefix.replace(/\/+$/, '') || '/';
const middlewarePattern = normalizedPrefix === '/' ? '/*' : `${normalizedPrefix}/*`;
app.use(middlewarePattern, prettyJsonMiddleware);
app.use(middlewarePattern, redactionMiddleware);
// Cast to literal type for RPC client type inference (webui uses default '/api')
const routePrefix = normalizedPrefix as typeof DEFAULT_API_PREFIX;
// Mount all API routers at the configured prefix for proper type inference
// Each router is mounted individually so Hono can properly track route types
const fullApp = app
// Public health endpoint
.route('/health', createHealthRouter(getAgent))
// Follows A2A discovery protocol
.route('/', createA2aRouter(getAgentCard))
.route('/', createA2AJsonRpcRouter(getAgent, sseSubscriber))
.route('/', createA2ATasksRouter(getAgent, sseSubscriber))
// Add agent-specific routes
.route(routePrefix, createGreetingRouter(getAgent))
.route(routePrefix, createMessagesRouter(getAgent, approvalCoordinator))
.route(routePrefix, createLlmRouter(getAgent))
.route(routePrefix, createSessionsRouter(getAgent))
.route(routePrefix, createSearchRouter(getAgent))
.route(routePrefix, createMcpRouter(getAgent))
.route(routePrefix, createWebhooksRouter(getAgent, webhookSubscriber))
.route(routePrefix, createPromptsRouter(getAgent))
.route(routePrefix, createResourcesRouter(getAgent))
.route(routePrefix, createMemoryRouter(getAgent))
.route(routePrefix, createApprovalsRouter(getAgent, approvalCoordinator))
.route(routePrefix, createAgentsRouter(getAgent, agentsContext || dummyAgentsContext))
.route(routePrefix, createQueueRouter(getAgent))
.route(routePrefix, createOpenRouterRouter())
.route(routePrefix, createKeyRouter())
.route(routePrefix, createToolsRouter(getAgent))
.route(routePrefix, createDiscoveryRouter())
.route(routePrefix, createModelsRouter())
.route(routePrefix, createDextoAuthRouter(getAgent));
// Expose OpenAPI document
// Current approach uses @hono/zod-openapi's .doc() method for OpenAPI spec generation
// Alternative: Use openAPIRouteHandler from hono-openapi (third-party) for auto-generation
// Keeping current approach since:
// 1. @hono/zod-openapi is official Hono package with first-class support
// 2. We already generate spec via scripts/generate-openapi-spec.ts to docs/
// 3. Switching would require adding hono-openapi dependency and migration effort
// See: https://honohub.dev/docs/openapi/zod#generating-the-openapi-spec
fullApp.doc('/openapi.json', {
openapi: '3.0.0',
info: {
title: 'Dexto API',
version: packageJson.version,
description: 'OpenAPI spec for the Dexto REST API server',
},
servers: [
{
url: 'http://localhost:3001',
description: 'Local development server (default port)',
},
{
url: 'http://localhost:{port}',
description: 'Local development server (custom port)',
variables: {
port: {
default: '3001',
description: 'API server port',
},
},
},
],
tags: [
{
name: 'system',
description: 'System health and status endpoints',
},
{
name: 'config',
description: 'Agent configuration and greeting management',
},
{
name: 'messages',
description: 'Send messages to the agent and manage conversations',
},
{
name: 'sessions',
description: 'Create and manage conversation sessions',
},
{
name: 'llm',
description: 'Configure and switch between LLM providers and models',
},
{
name: 'mcp',
description: 'Manage Model Context Protocol (MCP) servers and tools',
},
{
name: 'webhooks',
description: 'Register and manage webhook endpoints for agent events',
},
{
name: 'search',
description: 'Search through messages and sessions',
},
{
name: 'memory',
description: 'Store and retrieve agent memories for context',
},
{
name: 'prompts',
description: 'Manage custom prompts and templates',
},
{
name: 'resources',
description: 'Access and manage resources from MCP servers and internal providers',
},
{
name: 'agent',
description: 'Current agent configuration and file operations',
},
{
name: 'agents',
description: 'Install, switch, and manage agent configurations',
},
{
name: 'queue',
description: 'Manage message queue for busy sessions',
},
{
name: 'openrouter',
description: 'OpenRouter model validation and cache management',
},
{
name: 'discovery',
description: 'Discover available providers and capabilities',
},
{
name: 'tools',
description:
'List and inspect available tools from internal, custom, and MCP sources',
},
{
name: 'models',
description: 'List and manage local GGUF models and Ollama models',
},
{
name: 'auth',
description: 'Dexto authentication status and management',
},
],
});
// Mount static file router for WebUI if webRoot is provided
if (webRoot) {
fullApp.route('/', createStaticRouter(webRoot));
// SPA fallback: serve index.html for unmatched routes without file extensions
// Must be registered as notFound handler so it runs AFTER all routes (including /openapi.json)
// webUIConfig is injected into index.html for runtime configuration (analytics, etc.)
fullApp.notFound(createSpaFallbackHandler(webRoot, webUIConfig));
}
// NOTE: Subscribers and approval handler are wired in CLI layer before agent.start()
// This ensures proper initialization order and validation
// We attach webhookSubscriber as a property but don't include it in the return type
// to preserve Hono's route type inference
Object.assign(fullApp, { webhookSubscriber });
return fullApp;
}
// Export inferred AppType
// Routes are now properly typed since they're all mounted directly
export type AppType = ReturnType<typeof createDextoApp>;
// Re-export types needed by CLI
export type { WebUIRuntimeConfig } from './routes/static.js';