Wire agent.delegate into TUI tool registry
This commit is contained in:
@@ -3754,6 +3754,19 @@
|
||||
"docs/plans/state.json"
|
||||
],
|
||||
"test_status": "pnpm test:run src/frontends/tui/minimal.test.ts src/models/gemini.test.ts + pnpm typecheck passing"
|
||||
},
|
||||
"tui-agent-delegate-registration": {
|
||||
"status": "completed",
|
||||
"date": "2026-02-17",
|
||||
"updated": "2026-02-17",
|
||||
"summary": "Wired minimal/fullscreen TUI tool registry to register `agents.list` and `agent.delegate` when `agent_configs` exist. Added a TUI delegation bridge that executes delegated single-turn tasks through `ModelRouter` while preserving per-agent tier/system prompt behavior and keeping existing TUI `NativeAgent` flow unchanged.",
|
||||
"files_modified": [
|
||||
"src/cli/tui.ts",
|
||||
"src/tools/builtin/agent-delegate.ts",
|
||||
"src/tools/builtin/agent-delegate.test.ts",
|
||||
"docs/plans/state.json"
|
||||
],
|
||||
"test_status": "pnpm test:run src/tools/builtin/agent-delegate.test.ts + pnpm typecheck passing"
|
||||
}
|
||||
},
|
||||
"overall_progress": {
|
||||
|
||||
+40
-1
@@ -102,9 +102,25 @@ export function registerTuiCommand(program: Command): void {
|
||||
setLogLevel(tuiLogLevel);
|
||||
const { MinimalTui, startFullscreenTui } = await import('../frontends/tui/index.js');
|
||||
const { NativeAgent } = await import('../backends/index.js');
|
||||
const { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager, createGmailTools, createGcalTools, createGdocsTools, createGdriveTools, createGtasksTools } = await import('../tools/index.js');
|
||||
const {
|
||||
ToolRegistry,
|
||||
ToolExecutor,
|
||||
ToolPolicy,
|
||||
allBuiltinTools,
|
||||
createWebSearchTools,
|
||||
createProcessTools,
|
||||
ProcessManager,
|
||||
createGmailTools,
|
||||
createGcalTools,
|
||||
createGdocsTools,
|
||||
createGdriveTools,
|
||||
createGtasksTools,
|
||||
createAgentsListTool,
|
||||
createAgentDelegateTool,
|
||||
} = await import('../tools/index.js');
|
||||
const { HookEngine } = await import('../hooks/index.js');
|
||||
const { createModelRouter } = await import('../daemon/index.js');
|
||||
const { AgentConfigRegistry } = await import('../agents/index.js');
|
||||
|
||||
const dataDir = process.env.FLYNN_DATA_DIR ?? resolve(homedir(), '.local/share/flynn');
|
||||
mkdirSync(dataDir, { recursive: true });
|
||||
@@ -194,6 +210,29 @@ export function registerTuiCommand(program: Command): void {
|
||||
}
|
||||
}
|
||||
|
||||
const agentConfigRegistry = new AgentConfigRegistry();
|
||||
agentConfigRegistry.loadFromConfig(config.agent_configs);
|
||||
if (agentConfigRegistry.list().length > 0) {
|
||||
toolRegistry.register(createAgentsListTool(agentConfigRegistry));
|
||||
toolRegistry.register(createAgentDelegateTool({
|
||||
registry: agentConfigRegistry,
|
||||
orchestrator: {
|
||||
async delegate(request) {
|
||||
const response = await modelRouter.chat({
|
||||
messages: [{ role: 'user', content: request.message }],
|
||||
system: request.systemPrompt,
|
||||
maxTokens: request.maxTokens,
|
||||
}, request.tier);
|
||||
return {
|
||||
content: response.content,
|
||||
usage: response.usage,
|
||||
tier: request.tier,
|
||||
};
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
toolRegistry.setPolicy(new ToolPolicy(config.tools));
|
||||
|
||||
const toolExecutor = new ToolExecutor(toolRegistry, hookEngine);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { createAgentDelegateTool } from './agent-delegate.js';
|
||||
import type { AgentDelegateDeps } from './agent-delegate.js';
|
||||
import type { AgentConfigRegistry } from '../../agents/registry.js';
|
||||
import type { AgentOrchestrator } from '../../backends/native/orchestrator.js';
|
||||
|
||||
function createMockRegistry(configs: Record<string, { systemPrompt?: string; modelTier?: string }>): AgentConfigRegistry {
|
||||
const entries = Object.entries(configs).map(([name, cfg]) => ({
|
||||
@@ -17,19 +16,21 @@ function createMockRegistry(configs: Record<string, { systemPrompt?: string; mod
|
||||
} as unknown as AgentConfigRegistry;
|
||||
}
|
||||
|
||||
function createMockOrchestrator(response?: { content: string; usage: { inputTokens: number; outputTokens: number }; tier: string }): AgentOrchestrator {
|
||||
function createMockOrchestrator(
|
||||
response?: { content: string; usage: { inputTokens: number; outputTokens: number }; tier: 'fast' | 'default' | 'complex' | 'local' },
|
||||
): AgentDelegateDeps['orchestrator'] {
|
||||
return {
|
||||
delegate: vi.fn().mockResolvedValue(response ?? {
|
||||
content: 'Mock agent response',
|
||||
usage: { inputTokens: 100, outputTokens: 50 },
|
||||
tier: 'default',
|
||||
}),
|
||||
} as unknown as AgentOrchestrator;
|
||||
};
|
||||
}
|
||||
|
||||
describe('agent.delegate tool', () => {
|
||||
let deps: AgentDelegateDeps;
|
||||
let mockOrchestrator: AgentOrchestrator;
|
||||
let mockOrchestrator: AgentDelegateDeps['orchestrator'];
|
||||
|
||||
beforeEach(() => {
|
||||
mockOrchestrator = createMockOrchestrator();
|
||||
@@ -127,7 +128,7 @@ describe('agent.delegate tool', () => {
|
||||
it('handles orchestrator errors gracefully', async () => {
|
||||
const failingOrchestrator = {
|
||||
delegate: vi.fn().mockRejectedValue(new Error('Model provider unavailable')),
|
||||
} as unknown as AgentOrchestrator;
|
||||
} as AgentDelegateDeps['orchestrator'];
|
||||
|
||||
const tool = createAgentDelegateTool({ ...deps, orchestrator: failingOrchestrator });
|
||||
const result = await tool.execute({ agent: 'research', task: 'This will fail' });
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
import type { Tool, ToolResult } from '../types.js';
|
||||
import type { AgentConfigRegistry } from '../../agents/registry.js';
|
||||
import type { AgentOrchestrator } from '../../backends/native/orchestrator.js';
|
||||
import type { ModelTier } from '../../models/router.js';
|
||||
import type { TokenUsage } from '../../models/types.js';
|
||||
|
||||
interface AgentDelegateRunner {
|
||||
delegate(request: {
|
||||
tier: ModelTier;
|
||||
systemPrompt: string;
|
||||
message: string;
|
||||
maxTokens?: number;
|
||||
}): Promise<{
|
||||
content: string;
|
||||
usage: TokenUsage;
|
||||
tier: ModelTier;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface AgentDelegateDeps {
|
||||
registry: AgentConfigRegistry;
|
||||
orchestrator: AgentOrchestrator;
|
||||
orchestrator: AgentDelegateRunner;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user