sourcewizard
Version:
SourceWizard - AI-powered setup wizard for dev tools and libraries with MCP integration
136 lines (135 loc) • 4.68 kB
JavaScript
import { createAnthropic } from "@ai-sdk/anthropic";
import { generateText } from "ai";
import { createFileOperationTools } from "./ai-tools.js";
import { getBulkTargetData } from "./repository-detector.js";
import { readRelevantFiles } from "./file-utils.js";
export class AIAgent {
projectContext;
cwd;
serverUrl;
apiKey;
jwt;
onStepFinish;
constructor(options) {
this.cwd = options.cwd;
this.projectContext = options.projectContext;
this.onStepFinish = options.onStepFinish;
this.serverUrl = options.serverUrl;
this.apiKey = options.apiKey;
this.jwt = options.jwt;
if (!this.apiKey && !this.jwt) {
throw new Error("API key or JWT token is required");
}
}
async getConfig(packageName) {
let authHeaders = {};
if (this.apiKey) {
authHeaders["x-api-key"] = this.apiKey;
}
if (this.jwt) {
authHeaders["Authorization"] = `Bearer ${this.jwt}`;
}
const response = await fetch(`${this.serverUrl}/api/agent/config`, {
method: "POST",
headers: {
"Content-Type": "application/json",
...authHeaders,
},
body: JSON.stringify({
package_name: packageName,
}),
});
const data = await response.json();
return data;
}
async searchPackages(query) {
let authHeaders = {};
if (this.apiKey) {
authHeaders["x-api-key"] = this.apiKey;
}
if (this.jwt) {
authHeaders["Authorization"] = `Bearer ${this.jwt}`;
}
const anthropic = createAnthropic({
apiKey: this.apiKey || '',
baseURL: this.serverUrl + "/api/agent",
headers: {
...authHeaders,
},
});
const bulkTargetData = await getBulkTargetData(this.projectContext.targets, this.cwd);
this.projectContext.target_dependencies = bulkTargetData;
const prompt = {
operation: "search",
search_query: query,
project_context: this.projectContext,
};
// console.log("Prompt", prompt);
const result = await generateText({
// this is ignored on the server side
model: anthropic("claude-4-sonnet-20250514"),
prompt: JSON.stringify(prompt),
onStepFinish: this.onStepFinish,
});
return {
text: result.text,
toolCalls: result.toolCalls,
toolResults: result.toolResults,
finishReason: result.finishReason,
usage: result.usage,
};
}
async installPackage(packageName) {
const config = await this.getConfig(packageName);
let relevantFiles = {};
if (config.relevant_files_pattern) {
console.log("Reading relevant files");
relevantFiles = await readRelevantFiles(this.cwd, config.relevant_files_pattern);
}
let authHeaders = {};
if (this.apiKey) {
authHeaders["x-api-key"] = this.apiKey;
}
if (this.jwt) {
authHeaders["Authorization"] = `Bearer ${this.jwt}`;
}
const anthropic = createAnthropic({
apiKey: this.apiKey || '',
baseURL: this.serverUrl + "/api/agent",
headers: {
...authHeaders,
},
});
const tools = createFileOperationTools(this.cwd, this.projectContext.targets);
const prompt = {
operation: "integrate",
package_name: packageName,
relevant_files: relevantFiles,
project_context: this.projectContext,
};
const result = await generateText({
// this is ignored on the server side
model: anthropic("claude-4-sonnet-20250514"),
maxSteps: config.max_steps,
prompt: JSON.stringify(prompt),
onStepFinish: this.onStepFinish ||
(({ text, toolCalls, toolResults, finishReason, usage }) => {
console.log("Step finished:", {
text,
toolCalls,
toolResults,
finishReason,
usage,
});
}),
tools,
});
return {
text: result.text,
toolCalls: result.toolCalls,
toolResults: result.toolResults,
finishReason: result.finishReason,
usage: result.usage,
};
}
}