Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/tools/prompt-score.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ interface ScoreResult {
feedback: string[];
}

function scorePrompt(text: string): ScoreResult {
export function scorePrompt(text: string): ScoreResult {
const feedback: string[] = [];
let specificity: number;
let scope: number;
Expand All @@ -59,8 +59,10 @@ function scorePrompt(text: string): ScoreResult {
}

// Scope: bounded task
if (/\b(only|just|single|one|specific|this)\b/i.test(text) || text.length > 100) {
if (/\b(only|just|single|one|specific|this)\b/i.test(text)) {
scope = 25;
} else if (text.length > 100) {
scope = 20;
} else if (/\b(all|every|entire|whole)\b/i.test(text)) {
scope = 10;
feedback.push("🎯 'All/every' is broad — can you narrow the scope?");
Expand Down
95 changes: 95 additions & 0 deletions tests/tools/prompt-score.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { describe, it, expect } from "vitest";
import { scorePrompt } from "../../src/tools/prompt-score.js";

describe("scorePrompt", () => {
it("gives high specificity for file paths", () => {
const result = scorePrompt("Fix the bug in src/tools/prompt-score.ts");
expect(result.specificity).toBe(25);
});

it("gives high specificity for backtick identifiers", () => {
const result = scorePrompt("Rename `scorePrompt` to `evaluatePrompt`");
expect(result.specificity).toBe(25);
});

it("gives medium specificity for generic terms", () => {
const result = scorePrompt("Fix the component");
expect(result.specificity).toBe(15);
});

it("gives low specificity for vague prompts", () => {
const result = scorePrompt("Make it work");
expect(result.specificity).toBe(5);
});

it("gives high scope for bounded keywords", () => {
const result = scorePrompt("Only update the return type");
expect(result.actionability).toBeGreaterThan(0);
expect(result.scope).toBe(25);
});

it("gives medium scope for long prompts without scope keywords", () => {
const longPrompt = "I need you to look at the authentication flow and figure out why the tokens are expiring too quickly and causing users to get logged out repeatedly during their session";
const result = scorePrompt(longPrompt);
expect(result.scope).toBe(20);
});

it("penalizes unbounded scope keywords", () => {
const result = scorePrompt("Fix all the bugs");
expect(result.scope).toBe(10);
});

it("gives high actionability for specific verbs", () => {
const result = scorePrompt("Extract the validation logic into a helper");
expect(result.actionability).toBe(25);
});

it("gives medium actionability for vague verbs", () => {
const result = scorePrompt("Make the login page work better");
expect(result.actionability).toBe(15);
});

it("gives high done-condition for outcome words", () => {
const result = scorePrompt("Fix the test so it should return 200");
expect(result.doneCondition).toBe(25);
});

it("gives decent done-condition for questions", () => {
const result = scorePrompt("Why is the build failing?");
expect(result.doneCondition).toBe(20);
});

it("grades A+ for excellent prompts", () => {
const result = scorePrompt(
"Rename only the `validateToken` function in src/auth/tokens.ts — it should return a Result type instead of throwing"
);
expect(result.total).toBeGreaterThanOrEqual(90);
expect(result.grade).toBe("A+");
});

it("grades poorly for vague prompts", () => {
const result = scorePrompt("do stuff");
expect(result.total).toBeLessThan(45);
expect(result.grade).toBe("F");
});

it("returns feedback suggestions for weak areas", () => {
const result = scorePrompt("do stuff");
expect(result.feedback.length).toBeGreaterThan(0);
expect(result.feedback.some(f => f.includes("📁"))).toBe(true);
});

it("returns praise for excellent prompts", () => {
const result = scorePrompt(
"Rename only the `validateToken` function in src/auth/tokens.ts — it should return a Result type"
);
expect(result.feedback.some(f => f.includes("🏆"))).toBe(true);
});

it("total is sum of all dimensions", () => {
const result = scorePrompt("Fix the bug in src/app.ts");
expect(result.total).toBe(
result.specificity + result.scope + result.actionability + result.doneCondition
);
});
});
Loading