Skip to content

Commit

Permalink
🔧 refactor: Simplify prompt-related files and functions
Browse files Browse the repository at this point in the history
  • Loading branch information
thibaultyou committed Oct 22, 2024
1 parent aa92f93 commit e06502e
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 171 deletions.
5 changes: 2 additions & 3 deletions src/app/templates/main_readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ Key options:
- `-p, --prompt <id>`: Execute a stored prompt by ID
- `-i, --inspect`: Inspect the prompt variables without executing
- `-fi, --file-input <variable>=<file>`: Specify a file to use as input for a variable
- `-c, --ci`: Run in CI mode (non-interactive)

In CI mode, the `execute` command acts as a dynamic CLI, allowing you to pass prompt variables as command-line arguments:
The `execute` command acts as a dynamic CLI, allowing you to pass prompt variables as command-line arguments:

```sh
prompt-library-cli execute -p <prompt_id> --<variable1> <value1> --<variable2> <value2> -c
Expand Down Expand Up @@ -166,7 +165,7 @@ Fragments are reusable prompt components:
## ⚙️ Metadata Customization

1. Edit `src/system_prompts/prompt_analysis_agent/prompt.md`.
2. Test with `npm run generate-metadata`.
2. Test with `npm run update-metadata`.
3. Commit and push to trigger GitHub Actions.

> **Note**: Changes affect future metadata generations. Test thoroughly before committing.
Expand Down
5 changes: 3 additions & 2 deletions src/app/utils/prompt_analyzer.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parseYamlContent } from './yaml_operations.util';
import { Metadata } from '../../shared/types';
import { readFileContent } from '../../shared/utils/file_system.util';
import logger from '../../shared/utils/logger.util';
import { processPromptContent } from '../../shared/utils/prompt_processing.util';
import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
import { appConfig } from '../config/app.config';

export async function loadAnalyzerPrompt(): Promise<string> {
Expand All @@ -30,7 +30,8 @@ export async function processMetadataGeneration(promptContent: string): Promise<
PROMPT_TO_ANALYZE: promptContent,
AVAILABLE_PROMPT_FRAGMENTS: availableFragments
};
const content = await processPromptContent([{ role: 'user', content: analyzerPrompt }], variables, false);
const updatedPromptContent = updatePromptWithVariables(analyzerPrompt, variables);
const content = await processPromptContent([{ role: 'user', content: updatedPromptContent }], false);
const yamlContent = extractOutputContent(content);
const parsedMetadata = parseYamlContent(yamlContent);
const metadata: Metadata = {
Expand Down
43 changes: 7 additions & 36 deletions src/cli/commands/execute.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import yaml from 'js-yaml';

import { BaseCommand } from './base.command';
import { Metadata, Prompt, Variable } from '../../shared/types';
import { processPromptContent } from '../../shared/utils/prompt_processing.util';
import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
import { getPromptFiles } from '../utils/prompt_crud.util';
import { viewPromptDetails } from '../utils/prompt_display.util';

Expand All @@ -14,7 +14,6 @@ class ExecuteCommand extends BaseCommand {
this.option('-p, --prompt <id>', 'Execute a stored prompt by ID')
.option('-f, --prompt-file <file>', 'Path to the prompt file (usually prompt.md)')
.option('-m, --metadata-file <file>', 'Path to the metadata file (usually metadata.yml)')
.option('-c, --ci', 'Run in CI mode (single response, no streaming)')
.option('-i, --inspect', 'Inspect the prompt variables without executing')
.option(
'-fi, --file-input <variable>=<file>',
Expand Down Expand Up @@ -71,7 +70,6 @@ Example Workflow:
Note:
- File paths are relative to the current working directory.
- In CI mode (-c or --ci), all required variables must be provided.
- Use quotes for values containing spaces.
`
)
Expand Down Expand Up @@ -105,18 +103,11 @@ Note:
const dynamicOptions = this.parseDynamicOptions(command.args);

