Skip to content

Commit 1b75587

Browse files
committed
🔧 refactor: Simplify prompt-related files and functions
1 parent aa92f93 commit 1b75587

File tree

8 files changed

+98
-172
lines changed

8 files changed

+98
-172
lines changed

src/app/templates/main_readme.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,11 @@ Key options:
8888
- `-p, --prompt <id>`: Execute a stored prompt by ID
8989
- `-i, --inspect`: Inspect the prompt variables without executing
9090
- `-fi, --file-input <variable>=<file>`: Specify a file to use as input for a variable
91-
- `-c, --ci`: Run in CI mode (non-interactive)
9291

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

9594
```sh
96-
prompt-library-cli execute -p <prompt_id> --<variable1> <value1> --<variable2> <value2> -c
95+
prompt-library-cli execute -p <prompt_id> --<variable1> <value1> --<variable2> <value2>
9796
```
9897

9998
For detailed usage, run:
@@ -166,7 +165,7 @@ Fragments are reusable prompt components:
166165
## ⚙️ Metadata Customization
167166

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

172171
> **Note**: Changes affect future metadata generations. Test thoroughly before committing.

src/app/utils/prompt_analyzer.util.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { parseYamlContent } from './yaml_operations.util';
33
import { Metadata } from '../../shared/types';
44
import { readFileContent } from '../../shared/utils/file_system.util';
55
import logger from '../../shared/utils/logger.util';
6-
import { processPromptContent } from '../../shared/utils/prompt_processing.util';
6+
import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
77
import { appConfig } from '../config/app.config';
88

