feat(cli): implement send command for one-shot agent messages
This commit is contained in:
+73
-3
@@ -1,12 +1,82 @@
|
||||
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')
|
||||
.action(async (_message: string, _opts: { config?: string }) => {
|
||||
console.error('Not yet implemented');
|
||||
process.exit(1);
|
||||
.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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user