@stackmemoryai/stackmemory 0.5.31 → 0.5.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/core/agent-task-manager.js.map +1 -1
- package/dist/cli/claude-sm.js +199 -16
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/commands/clear.js +1 -1
- package/dist/cli/commands/clear.js.map +1 -1
- package/dist/cli/commands/context.js +1 -12
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/discovery.js +1 -1
- package/dist/cli/commands/discovery.js.map +1 -1
- package/dist/cli/commands/handoff.js +1 -1
- package/dist/cli/commands/handoff.js.map +1 -1
- package/dist/cli/commands/linear.js +1 -14
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/login.js +32 -10
- package/dist/cli/commands/login.js.map +2 -2
- package/dist/cli/commands/migrate.js +80 -22
- package/dist/cli/commands/migrate.js.map +2 -2
- package/dist/cli/commands/model.js +533 -0
- package/dist/cli/commands/model.js.map +7 -0
- package/dist/cli/commands/monitor.js +1 -1
- package/dist/cli/commands/monitor.js.map +1 -1
- package/dist/cli/commands/quality.js +1 -1
- package/dist/cli/commands/quality.js.map +1 -1
- package/dist/cli/commands/ralph.js +93 -28
- package/dist/cli/commands/ralph.js.map +2 -2
- package/dist/cli/commands/service.js +10 -3
- package/dist/cli/commands/service.js.map +2 -2
- package/dist/cli/commands/skills.js +61 -11
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/sms-notify.js +342 -22
- package/dist/cli/commands/sms-notify.js.map +3 -3
- package/dist/cli/commands/workflow.js +1 -1
- package/dist/cli/commands/workflow.js.map +1 -1
- package/dist/cli/commands/worktree.js +1 -1
- package/dist/cli/commands/worktree.js.map +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +2 -2
- package/dist/core/context/auto-context.js.map +1 -1
- package/dist/core/context/compaction-handler.js.map +2 -2
- package/dist/core/context/context-bridge.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js +24 -8
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/enhanced-rehydration.js.map +1 -1
- package/dist/core/context/frame-database.js +41 -5
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js +6 -1
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-handoff-manager.js.map +1 -1
- package/dist/core/context/frame-lifecycle-hooks.js +119 -0
- package/dist/core/context/frame-lifecycle-hooks.js.map +7 -0
- package/dist/core/context/frame-manager.js +56 -9
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/frame-stack.js +29 -0
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js.map +2 -2
- package/dist/core/context/index.js +4 -22
- package/dist/core/context/index.js.map +2 -2
- package/dist/core/context/permission-manager.js +0 -11
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/recursive-context-manager.js +15 -9
- package/dist/core/context/recursive-context-manager.js.map +2 -2
- package/dist/core/context/refactored-frame-manager.js +140 -34
- package/dist/core/context/refactored-frame-manager.js.map +3 -3
- package/dist/core/context/shared-context-layer.js +0 -11
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/stack-merge-resolver.js.map +1 -1
- package/dist/core/context/validation.js +6 -1
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/database/database-adapter.js.map +1 -1
- package/dist/core/database/paradedb-adapter.js.map +1 -1
- package/dist/core/database/query-router.js.map +1 -1
- package/dist/core/database/sqlite-adapter.js.map +1 -1
- package/dist/core/digest/frame-digest-integration.js.map +1 -1
- package/dist/core/digest/hybrid-digest-generator.js.map +1 -1
- package/dist/core/digest/types.js.map +1 -1
- package/dist/core/errors/index.js +249 -0
- package/dist/core/errors/index.js.map +2 -2
- package/dist/core/frame/workflow-templates.js.map +2 -2
- package/dist/core/merge/conflict-detector.js.map +1 -1
- package/dist/core/merge/resolution-engine.js.map +1 -1
- package/dist/core/merge/stack-diff.js.map +1 -1
- package/dist/core/models/fallback-monitor.js +229 -0
- package/dist/core/models/fallback-monitor.js.map +7 -0
- package/dist/core/models/model-router.js +340 -0
- package/dist/core/models/model-router.js.map +7 -0
- package/dist/core/monitoring/error-handler.js +37 -270
- package/dist/core/monitoring/error-handler.js.map +3 -3
- package/dist/core/monitoring/session-monitor.js.map +1 -1
- package/dist/core/performance/lazy-context-loader.js.map +1 -1
- package/dist/core/performance/optimized-frame-context.js.map +1 -1
- package/dist/core/retrieval/context-retriever.js.map +1 -1
- package/dist/core/retrieval/graph-retrieval.js.map +1 -1
- package/dist/core/retrieval/hierarchical-retrieval.js.map +1 -1
- package/dist/core/retrieval/llm-context-retrieval.js.map +1 -1
- package/dist/core/retrieval/retrieval-benchmarks.js.map +1 -1
- package/dist/core/retrieval/summary-generator.js.map +1 -1
- package/dist/core/retrieval/types.js.map +1 -1
- package/dist/core/storage/chromadb-adapter.js.map +1 -1
- package/dist/core/storage/infinite-storage.js.map +1 -1
- package/dist/core/storage/two-tier-storage.js.map +1 -1
- package/dist/features/tasks/task-aware-context.js.map +1 -1
- package/dist/features/web/server/index.js +1 -1
- package/dist/features/web/server/index.js.map +1 -1
- package/dist/hooks/claude-code-whatsapp-hook.js +197 -0
- package/dist/hooks/claude-code-whatsapp-hook.js.map +7 -0
- package/dist/hooks/linear-task-picker.js +1 -1
- package/dist/hooks/linear-task-picker.js.map +2 -2
- package/dist/hooks/schemas.js +105 -1
- package/dist/hooks/schemas.js.map +2 -2
- package/dist/hooks/session-summary.js +5 -1
- package/dist/hooks/session-summary.js.map +2 -2
- package/dist/hooks/sms-action-runner.js +16 -1
- package/dist/hooks/sms-action-runner.js.map +2 -2
- package/dist/hooks/sms-notify.js +4 -2
- package/dist/hooks/sms-notify.js.map +2 -2
- package/dist/hooks/sms-webhook.js +23 -2
- package/dist/hooks/sms-webhook.js.map +2 -2
- package/dist/hooks/whatsapp-commands.js +516 -0
- package/dist/hooks/whatsapp-commands.js.map +7 -0
- package/dist/hooks/whatsapp-scheduler.js +317 -0
- package/dist/hooks/whatsapp-scheduler.js.map +7 -0
- package/dist/hooks/whatsapp-sync.js +409 -0
- package/dist/hooks/whatsapp-sync.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/mcp/handlers/context-handlers.js.map +1 -1
- package/dist/integrations/mcp/handlers/discovery-handlers.js.map +1 -1
- package/dist/integrations/mcp/server.js +1 -1
- package/dist/integrations/mcp/server.js.map +1 -1
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js +1 -1
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +1 -1
- package/dist/integrations/ralph/context/stackmemory-context-loader.js +1 -1
- package/dist/integrations/ralph/context/stackmemory-context-loader.js.map +1 -1
- package/dist/integrations/ralph/learning/pattern-learner.js +1 -1
- package/dist/integrations/ralph/learning/pattern-learner.js.map +1 -1
- package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js +1 -1
- package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js.map +1 -1
- package/dist/integrations/ralph/swarm/swarm-coordinator.js +1 -1
- package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +1 -1
- package/dist/integrations/ralph/visualization/ralph-debugger.js +1 -1
- package/dist/integrations/ralph/visualization/ralph-debugger.js.map +1 -1
- package/dist/mcp/stackmemory-mcp-server.js +1 -1
- package/dist/mcp/stackmemory-mcp-server.js.map +1 -1
- package/dist/skills/claude-skills.js.map +1 -1
- package/dist/skills/recursive-agent-orchestrator.js.map +1 -1
- package/dist/skills/unified-rlm-orchestrator.js.map +1 -1
- package/package.json +2 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/agents/core/agent-task-manager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Agent Task Manager - Spotify-inspired task handling for StackMemory\n *\n * Integrates Spotify's background coding agent strategies:\n * - 10-turn session limits with automatic task breakdown\n * - Strong verification loops with incremental feedback\n * - Context-aware task prioritization\n * - LLM judge for semantic validation\n */\n\nimport {\n LinearTaskManager,\n PebblesTask,\n TaskStatus,\n TaskPriority,\n} from '../../features/tasks/linear-task-manager.js';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { FrameManager } from '../../core/context/frame-manager.js';\nimport { TaskError, ErrorCode } from '../../core/errors/index.js';\n\nexport interface AgentTaskSession {\n id: string;\n frameId: string;\n taskId: string;\n turnCount: number;\n maxTurns: number;\n status: 'active' | 'completed' | 'failed' | 'timeout';\n startedAt: Date;\n completedAt?: Date;\n verificationResults: VerificationResult[];\n contextWindow: string[];\n feedbackLoop: FeedbackEntry[];\n}\n\nexport interface VerificationResult {\n verifierId: string;\n passed: boolean;\n message: string;\n severity: 'error' | 'warning' | 'info';\n timestamp: Date;\n autoFix?: string;\n}\n\nexport interface FeedbackEntry {\n turn: number;\n action: string;\n result: string;\n verificationPassed: boolean;\n contextAdjustment?: string;\n}\n\nexport interface TaskBreakdown {\n parentTaskId: string;\n subtasks: SubtaskDefinition[];\n dependencies: Map<string, string[]>;\n estimatedTurns: number;\n}\n\nexport interface SubtaskDefinition {\n title: string;\n description: string;\n acceptanceCriteria: string[];\n estimatedTurns: number;\n verifiers: string[];\n}\n\n/**\n * Supported agent types\n */\nexport enum AgentType {\n FORMATTER = 'formatter',\n SECURITY = 'security',\n TESTING = 'testing',\n PERFORMANCE = 'performance',\n DOCUMENTATION = 'documentation',\n REFACTORING = 'refactoring'\n}\n\n/**\n * Spotify-inspired Agent Task Manager\n */\nexport class AgentTaskManager {\n private taskStore: LinearTaskManager;\n private frameManager: FrameManager;\n private activeSessions: Map<string, AgentTaskSession> = new Map();\n private sessionTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private agentRegistry: Map<AgentType, any> = new Map();\n\n // Spotify strategy constants\n private readonly MAX_TURNS_PER_SESSION = 10;\n private readonly MAX_SESSION_RETRIES = 3;\n private readonly SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n private readonly CONTEXT_WINDOW_SIZE = 5; // Last 5 significant events\n\n constructor(taskStore: LinearTaskManager, frameManager: FrameManager) {\n this.taskStore = taskStore;\n this.frameManager = frameManager;\n }\n\n /**\n * Start a new agent task session with Spotify's 10-turn limit\n */\n async startTaskSession(\n taskId: string,\n frameId: string\n ): Promise<AgentTaskSession> {\n const task = this.taskStore.getTask(taskId);\n if (!task) {\n throw new TaskError(\n `Task ${taskId} not found`,\n ErrorCode.TASK_NOT_FOUND,\n { taskId }\n );\n }\n\n // Check if task needs breakdown (Spotify strategy)\n if (this.needsBreakdown(task)) {\n const breakdown = await this.breakdownTask(task);\n return this.startMultiTaskSession(breakdown, frameId);\n }\n\n const sessionId = this.generateSessionId(taskId);\n const session: AgentTaskSession = {\n id: sessionId,\n frameId,\n taskId,\n turnCount: 0,\n maxTurns: this.MAX_TURNS_PER_SESSION,\n status: 'active',\n startedAt: new Date(),\n verificationResults: [],\n contextWindow: [],\n feedbackLoop: [],\n };\n\n this.activeSessions.set(sessionId, session);\n this.startSessionTimeout(sessionId);\n\n // Update task status\n this.taskStore.updateTaskStatus(\n taskId,\n 'in_progress',\n 'Agent session started'\n );\n\n logger.info('Started agent task session', {\n sessionId,\n taskId,\n taskTitle: task.title,\n maxTurns: this.MAX_TURNS_PER_SESSION,\n });\n\n return session;\n }\n\n /**\n * Execute a turn in the session with verification\n */\n async executeTurn(\n sessionId: string,\n action: string,\n context: Record<string, any>\n ): Promise<{\n success: boolean;\n feedback: string;\n shouldContinue: boolean;\n verificationResults: VerificationResult[];\n }> {\n const session = this.activeSessions.get(sessionId);\n if (!session || session.status !== 'active') {\n throw new TaskError(\n 'Invalid or inactive session',\n ErrorCode.TASK_INVALID_STATE,\n { sessionId }\n );\n }\n\n session.turnCount++;\n\n // Check turn limit (Spotify strategy)\n if (session.turnCount >= session.maxTurns) {\n return this.handleTurnLimitReached(session);\n }\n\n // Execute action with verification loop\n const verificationResults = await this.runVerificationLoop(\n action,\n context,\n session\n );\n\n // Update context window (keep last N significant events)\n this.updateContextWindow(session, action, verificationResults);\n\n // Generate feedback based on verification\n const feedback = this.generateFeedback(verificationResults);\n const success = verificationResults.every(\n (r) => r.passed || r.severity !== 'error'\n );\n\n // Record in feedback loop\n session.feedbackLoop.push({\n turn: session.turnCount,\n action,\n result: feedback,\n verificationPassed: success,\n contextAdjustment:\n this.suggestContextAdjustment(verificationResults) || undefined,\n });\n\n // Determine if should continue\n const shouldContinue = success && session.turnCount < session.maxTurns;\n\n if (!shouldContinue && success) {\n await this.completeSession(session);\n }\n\n return {\n success,\n feedback,\n shouldContinue,\n verificationResults,\n };\n }\n\n /**\n * Run Spotify-style verification loop\n */\n private async runVerificationLoop(\n action: string,\n context: Record<string, any>,\n session: AgentTaskSession\n ): Promise<VerificationResult[]> {\n const results: VerificationResult[] = [];\n\n // Get applicable verifiers based on context\n const verifiers = this.getApplicableVerifiers(context);\n\n for (const verifier of verifiers) {\n const result = await this.runVerifier(verifier, action, context);\n results.push(result);\n session.verificationResults.push(result);\n\n // Stop on critical errors (Spotify strategy)\n if (!result.passed && result.severity === 'error') {\n logger.warn('Verification failed, stopping execution', {\n verifier: result.verifierId,\n message: result.message,\n });\n break;\n }\n }\n\n return results;\n }\n\n /**\n * Get verifiers applicable to current context\n */\n private getApplicableVerifiers(context: Record<string, any>): string[] {\n const verifiers: string[] = [];\n\n // Add verifiers based on context (Spotify's context-aware approach)\n if (context['codeChange']) {\n verifiers.push('formatter', 'linter', 'type-checker');\n }\n if (context['testsPresent']) {\n verifiers.push('test-runner');\n }\n if (context['hasDocumentation']) {\n verifiers.push('doc-validator');\n }\n if (context['performanceCritical']) {\n verifiers.push('performance-analyzer');\n }\n\n // Always include semantic validator (LLM judge from Spotify)\n verifiers.push('semantic-validator');\n\n return verifiers;\n }\n\n /**\n * Run a single verifier\n */\n private async runVerifier(\n verifierId: string,\n action: string,\n context: Record<string, any>\n ): Promise<VerificationResult> {\n // This would integrate with actual verifiers\n // For now, return mock result\n const mockResults: Record<string, () => VerificationResult> = {\n formatter: () => ({\n verifierId: 'formatter',\n passed: Math.random() > 0.1,\n message: 'Code formatting check',\n severity: 'warning',\n timestamp: new Date(),\n autoFix: 'prettier --write',\n }),\n linter: () => ({\n verifierId: 'linter',\n passed: Math.random() > 0.2,\n message: 'Linting check',\n severity: 'error',\n timestamp: new Date(),\n }),\n 'test-runner': () => ({\n verifierId: 'test-runner',\n passed: Math.random() > 0.3,\n message: 'Test execution',\n severity: 'error',\n timestamp: new Date(),\n }),\n 'semantic-validator': () => ({\n verifierId: 'semantic-validator',\n passed: Math.random() > 0.25, // ~75% pass rate like Spotify\n message: 'Semantic validation against original requirements',\n severity: 'error',\n timestamp: new Date(),\n }),\n };\n\n const verifierFn =\n mockResults[verifierId] ||\n (() => ({\n verifierId,\n passed: true,\n message: 'Unknown verifier',\n severity: 'info' as const,\n timestamp: new Date(),\n }));\n\n return verifierFn();\n }\n\n /**\n * Check if task needs breakdown (Spotify strategy for complex tasks)\n */\n private needsBreakdown(task: PebblesTask): boolean {\n // Heuristics for determining if task is too complex\n const indicators = {\n hasMultipleComponents:\n (task.description?.match(/\\band\\b/gi)?.length || 0) > 2,\n longDescription: (task.description?.length || 0) > 500,\n highComplexityTags: task.tags.some((tag) =>\n ['refactor', 'migration', 'architecture', 'redesign'].includes(\n tag.toLowerCase()\n )\n ),\n hasManydependencies: task.depends_on.length > 3,\n };\n\n const complexityScore = Object.values(indicators).filter(Boolean).length;\n return complexityScore >= 2;\n }\n\n /**\n * Break down complex task into subtasks\n */\n private async breakdownTask(task: PebblesTask): Promise<TaskBreakdown> {\n // This would use LLM to intelligently break down the task\n // For now, return a simple breakdown\n const subtasks: SubtaskDefinition[] = [\n {\n title: `Analyze requirements for ${task.title}`,\n description: 'Understand and document requirements',\n acceptanceCriteria: [\n 'Requirements documented',\n 'Constraints identified',\n ],\n estimatedTurns: 2,\n verifiers: ['semantic-validator'],\n },\n {\n title: `Implement core functionality for ${task.title}`,\n description: 'Build the main implementation',\n acceptanceCriteria: ['Core logic implemented', 'Tests passing'],\n estimatedTurns: 5,\n verifiers: ['linter', 'test-runner'],\n },\n {\n title: `Verify and refine ${task.title}`,\n description: 'Final verification and improvements',\n acceptanceCriteria: ['All tests passing', 'Documentation complete'],\n estimatedTurns: 3,\n verifiers: ['formatter', 'linter', 'test-runner', 'semantic-validator'],\n },\n ];\n\n return {\n parentTaskId: task.id,\n subtasks,\n dependencies: new Map([\n [subtasks[1]!.title, [subtasks[0]!.title]],\n [subtasks[2]!.title, [subtasks[1]!.title]],\n ]),\n estimatedTurns: subtasks.reduce((sum, st) => sum + st.estimatedTurns, 0),\n };\n }\n\n /**\n * Start multi-task session for complex tasks\n */\n private async startMultiTaskSession(\n breakdown: TaskBreakdown,\n frameId: string\n ): Promise<AgentTaskSession> {\n // Create subtasks in task store\n const subtaskIds: string[] = [];\n\n for (const subtask of breakdown.subtasks) {\n const subtaskId = this.taskStore.createTask({\n title: subtask.title,\n description: subtask.description,\n frameId,\n parentId: breakdown.parentTaskId,\n tags: ['agent-subtask', ...subtask.verifiers],\n estimatedEffort: subtask.estimatedTurns * 5, // Rough conversion to minutes\n });\n subtaskIds.push(subtaskId);\n }\n\n // Add dependencies\n const titleToId = new Map(\n breakdown.subtasks.map((st, i) => [st.title, subtaskIds[i]])\n );\n\n for (const [title, deps] of breakdown.dependencies) {\n const taskId = titleToId.get(title);\n if (taskId) {\n for (const dep of deps) {\n const depId = titleToId.get(dep);\n if (depId) {\n this.taskStore.addDependency(taskId, depId);\n }\n }\n }\n }\n\n // Start session for first subtask\n return this.startTaskSession(subtaskIds[0]!, frameId);\n }\n\n /**\n * Update context window with significant events\n */\n private updateContextWindow(\n session: AgentTaskSession,\n action: string,\n verificationResults: VerificationResult[]\n ): void {\n const significantEvent = {\n turn: session.turnCount,\n action: action.substring(0, 100),\n verificationSummary: verificationResults.map((r) => ({\n verifier: r.verifierId,\n passed: r.passed,\n })),\n timestamp: new Date().toISOString(),\n };\n\n session.contextWindow.push(JSON.stringify(significantEvent));\n\n // Keep only last N events (Spotify's context window optimization)\n if (session.contextWindow.length > this.CONTEXT_WINDOW_SIZE) {\n session.contextWindow = session.contextWindow.slice(\n -this.CONTEXT_WINDOW_SIZE\n );\n }\n }\n\n /**\n * Generate feedback from verification results\n */\n private generateFeedback(results: VerificationResult[]): string {\n const failed = results.filter((r) => !r.passed);\n const warnings = results.filter(\n (r) => !r.passed && r.severity === 'warning'\n );\n const errors = results.filter((r) => !r.passed && r.severity === 'error');\n\n if (errors.length > 0) {\n const errorMessages = errors.map((e) => `- ${e.message}`).join('\\n');\n return `Verification failed with ${errors.length} error(s):\\n${errorMessages}`;\n }\n\n if (warnings.length > 0) {\n const warningMessages = warnings.map((w) => `- ${w.message}`).join('\\n');\n return `Verification passed with ${warnings.length} warning(s):\\n${warningMessages}`;\n }\n\n return 'All verifications passed successfully';\n }\n\n /**\n * Suggest context adjustment based on verification results\n */\n private suggestContextAdjustment(\n results: VerificationResult[]\n ): string | undefined {\n const failed = results.filter((r) => !r.passed && r.severity === 'error');\n\n if (failed.length === 0) {\n return undefined;\n }\n\n // Generate suggestions based on failure patterns\n const suggestions: string[] = [];\n\n if (failed.some((r) => r.verifierId === 'test-runner')) {\n suggestions.push('Focus on fixing failing tests');\n }\n if (failed.some((r) => r.verifierId === 'linter')) {\n suggestions.push('Address linting errors before proceeding');\n }\n if (failed.some((r) => r.verifierId === 'semantic-validator')) {\n suggestions.push('Review original requirements and adjust approach');\n }\n\n return suggestions.length > 0 ? suggestions.join('; ') : undefined;\n }\n\n /**\n * Handle turn limit reached\n */\n private async handleTurnLimitReached(session: AgentTaskSession): Promise<{\n success: boolean;\n feedback: string;\n shouldContinue: boolean;\n verificationResults: VerificationResult[];\n }> {\n logger.warn('Session reached turn limit', {\n sessionId: session.id,\n taskId: session.taskId,\n turnCount: session.turnCount,\n });\n\n // Check if task can be considered complete\n const task = this.taskStore.getTask(session.taskId);\n const isComplete = this.assessTaskCompletion(session);\n\n if (isComplete) {\n await this.completeSession(session);\n return {\n success: true,\n feedback: 'Task completed successfully within turn limit',\n shouldContinue: false,\n verificationResults: [],\n };\n }\n\n // Mark session as timeout\n session.status = 'timeout';\n this.taskStore.updateTaskStatus(\n session.taskId,\n 'blocked',\n 'Session timeout - manual review needed'\n );\n\n return {\n success: false,\n feedback: `Session reached ${this.MAX_TURNS_PER_SESSION} turn limit. Task requires manual review or retry.`,\n shouldContinue: false,\n verificationResults: [],\n };\n }\n\n /**\n * Assess if task is complete enough\n */\n private assessTaskCompletion(session: AgentTaskSession): boolean {\n // Check if recent verifications are passing\n const recentResults = session.verificationResults.slice(-5);\n const recentPassRate =\n recentResults.filter((r) => r.passed).length / recentResults.length;\n\n // Check if semantic validator passed recently (Spotify's LLM judge)\n const semanticPassed = recentResults.some(\n (r) => r.verifierId === 'semantic-validator' && r.passed\n );\n\n return recentPassRate >= 0.8 && semanticPassed;\n }\n\n /**\n * Complete a session\n */\n private async completeSession(session: AgentTaskSession): Promise<void> {\n session.status = 'completed';\n session.completedAt = new Date();\n\n // Update task status\n this.taskStore.updateTaskStatus(\n session.taskId,\n 'completed',\n 'Agent session completed'\n );\n\n // Clear timeout\n const timeout = this.sessionTimeouts.get(session.id);\n if (timeout) {\n clearTimeout(timeout);\n this.sessionTimeouts.delete(session.id);\n }\n\n // Generate and save session summary to frame\n const summary = this.generateSessionSummary(session);\n this.frameManager.addEvent('observation', {\n type: 'session_summary',\n frameId: session.frameId,\n summary,\n });\n\n logger.info('Session completed', {\n sessionId: session.id,\n taskId: session.taskId,\n turnCount: session.turnCount,\n duration: session.completedAt.getTime() - session.startedAt.getTime(),\n });\n }\n\n /**\n * Generate session summary for frame digest\n */\n private generateSessionSummary(\n session: AgentTaskSession\n ): Record<string, any> {\n const verificationStats = {\n total: session.verificationResults.length,\n passed: session.verificationResults.filter((r) => r.passed).length,\n failed: session.verificationResults.filter((r) => !r.passed).length,\n };\n\n return {\n sessionId: session.id,\n taskId: session.taskId,\n status: session.status,\n turnCount: session.turnCount,\n duration: session.completedAt\n ? session.completedAt.getTime() - session.startedAt.getTime()\n : 0,\n verificationStats,\n feedbackLoop: session.feedbackLoop.slice(-3), // Last 3 feedback entries\n contextWindow: session.contextWindow.slice(-2), // Last 2 context entries\n };\n }\n\n /**\n * Start timeout for session\n */\n private startSessionTimeout(sessionId: string): void {\n const timeout = setTimeout(() => {\n const session = this.activeSessions.get(sessionId);\n if (session && session.status === 'active') {\n session.status = 'timeout';\n this.taskStore.updateTaskStatus(\n session.taskId,\n 'blocked',\n 'Session timeout - no activity'\n );\n logger.warn('Session timed out due to inactivity', { sessionId });\n }\n }, this.SESSION_TIMEOUT_MS);\n\n this.sessionTimeouts.set(sessionId, timeout);\n }\n\n /**\n * Generate unique session ID\n */\n private generateSessionId(taskId: string): string {\n return `session-${taskId}-${Date.now()}`;\n }\n\n /**\n * Get active sessions summary\n */\n getActiveSessions(): Array<{\n sessionId: string;\n taskId: string;\n turnCount: number;\n status: string;\n startedAt: Date;\n }> {\n return Array.from(this.activeSessions.values()).map((session) => ({\n sessionId: session.id,\n taskId: session.taskId,\n turnCount: session.turnCount,\n status: session.status,\n startedAt: session.startedAt,\n }));\n }\n\n /**\n * Retry a failed session (Spotify's 3-retry strategy)\n */\n async retrySession(sessionId: string): Promise<AgentTaskSession | null> {\n const session = this.activeSessions.get(sessionId);\n if (!session || session.status === 'active') {\n return null;\n }\n\n // Count previous retries\n const retryCount = Array.from(this.activeSessions.values()).filter(\n (s) => s.taskId === session.taskId && s.status === 'failed'\n ).length;\n\n if (retryCount >= this.MAX_SESSION_RETRIES) {\n logger.warn('Max retries reached for task', {\n taskId: session.taskId,\n retries: retryCount,\n });\n return null;\n }\n\n // Start new session with learned context\n const newSession = await this.startTaskSession(\n session.taskId,\n session.frameId\n );\n\n // Transfer learned context from previous session\n newSession.contextWindow = session.contextWindow.slice(-3);\n newSession.feedbackLoop = [\n {\n turn: 0,\n action: 'Session retry with learned context',\n result: `Retrying after ${retryCount} previous attempts`,\n verificationPassed: true,\n contextAdjustment: session.feedbackLoop\n .filter((f) => f.contextAdjustment)\n .map((f) => f.contextAdjustment)\n .join('; '),\n },\n ];\n\n return newSession;\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * Agent Task Manager - Spotify-inspired task handling for StackMemory\n *\n * Integrates Spotify's background coding agent strategies:\n * - 10-turn session limits with automatic task breakdown\n * - Strong verification loops with incremental feedback\n * - Context-aware task prioritization\n * - LLM judge for semantic validation\n */\n\nimport {\n LinearTaskManager,\n PebblesTask,\n TaskStatus,\n TaskPriority,\n} from '../../features/tasks/linear-task-manager.js';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { FrameManager } from '../../core/context/index.js';\nimport { TaskError, ErrorCode } from '../../core/errors/index.js';\n\nexport interface AgentTaskSession {\n id: string;\n frameId: string;\n taskId: string;\n turnCount: number;\n maxTurns: number;\n status: 'active' | 'completed' | 'failed' | 'timeout';\n startedAt: Date;\n completedAt?: Date;\n verificationResults: VerificationResult[];\n contextWindow: string[];\n feedbackLoop: FeedbackEntry[];\n}\n\nexport interface VerificationResult {\n verifierId: string;\n passed: boolean;\n message: string;\n severity: 'error' | 'warning' | 'info';\n timestamp: Date;\n autoFix?: string;\n}\n\nexport interface FeedbackEntry {\n turn: number;\n action: string;\n result: string;\n verificationPassed: boolean;\n contextAdjustment?: string;\n}\n\nexport interface TaskBreakdown {\n parentTaskId: string;\n subtasks: SubtaskDefinition[];\n dependencies: Map<string, string[]>;\n estimatedTurns: number;\n}\n\nexport interface SubtaskDefinition {\n title: string;\n description: string;\n acceptanceCriteria: string[];\n estimatedTurns: number;\n verifiers: string[];\n}\n\n/**\n * Supported agent types\n */\nexport enum AgentType {\n FORMATTER = 'formatter',\n SECURITY = 'security',\n TESTING = 'testing',\n PERFORMANCE = 'performance',\n DOCUMENTATION = 'documentation',\n REFACTORING = 'refactoring'\n}\n\n/**\n * Spotify-inspired Agent Task Manager\n */\nexport class AgentTaskManager {\n private taskStore: LinearTaskManager;\n private frameManager: FrameManager;\n private activeSessions: Map<string, AgentTaskSession> = new Map();\n private sessionTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private agentRegistry: Map<AgentType, any> = new Map();\n\n // Spotify strategy constants\n private readonly MAX_TURNS_PER_SESSION = 10;\n private readonly MAX_SESSION_RETRIES = 3;\n private readonly SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n private readonly CONTEXT_WINDOW_SIZE = 5; // Last 5 significant events\n\n constructor(taskStore: LinearTaskManager, frameManager: FrameManager) {\n this.taskStore = taskStore;\n this.frameManager = frameManager;\n }\n\n /**\n * Start a new agent task session with Spotify's 10-turn limit\n */\n async startTaskSession(\n taskId: string,\n frameId: string\n ): Promise<AgentTaskSession> {\n const task = this.taskStore.getTask(taskId);\n if (!task) {\n throw new TaskError(\n `Task ${taskId} not found`,\n ErrorCode.TASK_NOT_FOUND,\n { taskId }\n );\n }\n\n // Check if task needs breakdown (Spotify strategy)\n if (this.needsBreakdown(task)) {\n const breakdown = await this.breakdownTask(task);\n return this.startMultiTaskSession(breakdown, frameId);\n }\n\n const sessionId = this.generateSessionId(taskId);\n const session: AgentTaskSession = {\n id: sessionId,\n frameId,\n taskId,\n turnCount: 0,\n maxTurns: this.MAX_TURNS_PER_SESSION,\n status: 'active',\n startedAt: new Date(),\n verificationResults: [],\n contextWindow: [],\n feedbackLoop: [],\n };\n\n this.activeSessions.set(sessionId, session);\n this.startSessionTimeout(sessionId);\n\n // Update task status\n this.taskStore.updateTaskStatus(\n taskId,\n 'in_progress',\n 'Agent session started'\n );\n\n logger.info('Started agent task session', {\n sessionId,\n taskId,\n taskTitle: task.title,\n maxTurns: this.MAX_TURNS_PER_SESSION,\n });\n\n return session;\n }\n\n /**\n * Execute a turn in the session with verification\n */\n async executeTurn(\n sessionId: string,\n action: string,\n context: Record<string, any>\n ): Promise<{\n success: boolean;\n feedback: string;\n shouldContinue: boolean;\n verificationResults: VerificationResult[];\n }> {\n const session = this.activeSessions.get(sessionId);\n if (!session || session.status !== 'active') {\n throw new TaskError(\n 'Invalid or inactive session',\n ErrorCode.TASK_INVALID_STATE,\n { sessionId }\n );\n }\n\n session.turnCount++;\n\n // Check turn limit (Spotify strategy)\n if (session.turnCount >= session.maxTurns) {\n return this.handleTurnLimitReached(session);\n }\n\n // Execute action with verification loop\n const verificationResults = await this.runVerificationLoop(\n action,\n context,\n session\n );\n\n // Update context window (keep last N significant events)\n this.updateContextWindow(session, action, verificationResults);\n\n // Generate feedback based on verification\n const feedback = this.generateFeedback(verificationResults);\n const success = verificationResults.every(\n (r) => r.passed || r.severity !== 'error'\n );\n\n // Record in feedback loop\n session.feedbackLoop.push({\n turn: session.turnCount,\n action,\n result: feedback,\n verificationPassed: success,\n contextAdjustment:\n this.suggestContextAdjustment(verificationResults) || undefined,\n });\n\n // Determine if should continue\n const shouldContinue = success && session.turnCount < session.maxTurns;\n\n if (!shouldContinue && success) {\n await this.completeSession(session);\n }\n\n return {\n success,\n feedback,\n shouldContinue,\n verificationResults,\n };\n }\n\n /**\n * Run Spotify-style verification loop\n */\n private async runVerificationLoop(\n action: string,\n context: Record<string, any>,\n session: AgentTaskSession\n ): Promise<VerificationResult[]> {\n const results: VerificationResult[] = [];\n\n // Get applicable verifiers based on context\n const verifiers = this.getApplicableVerifiers(context);\n\n for (const verifier of verifiers) {\n const result = await this.runVerifier(verifier, action, context);\n results.push(result);\n session.verificationResults.push(result);\n\n // Stop on critical errors (Spotify strategy)\n if (!result.passed && result.severity === 'error') {\n logger.warn('Verification failed, stopping execution', {\n verifier: result.verifierId,\n message: result.message,\n });\n break;\n }\n }\n\n return results;\n }\n\n /**\n * Get verifiers applicable to current context\n */\n private getApplicableVerifiers(context: Record<string, any>): string[] {\n const verifiers: string[] = [];\n\n // Add verifiers based on context (Spotify's context-aware approach)\n if (context['codeChange']) {\n verifiers.push('formatter', 'linter', 'type-checker');\n }\n if (context['testsPresent']) {\n verifiers.push('test-runner');\n }\n if (context['hasDocumentation']) {\n verifiers.push('doc-validator');\n }\n if (context['performanceCritical']) {\n verifiers.push('performance-analyzer');\n }\n\n // Always include semantic validator (LLM judge from Spotify)\n verifiers.push('semantic-validator');\n\n return verifiers;\n }\n\n /**\n * Run a single verifier\n */\n private async runVerifier(\n verifierId: string,\n action: string,\n context: Record<string, any>\n ): Promise<VerificationResult> {\n // This would integrate with actual verifiers\n // For now, return mock result\n const mockResults: Record<string, () => VerificationResult> = {\n formatter: () => ({\n verifierId: 'formatter',\n passed: Math.random() > 0.1,\n message: 'Code formatting check',\n severity: 'warning',\n timestamp: new Date(),\n autoFix: 'prettier --write',\n }),\n linter: () => ({\n verifierId: 'linter',\n passed: Math.random() > 0.2,\n message: 'Linting check',\n severity: 'error',\n timestamp: new Date(),\n }),\n 'test-runner': () => ({\n verifierId: 'test-runner',\n passed: Math.random() > 0.3,\n message: 'Test execution',\n severity: 'error',\n timestamp: new Date(),\n }),\n 'semantic-validator': () => ({\n verifierId: 'semantic-validator',\n passed: Math.random() > 0.25, // ~75% pass rate like Spotify\n message: 'Semantic validation against original requirements',\n severity: 'error',\n timestamp: new Date(),\n }),\n };\n\n const verifierFn =\n mockResults[verifierId] ||\n (() => ({\n verifierId,\n passed: true,\n message: 'Unknown verifier',\n severity: 'info' as const,\n timestamp: new Date(),\n }));\n\n return verifierFn();\n }\n\n /**\n * Check if task needs breakdown (Spotify strategy for complex tasks)\n */\n private needsBreakdown(task: PebblesTask): boolean {\n // Heuristics for determining if task is too complex\n const indicators = {\n hasMultipleComponents:\n (task.description?.match(/\\band\\b/gi)?.length || 0) > 2,\n longDescription: (task.description?.length || 0) > 500,\n highComplexityTags: task.tags.some((tag) =>\n ['refactor', 'migration', 'architecture', 'redesign'].includes(\n tag.toLowerCase()\n )\n ),\n hasManydependencies: task.depends_on.length > 3,\n };\n\n const complexityScore = Object.values(indicators).filter(Boolean).length;\n return complexityScore >= 2;\n }\n\n /**\n * Break down complex task into subtasks\n */\n private async breakdownTask(task: PebblesTask): Promise<TaskBreakdown> {\n // This would use LLM to intelligently break down the task\n // For now, return a simple breakdown\n const subtasks: SubtaskDefinition[] = [\n {\n title: `Analyze requirements for ${task.title}`,\n description: 'Understand and document requirements',\n acceptanceCriteria: [\n 'Requirements documented',\n 'Constraints identified',\n ],\n estimatedTurns: 2,\n verifiers: ['semantic-validator'],\n },\n {\n title: `Implement core functionality for ${task.title}`,\n description: 'Build the main implementation',\n acceptanceCriteria: ['Core logic implemented', 'Tests passing'],\n estimatedTurns: 5,\n verifiers: ['linter', 'test-runner'],\n },\n {\n title: `Verify and refine ${task.title}`,\n description: 'Final verification and improvements',\n acceptanceCriteria: ['All tests passing', 'Documentation complete'],\n estimatedTurns: 3,\n verifiers: ['formatter', 'linter', 'test-runner', 'semantic-validator'],\n },\n ];\n\n return {\n parentTaskId: task.id,\n subtasks,\n dependencies: new Map([\n [subtasks[1]!.title, [subtasks[0]!.title]],\n [subtasks[2]!.title, [subtasks[1]!.title]],\n ]),\n estimatedTurns: subtasks.reduce((sum, st) => sum + st.estimatedTurns, 0),\n };\n }\n\n /**\n * Start multi-task session for complex tasks\n */\n private async startMultiTaskSession(\n breakdown: TaskBreakdown,\n frameId: string\n ): Promise<AgentTaskSession> {\n // Create subtasks in task store\n const subtaskIds: string[] = [];\n\n for (const subtask of breakdown.subtasks) {\n const subtaskId = this.taskStore.createTask({\n title: subtask.title,\n description: subtask.description,\n frameId,\n parentId: breakdown.parentTaskId,\n tags: ['agent-subtask', ...subtask.verifiers],\n estimatedEffort: subtask.estimatedTurns * 5, // Rough conversion to minutes\n });\n subtaskIds.push(subtaskId);\n }\n\n // Add dependencies\n const titleToId = new Map(\n breakdown.subtasks.map((st, i) => [st.title, subtaskIds[i]])\n );\n\n for (const [title, deps] of breakdown.dependencies) {\n const taskId = titleToId.get(title);\n if (taskId) {\n for (const dep of deps) {\n const depId = titleToId.get(dep);\n if (depId) {\n this.taskStore.addDependency(taskId, depId);\n }\n }\n }\n }\n\n // Start session for first subtask\n return this.startTaskSession(subtaskIds[0]!, frameId);\n }\n\n /**\n * Update context window with significant events\n */\n private updateContextWindow(\n session: AgentTaskSession,\n action: string,\n verificationResults: VerificationResult[]\n ): void {\n const significantEvent = {\n turn: session.turnCount,\n action: action.substring(0, 100),\n verificationSummary: verificationResults.map((r) => ({\n verifier: r.verifierId,\n passed: r.passed,\n })),\n timestamp: new Date().toISOString(),\n };\n\n session.contextWindow.push(JSON.stringify(significantEvent));\n\n // Keep only last N events (Spotify's context window optimization)\n if (session.contextWindow.length > this.CONTEXT_WINDOW_SIZE) {\n session.contextWindow = session.contextWindow.slice(\n -this.CONTEXT_WINDOW_SIZE\n );\n }\n }\n\n /**\n * Generate feedback from verification results\n */\n private generateFeedback(results: VerificationResult[]): string {\n const failed = results.filter((r) => !r.passed);\n const warnings = results.filter(\n (r) => !r.passed && r.severity === 'warning'\n );\n const errors = results.filter((r) => !r.passed && r.severity === 'error');\n\n if (errors.length > 0) {\n const errorMessages = errors.map((e) => `- ${e.message}`).join('\\n');\n return `Verification failed with ${errors.length} error(s):\\n${errorMessages}`;\n }\n\n if (warnings.length > 0) {\n const warningMessages = warnings.map((w) => `- ${w.message}`).join('\\n');\n return `Verification passed with ${warnings.length} warning(s):\\n${warningMessages}`;\n }\n\n return 'All verifications passed successfully';\n }\n\n /**\n * Suggest context adjustment based on verification results\n */\n private suggestContextAdjustment(\n results: VerificationResult[]\n ): string | undefined {\n const failed = results.filter((r) => !r.passed && r.severity === 'error');\n\n if (failed.length === 0) {\n return undefined;\n }\n\n // Generate suggestions based on failure patterns\n const suggestions: string[] = [];\n\n if (failed.some((r) => r.verifierId === 'test-runner')) {\n suggestions.push('Focus on fixing failing tests');\n }\n if (failed.some((r) => r.verifierId === 'linter')) {\n suggestions.push('Address linting errors before proceeding');\n }\n if (failed.some((r) => r.verifierId === 'semantic-validator')) {\n suggestions.push('Review original requirements and adjust approach');\n }\n\n return suggestions.length > 0 ? suggestions.join('; ') : undefined;\n }\n\n /**\n * Handle turn limit reached\n */\n private async handleTurnLimitReached(session: AgentTaskSession): Promise<{\n success: boolean;\n feedback: string;\n shouldContinue: boolean;\n verificationResults: VerificationResult[];\n }> {\n logger.warn('Session reached turn limit', {\n sessionId: session.id,\n taskId: session.taskId,\n turnCount: session.turnCount,\n });\n\n // Check if task can be considered complete\n const task = this.taskStore.getTask(session.taskId);\n const isComplete = this.assessTaskCompletion(session);\n\n if (isComplete) {\n await this.completeSession(session);\n return {\n success: true,\n feedback: 'Task completed successfully within turn limit',\n shouldContinue: false,\n verificationResults: [],\n };\n }\n\n // Mark session as timeout\n session.status = 'timeout';\n this.taskStore.updateTaskStatus(\n session.taskId,\n 'blocked',\n 'Session timeout - manual review needed'\n );\n\n return {\n success: false,\n feedback: `Session reached ${this.MAX_TURNS_PER_SESSION} turn limit. Task requires manual review or retry.`,\n shouldContinue: false,\n verificationResults: [],\n };\n }\n\n /**\n * Assess if task is complete enough\n */\n private assessTaskCompletion(session: AgentTaskSession): boolean {\n // Check if recent verifications are passing\n const recentResults = session.verificationResults.slice(-5);\n const recentPassRate =\n recentResults.filter((r) => r.passed).length / recentResults.length;\n\n // Check if semantic validator passed recently (Spotify's LLM judge)\n const semanticPassed = recentResults.some(\n (r) => r.verifierId === 'semantic-validator' && r.passed\n );\n\n return recentPassRate >= 0.8 && semanticPassed;\n }\n\n /**\n * Complete a session\n */\n private async completeSession(session: AgentTaskSession): Promise<void> {\n session.status = 'completed';\n session.completedAt = new Date();\n\n // Update task status\n this.taskStore.updateTaskStatus(\n session.taskId,\n 'completed',\n 'Agent session completed'\n );\n\n // Clear timeout\n const timeout = this.sessionTimeouts.get(session.id);\n if (timeout) {\n clearTimeout(timeout);\n this.sessionTimeouts.delete(session.id);\n }\n\n // Generate and save session summary to frame\n const summary = this.generateSessionSummary(session);\n this.frameManager.addEvent('observation', {\n type: 'session_summary',\n frameId: session.frameId,\n summary,\n });\n\n logger.info('Session completed', {\n sessionId: session.id,\n taskId: session.taskId,\n turnCount: session.turnCount,\n duration: session.completedAt.getTime() - session.startedAt.getTime(),\n });\n }\n\n /**\n * Generate session summary for frame digest\n */\n private generateSessionSummary(\n session: AgentTaskSession\n ): Record<string, any> {\n const verificationStats = {\n total: session.verificationResults.length,\n passed: session.verificationResults.filter((r) => r.passed).length,\n failed: session.verificationResults.filter((r) => !r.passed).length,\n };\n\n return {\n sessionId: session.id,\n taskId: session.taskId,\n status: session.status,\n turnCount: session.turnCount,\n duration: session.completedAt\n ? session.completedAt.getTime() - session.startedAt.getTime()\n : 0,\n verificationStats,\n feedbackLoop: session.feedbackLoop.slice(-3), // Last 3 feedback entries\n contextWindow: session.contextWindow.slice(-2), // Last 2 context entries\n };\n }\n\n /**\n * Start timeout for session\n */\n private startSessionTimeout(sessionId: string): void {\n const timeout = setTimeout(() => {\n const session = this.activeSessions.get(sessionId);\n if (session && session.status === 'active') {\n session.status = 'timeout';\n this.taskStore.updateTaskStatus(\n session.taskId,\n 'blocked',\n 'Session timeout - no activity'\n );\n logger.warn('Session timed out due to inactivity', { sessionId });\n }\n }, this.SESSION_TIMEOUT_MS);\n\n this.sessionTimeouts.set(sessionId, timeout);\n }\n\n /**\n * Generate unique session ID\n */\n private generateSessionId(taskId: string): string {\n return `session-${taskId}-${Date.now()}`;\n }\n\n /**\n * Get active sessions summary\n */\n getActiveSessions(): Array<{\n sessionId: string;\n taskId: string;\n turnCount: number;\n status: string;\n startedAt: Date;\n }> {\n return Array.from(this.activeSessions.values()).map((session) => ({\n sessionId: session.id,\n taskId: session.taskId,\n turnCount: session.turnCount,\n status: session.status,\n startedAt: session.startedAt,\n }));\n }\n\n /**\n * Retry a failed session (Spotify's 3-retry strategy)\n */\n async retrySession(sessionId: string): Promise<AgentTaskSession | null> {\n const session = this.activeSessions.get(sessionId);\n if (!session || session.status === 'active') {\n return null;\n }\n\n // Count previous retries\n const retryCount = Array.from(this.activeSessions.values()).filter(\n (s) => s.taskId === session.taskId && s.status === 'failed'\n ).length;\n\n if (retryCount >= this.MAX_SESSION_RETRIES) {\n logger.warn('Max retries reached for task', {\n taskId: session.taskId,\n retries: retryCount,\n });\n return null;\n }\n\n // Start new session with learned context\n const newSession = await this.startTaskSession(\n session.taskId,\n session.frameId\n );\n\n // Transfer learned context from previous session\n newSession.contextWindow = session.contextWindow.slice(-3);\n newSession.feedbackLoop = [\n {\n turn: 0,\n action: 'Session retry with learned context',\n result: `Retrying after ${retryCount} previous attempts`,\n verificationPassed: true,\n contextAdjustment: session.feedbackLoop\n .filter((f) => f.contextAdjustment)\n .map((f) => f.contextAdjustment)\n .join('; '),\n },\n ];\n\n return newSession;\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["AgentType"]
|
|
7
7
|
}
|
package/dist/cli/claude-sm.js
CHANGED
|
@@ -17,7 +17,15 @@ import {
|
|
|
17
17
|
generateSessionSummary,
|
|
18
18
|
formatSummaryMessage
|
|
19
19
|
} from "../hooks/session-summary.js";
|
|
20
|
-
import { sendNotification } from "../hooks/sms-notify.js";
|
|
20
|
+
import { sendNotification, loadSMSConfig } from "../hooks/sms-notify.js";
|
|
21
|
+
import { enableAutoSync } from "../hooks/whatsapp-sync.js";
|
|
22
|
+
import { enableCommands } from "../hooks/whatsapp-commands.js";
|
|
23
|
+
import { startScheduler, listSchedules } from "../hooks/whatsapp-scheduler.js";
|
|
24
|
+
import {
|
|
25
|
+
getModelRouter,
|
|
26
|
+
loadModelRouterConfig
|
|
27
|
+
} from "../core/models/model-router.js";
|
|
28
|
+
import { FallbackMonitor } from "../core/models/fallback-monitor.js";
|
|
21
29
|
const DEFAULT_SM_CONFIG = {
|
|
22
30
|
defaultWorktree: false,
|
|
23
31
|
defaultSandbox: false,
|
|
@@ -25,7 +33,8 @@ const DEFAULT_SM_CONFIG = {
|
|
|
25
33
|
defaultTracing: true,
|
|
26
34
|
defaultRemote: false,
|
|
27
35
|
defaultNotifyOnDone: true,
|
|
28
|
-
defaultWhatsApp: false
|
|
36
|
+
defaultWhatsApp: false,
|
|
37
|
+
defaultModelRouting: false
|
|
29
38
|
};
|
|
30
39
|
function getConfigPath() {
|
|
31
40
|
return path.join(os.homedir(), ".stackmemory", "claude-sm.json");
|
|
@@ -68,7 +77,9 @@ class ClaudeSM {
|
|
|
68
77
|
contextEnabled: true,
|
|
69
78
|
tracingEnabled: this.smConfig.defaultTracing,
|
|
70
79
|
verboseTracing: false,
|
|
71
|
-
sessionStartTime: Date.now()
|
|
80
|
+
sessionStartTime: Date.now(),
|
|
81
|
+
useModelRouting: this.smConfig.defaultModelRouting,
|
|
82
|
+
useThinkingMode: false
|
|
72
83
|
};
|
|
73
84
|
this.stackmemoryPath = this.findStackMemory();
|
|
74
85
|
this.worktreeScriptPath = path.join(
|
|
@@ -249,7 +260,41 @@ class ClaudeSM {
|
|
|
249
260
|
}
|
|
250
261
|
async startWhatsAppServices() {
|
|
251
262
|
const WEBHOOK_PORT = 3456;
|
|
252
|
-
console.log(chalk.cyan("
|
|
263
|
+
console.log(chalk.cyan("\n\u{1F4F1} WhatsApp Mode - Full Integration"));
|
|
264
|
+
console.log(chalk.gray("\u2500".repeat(42)));
|
|
265
|
+
const smsConfig = loadSMSConfig();
|
|
266
|
+
if (!smsConfig.enabled) {
|
|
267
|
+
console.log(
|
|
268
|
+
chalk.yellow(" Notifications disabled. Run: stackmemory notify enable")
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
enableAutoSync();
|
|
273
|
+
console.log(
|
|
274
|
+
chalk.green(" \u2713 Auto-sync enabled (digests on frame close)")
|
|
275
|
+
);
|
|
276
|
+
} catch {
|
|
277
|
+
console.log(chalk.gray(" Auto-sync: skipped"));
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
enableCommands();
|
|
281
|
+
console.log(chalk.green(" \u2713 Command processing enabled"));
|
|
282
|
+
console.log(
|
|
283
|
+
chalk.gray(" Reply: status, tasks, context, help, build, test, lint")
|
|
284
|
+
);
|
|
285
|
+
} catch {
|
|
286
|
+
console.log(chalk.gray(" Command processing: skipped"));
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
const schedules = listSchedules();
|
|
290
|
+
if (schedules.length > 0) {
|
|
291
|
+
startScheduler();
|
|
292
|
+
console.log(
|
|
293
|
+
chalk.green(` \u2713 Scheduler started (${schedules.length} schedules)`)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
} catch {
|
|
297
|
+
}
|
|
253
298
|
const webhookRunning = await fetch(
|
|
254
299
|
`http://localhost:${WEBHOOK_PORT}/health`
|
|
255
300
|
).then((r) => r.ok).catch(() => false);
|
|
@@ -262,11 +307,11 @@ class ClaudeSM {
|
|
|
262
307
|
});
|
|
263
308
|
webhookProcess.unref();
|
|
264
309
|
console.log(
|
|
265
|
-
chalk.
|
|
310
|
+
chalk.green(` \u2713 Webhook server started (port ${WEBHOOK_PORT})`)
|
|
266
311
|
);
|
|
267
312
|
} else {
|
|
268
313
|
console.log(
|
|
269
|
-
chalk.
|
|
314
|
+
chalk.green(` \u2713 Webhook already running (port ${WEBHOOK_PORT})`)
|
|
270
315
|
);
|
|
271
316
|
}
|
|
272
317
|
const ngrokRunning = await fetch("http://localhost:4040/api/tunnels").then((r) => r.ok).catch(() => false);
|
|
@@ -276,7 +321,7 @@ class ClaudeSM {
|
|
|
276
321
|
stdio: "ignore"
|
|
277
322
|
});
|
|
278
323
|
ngrokProcess.unref();
|
|
279
|
-
console.log(chalk.gray(" ngrok tunnel
|
|
324
|
+
console.log(chalk.gray(" Starting ngrok tunnel..."));
|
|
280
325
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
281
326
|
}
|
|
282
327
|
try {
|
|
@@ -291,15 +336,34 @@ class ClaudeSM {
|
|
|
291
336
|
fs.mkdirSync(configDir, { recursive: true });
|
|
292
337
|
}
|
|
293
338
|
fs.writeFileSync(configPath, publicUrl);
|
|
294
|
-
console.log(
|
|
295
|
-
chalk.green(` WhatsApp webhook: ${publicUrl}/sms/incoming`)
|
|
296
|
-
);
|
|
339
|
+
console.log(chalk.green(` \u2713 ngrok tunnel: ${publicUrl}/sms/incoming`));
|
|
297
340
|
}
|
|
298
341
|
} catch {
|
|
342
|
+
console.log(chalk.yellow(" ngrok: waiting for tunnel..."));
|
|
343
|
+
}
|
|
344
|
+
if (smsConfig.pendingPrompts.length > 0) {
|
|
345
|
+
console.log();
|
|
299
346
|
console.log(
|
|
300
|
-
chalk.yellow(
|
|
347
|
+
chalk.yellow(
|
|
348
|
+
` \u23F3 ${smsConfig.pendingPrompts.length} pending prompt(s) awaiting response:`
|
|
349
|
+
)
|
|
301
350
|
);
|
|
351
|
+
smsConfig.pendingPrompts.slice(0, 3).forEach((p, i) => {
|
|
352
|
+
const msg = p.message.length > 40 ? p.message.slice(0, 40) + "..." : p.message;
|
|
353
|
+
console.log(chalk.gray(` ${i + 1}. [${p.id}] ${msg}`));
|
|
354
|
+
});
|
|
355
|
+
if (smsConfig.pendingPrompts.length > 3) {
|
|
356
|
+
console.log(
|
|
357
|
+
chalk.gray(` ... and ${smsConfig.pendingPrompts.length - 3} more`)
|
|
358
|
+
);
|
|
359
|
+
}
|
|
302
360
|
}
|
|
361
|
+
console.log();
|
|
362
|
+
console.log(chalk.gray(" Quick actions from WhatsApp:"));
|
|
363
|
+
console.log(chalk.gray(' "status" - session status'));
|
|
364
|
+
console.log(chalk.gray(' "context" - current frame digest'));
|
|
365
|
+
console.log(chalk.gray(' "1", "2" - respond to prompts'));
|
|
366
|
+
console.log(chalk.gray("\u2500".repeat(42)));
|
|
303
367
|
}
|
|
304
368
|
async sendDoneNotification(exitCode) {
|
|
305
369
|
try {
|
|
@@ -430,6 +494,31 @@ class ClaudeSM {
|
|
|
430
494
|
this.config.useWorktree = this.hasUncommittedChanges() || this.detectMultipleInstances();
|
|
431
495
|
}
|
|
432
496
|
break;
|
|
497
|
+
case "--think":
|
|
498
|
+
case "--think-hard":
|
|
499
|
+
case "--ultrathink":
|
|
500
|
+
this.config.useThinkingMode = true;
|
|
501
|
+
this.config.useModelRouting = true;
|
|
502
|
+
this.config.forceProvider = "qwen";
|
|
503
|
+
break;
|
|
504
|
+
case "--qwen":
|
|
505
|
+
this.config.useModelRouting = true;
|
|
506
|
+
this.config.forceProvider = "qwen";
|
|
507
|
+
break;
|
|
508
|
+
case "--openai":
|
|
509
|
+
this.config.useModelRouting = true;
|
|
510
|
+
this.config.forceProvider = "openai";
|
|
511
|
+
break;
|
|
512
|
+
case "--ollama":
|
|
513
|
+
this.config.useModelRouting = true;
|
|
514
|
+
this.config.forceProvider = "ollama";
|
|
515
|
+
break;
|
|
516
|
+
case "--model-routing":
|
|
517
|
+
this.config.useModelRouting = true;
|
|
518
|
+
break;
|
|
519
|
+
case "--no-model-routing":
|
|
520
|
+
this.config.useModelRouting = false;
|
|
521
|
+
break;
|
|
433
522
|
default:
|
|
434
523
|
claudeArgs.push(arg);
|
|
435
524
|
}
|
|
@@ -517,6 +606,45 @@ class ClaudeSM {
|
|
|
517
606
|
);
|
|
518
607
|
}
|
|
519
608
|
}
|
|
609
|
+
if (this.config.useModelRouting) {
|
|
610
|
+
const routerConfig = loadModelRouterConfig();
|
|
611
|
+
if (routerConfig.enabled || this.config.forceProvider) {
|
|
612
|
+
const router = getModelRouter();
|
|
613
|
+
let routeResult;
|
|
614
|
+
if (this.config.forceProvider) {
|
|
615
|
+
const env = router.switchTo(this.config.forceProvider);
|
|
616
|
+
Object.assign(process.env, env);
|
|
617
|
+
console.log(
|
|
618
|
+
chalk.magenta(`\u{1F500} Model: ${this.config.forceProvider} (forced)`)
|
|
619
|
+
);
|
|
620
|
+
if (this.config.forceProvider === "qwen" && this.config.useThinkingMode) {
|
|
621
|
+
const qwenConfig = routerConfig.providers.qwen;
|
|
622
|
+
if (qwenConfig?.params?.enable_thinking) {
|
|
623
|
+
console.log(
|
|
624
|
+
chalk.gray(
|
|
625
|
+
` Thinking mode: budget ${qwenConfig.params.thinking_budget || 1e4} tokens`
|
|
626
|
+
)
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
} else {
|
|
631
|
+
const taskType = this.config.useThinkingMode ? "think" : "default";
|
|
632
|
+
routeResult = router.route(taskType, this.config.task);
|
|
633
|
+
Object.assign(process.env, routeResult.env);
|
|
634
|
+
if (routeResult.switched) {
|
|
635
|
+
console.log(
|
|
636
|
+
chalk.magenta(`\u{1F500} Model routed to: ${routeResult.provider}`)
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
} else {
|
|
641
|
+
console.log(
|
|
642
|
+
chalk.gray(
|
|
643
|
+
" Model routing: disabled (run: stackmemory model enable)"
|
|
644
|
+
)
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
520
648
|
if (this.config.useWhatsApp) {
|
|
521
649
|
console.log(
|
|
522
650
|
chalk.cyan("\u{1F4F1} WhatsApp mode: notifications + webhook enabled")
|
|
@@ -537,10 +665,36 @@ class ClaudeSM {
|
|
|
537
665
|
process.exit(1);
|
|
538
666
|
return;
|
|
539
667
|
}
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
668
|
+
const fallbackMonitor = new FallbackMonitor({
|
|
669
|
+
enabled: true,
|
|
670
|
+
maxRestarts: 2,
|
|
671
|
+
restartDelayMs: 1500,
|
|
672
|
+
onFallback: (provider, reason) => {
|
|
673
|
+
console.log(chalk.yellow(`
|
|
674
|
+
[auto-fallback] Switching to ${provider}`));
|
|
675
|
+
console.log(chalk.gray(` Reason: ${reason}`));
|
|
676
|
+
console.log(chalk.gray(` Session will continue on ${provider}...`));
|
|
677
|
+
if (this.config.notifyOnDone || this.config.useWhatsApp) {
|
|
678
|
+
sendNotification({
|
|
679
|
+
type: "custom",
|
|
680
|
+
title: "Model Fallback",
|
|
681
|
+
message: `Claude unavailable (${reason}). Switched to ${provider}.`
|
|
682
|
+
}).catch(() => {
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
543
686
|
});
|
|
687
|
+
const fallbackAvailable = fallbackMonitor.isFallbackAvailable();
|
|
688
|
+
if (fallbackAvailable) {
|
|
689
|
+
console.log(
|
|
690
|
+
chalk.gray(` Auto-fallback: Qwen ready (on rate limit/error)`)
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
const wrapper = fallbackMonitor.wrapProcess(claudeBin, claudeArgs, {
|
|
694
|
+
env: process.env,
|
|
695
|
+
cwd: process.cwd()
|
|
696
|
+
});
|
|
697
|
+
const claude = wrapper.start();
|
|
544
698
|
claude.on("error", (err) => {
|
|
545
699
|
console.error(chalk.red("\u274C Failed to launch Claude CLI."));
|
|
546
700
|
if (err.code === "ENOENT") {
|
|
@@ -559,6 +713,15 @@ class ClaudeSM {
|
|
|
559
713
|
process.exit(1);
|
|
560
714
|
});
|
|
561
715
|
claude.on("exit", async (code) => {
|
|
716
|
+
const status = fallbackMonitor.getStatus();
|
|
717
|
+
if (status.inFallback) {
|
|
718
|
+
console.log(
|
|
719
|
+
chalk.yellow(
|
|
720
|
+
`
|
|
721
|
+
Session completed on fallback provider: ${status.currentProvider}`
|
|
722
|
+
)
|
|
723
|
+
);
|
|
724
|
+
}
|
|
562
725
|
this.saveContext("Claude session ended", {
|
|
563
726
|
action: "session_end",
|
|
564
727
|
exitCode: code
|
|
@@ -624,6 +787,9 @@ configCmd.command("show").description("Show current default settings").action(()
|
|
|
624
787
|
console.log(
|
|
625
788
|
` defaultWhatsApp: ${config.defaultWhatsApp ? chalk.green("true") : chalk.gray("false")}`
|
|
626
789
|
);
|
|
790
|
+
console.log(
|
|
791
|
+
` defaultModelRouting: ${config.defaultModelRouting ? chalk.green("true") : chalk.gray("false")}`
|
|
792
|
+
);
|
|
627
793
|
console.log(chalk.gray(`
|
|
628
794
|
Config: ${getConfigPath()}`));
|
|
629
795
|
});
|
|
@@ -638,7 +804,9 @@ configCmd.command("set <key> <value>").description("Set a default (e.g., set wor
|
|
|
638
804
|
remote: "defaultRemote",
|
|
639
805
|
"notify-done": "defaultNotifyOnDone",
|
|
640
806
|
notifyondone: "defaultNotifyOnDone",
|
|
641
|
-
whatsapp: "defaultWhatsApp"
|
|
807
|
+
whatsapp: "defaultWhatsApp",
|
|
808
|
+
"model-routing": "defaultModelRouting",
|
|
809
|
+
modelrouting: "defaultModelRouting"
|
|
642
810
|
};
|
|
643
811
|
const configKey = keyMap[key];
|
|
644
812
|
if (!configKey) {
|
|
@@ -704,10 +872,25 @@ configCmd.command("whatsapp-off").description("Disable WhatsApp mode by default"
|
|
|
704
872
|
saveSMConfig(config);
|
|
705
873
|
console.log(chalk.green("WhatsApp mode disabled by default"));
|
|
706
874
|
});
|
|
875
|
+
configCmd.command("model-routing-on").description(
|
|
876
|
+
"Enable model routing by default (route tasks to Qwen/other models)"
|
|
877
|
+
).action(() => {
|
|
878
|
+
const config = loadSMConfig();
|
|
879
|
+
config.defaultModelRouting = true;
|
|
880
|
+
saveSMConfig(config);
|
|
881
|
+
console.log(chalk.green("Model routing enabled by default"));
|
|
882
|
+
console.log(chalk.gray("Configure with: stackmemory model setup-qwen"));
|
|
883
|
+
});
|
|
884
|
+
configCmd.command("model-routing-off").description("Disable model routing by default (use Claude only)").action(() => {
|
|
885
|
+
const config = loadSMConfig();
|
|
886
|
+
config.defaultModelRouting = false;
|
|
887
|
+
saveSMConfig(config);
|
|
888
|
+
console.log(chalk.green("Model routing disabled by default"));
|
|
889
|
+
});
|
|
707
890
|
program.option("-w, --worktree", "Create isolated worktree for this instance").option("-W, --no-worktree", "Disable worktree (override default)").option("-r, --remote", "Enable remote mode (WhatsApp for all questions)").option("--no-remote", "Disable remote mode (override default)").option("-n, --notify-done", "Send WhatsApp notification when session ends").option("--no-notify-done", "Disable notification when session ends").option(
|
|
708
891
|
"--whatsapp",
|
|
709
892
|
"Enable WhatsApp mode (auto-start webhook + ngrok + notifications)"
|
|
710
|
-
).option("--no-whatsapp", "Disable WhatsApp mode (override default)").option("-s, --sandbox", "Enable sandbox mode (file/network restrictions)").option("-c, --chrome", "Enable Chrome automation").option("-a, --auto", "Automatically detect and apply best settings").option("-b, --branch <name>", "Specify branch name for worktree").option("-t, --task <desc>", "Task description for context").option("--claude-bin <path>", "Path to claude CLI (or use CLAUDE_BIN)").option("--no-context", "Disable StackMemory context integration").option("--no-trace", "Disable debug tracing (enabled by default)").option("--verbose-trace", "Enable verbose debug tracing with full details").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
|
|
893
|
+
).option("--no-whatsapp", "Disable WhatsApp mode (override default)").option("-s, --sandbox", "Enable sandbox mode (file/network restrictions)").option("-c, --chrome", "Enable Chrome automation").option("-a, --auto", "Automatically detect and apply best settings").option("-b, --branch <name>", "Specify branch name for worktree").option("-t, --task <desc>", "Task description for context").option("--claude-bin <path>", "Path to claude CLI (or use CLAUDE_BIN)").option("--no-context", "Disable StackMemory context integration").option("--no-trace", "Disable debug tracing (enabled by default)").option("--verbose-trace", "Enable verbose debug tracing with full details").option("--think", "Enable thinking mode with Qwen (deep reasoning)").option("--think-hard", "Alias for --think").option("--ultrathink", "Alias for --think").option("--qwen", "Force Qwen provider for this session").option("--openai", "Force OpenAI provider for this session").option("--ollama", "Force Ollama provider for this session").option("--model-routing", "Enable model routing").option("--no-model-routing", "Disable model routing").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
|
|
711
894
|
const claudeSM = new ClaudeSM();
|
|
712
895
|
const args = process.argv.slice(2);
|
|
713
896
|
await claudeSM.run(args);
|