Some checks failed
CI — Test & Build / Test & Build (push) Failing after 39s
- Added a new "Prompt Builder" tab in the Popup for generating AI prompts with customizable parameters. - Introduced new state variables for managing prompt styles, personas, formats, and models. - Enhanced the Options page to fetch and display models based on the provided API key. - Updated the actions and types to include the new 'prompt' action and its associated parameters. - Implemented migration logic for legacy plaintext API keys to encrypted storage. - Updated the getSystemPrompt function to incorporate prompt parameters for better instruction generation. - Added tests for the new functionality, including context menu entries and prompt generation logic.
100 lines
4.0 KiB
TypeScript
100 lines
4.0 KiB
TypeScript
// Canonical action + writing-style lists shared by the toolbar, popup,
|
|
// context menus, and result modal. Values must stay in sync with the system
|
|
// prompts in the background worker.
|
|
|
|
// 'fix' is the user-facing id emitted by the context menu and popup; the
|
|
// background normalizes it to the 'grammar' prompt.
|
|
export const ACTIONS = ['fix', 'rephrase', 'shorten', 'expand', 'explain', 'prompt'] as const;
|
|
export type ActionId = (typeof ACTIONS)[number];
|
|
|
|
export const ACTION_LABELS: Record<ActionId, string> = {
|
|
fix: 'Fix Grammar',
|
|
rephrase: 'Rephrase',
|
|
shorten: 'Shorten',
|
|
expand: 'Expand',
|
|
explain: 'Explain',
|
|
prompt: 'Make Prompt',
|
|
};
|
|
|
|
// Full list, including the 'Default' pseudo-style (= no style modifier).
|
|
export const WRITING_STYLES = ['Default', 'Formal', 'Casual', 'Academic', 'Creative', 'Concise'] as const;
|
|
export type WritingStyle = (typeof WRITING_STYLES)[number];
|
|
|
|
// Context menus omit 'Default' — the parent action item already covers it.
|
|
export const CONTEXT_MENU_STYLES = WRITING_STYLES.filter((s) => s !== 'Default');
|
|
|
|
// ─── Prompt Builder parameters (the 'prompt' action) ─────────────────────────
|
|
// 'Auto' always means "let the prompt engineer decide from the input".
|
|
|
|
export const PROMPT_STYLES = ['Auto', 'Instructional', 'Role-play', 'Step-by-step', 'Few-shot', 'Structured'] as const;
|
|
export type PromptStyle = (typeof PROMPT_STYLES)[number];
|
|
|
|
// 'Custom…' switches the popup to a free-text persona field.
|
|
export const PROMPT_PERSONAS = [
|
|
'Auto',
|
|
'None',
|
|
'Expert Developer',
|
|
'Copywriter',
|
|
'Teacher',
|
|
'Data Analyst',
|
|
'Business Consultant',
|
|
'Researcher',
|
|
'Custom…',
|
|
] as const;
|
|
export type PromptPersona = (typeof PROMPT_PERSONAS)[number];
|
|
|
|
export const PROMPT_FORMATS = ['Auto', 'Plain text', 'Markdown', 'Bulleted list', 'Numbered steps', 'JSON', 'Table'] as const;
|
|
export type PromptFormat = (typeof PROMPT_FORMATS)[number];
|
|
|
|
// 'Custom…' means "use the free-text persona"; an empty custom text falls
|
|
// back to Auto. Shared by the popup and the background (which resolves saved
|
|
// Prompt Builder settings for toolbar/context-menu prompt requests).
|
|
export function resolvePromptPersona(persona?: string, customPersona?: string): string | undefined {
|
|
if (persona === 'Custom…') return customPersona?.trim() || 'Auto';
|
|
return persona;
|
|
}
|
|
|
|
// Minimum selection length (chars, after trim) before the floating toolbar
|
|
// appears. Kept deliberately above 1-2 chars so accidental double-click
|
|
// selections don't trigger the UI.
|
|
export const MIN_SELECTION_LENGTH = 10;
|
|
|
|
// ─── Context-menu registry ────────────────────────────────────────────────────
|
|
// Declarative id -> {action, style} mapping. Replaces the old split('-')
|
|
// parsing of menuItemId, which only worked because no action or style name
|
|
// contained a hyphen. Order matters: each parent precedes its children so
|
|
// chrome.contextMenus.create never sees an unknown parentId.
|
|
|
|
export interface ContextMenuEntry {
|
|
id: string;
|
|
action: ActionId;
|
|
style: WritingStyle;
|
|
// 'Default' entries are top-level parents; styled entries nest under them.
|
|
parentId?: string;
|
|
title: string;
|
|
}
|
|
|
|
export const CONTEXT_MENU_ENTRIES: ContextMenuEntry[] = ACTIONS.flatMap((action) => [
|
|
{
|
|
id: `lexai-${action}`,
|
|
action,
|
|
style: 'Default' as WritingStyle,
|
|
title: `⚡ LexAI: ${ACTION_LABELS[action]}`,
|
|
},
|
|
// 'prompt' opens the Prompt Builder dialog in the page, which has its own
|
|
// parameters — writing-style children don't apply to it.
|
|
...(action === 'prompt'
|
|
? []
|
|
: CONTEXT_MENU_STYLES.map((style) => ({
|
|
id: `lexai-${action}-${style.toLowerCase()}`,
|
|
action,
|
|
style,
|
|
parentId: `lexai-${action}`,
|
|
title: style as string,
|
|
}))),
|
|
]);
|
|
|
|
export function findContextMenuEntry(menuItemId: string): ContextMenuEntry | undefined {
|
|
return CONTEXT_MENU_ENTRIES.find((e) => e.id === menuItemId);
|
|
}
|