99
export async function loadAnalyzerPrompt(): Promise<string> {
@@ -30,7 +30,8 @@ export async function processMetadataGeneration(promptContent: string): Promise<
3030
PROMPT_TO_ANALYZE: promptContent,
3131
AVAILABLE_PROMPT_FRAGMENTS: availableFragments
3232
};
33-
const content = await processPromptContent([{ role: 'user', content: analyzerPrompt }], variables, false);
33+
const updatedPromptContent = updatePromptWithVariables(analyzerPrompt, variables);
34+
const content = await processPromptContent([{ role: 'user', content: updatedPromptContent }], false);
3435
const yamlContent = extractOutputContent(content);
3536
const parsedMetadata = parseYamlContent(yamlContent);
3637
const metadata: Metadata = {

src/cli/commands/execute.command.ts

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import yaml from 'js-yaml';
44

55
import { BaseCommand } from './base.command';
66
import { Metadata, Prompt, Variable } from '../../shared/types';
7-
import { processPromptContent } from '../../shared/utils/prompt_processing.util';
7+
import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
88
import { getPromptFiles } from '../utils/prompt_crud.util';
99
import { viewPromptDetails } from '../utils/prompt_display.util';
1010

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

107105
if (options.prompt) {
108-
await this.handleStoredPrompt(
109-
options.prompt,
110-
options.ci,
111-
dynamicOptions,
112-
options.inspect,
113-
options.fileInput
114-
);
106+
await this.handleStoredPrompt(options.prompt, dynamicOptions, options.inspect, options.fileInput);
115107
} else if (options.promptFile && options.metadataFile) {
116108
await this.handleFilePrompt(
117109
options.promptFile,
118110
options.metadataFile,
119-
options.ci,
120111
dynamicOptions,
121112
options.inspect,
122113
options.fileInput
@@ -134,7 +125,6 @@ Note:
134125

135126
private async handleStoredPrompt(
136127
promptId: string,
137-
ciMode: boolean,
138128
dynamicOptions: Record<string, string>,
139129
inspect: boolean,
140130
fileInputs: Record<string, string>
@@ -149,7 +139,7 @@ Note:
149139
if (inspect) {
150140
await this.inspectPrompt(metadata);
151141
} else {
152-
await this.executePromptWithMetadata(promptContent, metadata, ciMode, dynamicOptions, fileInputs);
142+
await this.executePromptWithMetadata(promptContent, metadata, dynamicOptions, fileInputs);
153143
}
154144
} catch (error) {
155145
this.handleError(error, 'handling stored prompt');
@@ -159,7 +149,6 @@ Note:
159149
private async handleFilePrompt(
160150
promptFile: string,
161151
metadataFile: string,
162-
ciMode: boolean,
163152
dynamicOptions: Record<string, string>,
164153
inspect: boolean,
165154
fileInputs: Record<string, string>
@@ -172,7 +161,7 @@ Note:
172161
if (inspect) {
173162
await this.inspectPrompt(metadata);
174163
} else {
175-
await this.executePromptWithMetadata(promptContent, metadata, ciMode, dynamicOptions, fileInputs);
164+
await this.executePromptWithMetadata(promptContent, metadata, dynamicOptions, fileInputs);
176165
}
177166
} catch (error) {
178167
this.handleError(error, 'handling file prompt');
@@ -200,7 +189,6 @@ Note:
200189
private async executePromptWithMetadata(
201190
promptContent: string,
202191
metadata: Metadata,
203-
ciMode: boolean,
204192
dynamicOptions: Record<string, string>,
205193
fileInputs: Record<string, string>
206194
): Promise<void> {
@@ -223,29 +211,12 @@ Note:
223211
if (value) {
224212
userInputs[variable.name] = value;
225213
} else if (!variable.optional_for_user) {
226-
if (ciMode) {
227-
throw new Error(`Required variable ${snakeCaseName} is not set.`);
228-
} else {
229-
userInputs[variable.name] = await this.getInput(`Enter value for ${snakeCaseName}:`);
230-
}
214+
throw new Error(`Required variable ${snakeCaseName} is not set.`);
231215
}
232216
}
233217

234-
const result = await processPromptContent(
235-
[{ role: 'user', content: promptContent }],
236-
userInputs,
237-
!ciMode,
238-
async (inputs) => inputs,
239-
(event) => {
240-
if (event.type === 'content_block_delta') {
241-
if ('text' in event.delta) {
242-
process.stdout.write(event.delta.text);
243-
} else if ('partial_json' in event.delta) {
244-
process.stdout.write(event.delta.partial_json);
245-
}
246-
}
247-
}
248-
);
218+
const updatedPromptContent = updatePromptWithVariables(promptContent, userInputs);
219+
const result = await processPromptContent([{ role: 'user', content: updatedPromptContent }], false, false);
249220

250221
if (typeof result === 'string') {
251222
console.log(result);

src/cli/utils/conversation_manager.util.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { handleError } from './error.util';
2-
import { resolveCliInputs } from './input_processing.util';
3-
import { processCliPromptContent } from './input_resolution.util';
2+
import { resolveInputs } from './input_resolution.util';
43
import { getPromptFiles } from './prompt_crud.util';
54
import { ApiResult } from '../../shared/types';
6-
import { processPromptContent, processPromptWithVariables } from '../../shared/utils/prompt_processing.util';
5+
import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
76

87
interface ConversationMessage {
98
role: 'user' | 'assistant';
@@ -31,13 +30,11 @@ export class ConversationManager {
3130
}
3231

3332
const { promptContent } = promptFilesResult.data;
34-
const resolvedInputs = isExecuteCommand ? userInputs : await resolveCliInputs(userInputs);
35-
const updatedPromptContent = await processPromptWithVariables(promptContent, resolvedInputs);
33+
const resolvedInputs = isExecuteCommand ? userInputs : await resolveInputs(userInputs);
34+
const updatedPromptContent = updatePromptWithVariables(promptContent, resolvedInputs);
3635
this.messages.push({ role: 'user', content: updatedPromptContent });
3736

38-
const result = await (isExecuteCommand
39-
? processPromptContent(this.messages, {}, false)
40-
: processCliPromptContent(this.messages, {}, true));
37+
const result = await processPromptContent(this.messages, isExecuteCommand ? false : true);
4138

4239
if (typeof result === 'string') {
4340
this.messages.push({ role: 'assistant', content: result });
@@ -54,10 +51,7 @@ export class ConversationManager {
5451
async continueConversation(userInput: string, useStreaming: boolean = true): Promise<ApiResult<string>> {
5552
try {
5653
this.messages.push({ role: 'user', content: userInput });
57-
58-
const result = useStreaming
59-
? await processCliPromptContent(this.messages, {}, true)
60-
: await processPromptContent(this.messages, {}, false);
54+
const result = await processPromptContent(this.messages, useStreaming);
6155

6256
if (typeof result === 'string') {
6357
this.messages.push({ role: 'user', content: result });

src/cli/utils/input_processing.util.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,51 @@
1+
import { EnvVar } from '../../shared/types';
2+
import logger from '../../shared/utils/logger.util';
3+
import { FRAGMENT_PREFIX, ENV_PREFIX } from '../cli.constants';
4+
import { readEnvVars } from './env.util';
15
import { handleError } from './error.util';
2-
import { resolveCliInputs } from './input_processing.util';
3-
import { processPromptContent } from '../../shared/utils/prompt_processing.util';
6+
import { viewFragmentContent } from './fragment_operations.util';
47

5-
export async function processCliPromptContent(
6-
messages: { role: string; content: string }[],
7-
inputs: Record<string, string> = {},
8-
useStreaming: boolean = true
9-
): Promise<string> {
8+
export async function resolveValue(value: string, envVars: EnvVar[]): Promise<string> {
9+
if (value.startsWith(FRAGMENT_PREFIX)) {
10+
const [category, name] = value.split(FRAGMENT_PREFIX)[1].split('/');
11+
const fragmentResult = await viewFragmentContent(category, name);
12+
13+
if (fragmentResult.success && fragmentResult.data) {
14+
return fragmentResult.data;
15+
} else {
16+
logger.warn(`Failed to load fragment: ${category}/${name}`);
17+
return value;
18+
}
19+
} else if (value.startsWith(ENV_PREFIX)) {
20+
const envVarName = value.split(ENV_PREFIX)[1];
21+
const actualEnvVar = envVars.find((v) => v.name === envVarName);
22+
23+
if (actualEnvVar) {
24+
return await resolveValue(actualEnvVar.value, envVars);
25+
} else {
26+
logger.warn(`Env var not found: ${envVarName}`);
27+
return value;
28+
}
29+
}
30+
return value;
31+
}
32+
33+
export async function resolveInputs(inputs: Record<string, string>): Promise<Record<string, string>> {
1034
try {
11-
return processPromptContent(messages, inputs, useStreaming, resolveCliInputs, (event) => {
12-
if (event.type === 'content_block_delta' && event.delta) {
13-
if ('text' in event.delta) {
14-
process.stdout.write(event.delta.text);
15-
} else if ('partial_json' in event.delta) {
16-
process.stdout.write(event.delta.partial_json);
17-
}
35+
const envVarsResult = await readEnvVars();
36+
const envVars = envVarsResult.success ? envVarsResult.data || [] : [];
37+
const resolvedInputs: Record<string, string> = {};
38+
39+
for (const [key, value] of Object.entries(inputs)) {
40+
if (value.startsWith(FRAGMENT_PREFIX) || value.startsWith(ENV_PREFIX)) {
41+
resolvedInputs[key] = await resolveValue(value, envVars);
42+
} else {
43+
resolvedInputs[key] = value;
1844
}
19-
});
45+
}
46+
return resolvedInputs;
2047
} catch (error) {
21-
handleError(error, 'processing CLI prompt content');
48+
handleError(error, 'resolving inputs');
2249
throw error;
2350
}
2451
}

src/shared/utils/anthropic_client.util.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function getAnthropicClient(): Anthropic {
2222

2323
export async function sendAnthropicRequestClassic(messages: { role: string; content: string }[]): Promise<Message> {
2424
const client = getAnthropicClient();
25+
2526
try {
2627
return await client.messages.create({
2728
model: commonConfig.ANTHROPIC_MODEL,

0 commit comments

Comments
 (0)