feat(#129): add LLM provider admin API endpoints

Implement REST API endpoints for managing LLM provider instances.

Changes:
- Created DTOs for provider CRUD operations (CreateLlmProviderDto, UpdateLlmProviderDto, LlmProviderResponseDto)
- Implemented LlmProviderAdminController with full CRUD endpoints:
  - GET /llm/admin/providers - List all providers
  - GET /llm/admin/providers/:id - Get provider details
  - POST /llm/admin/providers - Create new provider
  - PATCH /llm/admin/providers/:id - Update provider
  - DELETE /llm/admin/providers/:id - Delete provider
  - POST /llm/admin/providers/:id/test - Test connection
  - POST /llm/admin/reload - Reload from database
- Updated llm-manager.service.ts to support OpenAI and Claude providers
- Added comprehensive test suite with 97.95% coverage
- Proper validation, error handling, and type safety

All tests pass. Pre-commit hooks pass.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 14:37:55 -06:00
parent 772776bfd9
commit 4b4d21c732
6 changed files with 904 additions and 6 deletions

View File

@@ -1,2 +1,3 @@
export * from "./chat.dto";
export * from "./embed.dto";
export * from "./provider-admin.dto";

View File

@@ -0,0 +1,169 @@
import { IsString, IsIn, IsOptional, IsBoolean, IsUUID, IsObject } from "class-validator";
import type { JsonValue } from "@prisma/client/runtime/library";
/**
* DTO for creating a new LLM provider instance.
*
* @example
* ```typescript
* const dto: CreateLlmProviderDto = {
* providerType: "ollama",
* displayName: "Local Ollama",
* config: {
* endpoint: "http://localhost:11434",
* timeout: 30000
* },
* isDefault: true,
* isEnabled: true
* };
* ```
*/
export class CreateLlmProviderDto {
/**
* Provider type (ollama, openai, or claude)
*/
@IsString()
@IsIn(["ollama", "openai", "claude"])
providerType!: string;
/**
* Human-readable display name for the provider
*/
@IsString()
displayName!: string;
/**
* User ID for user-specific providers (null for system-level)
*/
@IsOptional()
@IsUUID()
userId?: string;
/**
* Provider-specific configuration (endpoint, apiKey, etc.)
*/
@IsObject()
config!: JsonValue;
/**
* Whether this is the default provider
*/
@IsOptional()
@IsBoolean()
isDefault?: boolean;
/**
* Whether this provider is enabled
*/
@IsOptional()
@IsBoolean()
isEnabled?: boolean;
}
/**
* DTO for updating an existing LLM provider instance.
* All fields are optional - only provided fields will be updated.
*
* @example
* ```typescript
* const dto: UpdateLlmProviderDto = {
* displayName: "Updated Ollama",
* isEnabled: false
* };
* ```
*/
export class UpdateLlmProviderDto {
/**
* Human-readable display name for the provider
*/
@IsOptional()
@IsString()
displayName?: string;
/**
* Provider-specific configuration (endpoint, apiKey, etc.)
*/
@IsOptional()
@IsObject()
config?: JsonValue;
/**
* Whether this is the default provider
*/
@IsOptional()
@IsBoolean()
isDefault?: boolean;
/**
* Whether this provider is enabled
*/
@IsOptional()
@IsBoolean()
isEnabled?: boolean;
}
/**
* Response DTO for LLM provider instance.
* Matches the Prisma LlmProviderInstance model.
*
* @example
* ```typescript
* const response: LlmProviderResponseDto = {
* id: "provider-123",
* providerType: "ollama",
* displayName: "Local Ollama",
* userId: null,
* config: { endpoint: "http://localhost:11434" },
* isDefault: true,
* isEnabled: true,
* createdAt: new Date(),
* updatedAt: new Date()
* };
* ```
*/
export class LlmProviderResponseDto {
/**
* Unique identifier for the provider instance
*/
id!: string;
/**
* Provider type (ollama, openai, or claude)
*/
providerType!: string;
/**
* Human-readable display name for the provider
*/
displayName!: string;
/**
* User ID for user-specific providers (null for system-level)
*/
userId?: string | null;
/**
* Provider-specific configuration (endpoint, apiKey, etc.)
*/
config!: JsonValue;
/**
* Whether this is the default provider
*/
isDefault!: boolean;
/**
* Whether this provider is enabled
*/
isEnabled!: boolean;
/**
* Timestamp when the provider was created
*/
createdAt!: Date;
/**
* Timestamp when the provider was last updated
*/
updatedAt!: Date;
}