todo-tool-integration.ts•20.7 kB
/**
* Todo Tool Integration for AI Models
* Provides unified Todo tool support for Claude, GPT, Gemini, and other models
*/
import { SRTSubtitle, SRTChunk } from '../types/srt.js';
/**
* Todo Tool Interface for AI Models
*/
export interface TodoToolInterface {
createTodoList(todos: TodoItem[]): Promise<TodoListResult>;
updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean>;
getTodoList(): Promise<TodoItem[]>;
markTodoComplete(todoId: string): Promise<boolean>;
getTodoById(todoId: string): Promise<TodoItem | null>;
deleteTodo(todoId: string): Promise<boolean>;
addTodo(todo: Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>): Promise<TodoItem>;
updateTodo(todoId: string, updates: Partial<TodoItem>): Promise<TodoItem | null>;
searchTodos(query: string): Promise<TodoItem[]>;
getTodosByCategory(category: string): Promise<TodoItem[]>;
getTodosByStatus(status: TodoStatus): Promise<TodoItem[]>;
getTodosByPriority(priority: TodoPriority): Promise<TodoItem[]>;
getTodoStatistics(): Promise<TodoStatistics>;
}
/**
* Todo Item Structure
*/
export interface TodoItem {
id: string;
content: string;
status: TodoStatus;
priority: TodoPriority;
category: string;
metadata?: TodoMetadata;
createdAt: Date;
updatedAt: Date;
completedAt?: Date;
dueDate?: Date;
tags?: string[];
dependencies?: string[]; // IDs of other todos this depends on
subtasks?: TodoItem[]; // Nested todos
}
/**
* Todo Status
*/
export type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled' | 'blocked';
/**
* Todo Priority
*/
export type TodoPriority = 'low' | 'medium' | 'high' | 'critical';
/**
* Todo Metadata
*/
export interface TodoMetadata {
modelSpecific?: Record<string, any>;
processingContext?: ProcessingContext;
chunkId?: string;
estimatedDuration?: number;
actualDuration?: number;
retryCount?: number;
errorHistory?: TodoError[];
progress?: number; // 0-100
notes?: string[];
}
/**
* Processing Context
*/
export interface ProcessingContext {
fileId?: string;
chunkId?: string;
processingType?: string;
modelType?: string;
contextSize?: number;
complexity?: 'low' | 'medium' | 'high';
}
/**
* Todo Error
*/
export interface TodoError {
timestamp: Date;
error: string;
context?: string;
retryable: boolean;
}
/**
* Todo List Result
*/
export interface TodoListResult {
success: boolean;
todoIds: string[];
message: string;
warnings?: string[];
}
/**
* Todo Statistics
*/
export interface TodoStatistics {
total: number;
pending: number;
inProgress: number;
completed: number;
cancelled: number;
blocked: number;
byPriority: Record<TodoPriority, number>;
byCategory: Record<string, number>;
averageCompletionTime?: number;
completionRate?: number;
}
/**
* SRT Processing Todo Categories
*/
export const SRT_TODO_CATEGORIES = {
FILE_ANALYSIS: 'file-analysis',
CHUNK_DETECTION: 'chunk-detection',
CHUNK_OPTIMIZATION: 'chunk-optimization',
TRANSLATION: 'translation',
ANALYSIS: 'analysis',
VALIDATION: 'validation',
QUALITY_CHECK: 'quality-check',
EXPORT: 'export',
ERROR_HANDLING: 'error-handling'
} as const;
/**
* SRT Processing Todo Templates
*/
export class SRTTodoTemplates {
/**
* Create file analysis todos
*/
static createFileAnalysisTodos(fileName: string): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] {
return [
{
content: `Analyze SRT file structure: ${fileName}`,
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.FILE_ANALYSIS,
metadata: {
processingContext: {
fileId: fileName,
processingType: 'file-analysis'
}
}
},
{
content: 'Validate SRT file format and syntax',
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.FILE_ANALYSIS,
metadata: {
processingContext: {
fileId: fileName,
processingType: 'validation'
}
}
},
{
content: 'Detect language and content characteristics',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.FILE_ANALYSIS,
metadata: {
processingContext: {
fileId: fileName,
processingType: 'language-detection'
}
}
}
];
}
/**
* Create chunk detection todos
*/
static createChunkDetectionTodos(chunkCount: number): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] {
return [
{
content: `Detect conversation boundaries in ${chunkCount} potential chunks`,
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.CHUNK_DETECTION,
metadata: {
processingContext: {
processingType: 'conversation-detection'
}
}
},
{
content: 'Apply semantic analysis to chunk boundaries',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.CHUNK_DETECTION,
metadata: {
processingContext: {
processingType: 'semantic-analysis'
}
}
},
{
content: 'Detect speaker changes and diarization',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.CHUNK_DETECTION,
metadata: {
processingContext: {
processingType: 'speaker-diarization'
}
}
}
];
}
/**
* Create chunk optimization todos
*/
static createChunkOptimizationTodos(chunkCount: number, modelType: string): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] {
return [
{
content: `Optimize ${chunkCount} chunks for ${modelType} context limits`,
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.CHUNK_OPTIMIZATION,
metadata: {
processingContext: {
processingType: 'context-optimization',
modelType
}
}
},
{
content: 'Calculate optimal chunk sizes and boundaries',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.CHUNK_OPTIMIZATION,
metadata: {
processingContext: {
processingType: 'size-optimization',
modelType
}
}
},
{
content: 'Validate chunk coherence and speaker consistency',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.CHUNK_OPTIMIZATION,
metadata: {
processingContext: {
processingType: 'coherence-validation',
modelType
}
}
}
];
}
/**
* Create translation todos
*/
static createTranslationTodos(chunkCount: number, targetLanguage: string): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] {
return [
{
content: `Translate ${chunkCount} chunks to ${targetLanguage}`,
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.TRANSLATION,
metadata: {
processingContext: {
processingType: 'translation',
complexity: 'high'
}
}
},
{
content: 'Maintain speaker consistency across translations',
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.TRANSLATION,
metadata: {
processingContext: {
processingType: 'speaker-consistency',
complexity: 'medium'
}
}
},
{
content: 'Preserve timing and formatting in translations',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.TRANSLATION,
metadata: {
processingContext: {
processingType: 'formatting-preservation',
complexity: 'medium'
}
}
}
];
}
/**
* Create analysis todos
*/
static createAnalysisTodos(chunkCount: number): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] {
return [
{
content: `Analyze content in ${chunkCount} chunks`,
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.ANALYSIS,
metadata: {
processingContext: {
processingType: 'content-analysis'
}
}
},
{
content: 'Extract key themes and topics',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.ANALYSIS,
metadata: {
processingContext: {
processingType: 'theme-extraction'
}
}
},
{
content: 'Generate conversation insights and patterns',
status: 'pending',
priority: 'low',
category: SRT_TODO_CATEGORIES.ANALYSIS,
metadata: {
processingContext: {
processingType: 'insight-generation'
}
}
}
];
}
/**
* Create validation todos
*/
static createValidationTodos(chunkCount: number): Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] {
return [
{
content: `Validate processing results for ${chunkCount} chunks`,
status: 'pending',
priority: 'high',
category: SRT_TODO_CATEGORIES.VALIDATION,
metadata: {
processingContext: {
processingType: 'result-validation'
}
}
},
{
content: 'Check timing and formatting integrity',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.VALIDATION,
metadata: {
processingContext: {
processingType: 'integrity-check'
}
}
},
{
content: 'Verify language detection accuracy',
status: 'pending',
priority: 'medium',
category: SRT_TODO_CATEGORIES.VALIDATION,
metadata: {
processingContext: {
processingType: 'language-validation'
}
}
}
];
}
}
/**
* Universal Todo Tool Implementation
*/
export class UniversalTodoTool implements TodoToolInterface {
private todos: Map<string, TodoItem> = new Map();
private todoCounter = 0;
private modelType: string;
constructor(modelType: string = 'generic') {
this.modelType = modelType;
}
/**
* Create todo list
*/
async createTodoList(todos: TodoItem[]): Promise<TodoListResult> {
const todoIds: string[] = [];
const warnings: string[] = [];
for (const todo of todos) {
try {
const createdTodo = await this.addTodo(todo);
todoIds.push(createdTodo.id);
} catch (error) {
warnings.push(`Failed to create todo: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
return {
success: todoIds.length > 0,
todoIds,
message: `Created ${todoIds.length} todos for ${this.modelType}`,
warnings: warnings.length > 0 ? warnings : undefined
};
}
/**
* Add single todo
*/
async addTodo(todo: Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>): Promise<TodoItem> {
const id = `${this.modelType}-todo-${++this.todoCounter}`;
const now = new Date();
const newTodo: TodoItem = {
...todo,
id,
createdAt: now,
updatedAt: now
};
this.todos.set(id, newTodo);
console.log(`[DEBUG] Added todo ${id}, total todos: ${this.todos.size}`);
return newTodo;
}
/**
* Update todo status
*/
async updateTodoStatus(todoId: string, status: TodoStatus): Promise<boolean> {
const todo = this.todos.get(todoId);
if (!todo) return false;
todo.status = status;
todo.updatedAt = new Date();
if (status === 'completed') {
todo.completedAt = new Date();
}
this.todos.set(todoId, todo);
return true;
}
/**
* Get todo list
*/
async getTodoList(): Promise<TodoItem[]> {
console.log(`[DEBUG] getTodoList called, todos count: ${this.todos.size}`);
const todos = Array.from(this.todos.values());
console.log(`[DEBUG] returning ${todos.length} todos`);
return todos;
}
/**
* Mark todo as complete
*/
async markTodoComplete(todoId: string): Promise<boolean> {
return this.updateTodoStatus(todoId, 'completed');
}
/**
* Get todo by ID
*/
async getTodoById(todoId: string): Promise<TodoItem | null> {
return this.todos.get(todoId) || null;
}
/**
* Delete todo
*/
async deleteTodo(todoId: string): Promise<boolean> {
return this.todos.delete(todoId);
}
/**
* Update todo
*/
async updateTodo(todoId: string, updates: Partial<TodoItem>): Promise<TodoItem | null> {
const todo = this.todos.get(todoId);
if (!todo) return null;
const updatedTodo = {
...todo,
...updates,
id: todoId, // Preserve ID
updatedAt: new Date()
};
this.todos.set(todoId, updatedTodo);
return updatedTodo;
}
/**
* Search todos
*/
async searchTodos(query: string): Promise<TodoItem[]> {
const allTodos = Array.from(this.todos.values());
const searchTerm = query.toLowerCase();
return allTodos.filter(todo =>
todo.content.toLowerCase().includes(searchTerm) ||
todo.category.toLowerCase().includes(searchTerm) ||
(todo.tags && todo.tags.some(tag => tag.toLowerCase().includes(searchTerm)))
);
}
/**
* Get todos by category
*/
async getTodosByCategory(category: string): Promise<TodoItem[]> {
const allTodos = Array.from(this.todos.values());
return allTodos.filter(todo => todo.category === category);
}
/**
* Get todos by status
*/
async getTodosByStatus(status: TodoStatus): Promise<TodoItem[]> {
const allTodos = Array.from(this.todos.values());
return allTodos.filter(todo => todo.status === status);
}
/**
* Get todos by priority
*/
async getTodosByPriority(priority: TodoPriority): Promise<TodoItem[]> {
const allTodos = Array.from(this.todos.values());
return allTodos.filter(todo => todo.priority === priority);
}
/**
* Get todo statistics
*/
async getTodoStatistics(): Promise<TodoStatistics> {
const allTodos = Array.from(this.todos.values());
const stats: TodoStatistics = {
total: allTodos.length,
pending: allTodos.filter(t => t.status === 'pending').length,
inProgress: allTodos.filter(t => t.status === 'in_progress').length,
completed: allTodos.filter(t => t.status === 'completed').length,
cancelled: allTodos.filter(t => t.status === 'cancelled').length,
blocked: allTodos.filter(t => t.status === 'blocked').length,
byPriority: {
low: allTodos.filter(t => t.priority === 'low').length,
medium: allTodos.filter(t => t.priority === 'medium').length,
high: allTodos.filter(t => t.priority === 'high').length,
critical: allTodos.filter(t => t.priority === 'critical').length
},
byCategory: {}
};
// Calculate category distribution
const categories = [...new Set(allTodos.map(t => t.category))];
categories.forEach(category => {
stats.byCategory[category] = allTodos.filter(t => t.category === category).length;
});
// Calculate completion rate
if (stats.total > 0) {
stats.completionRate = stats.completed / stats.total;
}
// Calculate average completion time for completed todos
const completedTodos = allTodos.filter(t => t.status === 'completed' && t.completedAt);
if (completedTodos.length > 0) {
const totalTime = completedTodos.reduce((sum, todo) => {
if (todo.completedAt && todo.createdAt) {
return sum + (todo.completedAt.getTime() - todo.createdAt.getTime());
}
return sum;
}, 0);
stats.averageCompletionTime = totalTime / completedTodos.length;
}
return stats;
}
}
/**
* Model-specific Todo Tool Implementations
*/
export class ClaudeTodoTool extends UniversalTodoTool {
constructor() {
super('claude');
}
async createTodoList(todos: TodoItem[]): Promise<TodoListResult> {
// Claude-specific todo creation with reasoning
const claudeTodos = todos.map(todo => ({
...todo,
metadata: {
...todo.metadata,
modelSpecific: {
claudeOptimized: true,
reasoningRequired: todo.priority === 'high' || todo.category.includes('analysis'),
anthropicFormat: true
}
}
}));
return super.createTodoList(claudeTodos);
}
}
export class GPTTodoTool extends UniversalTodoTool {
constructor() {
super('gpt');
}
async createTodoList(todos: TodoItem[]): Promise<TodoListResult> {
// GPT-specific todo creation
const gptTodos = todos.map(todo => ({
...todo,
metadata: {
...todo.metadata,
modelSpecific: {
gptOptimized: true,
openaiFormat: true,
functionCalling: true
}
}
}));
return super.createTodoList(gptTodos);
}
}
export class GeminiTodoTool extends UniversalTodoTool {
constructor() {
super('gemini');
}
async createTodoList(todos: TodoItem[]): Promise<TodoListResult> {
// Gemini-specific todo creation
const geminiTodos = todos.map(todo => ({
...todo,
metadata: {
...todo.metadata,
modelSpecific: {
geminiOptimized: true,
googleFormat: true,
multimodalCapable: true
}
}
}));
return super.createTodoList(geminiTodos);
}
}
/**
* Todo Tool Factory
*/
export class TodoToolFactory {
static createTodoTool(modelType: string): TodoToolInterface {
switch (modelType.toLowerCase()) {
case 'claude':
return new ClaudeTodoTool();
case 'gpt':
return new GPTTodoTool();
case 'gemini':
return new GeminiTodoTool();
default:
return new UniversalTodoTool(modelType);
}
}
}
/**
* SRT Processing Todo Manager
*/
export class SRTProcessingTodoManager {
private todoTool: TodoToolInterface;
private modelType: string;
constructor(modelType: string) {
this.modelType = modelType;
this.todoTool = TodoToolFactory.createTodoTool(modelType);
}
/**
* Create comprehensive SRT processing todos
*/
async createSRTProcessingTodos(
fileName: string,
chunkCount: number,
processingType: 'translation' | 'analysis' | 'conversation-detection',
targetLanguage?: string
): Promise<TodoListResult> {
const todos: Omit<TodoItem, 'id' | 'createdAt' | 'updatedAt'>[] = [];
// Add file analysis todos
todos.push(...SRTTodoTemplates.createFileAnalysisTodos(fileName));
// Add chunk detection todos
todos.push(...SRTTodoTemplates.createChunkDetectionTodos(chunkCount));
// Add chunk optimization todos
todos.push(...SRTTodoTemplates.createChunkOptimizationTodos(chunkCount, this.modelType));
// Add processing-specific todos
switch (processingType) {
case 'translation':
if (targetLanguage) {
todos.push(...SRTTodoTemplates.createTranslationTodos(chunkCount, targetLanguage));
}
break;
case 'analysis':
todos.push(...SRTTodoTemplates.createAnalysisTodos(chunkCount));
break;
case 'conversation-detection':
// Already covered by chunk detection todos
break;
}
// Add validation todos
todos.push(...SRTTodoTemplates.createValidationTodos(chunkCount));
return this.todoTool.createTodoList(todos as TodoItem[]);
}
/**
* Update processing progress
*/
async updateProcessingProgress(
stage: 'file-analysis' | 'chunk-detection' | 'chunk-optimization' | 'processing' | 'validation',
status: TodoStatus
): Promise<void> {
const todos = await this.todoTool.getTodoList();
const stageTodos = todos.filter(todo =>
todo.metadata?.processingContext?.processingType === stage
);
for (const todo of stageTodos) {
await this.todoTool.updateTodoStatus(todo.id, status);
}
}
/**
* Get processing statistics
*/
async getProcessingStatistics(): Promise<TodoStatistics> {
return this.todoTool.getTodoStatistics();
}
/**
* Get todos by processing stage
*/
async getTodosByStage(stage: string): Promise<TodoItem[]> {
const todos = await this.todoTool.getTodoList();
if (stage === 'all') {
return todos;
}
return todos.filter(todo =>
todo.metadata?.processingContext?.processingType === stage
);
}
}