Some checks failed
ci/woodpecker/push/ci Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
367 lines
14 KiB
TypeScript
367 lines
14 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { classifyTask } from './task-classifier.js';
|
|
|
|
// ─── Task Type Detection ──────────────────────────────────────────────────────
|
|
|
|
describe('classifyTask — taskType', () => {
|
|
it('detects coding from "code" keyword', () => {
|
|
expect(classifyTask('Can you write some code for me?').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "implement" keyword', () => {
|
|
expect(classifyTask('Implement a binary search algorithm').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "function" keyword', () => {
|
|
expect(classifyTask('Write a function that reverses a string').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "debug" keyword', () => {
|
|
expect(classifyTask('Help me debug this error').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "fix" keyword', () => {
|
|
expect(classifyTask('fix the broken test').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "refactor" keyword', () => {
|
|
expect(classifyTask('Please refactor this module').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "typescript" keyword', () => {
|
|
expect(classifyTask('How do I use generics in TypeScript?').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "javascript" keyword', () => {
|
|
expect(classifyTask('JavaScript promises explained').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "python" keyword', () => {
|
|
expect(classifyTask('Write a Python script to parse CSV').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "SQL" keyword', () => {
|
|
expect(classifyTask('Write a SQL query to join these tables').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "API" keyword', () => {
|
|
expect(classifyTask('Design an API for user management').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "endpoint" keyword', () => {
|
|
expect(classifyTask('Add a new endpoint for user profiles').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "class" keyword', () => {
|
|
expect(classifyTask('Create a class for handling payments').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from "method" keyword', () => {
|
|
expect(classifyTask('Add a method to validate emails').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects coding from inline backtick code', () => {
|
|
expect(classifyTask('What does `Array.prototype.reduce` do?').taskType).toBe('coding');
|
|
});
|
|
|
|
it('detects summarization from "summarize"', () => {
|
|
expect(classifyTask('Please summarize this document').taskType).toBe('summarization');
|
|
});
|
|
|
|
it('detects summarization from "summary"', () => {
|
|
expect(classifyTask('Give me a summary of the meeting').taskType).toBe('summarization');
|
|
});
|
|
|
|
it('detects summarization from "tldr"', () => {
|
|
expect(classifyTask('TLDR this article for me').taskType).toBe('summarization');
|
|
});
|
|
|
|
it('detects summarization from "condense"', () => {
|
|
expect(classifyTask('Condense this into 3 bullet points').taskType).toBe('summarization');
|
|
});
|
|
|
|
it('detects summarization from "brief"', () => {
|
|
expect(classifyTask('Give me a brief overview of this topic').taskType).toBe('summarization');
|
|
});
|
|
|
|
it('detects creative from "write"', () => {
|
|
expect(classifyTask('Write a short story about a dragon').taskType).toBe('creative');
|
|
});
|
|
|
|
it('detects creative from "story"', () => {
|
|
expect(classifyTask('Tell me a story about space exploration').taskType).toBe('creative');
|
|
});
|
|
|
|
it('detects creative from "poem"', () => {
|
|
expect(classifyTask('Write a poem about autumn').taskType).toBe('creative');
|
|
});
|
|
|
|
it('detects creative from "generate"', () => {
|
|
expect(classifyTask('Generate some creative marketing copy').taskType).toBe('creative');
|
|
});
|
|
|
|
it('detects creative from "create content"', () => {
|
|
expect(classifyTask('Help me create content for my website').taskType).toBe('creative');
|
|
});
|
|
|
|
it('detects creative from "blog post"', () => {
|
|
expect(classifyTask('Write a blog post about productivity habits').taskType).toBe('creative');
|
|
});
|
|
|
|
it('detects analysis from "analyze"', () => {
|
|
expect(classifyTask('Analyze the performance of this system').taskType).toBe('analysis');
|
|
});
|
|
|
|
it('detects analysis from "review"', () => {
|
|
expect(classifyTask('Please review my pull request changes').taskType).toBe('analysis');
|
|
});
|
|
|
|
it('detects analysis from "evaluate"', () => {
|
|
expect(classifyTask('Evaluate the pros and cons of this approach').taskType).toBe('analysis');
|
|
});
|
|
|
|
it('detects analysis from "assess"', () => {
|
|
expect(classifyTask('Assess the security risks here').taskType).toBe('analysis');
|
|
});
|
|
|
|
it('detects analysis from "audit"', () => {
|
|
expect(classifyTask('Audit this codebase for vulnerabilities').taskType).toBe('analysis');
|
|
});
|
|
|
|
it('detects research from "research"', () => {
|
|
expect(classifyTask('Research the best state management libraries').taskType).toBe('research');
|
|
});
|
|
|
|
it('detects research from "find"', () => {
|
|
expect(classifyTask('Find all open issues in our backlog').taskType).toBe('research');
|
|
});
|
|
|
|
it('detects research from "search"', () => {
|
|
expect(classifyTask('Search for papers on transformer architectures').taskType).toBe(
|
|
'research',
|
|
);
|
|
});
|
|
|
|
it('detects research from "what is"', () => {
|
|
expect(classifyTask('What is the difference between REST and GraphQL?').taskType).toBe(
|
|
'research',
|
|
);
|
|
});
|
|
|
|
it('detects research from "explain"', () => {
|
|
expect(classifyTask('Explain how OAuth2 works').taskType).toBe('research');
|
|
});
|
|
|
|
it('detects research from "how does"', () => {
|
|
expect(classifyTask('How does garbage collection work in V8?').taskType).toBe('research');
|
|
});
|
|
|
|
it('detects research from "compare"', () => {
|
|
expect(classifyTask('Compare Postgres and MySQL for this use case').taskType).toBe('research');
|
|
});
|
|
|
|
it('falls back to conversation with no strong signal', () => {
|
|
expect(classifyTask('Hello, how are you?').taskType).toBe('conversation');
|
|
});
|
|
|
|
it('falls back to conversation for generic greetings', () => {
|
|
expect(classifyTask('Good morning!').taskType).toBe('conversation');
|
|
});
|
|
|
|
// Priority: coding wins over research when both keywords present
|
|
it('coding takes priority over research', () => {
|
|
expect(classifyTask('find a code example for sorting').taskType).toBe('coding');
|
|
});
|
|
|
|
// Priority: summarization wins over creative
|
|
it('summarization takes priority over creative', () => {
|
|
expect(classifyTask('write a summary of this article').taskType).toBe('summarization');
|
|
});
|
|
});
|
|
|
|
// ─── Complexity Estimation ────────────────────────────────────────────────────
|
|
|
|
describe('classifyTask — complexity', () => {
|
|
it('classifies short message as simple', () => {
|
|
expect(classifyTask('Fix typo').complexity).toBe('simple');
|
|
});
|
|
|
|
it('classifies single question as simple', () => {
|
|
expect(classifyTask('What is a closure?').complexity).toBe('simple');
|
|
});
|
|
|
|
it('classifies message > 500 chars as complex', () => {
|
|
const long = 'a'.repeat(501);
|
|
expect(classifyTask(long).complexity).toBe('complex');
|
|
});
|
|
|
|
it('classifies message with "architecture" keyword as complex', () => {
|
|
expect(
|
|
classifyTask('Can you help me think through the architecture of this system?').complexity,
|
|
).toBe('complex');
|
|
});
|
|
|
|
it('classifies message with "design" keyword as complex', () => {
|
|
expect(classifyTask('Design a data model for this feature').complexity).toBe('complex');
|
|
});
|
|
|
|
it('classifies message with "complex" keyword as complex', () => {
|
|
expect(classifyTask('This is a complex problem involving multiple services').complexity).toBe(
|
|
'complex',
|
|
);
|
|
});
|
|
|
|
it('classifies message with "system" keyword as complex', () => {
|
|
expect(classifyTask('Explain the whole system behavior').complexity).toBe('complex');
|
|
});
|
|
|
|
it('classifies message with multiple code blocks as complex', () => {
|
|
const msg = '```\nconst a = 1;\n```\n\nAlso look at\n\n```\nconst b = 2;\n```';
|
|
expect(classifyTask(msg).complexity).toBe('complex');
|
|
});
|
|
|
|
it('classifies moderate-length message as moderate', () => {
|
|
const msg =
|
|
'Please help me implement a small utility function that parses query strings. It should handle arrays and nested objects properly.';
|
|
expect(classifyTask(msg).complexity).toBe('moderate');
|
|
});
|
|
});
|
|
|
|
// ─── Domain Detection ─────────────────────────────────────────────────────────
|
|
|
|
describe('classifyTask — domain', () => {
|
|
it('detects frontend from "react"', () => {
|
|
expect(classifyTask('How do I use React hooks?').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects frontend from "css"', () => {
|
|
expect(classifyTask('Fix the CSS layout issue').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects frontend from "html"', () => {
|
|
expect(classifyTask('Add an HTML form element').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects frontend from "component"', () => {
|
|
expect(classifyTask('Create a reusable component').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects frontend from "UI"', () => {
|
|
expect(classifyTask('Update the UI spacing').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects frontend from "tailwind"', () => {
|
|
expect(classifyTask('Style this button with Tailwind').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects frontend from "next.js"', () => {
|
|
expect(classifyTask('Configure Next.js routing').domain).toBe('frontend');
|
|
});
|
|
|
|
it('detects backend from "server"', () => {
|
|
expect(classifyTask('Set up the server to handle requests').domain).toBe('backend');
|
|
});
|
|
|
|
it('detects backend from "database"', () => {
|
|
expect(classifyTask('Optimize this database query').domain).toBe('backend');
|
|
});
|
|
|
|
it('detects backend from "endpoint"', () => {
|
|
expect(classifyTask('Add an endpoint for authentication').domain).toBe('backend');
|
|
});
|
|
|
|
it('detects backend from "nest"', () => {
|
|
expect(classifyTask('Add a NestJS guard for this route').domain).toBe('backend');
|
|
});
|
|
|
|
it('detects backend from "express"', () => {
|
|
expect(classifyTask('Middleware in Express explained').domain).toBe('backend');
|
|
});
|
|
|
|
it('detects devops from "docker"', () => {
|
|
expect(classifyTask('Write a Dockerfile for this app').domain).toBe('devops');
|
|
});
|
|
|
|
it('detects devops from "deploy"', () => {
|
|
expect(classifyTask('Deploy this service to production').domain).toBe('devops');
|
|
});
|
|
|
|
it('detects devops from "pipeline"', () => {
|
|
expect(classifyTask('Set up a CI pipeline').domain).toBe('devops');
|
|
});
|
|
|
|
it('detects devops from "kubernetes"', () => {
|
|
expect(classifyTask('Configure a Kubernetes deployment').domain).toBe('devops');
|
|
});
|
|
|
|
it('detects docs from "documentation"', () => {
|
|
expect(classifyTask('Write documentation for this module').domain).toBe('docs');
|
|
});
|
|
|
|
it('detects docs from "readme"', () => {
|
|
expect(classifyTask('Update the README').domain).toBe('docs');
|
|
});
|
|
|
|
it('detects docs from "guide"', () => {
|
|
expect(classifyTask('Create a user guide for this feature').domain).toBe('docs');
|
|
});
|
|
|
|
it('falls back to general domain', () => {
|
|
expect(classifyTask('What time is it?').domain).toBe('general');
|
|
});
|
|
|
|
// devops takes priority over backend when both match
|
|
it('devops takes priority over backend (both keywords)', () => {
|
|
expect(classifyTask('Deploy the API server using Docker').domain).toBe('devops');
|
|
});
|
|
|
|
// docs takes priority over frontend when both match
|
|
it('docs takes priority over frontend (both keywords)', () => {
|
|
expect(classifyTask('Write documentation for React components').domain).toBe('docs');
|
|
});
|
|
});
|
|
|
|
// ─── Combined Classification ──────────────────────────────────────────────────
|
|
|
|
describe('classifyTask — combined', () => {
|
|
it('returns full classification object', () => {
|
|
const result = classifyTask('Fix the bug?');
|
|
expect(result).toHaveProperty('taskType');
|
|
expect(result).toHaveProperty('complexity');
|
|
expect(result).toHaveProperty('domain');
|
|
});
|
|
|
|
it('classifies complex TypeScript architecture request', () => {
|
|
const msg =
|
|
'Design the architecture for a multi-tenant TypeScript system using NestJS with proper database isolation and role-based access control. The system needs to support multiple organizations each with their own data namespace.';
|
|
const result = classifyTask(msg);
|
|
expect(result.taskType).toBe('coding');
|
|
expect(result.complexity).toBe('complex');
|
|
expect(result.domain).toBe('backend');
|
|
});
|
|
|
|
it('classifies simple frontend question', () => {
|
|
const result = classifyTask('How do I center a div in CSS?');
|
|
expect(result.taskType).toBe('research');
|
|
expect(result.domain).toBe('frontend');
|
|
});
|
|
|
|
it('classifies a DevOps pipeline task as complex', () => {
|
|
const msg =
|
|
'Design a complete CI/CD pipeline architecture using Docker and Kubernetes with blue-green deployments and automatic rollback capabilities for a complex microservices system.';
|
|
const result = classifyTask(msg);
|
|
expect(result.domain).toBe('devops');
|
|
expect(result.complexity).toBe('complex');
|
|
});
|
|
|
|
it('classifies summarization task correctly', () => {
|
|
const result = classifyTask('Summarize the key points from this document');
|
|
expect(result.taskType).toBe('summarization');
|
|
});
|
|
|
|
it('classifies creative writing task correctly', () => {
|
|
const result = classifyTask('Write a poem about the ocean');
|
|
expect(result.taskType).toBe('creative');
|
|
});
|
|
});
|