Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions agent/llcraft/dist/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Supports both Anthropic API and OpenAI-compatible APIs (like Copilot bridge)
* With tool calling support including browser tools
*/
import { builtinTools, executeTool } from './tools.js';
import { builtinTools, executeTool, llmccTool } from './tools.js';
import { browserTools, isBrowserTool, executeBrowserTool } from './browser.js';
/**
* Call API - auto-detects Anthropic vs OpenAI format based on URL
Expand Down Expand Up @@ -34,6 +34,9 @@ export async function callAPI(messages, config, onToolCall) {
async function callOpenAIAPIWithTools(messages, config, onToolCall) {
// Collect available tools
const availableTools = [...builtinTools];
if (config.llmcc) {
availableTools.push(llmccTool);
}
if (config.chrome) {
availableTools.push(...browserTools);
}
Expand Down Expand Up @@ -62,7 +65,7 @@ Only use tools when necessary to complete the user's request.`;
content: m.content,
})),
];
const maxIterations = 10;
const maxIterations = 50; // Increased for complex tasks
let iterations = 0;
while (iterations < maxIterations) {
iterations++;
Expand Down
11 changes: 10 additions & 1 deletion agent/llcraft/dist/index.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ ${JSON.stringify(session, null, 2)}
}
function printWelcome(session, config) {
console.log(`${colors.cyan}${colors.bold}llcraft${colors.reset} ${colors.dim}v0.1.0${colors.reset}`);
const llmccStatus = config.llmcc ? `${colors.green}✓ llmcc${colors.reset}` : '';
const chromeStatus = config.chrome ? `${colors.green}✓ chrome${colors.reset}` : '';
console.log(`${colors.dim}Model: ${config.model} | API: ${config.baseUrl}${colors.reset} ${chromeStatus}`);
console.log(`${colors.dim}Model: ${config.model} | API: ${config.baseUrl}${colors.reset} ${llmccStatus} ${chromeStatus}`);
if (session.messages.length > 0) {
console.log(`${colors.dim}Restored session with ${session.messages.length} messages${colors.reset}`);
}
Expand Down Expand Up @@ -232,6 +233,10 @@ async function handleInput(input, session, config) {
else if (name === 'computer' && parsed.action) {
summary = `: ${parsed.action}`;
}
else if (name === 'llmcc' && parsed.dirs) {
const dirList = Array.isArray(parsed.dirs) ? parsed.dirs.join(', ') : parsed.dirs;
summary = `: ${dirList} (depth=${parsed.depth || 3})`;
}
}
catch {
// Ignore parse errors
Expand Down Expand Up @@ -286,6 +291,10 @@ async function main() {
config.chrome = false;
}
}
// Enable llmcc if --llmcc flag is passed
if (args.includes('--llmcc') || args.includes('-l')) {
config.llmcc = true;
}
printWelcome(session, config);
const rl = readline.createInterface({
input: process.stdin,
Expand Down
7 changes: 6 additions & 1 deletion agent/llcraft/dist/tools.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export interface ToolResult {
role: 'tool';
content: string;
}
/**
* llmcc tool definition - for code architecture analysis
* Exported separately so it can be conditionally included
*/
export declare const llmccTool: ToolDefinition;
export declare const builtinTools: ToolDefinition[];
/**
* Execute a tool call and return the result
Expand All @@ -39,4 +44,4 @@ export declare function executeTool(toolCall: ToolCall): ToolResult;
/**
* Format tools for display
*/
export declare function formatToolList(includeBrowser?: boolean): string;
export declare function formatToolList(includeBrowser?: boolean, includeLlmcc?: boolean): string;
109 changes: 108 additions & 1 deletion agent/llcraft/dist/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,51 @@ import * as fs from 'fs';
import * as path from 'path';
import { execSync } from 'child_process';
import { applyPatch, parsePatch, createPatch } from 'diff';
/**
* llmcc tool definition - for code architecture analysis
* Exported separately so it can be conditionally included
*/
export const llmccTool = {
type: 'function',
function: {
name: 'llmcc',
description: 'Generate multi-depth architecture graphs for code understanding. Analyzes Rust or TypeScript codebases and produces DOT graph output showing dependencies at various granularity levels. Use this to quickly understand the structure and architecture of complex codebases.',
parameters: {
type: 'object',
properties: {
dirs: {
type: 'array',
description: 'Directories to scan recursively (conflicts with files)',
},
files: {
type: 'array',
description: 'Individual files to compile (conflicts with dirs)',
},
lang: {
type: 'string',
description: 'Language: rust, typescript, or ts (default: rust)',
},
depth: {
type: 'number',
description: 'Component depth: 0=project, 1=crate/lib, 2=module, 3=file+symbol (default: 3)',
},
pagerank_top_k: {
type: 'number',
description: 'Show only top K nodes by PageRank score to focus on most important components',
},
cluster_by_crate: {
type: 'boolean',
description: 'Cluster modules by their parent crate (default: false)',
},
short_labels: {
type: 'boolean',
description: 'Use shortened labels - module name only (default: false)',
},
},
required: [],
},
},
};
// Built-in tools
export const builtinTools = [
{
Expand Down Expand Up @@ -226,6 +271,9 @@ export function executeTool(toolCall) {
case 'create_patch':
result = executeCreatePatch(args.path, args.oldContent, args.newContent);
break;
case 'llmcc':
result = executeLlmcc(args.dirs, args.files, args.lang, args.depth, args.pagerank_top_k, args.cluster_by_crate, args.short_labels);
break;
default:
result = `Unknown tool: ${name}`;
}
Expand Down Expand Up @@ -387,15 +435,74 @@ function executeCreatePatch(filePath, oldContent, newContent) {
return `Failed to create patch: ${error.message}`;
}
}
/**
* Execute llmcc to generate architecture graphs
*/
function executeLlmcc(dirs, files, lang, depth, pagerankTopK, clusterByCrate, shortLabels) {
if (!dirs && !files) {
return 'Error: Either dirs or files must be provided';
}
try {
// Build the llmcc command
const cmdParts = ['llmcc'];
// Add directories
if (dirs && Array.isArray(dirs)) {
for (const dir of dirs) {
cmdParts.push('-d', `"${dir}"`);
}
}
// Add files
if (files && Array.isArray(files)) {
for (const file of files) {
cmdParts.push('-f', `"${file}"`);
}
}
// Add language (default to rust)
cmdParts.push('--lang', lang || 'rust');
// Add graph flag (always generate graph output)
cmdParts.push('--graph');
// Add depth (default to 3)
cmdParts.push('--depth', (depth ?? 3).toString());
// Add optional flags
if (pagerankTopK) {
cmdParts.push('--pagerank-top-k', pagerankTopK.toString());
}
if (clusterByCrate) {
cmdParts.push('--cluster-by-crate');
}
if (shortLabels) {
cmdParts.push('--short-labels');
}
const command = cmdParts.join(' ');
const result = execSync(command, {
encoding: 'utf-8',
timeout: 120 * 1000, // 2 minute timeout
maxBuffer: 50 * 1024 * 1024, // 50MB max output for large graphs
});
return result || '(no output)';
}
catch (error) {
if (error.stdout || error.stderr) {
return `Exit code: ${error.status}\nstdout: ${error.stdout}\nstderr: ${error.stderr}`;
}
return `llmcc failed: ${error.message}`;
}
}
/**
* Format tools for display
*/
export function formatToolList(includeBrowser) {
export function formatToolList(includeBrowser, includeLlmcc) {
let tools = builtinTools.map(t => {
const f = t.function;
const params = Object.keys(f.parameters.properties).join(', ');
return ` ${f.name}(${params}) - ${f.description}`;
}).join('\n');
if (includeLlmcc) {
tools += '\n\n Code Architecture tool (--llmcc):\n';
const f = llmccTool.function;
const params = Object.keys(f.parameters.properties).join(', ');
tools += ` ${f.name}(${params}) - ${f.description}`;
}
if (includeBrowser) {
tools += '\n\n Browser tools (--chrome):\n';
// Import browser tools dynamically to avoid circular deps
Expand Down
1 change: 1 addition & 0 deletions agent/llcraft/dist/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface Config {
maxTokens: number;
systemPrompt: string;
chrome?: boolean;
llmcc?: boolean;
}
export interface APIMessage {
role: 'user' | 'assistant';
Expand Down
7 changes: 5 additions & 2 deletions agent/llcraft/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { Message, Config, APIMessage } from './types.js';
import { builtinTools, executeTool, ToolCall, ToolDefinition } from './tools.js';
import { builtinTools, executeTool, ToolCall, ToolDefinition, llmccTool } from './tools.js';
import { browserTools, isBrowserTool, executeBrowserTool } from './browser.js';

interface OpenAIMessage {
Expand Down Expand Up @@ -81,6 +81,9 @@ async function callOpenAIAPIWithTools(
): Promise<string> {
// Collect available tools
const availableTools = [...builtinTools];
if (config.llmcc) {
availableTools.push(llmccTool);
}
if (config.chrome) {
availableTools.push(...browserTools);
}
Expand Down Expand Up @@ -113,7 +116,7 @@ Only use tools when necessary to complete the user's request.`;
})),
];

const maxIterations = 10;
const maxIterations = 50; // Increased for complex tasks
let iterations = 0;

while (iterations < maxIterations) {
Expand Down
11 changes: 10 additions & 1 deletion agent/llcraft/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ ${JSON.stringify(session, null, 2)}

function printWelcome(session: Session, config: Config): void {
console.log(`${colors.cyan}${colors.bold}llcraft${colors.reset} ${colors.dim}v0.1.0${colors.reset}`);
const llmccStatus = config.llmcc ? `${colors.green}✓ llmcc${colors.reset}` : '';
const chromeStatus = config.chrome ? `${colors.green}✓ chrome${colors.reset}` : '';
console.log(`${colors.dim}Model: ${config.model} | API: ${config.baseUrl}${colors.reset} ${chromeStatus}`);
console.log(`${colors.dim}Model: ${config.model} | API: ${config.baseUrl}${colors.reset} ${llmccStatus} ${chromeStatus}`);

if (session.messages.length > 0) {
console.log(`${colors.dim}Restored session with ${session.messages.length} messages${colors.reset}`);
Expand Down Expand Up @@ -254,6 +255,9 @@ async function handleInput(
summary = `: ${parsed.query}`;
} else if (name === 'computer' && parsed.action) {
summary = `: ${parsed.action}`;
} else if (name === 'llmcc' && parsed.dirs) {
const dirList = Array.isArray(parsed.dirs) ? parsed.dirs.join(', ') : parsed.dirs;
summary = `: ${dirList} (depth=${parsed.depth || 3})`;
}
} catch {
// Ignore parse errors
Expand Down Expand Up @@ -318,6 +322,11 @@ async function main(): Promise<void> {
}
}

// Enable llmcc if --llmcc flag is passed
if (args.includes('--llmcc') || args.includes('-l')) {
config.llmcc = true;
}

printWelcome(session, config);

const rl = readline.createInterface({
Expand Down
Loading
Loading