import { HttpModule } from "@nestjs/axios"; import { Logger, Module, OnModuleInit } from "@nestjs/common"; import type { AgentProviderConfig } from "@prisma/client"; import { PrismaModule } from "../../prisma/prisma.module"; import { PrismaService } from "../../prisma/prisma.service"; import { EncryptionService } from "../../security/encryption.service"; import { AgentProviderRegistry } from "../agents/agent-provider.registry"; import { AgentsModule } from "../agents/agents.module"; import { OpenClawProviderFactory } from "./openclaw/openclaw.provider-factory"; import { OpenClawSseBridge } from "./openclaw/openclaw-sse.bridge"; const OPENCLAW_PROVIDER_TYPE = "openclaw"; @Module({ imports: [ AgentsModule, PrismaModule, HttpModule.register({ timeout: 10000, maxRedirects: 5, }), ], providers: [EncryptionService, OpenClawSseBridge, OpenClawProviderFactory], }) export class ProvidersModule implements OnModuleInit { private readonly logger = new Logger(ProvidersModule.name); constructor( private readonly prisma: PrismaService, private readonly registry: AgentProviderRegistry, private readonly openClawProviderFactory: OpenClawProviderFactory ) {} async onModuleInit(): Promise { const configs = await this.prisma.agentProviderConfig.findMany({ where: { provider: OPENCLAW_PROVIDER_TYPE, isActive: true, }, orderBy: [{ createdAt: "asc" }, { id: "asc" }], }); for (const config of configs) { await this.registerProvider(config); } } private async registerProvider(config: AgentProviderConfig): Promise { const provider = this.openClawProviderFactory.createProvider(config); try { provider.validateBaseUrl(); } catch (error) { this.logger.warn( `Skipping OpenClaw provider ${config.name}: invalid configuration (${this.toErrorMessage(error)})` ); return; } try { provider.validateToken(); } catch (error) { this.logger.error( `Skipping OpenClaw provider ${config.name}: token decryption failed (${this.toErrorMessage(error)})` ); return; } try { const available = await provider.isAvailable(); if (!available) { this.logger.warn( `Skipping OpenClaw provider ${config.name}: gateway ${config.gatewayUrl} is unreachable` ); return; } } catch (error) { this.logger.warn( `Skipping OpenClaw provider ${config.name}: gateway ${config.gatewayUrl} is unreachable (${this.toErrorMessage(error)})` ); return; } this.registry.registerProvider(provider); this.logger.log(`Registered OpenClaw provider ${provider.providerId}`); } private toErrorMessage(error: unknown): string { if (error instanceof Error) { return error.message; } return String(error); } }