Add support for Factory.ai droid agent.

See: https://factory.ai/product/cli
This commit is contained in:
VVX7
2026-01-22 14:04:40 -05:00
committed by Pedram Amini
parent e9af499004
commit aa91a113cd
6 changed files with 113 additions and 2 deletions

View File

@@ -612,7 +612,7 @@ describe('buildContextTransferPrompt', () => {
});
it('should work for all agent type combinations', () => {
const agents: ToolType[] = ['claude-code', 'opencode', 'codex', 'factory-droid', 'claude', 'terminal'];
const agents: ToolType[] = ['claude-code', 'aider', 'opencode', 'codex', 'factory-droid', 'claude', 'terminal'];
for (const source of agents) {
for (const target of agents) {

View File

@@ -213,6 +213,93 @@ export const AGENT_DEFINITIONS: Omit<AgentConfig, 'available' | 'path' | 'capabi
// Default env vars - don't set NO_COLOR as it conflicts with FORCE_COLOR
defaultEnvVars: {},
// UI config options
// Model IDs from droid CLI (exact IDs required)
// NOTE: autonomyLevel is NOT configurable - Maestro always uses --skip-permissions-unsafe
// which conflicts with --auto. This matches Claude Code's behavior.
configOptions: [
{
key: 'model',
type: 'select',
label: 'Model',
description: 'Model to use for Factory Droid',
// Model IDs from `droid exec --help` (2026-01-22)
options: [
'', // Empty = use droid's default (claude-opus-4-5-20251101)
// OpenAI models
'gpt-5.1',
'gpt-5.1-codex',
'gpt-5.1-codex-max',
'gpt-5.2',
// Claude models
'claude-sonnet-4-5-20250929',
'claude-opus-4-5-20251101',
'claude-haiku-4-5-20251001',
// Google models
'gemini-3-pro-preview',
],
default: '', // Empty = use droid's default (claude-opus-4-5-20251101)
argBuilder: (value: string) => (value && value.trim() ? ['-m', value.trim()] : []),
},
{
key: 'reasoningEffort',
type: 'select',
label: 'Reasoning Effort',
description: 'How much the model should reason before responding',
options: ['', 'low', 'medium', 'high'],
default: '', // Empty = use droid's default reasoning
argBuilder: (value: string) => (value && value.trim() ? ['-r', value.trim()] : []),
},
{
key: 'contextWindow',
type: 'number',
label: 'Context Window Size',
description: 'Maximum context window in tokens (for UI display)',
default: 200000,
},
],
},
{
id: 'factory-droid',
name: 'Factory Droid',
binaryName: 'droid',
command: 'droid',
args: [], // Base args for interactive mode (none)
requiresPty: false, // Batch mode uses child process
// Batch mode: droid exec [options] "prompt"
batchModePrefix: ['exec'],
// Always skip permissions in batch mode (like Claude Code's --dangerously-skip-permissions)
// Maestro requires full access to work properly
batchModeArgs: ['--skip-permissions-unsafe'],
// JSON output for parsing
jsonOutputArgs: ['-o', 'stream-json'],
// Session resume: -s <id> (requires a prompt)
resumeArgs: (sessionId: string) => ['-s', sessionId],
// Read-only mode is DEFAULT in droid exec (no flag needed)
readOnlyArgs: [],
// YOLO mode (same as batchModeArgs, kept for explicit yoloMode requests)
yoloModeArgs: ['--skip-permissions-unsafe'],
// Model selection is handled by configOptions.model.argBuilder below
// Don't define modelArgs here to avoid duplicate -m flags
// Working directory
workingDirArgs: (dir: string) => ['--cwd', dir],
// File/image input
imageArgs: (imagePath: string) => ['-f', imagePath],
// Prompt is positional argument (no separator needed)
noPromptSeparator: true,
// Default env vars - don't set NO_COLOR as it conflicts with FORCE_COLOR
defaultEnvVars: {},
// UI config options
// Model IDs from droid CLI (exact IDs required)
// NOTE: autonomyLevel is NOT configurable - Maestro always uses --skip-permissions-unsafe
@@ -627,6 +714,16 @@ export class AgentDetector {
path.join(appData, 'npm', 'droid.cmd'),
path.join(localAppData, 'npm', 'droid.cmd'),
],
droid: [
// Factory Droid installation paths
path.join(home, '.factory', 'bin', 'droid.exe'),
path.join(localAppData, 'Factory', 'droid.exe'),
path.join(appData, 'Factory', 'droid.exe'),
path.join(home, '.local', 'bin', 'droid.exe'),
// npm global installation
path.join(appData, 'npm', 'droid.cmd'),
path.join(localAppData, 'npm', 'droid.cmd'),
],
};
const pathsToCheck = knownPaths[binaryName] || [];
@@ -715,6 +812,15 @@ export class AgentDetector {
// Add paths from Node version managers (in case installed via npm)
...versionManagerPaths.map((p) => path.join(p, 'droid')),
],
droid: [
// Factory Droid installation paths
path.join(home, '.factory', 'bin', 'droid'),
path.join(home, '.local', 'bin', 'droid'),
'/opt/homebrew/bin/droid',
'/usr/local/bin/droid',
// Add paths from Node version managers (in case installed via npm)
...versionManagerPaths.map((p) => path.join(p, 'droid')),
],
};
const pathsToCheck = knownPaths[binaryName] || [];

View File

@@ -41,6 +41,7 @@ const VALID_TOOL_TYPES: ToolType[] = [
'codex',
'terminal',
'claude',
'aider',
'factory-droid',
];

View File

@@ -45,6 +45,9 @@ export const AGENT_ICONS: Record<string, string> = {
// Enterprise
'factory-droid': '🏭',
// Enterprise
'factory-droid': '🏭',
// Terminal/shell (internal)
terminal: '💻',
};

View File

@@ -17,6 +17,7 @@ export const DEFAULT_CONTEXT_WINDOWS: Record<ToolType, number> = {
claude: 200000, // Legacy Claude
codex: 200000, // OpenAI o3/o4-mini context window
opencode: 128000, // OpenCode (depends on model, 128k is conservative default)
aider: 128000, // Aider (varies by model, 128k is conservative default)
'factory-droid': 200000, // Factory Droid (varies by model, defaults to Claude Opus)
terminal: 0, // Terminal has no context window
};

View File

@@ -1,7 +1,7 @@
// Shared type definitions for Maestro CLI and Electron app
// These types are used by both the CLI tool and the renderer process
export type ToolType = 'claude' | 'claude-code' | 'opencode' | 'codex' | 'terminal' | 'factory-droid';
export type ToolType = 'claude' | 'claude-code' | 'aider' | 'opencode' | 'codex' | 'terminal' | 'factory-droid';
/**
* ThinkingMode controls how AI reasoning/thinking content is displayed.