125 lines
4.5 KiB
TypeScript
125 lines
4.5 KiB
TypeScript
import type { Config } from '../config/index.js';
|
|
import type { Lifecycle } from './lifecycle.js';
|
|
import type { AudioTranscriptionConfig } from '../models/media.js';
|
|
import { HookEngine } from '../hooks/index.js';
|
|
import { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager, BrowserManager, createBrowserTools, createAudioTranscribeTool } from '../tools/index.js';
|
|
|
|
export interface ToolsDeps {
|
|
config: Config;
|
|
lifecycle: Lifecycle;
|
|
hookEngine: HookEngine;
|
|
}
|
|
|
|
export interface ToolsResult {
|
|
toolRegistry: ToolRegistry;
|
|
toolExecutor: ToolExecutor;
|
|
browserManager?: BrowserManager;
|
|
}
|
|
|
|
export function initTools(deps: ToolsDeps): ToolsResult {
|
|
const { config, lifecycle, hookEngine } = deps;
|
|
|
|
// Initialize tool registry and register all builtin tools
|
|
const toolRegistry = new ToolRegistry();
|
|
for (const tool of allBuiltinTools) {
|
|
toolRegistry.register(tool);
|
|
}
|
|
|
|
// Register web search tool if configured with credentials
|
|
if (config.web_search.api_key || config.web_search.endpoint) {
|
|
for (const tool of createWebSearchTools({
|
|
provider: config.web_search.provider,
|
|
apiKey: config.web_search.api_key,
|
|
endpoint: config.web_search.endpoint,
|
|
maxResults: config.web_search.max_results,
|
|
})) {
|
|
toolRegistry.register(tool);
|
|
}
|
|
}
|
|
|
|
// Initialize process manager and register process tools
|
|
const processManager = new ProcessManager({
|
|
maxConcurrent: config.process.max_concurrent,
|
|
maxRuntimeMinutes: config.process.max_runtime_minutes,
|
|
bufferSize: config.process.buffer_size,
|
|
});
|
|
|
|
for (const tool of createProcessTools(processManager)) {
|
|
toolRegistry.register(tool);
|
|
}
|
|
|
|
lifecycle.onShutdown(async () => {
|
|
await processManager.shutdown();
|
|
console.log('Process manager stopped');
|
|
});
|
|
|
|
// Register audio transcription tool if configured
|
|
if (config.audio?.enabled && config.audio.provider) {
|
|
const audioConfig: AudioTranscriptionConfig = {
|
|
endpoint: config.audio.provider.endpoint,
|
|
apiKey: config.audio.provider.api_key,
|
|
model: config.audio.provider.model,
|
|
};
|
|
const audioTool = createAudioTranscribeTool(audioConfig);
|
|
toolRegistry.register(audioTool);
|
|
console.log(`Audio transcription enabled (type=${config.audio.provider.type}, endpoint=${audioConfig.endpoint})`);
|
|
}
|
|
|
|
// Initialize browser manager and register browser tools (if enabled)
|
|
const browserToolNames = ['browser.navigate', 'browser.screenshot', 'browser.click', 'browser.type', 'browser.content', 'browser.eval', 'browser.evaluate'];
|
|
let browserManager: BrowserManager | undefined;
|
|
if (config.browser?.enabled) {
|
|
const manager = new BrowserManager({
|
|
executablePath: config.browser.executable_path,
|
|
wsEndpoint: config.browser.ws_endpoint,
|
|
headless: config.browser.headless,
|
|
maxPages: config.browser.max_pages,
|
|
defaultTimeout: config.browser.default_timeout,
|
|
});
|
|
browserManager = manager;
|
|
|
|
for (const tool of createBrowserTools(manager)) {
|
|
toolRegistry.register(tool);
|
|
}
|
|
console.log(`Browser tools enabled (headless=${config.browser.headless})`);
|
|
|
|
lifecycle.onShutdown(async () => {
|
|
await manager.shutdown();
|
|
console.log('Browser manager stopped');
|
|
});
|
|
} else {
|
|
console.log('Browser tools disabled (set browser.enabled=true to register browser.* tools)');
|
|
}
|
|
|
|
const toolExecutor = new ToolExecutor(toolRegistry, hookEngine, {
|
|
sensitiveMode: config.agents.sensitive_mode,
|
|
immutableDenylist: config.agents.immutable_denylist.map((rule) => ({
|
|
tool: rule.tool,
|
|
argsPattern: rule.args_pattern,
|
|
reason: rule.reason,
|
|
})),
|
|
});
|
|
|
|
// Initialize tool policy from config
|
|
const toolPolicy = new ToolPolicy(config.tools);
|
|
toolRegistry.setPolicy(toolPolicy);
|
|
|
|
const effectiveProfile = toolPolicy.getEffectiveProfile();
|
|
if (effectiveProfile !== 'full') {
|
|
console.log(`Tool policy: profile=${effectiveProfile}, deny=[${config.tools.deny.join(', ')}]`);
|
|
}
|
|
|
|
if (config.browser?.enabled) {
|
|
const allNames = toolRegistry.list().map((tool) => tool.name);
|
|
const allowed = toolPolicy.resolveAllowedNames(allNames);
|
|
const availableBrowserTools = browserToolNames.filter((name) => allowed.has(name));
|
|
if (availableBrowserTools.length === 0) {
|
|
console.log('Browser tools are registered but blocked by tool policy (use tools.profile=coding/full or tools.allow).');
|
|
} else {
|
|
console.log(`Browser tools available after policy: ${availableBrowserTools.join(', ')}`);
|
|
}
|
|
}
|
|
|
|
return { toolRegistry, toolExecutor, browserManager };
|
|
}
|