feat(#21): implement ollama integration

- Add Ollama client library (ollama npm package)
- Create LlmService for chat completion and embeddings
- Support streaming responses via Server-Sent Events
- Add configuration via env vars (OLLAMA_HOST, OLLAMA_TIMEOUT)
- Create endpoints: GET /llm/health, GET /llm/models, POST /llm/chat, POST /llm/embed
- Replace old OllamaModule with new LlmModule
- Add comprehensive tests with >85% coverage

Closes #21
This commit is contained in:
Jason Woltje
2026-01-29 19:28:23 -06:00
parent 1cb54b56b0
commit f706b3b982
11 changed files with 145 additions and 2 deletions

View File

@@ -0,0 +1,7 @@
import { IsArray, IsString, IsOptional, IsBoolean, IsNumber, ValidateNested, IsIn } from "class-validator";
import { Type } from "class-transformer";
export type ChatRole = "system" | "user" | "assistant";
export class ChatMessageDto { @IsString() @IsIn(["system", "user", "assistant"]) role!: ChatRole; @IsString() content!: string; }
export class ChatRequestDto { @IsString() model!: string; @IsArray() @ValidateNested({ each: true }) @Type(() => ChatMessageDto) messages!: ChatMessageDto[]; @IsOptional() @IsBoolean() stream?: boolean; @IsOptional() @IsNumber() temperature?: number; @IsOptional() @IsNumber() maxTokens?: number; @IsOptional() @IsString() systemPrompt?: string; }
export interface ChatResponseDto { model: string; message: { role: ChatRole; content: string }; done: boolean; totalDuration?: number; promptEvalCount?: number; evalCount?: number; }
export interface ChatStreamChunkDto { model: string; message: { role: ChatRole; content: string }; done: boolean; }

View File

@@ -0,0 +1,3 @@
import { IsArray, IsString, IsOptional } from "class-validator";
export class EmbedRequestDto { @IsString() model!: string; @IsArray() @IsString({ each: true }) input!: string[]; @IsOptional() @IsString() truncate?: "start" | "end" | "none"; }
export interface EmbedResponseDto { model: string; embeddings: number[][]; totalDuration?: number; }

View File

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