// Workflow Orchestrator - Controls which tools Claude Desktop can access based on session state
export interface WorkflowSession {
id: string;
stage: WorkflowStage;
context: Record<string, any>;
createdAt: Date;
lastActivity: Date;
}
export enum WorkflowStage {
CHARACTER_ANALYSIS = 'character_analysis',
PUPPET_GENERATION = 'puppet_generation',
VOICE_CREATION = 'voice_creation',
PRODUCTION_REVIEW = 'production_review',
COMPLETE = 'complete'
}
export interface ToolDefinition {
name: string;
description: string;
inputSchema: any;
allowedStages?: WorkflowStage[];
isCore?: boolean; // Core puppet production tools
}
class WorkflowOrchestrator {
private sessions = new Map<string, WorkflowSession>();
// Get session ID from connection (simplified - could use connection metadata)
private getSessionId(connectionId?: string): string {
return connectionId || 'default-session';
}
// Get or create workflow session
getSession(connectionId?: string): WorkflowSession {
const sessionId = this.getSessionId(connectionId);
if (!this.sessions.has(sessionId)) {
this.sessions.set(sessionId, {
id: sessionId,
stage: WorkflowStage.CHARACTER_ANALYSIS,
context: {},
createdAt: new Date(),
lastActivity: new Date()
});
}
const session = this.sessions.get(sessionId)!;
session.lastActivity = new Date();
return session;
}
// Filter tools based on current workflow stage
filterToolsForSession(allTools: ToolDefinition[], connectionId?: string): ToolDefinition[] {
const session = this.getSession(connectionId);
// Always include core puppet production tools
const coreTools = allTools.filter(tool => tool.isCore);
// Add stage-specific tools
const stageTools = allTools.filter(tool =>
!tool.isCore &&
(!tool.allowedStages || tool.allowedStages.includes(session.stage))
);
return [...coreTools, ...stageTools];
}
// Validate if a tool call is allowed in current stage
isToolAllowed(toolName: string, allTools: ToolDefinition[], connectionId?: string): {
allowed: boolean;
message?: string;
redirect?: string;
} {
const session = this.getSession(connectionId);
const tool = allTools.find(t => t.name === toolName);
if (!tool) {
return {
allowed: false,
message: "Unknown tool. Please use the puppet production tools to create your character.",
redirect: "Use 'analyze_character_image' to start creating a puppet character from a photo."
};
}
// Core puppet tools are always allowed
if (tool.isCore) {
return { allowed: true };
}
// Check stage-specific tools
if (tool.allowedStages && !tool.allowedStages.includes(session.stage)) {
return {
allowed: false,
message: `This tool is not available in the current workflow stage (${session.stage}). Please continue with puppet production.`,
redirect: this.getStageGuidance(session.stage)
};
}
return { allowed: true };
}
// Get guidance for current stage
private getStageGuidance(stage: WorkflowStage): string {
switch (stage) {
case WorkflowStage.CHARACTER_ANALYSIS:
return "Upload a photo and use 'analyze_character_image' to start character analysis.";
case WorkflowStage.PUPPET_GENERATION:
return "Use 'generate_puppet_image' to create your puppet character.";
case WorkflowStage.VOICE_CREATION:
return "Use 'create_voice_profile' to add voice to your character.";
case WorkflowStage.PRODUCTION_REVIEW:
return "Review and finalize your puppet character production.";
default:
return "Continue with the puppet production workflow.";
}
}
// Update session stage
updateStage(stage: WorkflowStage, connectionId?: string): void {
const session = this.getSession(connectionId);
session.stage = stage;
session.lastActivity = new Date();
}
// Add context to session
addContext(key: string, value: any, connectionId?: string): void {
const session = this.getSession(connectionId);
session.context[key] = value;
session.lastActivity = new Date();
}
// Clean up old sessions (older than 1 hour)
cleanup(): void {
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
for (const [sessionId, session] of this.sessions) {
if (session.lastActivity < oneHourAgo) {
this.sessions.delete(sessionId);
}
}
}
}
// Singleton instance
export const workflowOrchestrator = new WorkflowOrchestrator();
// Tool definitions with workflow stages
export const getPuppetProductionTools = (): ToolDefinition[] => [
{
name: 'analyze_character_image',
description: 'Analyze uploaded photo to extract character features for puppet creation',
inputSchema: {
type: 'object',
properties: {
image_url: { type: 'string' },
analysis_type: { type: 'string', enum: ['full', 'face_only', 'style_only'] }
},
required: ['image_url']
},
isCore: true,
allowedStages: [WorkflowStage.CHARACTER_ANALYSIS]
},
{
name: 'generate_puppet_image',
description: 'Generate puppet character image with hand controls based on character analysis',
inputSchema: {
type: 'object',
properties: {
character_features: { type: 'object' },
puppet_style: { type: 'string', enum: ['hand_puppet', 'marionette_hand', 'finger_puppet'] },
background: { type: 'string' }
},
required: ['character_features']
},
isCore: true,
allowedStages: [WorkflowStage.PUPPET_GENERATION]
},
{
name: 'create_voice_profile',
description: 'Create ElevenLabs voice profile for the puppet character',
inputSchema: {
type: 'object',
properties: {
character_name: { type: 'string' },
voice_style: { type: 'string' },
sample_text: { type: 'string' }
},
required: ['character_name']
},
isCore: true,
allowedStages: [WorkflowStage.VOICE_CREATION]
},
{
name: 'finalize_character',
description: 'Complete puppet character production and generate final assets',
inputSchema: {
type: 'object',
properties: {
character_data: { type: 'object' },
export_format: { type: 'string', enum: ['json', 'zip', 'pdf'] }
},
required: ['character_data']
},
isCore: true,
allowedStages: [WorkflowStage.PRODUCTION_REVIEW, WorkflowStage.COMPLETE]
}
];