Skip to content

Commit

Permalink
chore: use claude instead of chatgpt
Browse files Browse the repository at this point in the history
  • Loading branch information
0x4007 committed Oct 1, 2024
1 parent 5028103 commit b60e2d8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 73 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ static/dist
coverage
junit.xml
cypress/screenshots
src/organizations/
src/organizations/
.swp
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"open-source"
],
"dependencies": {
"axios": "^1.7.7",
"@anthropic-ai/sdk": "^0.27.3",
"dotenv": "^16.4.4",
"inquirer": "^11.1.0",
"js-yaml": "^4.1.0",
Expand Down
39 changes: 22 additions & 17 deletions src/sync-configs/render-prompt.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
export function renderPrompt(originalContent: string, instruction: string): string {
return [
`You are to act as a YAML configuration editor. Your goal is to modify the provided YAML file according to the given instructions while ensuring that the syntax remains valid and no necessary formatting is lost. Be especially careful with list indicators (like hyphens) and ensure they are preserved appropriately.`,

`**Important:** Do **not** remove any hyphens (\`-\`) that indicate items in a list (e.g., plugins). These hyphens are critical for YAML syntax and must be retained.`,

`Additionally, correct any syntax errors present in the original YAML file. Do not remove comments intended for human readers; only remove commented-out YAML markup that is unnecessary for the file to function.`,

`Here is the original YAML configuration file:`,
export function renderPrompt(originalContent: string, instruction: string, parserCode: string): string {
// eslint-disable-next-line sonarjs/prefer-immediate-return
const prompt = [
`
- You are to act as a YAML configuration editor.
- Your goal is to modify the provided YAML file according to the user's instructions while ensuring that the syntax remains valid and no necessary formatting is lost.
- Be especially careful with list indicators (like hyphens) and ensure they are preserved appropriately.
- **Important:** Do **not** remove any hyphens (\`-\`) that indicate items in a list (e.g., plugins). These hyphens are critical for YAML syntax and must be retained.
- Additionally, correct any syntax errors present in the original YAML file.
- Do not remove comments intended for human readers; only remove commented-out YAML markup that is unnecessary for the file to function.
- **Do not alter any URLs in the configuration file. Assume that all URLs provided are correct and must remain unchanged.**
- Here is the original YAML configuration file:`,

originalContent,

`Modify this file according to the following instruction:`,
`Provide the modified YAML file without any additional explanation or extraneous characters. Do not include any headers, footers, code block markers (like triple backticks), or language identifiers (like 'yaml'). **Only output the modified YAML content.**
instruction,
**Example of correct plugin formatting:**
`Provide the modified YAML file without any additional explanation or extraneous characters. Do not include any headers, footers, code block markers (like triple backticks), or language identifiers (like 'yaml'). **Only output the modified YAML content.**`,
- uses:
- plugin: ubiquibot/issue-comment-embeddings@main
`**Example of correct plugin formatting:**
Ensure that the hyphens before each plugin are retained as shown above. **Remember, do not change any URLs in the configuration.** Finally, for additional context, here is the source code of the yml configuration parser for your reference:`,

- uses:
- plugin: ubiquibot/issue-comment-embeddings@main
Ensure that the hyphens before each plugin are retained as shown above.`,
parserCode,
].join("\n\n===\n\n");

// console.trace(prompt);

return prompt;
}
10 changes: 10 additions & 0 deletions src/sync-configs/repositories.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
const CONFIG_FILE_PATH = ".github/.ubiquibot-config.yml";

export const repositories = [
{
// https://github.com/ubiquity-os/ubiquity-os-kernel/blob/development/src/github/types/plugin-configuration.ts
url: "https://github.com/ubiquity-os/ubiquity-os-kernel.git",
filePath: "src/github/types/plugin-configuration.ts",
localDir: "ubiquity-os-kernel",
type: "parser",
},
{
url: "https://github.com/ubiquity/ubiquibot-config.git",
filePath: CONFIG_FILE_PATH,
localDir: "ubiquity",
type: "config",
},
{
url: "https://github.com/ubiquity-os/ubiquibot-config.git",
filePath: CONFIG_FILE_PATH,
localDir: "ubiquity-os",
type: "config",
},
{
url: "https://github.com/ubiquity-os-marketplace/ubiquibot-config.git",
filePath: CONFIG_FILE_PATH,
localDir: "ubiquity-os-marketplace",
type: "config",
},
];
108 changes: 54 additions & 54 deletions src/sync-configs/sync-configs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import axios from "axios";
import * as fs from "fs";
import inquirer from "inquirer";
import * as path from "path";
Expand All @@ -10,10 +9,10 @@ import { repositories } from "./repositories";

const REPOS_DIR = "../organizations";

const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;

if (!OPENAI_API_KEY) {
console.error("Error: OPENAI_API_KEY environment variable is not set.");
if (!ANTHROPIC_API_KEY) {
console.error("Error: ANTHROPIC_API_KEY environment variable is not set.");
process.exit(1);
}

Expand All @@ -24,7 +23,7 @@ function cloneOrPullRepo(repo: { url: string; localDir: string }, defaultBranch:
return new Promise((resolve, reject) => {
if (fs.existsSync(repoDir)) {
// Repo already cloned, do git pull
console.log(`Pulling latest changes for ${repo.url}`);
// console.log(`Pulling latest changes for ${repo.url}`);
git
.cwd(repoDir)
.then(() => Promise.all([git.checkout(defaultBranch), git.pull("origin", defaultBranch)]))
Expand Down Expand Up @@ -60,14 +59,13 @@ export async function syncConfigs() {
if (!fs.existsSync(reposPath)) {
fs.mkdirSync(reposPath, { recursive: true });
}

// Clone or pull the repositories
for (const repo of repositories) {
// Start cloning or pulling repositories in the background
const clonePromises = repositories.map(async (repo) => {
const defaultBranch = await getDefaultBranch(repo.url);
void cloneOrPullRepo(repo, defaultBranch);
}
return cloneOrPullRepo(repo, defaultBranch);
});

// Get user input
// Get user input while repositories are being cloned/pulled
const { instruction } = await inquirer.prompt([
{
type: "input",
Expand All @@ -76,6 +74,25 @@ export async function syncConfigs() {
},
]);

// Wait for all clone/pull operations to complete
await Promise.all(clonePromises);

// Find and remove the parser repository from the array
const parserRepoIndex = repositories.findIndex((repo) => repo.type === "parser");
if (parserRepoIndex === -1) {
console.error("Parser repository not found. Unable to proceed.");
return;
}
const [parserRepo] = repositories.splice(parserRepoIndex, 1);

// Read the parser file content
const parserFilePath = path.join(__dirname, REPOS_DIR, parserRepo.localDir, parserRepo.filePath);
if (!fs.existsSync(parserFilePath)) {
console.error(`Parser file ${parserFilePath} does not exist. Unable to proceed.`);
return;
}
const parserCode = fs.readFileSync(parserFilePath, "utf8");

// Process each file
for (const repo of repositories) {
const filePath = path.join(__dirname, REPOS_DIR, repo.localDir, repo.filePath);
Expand All @@ -86,7 +103,7 @@ export async function syncConfigs() {
const fileContent = fs.readFileSync(filePath, "utf8");

// Use OpenAI API to get the modified content
const modifiedContent = await getModifiedContent(fileContent, instruction);
const modifiedContent = await getModifiedContent(fileContent, instruction, parserCode);

// Save the modified content to a temporary file
const tempFilePath = `${filePath}.modified`;
Expand Down Expand Up @@ -129,53 +146,36 @@ ${instruction}
}
}

async function getModifiedContent(originalContent: string, instruction: string): Promise<string> {
const prompt = renderPrompt(originalContent, instruction);
import Anthropic from "@anthropic-ai/sdk";

// console.trace(prompt)
async function getModifiedContent(originalContent: string, instruction: string, parserCode: string): Promise<string> {
const prompt = renderPrompt(originalContent, instruction, parserCode);

const response = await axios.post(
"https://api.openai.com/v1/chat/completions",
{
model: "gpt-4o",
messages: [
{
role: "system",
content: "You are an assistant that modifies YAML configuration files based on instructions.",
},
{ role: "user", content: prompt },
],
stream: true,
},
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${OPENAI_API_KEY}`,
const anthropic = new Anthropic({
apiKey: ANTHROPIC_API_KEY,
});

const stream = await anthropic.messages.create({
model: "claude-3-5-sonnet-20240620",
max_tokens: 4000,
temperature: 0,
system: prompt,
messages: [
{
role: "user",
content: instruction,
},
responseType: "stream",
}
);
],
stream: true,
});

let fullContent = "";
for await (const chunk of response.data) {
const lines = chunk
.toString()
.split("\n")
.filter((line: string) => line.trim() !== "");
for (const line of lines) {
const message = line.replace(/^data: /, "");
if (message === "[DONE]") {
return fullContent.trim();
}
try {
const parsed = JSON.parse(message);
const content = parsed.choices[0].delta.content;
if (content) {
fullContent += content;
process.stdout.write(content);
}
} catch (error) {
console.error("Error parsing stream:", error);
for await (const chunk of stream) {
if (chunk.type === "content_block_delta") {
const content = chunk.delta.text;
if (content) {
fullContent += content;
process.stdout.write(content);
}
}
}
Expand Down

0 comments on commit b60e2d8

Please sign in to comment.