Skip to content

Commit

Permalink
🐛 fix(anthropic_client): Update anthropic client to use messages in a…
Browse files Browse the repository at this point in the history
… proper way
  • Loading branch information
thibaultyou committed Oct 19, 2024
1 parent 5058850 commit 54f55e2
Show file tree
Hide file tree
Showing 16 changed files with 81 additions and 101 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/update_views.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- "prompts/**/*.md"
- "prompts/prompt.md"
- "src/app/**/*.ts"
- "src/app/system_prompts/**/*.md"
- "src/system_prompts/**/*.md"
- "src/app/templates/*.md"

jobs:
Expand All @@ -20,7 +20,7 @@ jobs:

- name: Validate critical files
run: |
if [ ! -f "src/app/system_prompts/prompt_analysis_agent/prompt.md" ]; then
if [ ! -f "src/system_prompts/prompt_analysis_agent/prompt.md" ]; then
echo "Error: AI prompt analyzer file is missing"
exit 1
fi
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
- name: Check for system prompt changes
id: check_changes
run: |
if git diff --name-only HEAD^ HEAD | grep -q "src/app/system_prompts/prompt_analysis_agent/"; then
if git diff --name-only HEAD^ HEAD | grep -q "src/system_prompts/prompt_analysis_agent/"; then
echo "FORCE_REGENERATE=true" >> $GITHUB_ENV
else
echo "FORCE_REGENERATE=false" >> $GITHUB_ENV
Expand Down
13 changes: 1 addition & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,7 @@ Detailed setup instructions in [Getting Started](#-getting-started).
prompt-library-cli
```

For all CLI options, run:

```sh
prompt-library-cli --help
```

### List Prompts and Categories

```sh
prompt-library-cli prompts --list
prompt-library-cli prompts --categories
```

### Sync Personal Library

Expand Down Expand Up @@ -203,7 +192,7 @@ prompt-library-cli execute --help

Fragments are reusable prompt components:

1. Create `.md` files in `fragments` directory under the appropriate [categories](/src/app/system_prompts/prompt_analysis_agent/prompt.md)).
1. Create `.md` files in `fragments` directory under the appropriate [categories](/src/system_prompts/prompt_analysis_agent/prompt.md)).
2. Reference in prompts: `` (e.g., `` for `awesome_guidelines.md`).
3. Manage and use via CLI.

Expand Down
2 changes: 1 addition & 1 deletion src/app/config/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const appConfig: AppConfig = {
PROMPTS_DIR: 'prompts',
FRAGMENTS_DIR: 'fragments',
TEMPLATES_DIR: path.join('src', 'app', 'templates'),
ANALYZER_PROMPT_PATH: path.join('src', 'app', 'system_prompts', 'prompt_analysis_agent', 'prompt.md'),
ANALYZER_PROMPT_PATH: path.join('src', 'system_prompts', 'prompt_analysis_agent', 'prompt.md'),
README_PATH: 'README.md',
VIEW_FILE_NAME: 'README.md',
VIEW_TEMPLATE_NAME: 'sub_readme.md',
Expand Down
2 changes: 1 addition & 1 deletion src/app/templates/main_readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ prompt-library-cli execute --help

Fragments are reusable prompt components:

1. Create `.md` files in `fragments` directory under the appropriate [categories](/src/app/system_prompts/prompt_analysis_agent/prompt.md)).
1. Create `.md` files in `fragments` directory under the appropriate [categories](/src/system_prompts/prompt_analysis_agent/prompt.md)).
2. Reference in prompts: `{{FRAGMENT_NAME}}` (e.g., `{{AWESOME_GUIDELINES}}` for `awesome_guidelines.md`).
3. Manage and use via CLI.

Expand Down
2 changes: 1 addition & 1 deletion src/app/utils/prompt_operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function processMetadataGeneration(promptContent: string): Promise<
PROMPT_TO_ANALYZE: promptContent,
AVAILABLE_PROMPT_FRAGMENTS: availableFragments
};
const content = await processPromptContent(analyzerPrompt, variables, false);
const content = await processPromptContent([{ role: 'user', content: analyzerPrompt }], variables, false);
const yamlContent = extractOutputContent(content);
return parseYamlContent(yamlContent);
} catch (error) {
Expand Down
20 changes: 13 additions & 7 deletions src/cli/commands/execute.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,21 @@ Note:
}

try {
const result = await processPromptContent(promptContent, userInputs, false, undefined, (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 result = await processPromptContent(
[{ role: 'user', content: promptContent }],
userInputs,
!ciMode, // Use streaming if not in CI mode
async (inputs) => inputs, // Simple pass-through function for resolveInputs
(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);
}
}
}
});
);

if (typeof result === 'string') {
console.log(result);
Expand Down
6 changes: 2 additions & 4 deletions src/cli/commands/prompts.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ class PromptCommand extends BaseCommand {
return;
}

await this.pressKeyToContinue();
// await this.pressKeyToContinue();
}

async assignValueToVariable(promptId: string, variable: Variable): Promise<void> {
Expand Down Expand Up @@ -448,8 +448,6 @@ class PromptCommand extends BaseCommand {
);

if (result) {
// console.log(result);

while (true) {
const nextAction = await this.showMenu<'continue' | 'back'>('What would you like to do next?', [
{ name: chalk.green(chalk.bold('Continue conversation')), value: 'continue' }
Expand All @@ -459,7 +457,7 @@ class PromptCommand extends BaseCommand {

const userInput = await this.getMultilineInput(chalk.blue('You: '));
const response = await this.handleApiResult(
await conversationManager.continueConversation(userInput, true),
await conversationManager.continueConversation(userInput),
'Continued conversation'
);

Expand Down
2 changes: 1 addition & 1 deletion src/cli/utils/content.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ export async function hasFragments(): Promise<boolean> {
console.error('Error checking fragments directory:', error);
return false;
}
}
}
43 changes: 19 additions & 24 deletions src/cli/utils/conversation.util.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import chalk from 'chalk';
// Updated ConversationManager class

import { processCliPromptContent, resolveCliInputs } from './prompt.cli.util';
import { getPromptFiles } from './prompt.util';
import { ApiResult } from '../../shared/types';
import logger from '../../shared/utils/logger';
import { processPromptContent, processPromptWithVariables } from '../../shared/utils/prompt_operations';

interface ConversationMessage {
role: 'human' | 'assistant';
content: string;
}

export class ConversationManager {
private conversationContext: string;
private messages: ConversationMessage[];
private promptId: string;

constructor(promptId: string) {
this.promptId = promptId;
this.conversationContext = '';
this.messages = [];
}

async initializeConversation(
Expand All @@ -29,18 +34,14 @@ export class ConversationManager {
const { promptContent } = promptFilesResult.data;
const resolvedInputs = isExecuteCommand ? userInputs : await resolveCliInputs(userInputs);
const updatedPromptContent = await processPromptWithVariables(promptContent, resolvedInputs);
let result: string;
this.messages.push({ role: 'human', content: updatedPromptContent });

if (isExecuteCommand) {
result = await processPromptContent(updatedPromptContent, {}, false);
} else {
console.log(chalk.green('\nHuman:'), updatedPromptContent);
console.log(chalk.green('AI:'));
result = await processCliPromptContent(updatedPromptContent, {}, true);
}
const result = await (isExecuteCommand
? processPromptContent(this.messages, {}, false)
: processCliPromptContent(this.messages, {}, true));

if (typeof result === 'string') {
this.conversationContext = `Initial Prompt:\n${updatedPromptContent}\n\nAI: ${result}`;
this.messages.push({ role: 'assistant', content: result });
return { success: true, data: result };
} else {
return { success: false, error: 'Unexpected result format' };
Expand All @@ -54,22 +55,16 @@ export class ConversationManager {
}
}

async continueConversation(userInput: string, useStreaming: boolean): Promise<ApiResult<string>> {
async continueConversation(userInput: string, useStreaming: boolean = true): Promise<ApiResult<string>> {
try {
const continuationPrompt = `${this.conversationContext}\n\nHuman: ${userInput}\n\nAI:`;
let result: string;
this.messages.push({ role: 'human', content: userInput });

if (!useStreaming) {
result = await processPromptContent(continuationPrompt, {}, false);
} else {
console.log(chalk.green('\nHuman:'), userInput);
console.log(chalk.green('\nAI:'));
result = await processCliPromptContent(continuationPrompt, {}, true);
console.log();
}
const result = useStreaming
? await processCliPromptContent(this.messages, {}, true)
: await processPromptContent(this.messages, {}, false);

if (typeof result === 'string') {
this.conversationContext += `\nHuman: ${userInput}\nAI: ${result}`;
this.messages.push({ role: 'assistant', content: result });
return { success: true, data: result };
} else {
return { success: false, error: 'Unexpected result format' };
Expand Down
6 changes: 3 additions & 3 deletions src/cli/utils/prompt.cli.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ export async function resolveCliInputs(inputs: Record<string, string>): Promise<
}

export async function processCliPromptContent(
promptContent: string,
messages: { role: string; content: string }[],
inputs: Record<string, string> = {},
useStreaming: boolean = true
): Promise<string> {
return processPromptContent(promptContent, inputs, useStreaming, resolveCliInputs, (event) => {
if (event.type === 'content_block_delta') {
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) {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/utils/prompt.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export async function executePrompt(
}

const { promptContent } = promptFilesResult.data;
const result = await processPromptContent(promptContent, userInputs, useStreaming);
const result = await processPromptContent([{ role: 'user', content: promptContent }], userInputs, useStreaming);
return { success: true, data: result };
} catch (error) {
return {
Expand Down
50 changes: 15 additions & 35 deletions src/shared/utils/anthropic_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import logger from './logger';
import { config } from '../config';
import { commonConfig } from '../config/common.config';

/**
* Initializes and returns an Anthropic client.
* @throws {Error} If the ANTHROPIC_API_KEY is not set in the environment.
* @returns {Anthropic} An initialized Anthropic client.
*/
export function initializeAnthropicClient(): Anthropic {
const apiKey = commonConfig.ANTHROPIC_API_KEY;

Expand All @@ -22,25 +17,19 @@ export function initializeAnthropicClient(): Anthropic {
return new Anthropic({ apiKey });
}

/**
* Sends a request to the Anthropic API in classic mode.
* @param {Anthropic} client - The initialized Anthropic client.
* @param {string} prompt - The prompt to send to the API.
* @returns {Promise<Message>} The response from the Anthropic API.
* @throws {Error} If there's an error sending the request to the API.
*/
export async function sendAnthropicRequestClassic(client: Anthropic, prompt: string): Promise<Message> {
export async function sendAnthropicRequestClassic(
client: Anthropic,
messages: { role: string; content: string }[]
): Promise<Message> {
try {
logger.info('Sending classic request to Anthropic API');
const message = await client.messages.create({
model: commonConfig.ANTHROPIC_MODEL,
max_tokens: commonConfig.ANTHROPIC_MAX_TOKENS,
messages: [
{
role: 'user',
content: prompt
}
]
messages: messages.map((msg) => ({
role: msg.role === 'human' ? 'user' : 'assistant',
content: msg.content
}))
});
logger.info('Received classic response from Anthropic API');
return message;
Expand All @@ -50,28 +39,19 @@ export async function sendAnthropicRequestClassic(client: Anthropic, prompt: str
}
}

/**
* Sends a request to the Anthropic API in streaming mode.
* @param {Anthropic} client - The initialized Anthropic client.
* @param {string} prompt - The prompt to send to the API.
* @returns {AsyncGenerator<MessageStreamEvent>} An async generator of message stream events.
* @throws {Error} If there's an error sending the request to the API.
*/
export async function* sendAnthropicRequestStream(
client: Anthropic,
prompt: string
messages: { role: string; content: string }[]
): AsyncGenerator<MessageStreamEvent> {
try {
logger.info('Sending streaming request to Anthropic API');
const stream = await client.messages.stream({
const stream = client.messages.stream({
model: config.ANTHROPIC_MODEL,
max_tokens: config.ANTHROPIC_MAX_TOKENS,
messages: [
{
role: 'user',
content: prompt
}
]
messages: messages.map((msg) => ({
role: msg.role === 'human' ? 'user' : 'assistant',
content: msg.content
}))
});

for await (const event of stream) {
Expand All @@ -93,7 +73,7 @@ export async function validateAnthropicApiKey(): Promise<boolean> {
try {
const client = initializeAnthropicClient();
// Attempt a simple request to validate the API key
await sendAnthropicRequestClassic(client, 'Test request');
await sendAnthropicRequestClassic(client, [{ role: 'user', content: 'Test request' }]);
logger.info('Anthropic API key is valid');
return true;
} catch (error) {
Expand Down
Loading

0 comments on commit 54f55e2

Please sign in to comment.