mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-22 05:11:06 -05:00
Add a command-line cline powered by deno
This commit is contained in:
164
cli/core/StandaloneAgent.ts
Normal file
164
cli/core/StandaloneAgent.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import { blue, red, yellow } from "../deps.ts";
|
||||
import { ApiHandler } from "../api/mod.ts";
|
||||
import { executeCommand, readFile, writeFile, searchFiles, listFiles, listCodeDefinitions } from "../tools/mod.ts";
|
||||
import type { Message, TextBlock, ToolResult } from "../types.d.ts";
|
||||
|
||||
interface AgentConfig {
|
||||
api: ApiHandler;
|
||||
systemPrompt: string;
|
||||
workingDir: string;
|
||||
}
|
||||
|
||||
export class StandaloneAgent {
|
||||
private api: ApiHandler;
|
||||
private systemPrompt: string;
|
||||
private workingDir: string;
|
||||
private conversationHistory: Message[] = [];
|
||||
|
||||
constructor(config: AgentConfig) {
|
||||
this.api = config.api;
|
||||
this.systemPrompt = config.systemPrompt;
|
||||
this.workingDir = config.workingDir;
|
||||
}
|
||||
|
||||
async runTask(task: string): Promise<void> {
|
||||
this.conversationHistory.push({
|
||||
role: "user",
|
||||
content: [{ type: "text", text: `<task>\n${task}\n</task>` }]
|
||||
});
|
||||
|
||||
let isTaskComplete = false;
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
while (!isTaskComplete) {
|
||||
const stream = this.api.createMessage(this.systemPrompt, this.conversationHistory);
|
||||
let assistantMessage = "";
|
||||
|
||||
console.log(blue("Thinking..."));
|
||||
for await (const chunk of stream) {
|
||||
if (chunk.type === "text") {
|
||||
assistantMessage += chunk.text;
|
||||
await Deno.stdout.write(encoder.encode(chunk.text));
|
||||
}
|
||||
}
|
||||
|
||||
this.conversationHistory.push({
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: assistantMessage }]
|
||||
});
|
||||
|
||||
const toolResults = await this.executeTools(assistantMessage);
|
||||
|
||||
if (toolResults.length > 0) {
|
||||
this.conversationHistory.push({
|
||||
role: "user",
|
||||
content: toolResults.map(result => ({
|
||||
type: "text",
|
||||
text: `[${result.tool}] Result:${result.output}`
|
||||
})) as TextBlock[]
|
||||
});
|
||||
} else {
|
||||
if (assistantMessage.includes("<attempt_completion>")) {
|
||||
isTaskComplete = true;
|
||||
} else {
|
||||
this.conversationHistory.push({
|
||||
role: "user",
|
||||
content: [{
|
||||
type: "text",
|
||||
text: "You must either use available tools to accomplish the task or call attempt_completion when the task is complete."
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async executeTools(message: string): Promise<ToolResult[]> {
|
||||
const results: ToolResult[] = [];
|
||||
const toolRegex = /<(\w+)>\s*([\s\S]*?)\s*<\/\1>/g;
|
||||
let match;
|
||||
|
||||
while ((match = toolRegex.exec(message)) !== null) {
|
||||
const [_, toolName, paramsXml] = match;
|
||||
const params: Record<string, string> = {};
|
||||
const paramRegex = /<(\w+)>\s*([\s\S]*?)\s*<\/\1>/g;
|
||||
let paramMatch;
|
||||
|
||||
while ((paramMatch = paramRegex.exec(paramsXml)) !== null) {
|
||||
const [__, paramName, paramValue] = paramMatch;
|
||||
params[paramName] = paramValue.trim();
|
||||
}
|
||||
|
||||
let output: string;
|
||||
try {
|
||||
console.log(yellow(`\nExecuting: ${this.getToolDescription(toolName, params)}`));
|
||||
|
||||
switch (toolName) {
|
||||
case "execute_command":
|
||||
output = await executeCommand(params.command);
|
||||
break;
|
||||
case "read_file":
|
||||
output = await readFile(this.workingDir, params.path);
|
||||
break;
|
||||
case "write_to_file":
|
||||
output = await writeFile(this.workingDir, params.path, params.content);
|
||||
break;
|
||||
case "search_files":
|
||||
output = await searchFiles(this.workingDir, params.path, params.regex, params.file_pattern);
|
||||
break;
|
||||
case "list_files":
|
||||
output = await listFiles(this.workingDir, params.path, params.recursive === "true");
|
||||
break;
|
||||
case "list_code_definition_names":
|
||||
output = await listCodeDefinitions(this.workingDir, params.path);
|
||||
break;
|
||||
case "attempt_completion":
|
||||
return results;
|
||||
default:
|
||||
console.warn(red(`Unknown tool: ${toolName}`));
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push({
|
||||
tool: toolName,
|
||||
params,
|
||||
output: output || "(No output)"
|
||||
});
|
||||
|
||||
break;
|
||||
} catch (error) {
|
||||
const errorMessage = `Error executing ${toolName}: ${error instanceof Error ? error.message : String(error)}`;
|
||||
console.error(red(errorMessage));
|
||||
results.push({
|
||||
tool: toolName,
|
||||
params,
|
||||
output: errorMessage
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private getToolDescription(toolName: string, params: Record<string, string>): string {
|
||||
switch (toolName) {
|
||||
case "execute_command":
|
||||
return `Running command: ${params.command}`;
|
||||
case "read_file":
|
||||
return `Reading file: ${params.path}`;
|
||||
case "write_to_file":
|
||||
return `Writing to file: ${params.path}`;
|
||||
case "search_files":
|
||||
return `Searching for "${params.regex}" in ${params.path}`;
|
||||
case "list_files":
|
||||
return `Listing files in ${params.path}`;
|
||||
case "list_code_definition_names":
|
||||
return `Analyzing code in ${params.path}`;
|
||||
case "attempt_completion":
|
||||
return "Completing task";
|
||||
default:
|
||||
return toolName;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
cli/core/prompts.ts
Normal file
120
cli/core/prompts.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { join } from "https://deno.land/std@0.220.1/path/mod.ts";
|
||||
|
||||
export const SYSTEM_PROMPT = async (cwd: string): Promise<string> => {
|
||||
let rulesContent = "";
|
||||
|
||||
// Load and combine rules from configuration files
|
||||
const ruleFiles = ['.clinerules', '.cursorrules'];
|
||||
for (const file of ruleFiles) {
|
||||
const rulePath = join(cwd, file);
|
||||
try {
|
||||
const stat = await Deno.stat(rulePath);
|
||||
if (stat.isFile) {
|
||||
const content = await Deno.readTextFile(rulePath);
|
||||
if (content.trim()) {
|
||||
rulesContent += `\n# Rules from ${file}:\n${content.trim()}\n\n`;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// Only ignore ENOENT (file not found) errors
|
||||
if (!(err instanceof Deno.errors.NotFound)) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `You are Cline, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.
|
||||
|
||||
====
|
||||
|
||||
TOOL USE
|
||||
|
||||
You have access to tools that are executed upon approval. Use one tool per message and wait for the result before proceeding. Each tool must be used with proper XML-style formatting:
|
||||
|
||||
<tool_name>
|
||||
<parameter1_name>value1</parameter1_name>
|
||||
<parameter2_name>value2</parameter2_name>
|
||||
</tool_name>
|
||||
|
||||
# Available Tools
|
||||
|
||||
## execute_command
|
||||
Description: Execute a CLI command on the system. Commands run in the current working directory: ${cwd}
|
||||
Parameters:
|
||||
- command: (required) The command to execute. Must be valid for the current OS.
|
||||
Usage:
|
||||
<execute_command>
|
||||
<command>command to run</command>
|
||||
</execute_command>
|
||||
|
||||
## read_file
|
||||
Description: Read contents of a file. Supports text files and automatically extracts content from PDFs/DOCXs.
|
||||
Parameters:
|
||||
- path: (required) Path to file (relative to ${cwd})
|
||||
Usage:
|
||||
<read_file>
|
||||
<path>path to file</path>
|
||||
</read_file>
|
||||
|
||||
## write_to_file
|
||||
Description: Write content to a file. Creates directories as needed. Will overwrite existing files.
|
||||
Parameters:
|
||||
- path: (required) Path to write to (relative to ${cwd})
|
||||
- content: (required) Complete file content. Must include ALL parts, even unchanged sections.
|
||||
Usage:
|
||||
<write_to_file>
|
||||
<path>path to file</path>
|
||||
<content>complete file content</content>
|
||||
</write_to_file>
|
||||
|
||||
## search_files
|
||||
Description: Search files using regex patterns. Shows matches with surrounding context.
|
||||
Parameters:
|
||||
- path: (required) Directory to search (relative to ${cwd})
|
||||
- regex: (required) Rust regex pattern to search for
|
||||
- file_pattern: (optional) Glob pattern to filter files (e.g. "*.ts")
|
||||
Usage:
|
||||
<search_files>
|
||||
<path>directory to search</path>
|
||||
<regex>pattern to search</regex>
|
||||
<file_pattern>optional file pattern</file_pattern>
|
||||
</search_files>
|
||||
|
||||
## list_code_definition_names
|
||||
Description: List code definitions (classes, functions, etc.) in source files.
|
||||
Parameters:
|
||||
- path: (required) Directory to analyze (relative to ${cwd})
|
||||
Usage:
|
||||
<list_code_definition_names>
|
||||
<path>directory to analyze</path>
|
||||
</list_code_definition_names>
|
||||
|
||||
## attempt_completion
|
||||
Description: Signal task completion and present results.
|
||||
Parameters:
|
||||
- result: (required) Description of completed work
|
||||
- command: (optional) Command to demonstrate result
|
||||
Usage:
|
||||
<attempt_completion>
|
||||
<result>description of completed work</result>
|
||||
<command>optional demo command</command>
|
||||
</attempt_completion>
|
||||
|
||||
# Guidelines
|
||||
|
||||
1. Use one tool at a time and wait for results
|
||||
2. Provide complete file content when using write_to_file
|
||||
3. Be direct and technical in responses
|
||||
4. Present final results using attempt_completion
|
||||
5. Do not make assumptions about command success
|
||||
6. Do not make up commands that don't exist
|
||||
|
||||
# Rules
|
||||
|
||||
- Current working directory is: ${cwd}
|
||||
- Cannot cd to different directories
|
||||
- Must wait for confirmation after each tool use
|
||||
- Must provide complete file content when writing files
|
||||
- Be direct and technical, not conversational
|
||||
- Do not end messages with questions${rulesContent}`;
|
||||
};
|
||||
Reference in New Issue
Block a user