83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
import type { Command } from 'commander';
|
|
import type { ModelClient } from '../models/types.js';
|
|
import { NativeAgent } from '../backends/index.js';
|
|
import { ToolRegistry, ToolExecutor, allBuiltinTools } from '../tools/index.js';
|
|
import { HookEngine } from '../hooks/index.js';
|
|
import { loadConfigSafe, getConfigPath } from './shared.js';
|
|
import { existsSync, readFileSync } from 'fs';
|
|
import { resolve } from 'path';
|
|
|
|
/** Create a lightweight agent for one-shot message processing. */
|
|
export function createSendAgent(deps: {
|
|
modelClient: ModelClient;
|
|
systemPrompt: string;
|
|
enableTools?: boolean;
|
|
}): NativeAgent {
|
|
const config: ConstructorParameters<typeof NativeAgent>[0] = {
|
|
modelClient: deps.modelClient,
|
|
systemPrompt: deps.systemPrompt,
|
|
};
|
|
|
|
if (deps.enableTools !== false) {
|
|
const hookEngine = new HookEngine({ confirm: [], log: [], silent: [] });
|
|
const toolRegistry = new ToolRegistry();
|
|
for (const tool of allBuiltinTools) {
|
|
toolRegistry.register(tool);
|
|
}
|
|
const toolExecutor = new ToolExecutor(toolRegistry, hookEngine);
|
|
config.toolRegistry = toolRegistry;
|
|
config.toolExecutor = toolExecutor;
|
|
}
|
|
|
|
return new NativeAgent(config);
|
|
}
|
|
|
|
function loadSystemPrompt(): string {
|
|
const paths = [
|
|
resolve(process.cwd(), 'SOUL.md'),
|
|
resolve(import.meta.dirname, '../../SOUL.md'),
|
|
];
|
|
for (const p of paths) {
|
|
if (existsSync(p)) return readFileSync(p, 'utf-8');
|
|
}
|
|
return 'You are Flynn, a helpful personal AI assistant.';
|
|
}
|
|
|
|
export function registerSendCommand(program: Command): void {
|
|
program
|
|
.command('send <message>')
|
|
.description('Send a one-shot message and print the response')
|
|
.option('-c, --config <path>', 'Config file path')
|
|
.option('--no-tools', 'Disable tool use')
|
|
.action(async (message: string, opts: { config?: string; tools?: boolean }) => {
|
|
const configPath = opts.config ?? getConfigPath();
|
|
const { config, error } = loadConfigSafe(configPath);
|
|
if (!config) {
|
|
console.error(error);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Dynamic import to avoid loading model code eagerly
|
|
const { AnthropicClient } = await import('../models/index.js');
|
|
const modelClient = new AnthropicClient({
|
|
model: config.models.default.model,
|
|
apiKey: config.models.default.api_key,
|
|
authToken: config.models.default.auth_token,
|
|
});
|
|
|
|
const agent = createSendAgent({
|
|
modelClient,
|
|
systemPrompt: loadSystemPrompt(),
|
|
enableTools: opts.tools,
|
|
});
|
|
|
|
try {
|
|
const response = await agent.process(message);
|
|
console.log(response);
|
|
} catch (err) {
|
|
console.error('Error:', err instanceof Error ? err.message : err);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
}
|