if (options.prompt) {
await this.handleStoredPrompt(
options.prompt,
options.ci,
dynamicOptions,
options.inspect,
options.fileInput
);
await this.handleStoredPrompt(options.prompt, dynamicOptions, options.inspect, options.fileInput);
} else if (options.promptFile && options.metadataFile) {
await this.handleFilePrompt(
options.promptFile,
options.metadataFile,
options.ci,
dynamicOptions,
options.inspect,
options.fileInput
Expand All @@ -134,7 +125,6 @@ Note:

private async handleStoredPrompt(
promptId: string,
ciMode: boolean,
dynamicOptions: Record<string, string>,
inspect: boolean,
fileInputs: Record<string, string>
Expand All @@ -149,7 +139,7 @@ Note:
if (inspect) {
await this.inspectPrompt(metadata);
} else {
await this.executePromptWithMetadata(promptContent, metadata, ciMode, dynamicOptions, fileInputs);
await this.executePromptWithMetadata(promptContent, metadata, dynamicOptions, fileInputs);
}
} catch (error) {
this.handleError(error, 'handling stored prompt');
Expand All @@ -159,7 +149,6 @@ Note:
private async handleFilePrompt(
promptFile: string,
metadataFile: string,
ciMode: boolean,
dynamicOptions: Record<string, string>,
inspect: boolean,
fileInputs: Record<string, string>
Expand All @@ -172,7 +161,7 @@ Note:
if (inspect) {
await this.inspectPrompt(metadata);
} else {
await this.executePromptWithMetadata(promptContent, metadata, ciMode, dynamicOptions, fileInputs);
await this.executePromptWithMetadata(promptContent, metadata, dynamicOptions, fileInputs);
}
} catch (error) {
this.handleError(error, 'handling file prompt');
Expand Down Expand Up @@ -200,7 +189,6 @@ Note:
private async executePromptWithMetadata(
promptContent: string,
metadata: Metadata,
ciMode: boolean,
dynamicOptions: Record<string, string>,
fileInputs: Record<string, string>
): Promise<void> {
Expand All @@ -223,29 +211,12 @@ Note:
if (value) {
userInputs[variable.name] = value;
} else if (!variable.optional_for_user) {
if (ciMode) {
throw new Error(`Required variable ${snakeCaseName} is not set.`);
} else {
userInputs[variable.name] = await this.getInput(`Enter value for ${snakeCaseName}:`);
}
throw new Error(`Required variable ${snakeCaseName} is not set.`);
}
}

const result = await processPromptContent(
[{ role: 'user', content: promptContent }],
userInputs,
!ciMode,
async (inputs) => inputs,
(event) => {
if (event.type === 'content_block_delta') {
if ('text' in event.delta) {
process.stdout.write(event.delta.text);
} else if ('partial_json' in event.delta) {
process.stdout.write(event.delta.partial_json);
}
}
}
);
const updatedPromptContent = updatePromptWithVariables(promptContent, userInputs);
const result = await processPromptContent([{ role: 'user', content: updatedPromptContent }], false, false);

if (typeof result === 'string') {
console.log(result);
Expand Down
18 changes: 6 additions & 12 deletions src/cli/utils/conversation_manager.util.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { handleError } from './error.util';
import { resolveCliInputs } from './input_processing.util';
import { processCliPromptContent } from './input_resolution.util';
import { resolveInputs } from './input_resolution.util';
import { getPromptFiles } from './prompt_crud.util';
import { ApiResult } from '../../shared/types';
import { processPromptContent, processPromptWithVariables } from '../../shared/utils/prompt_processing.util';
import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';

interface ConversationMessage {
role: 'user' | 'assistant';
Expand Down Expand Up @@ -31,13 +30,11 @@ export class ConversationManager {
}

const { promptContent } = promptFilesResult.data;
const resolvedInputs = isExecuteCommand ? userInputs : await resolveCliInputs(userInputs);
const updatedPromptContent = await processPromptWithVariables(promptContent, resolvedInputs);
const resolvedInputs = isExecuteCommand ? userInputs : await resolveInputs(userInputs);
const updatedPromptContent = updatePromptWithVariables(promptContent, resolvedInputs);
this.messages.push({ role: 'user', content: updatedPromptContent });

const result = await (isExecuteCommand
? processPromptContent(this.messages, {}, false)
: processCliPromptContent(this.messages, {}, true));
const result = await processPromptContent(this.messages, isExecuteCommand ? false : true);

if (typeof result === 'string') {
this.messages.push({ role: 'assistant', content: result });
Expand All @@ -54,10 +51,7 @@ export class ConversationManager {
async continueConversation(userInput: string, useStreaming: boolean = true): Promise<ApiResult<string>> {
try {
this.messages.push({ role: 'user', content: userInput });

const result = useStreaming
? await processCliPromptContent(this.messages, {}, true)
: await processPromptContent(this.messages, {}, false);
const result = await processPromptContent(this.messages, useStreaming);

if (typeof result === 'string') {
this.messages.push({ role: 'user', content: result });
Expand Down
51 changes: 0 additions & 51 deletions src/cli/utils/input_processing.util.ts

This file was deleted.

59 changes: 43 additions & 16 deletions src/cli/utils/input_resolution.util.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
import { EnvVar } from '../../shared/types';
import logger from '../../shared/utils/logger.util';
import { FRAGMENT_PREFIX, ENV_PREFIX } from '../cli.constants';
import { readEnvVars } from './env.util';
import { handleError } from './error.util';
import { resolveCliInputs } from './input_processing.util';
import { processPromptContent } from '../../shared/utils/prompt_processing.util';
import { viewFragmentContent } from './fragment_operations.util';

export async function processCliPromptContent(
messages: { role: string; content: string }[],
inputs: Record<string, string> = {},
useStreaming: boolean = true
): Promise<string> {
export async function resolveValue(value: string, envVars: EnvVar[]): Promise<string> {
if (value.startsWith(FRAGMENT_PREFIX)) {
const [category, name] = value.split(FRAGMENT_PREFIX)[1].split('/');
const fragmentResult = await viewFragmentContent(category, name);

if (fragmentResult.success && fragmentResult.data) {
return fragmentResult.data;
} else {
logger.warn(`Failed to load fragment: ${category}/${name}`);
return value;
}
} else if (value.startsWith(ENV_PREFIX)) {
const envVarName = value.split(ENV_PREFIX)[1];
const actualEnvVar = envVars.find((v) => v.name === envVarName);

if (actualEnvVar) {
return await resolveValue(actualEnvVar.value, envVars);
} else {
logger.warn(`Env var not found: ${envVarName}`);
return value;
}
}
return value;
}

export async function resolveInputs(inputs: Record<string, string>): Promise<Record<string, string>> {
try {
return processPromptContent(messages, inputs, useStreaming, resolveCliInputs, (event) => {
if (event.type === 'content_block_delta' && event.delta) {
if ('text' in event.delta) {
process.stdout.write(event.delta.text);
} else if ('partial_json' in event.delta) {
process.stdout.write(event.delta.partial_json);
}
const envVarsResult = await readEnvVars();
const envVars = envVarsResult.success ? envVarsResult.data || [] : [];
const resolvedInputs: Record<string, string> = {};

for (const [key, value] of Object.entries(inputs)) {
if (value.startsWith(FRAGMENT_PREFIX) || value.startsWith(ENV_PREFIX)) {
resolvedInputs[key] = await resolveValue(value, envVars);
} else {
resolvedInputs[key] = value;
}
});
}
return resolvedInputs;
} catch (error) {
handleError(error, 'processing CLI prompt content');
handleError(error, 'resolving inputs');
throw error;
}
}
1 change: 1 addition & 0 deletions src/shared/utils/anthropic_client.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function getAnthropicClient(): Anthropic {

export async function sendAnthropicRequestClassic(messages: { role: string; content: string }[]): Promise<Message> {
const client = getAnthropicClient();

try {
return await client.messages.create({
model: commonConfig.ANTHROPIC_MODEL,
Expand Down
Loading

0 comments on commit e06502e

Please sign in to comment.