@swarmclawai/swarmclaw 1.5.35 → 1.5.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -1
- package/package.json +18 -1
- package/public/provider-logos/droid-cli.svg +7 -0
- package/src/app/api/setup/check-provider/route.ts +4 -2
- package/src/app/api/setup/doctor/route.ts +1 -0
- package/src/components/agents/agent-sheet.tsx +3 -1
- package/src/components/agents/inspector-panel.tsx +1 -0
- package/src/components/auth/access-key-gate.tsx +0 -24
- package/src/components/chat/activity-moment.tsx +1 -0
- package/src/components/chat/chat-header.tsx +2 -1
- package/src/components/chat/tool-call-bubble.tsx +5 -0
- package/src/components/layout/sidebar-rail.tsx +0 -47
- package/src/lib/orchestrator-config.ts +1 -0
- package/src/lib/provider-sets.ts +3 -3
- package/src/lib/providers/cli-utils.test.ts +2 -0
- package/src/lib/providers/cli-utils.ts +28 -1
- package/src/lib/providers/droid-cli.ts +220 -0
- package/src/lib/providers/index.ts +11 -1
- package/src/lib/server/agents/agent-availability.test.ts +1 -1
- package/src/lib/server/agents/agent-thread-session.ts +1 -0
- package/src/lib/server/agents/task-session.ts +2 -0
- package/src/lib/server/capability-router.ts +3 -1
- package/src/lib/server/chat-execution/chat-execution-utils.ts +11 -0
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +2 -0
- package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +1 -0
- package/src/lib/server/chat-execution/prompt-sections.ts +2 -0
- package/src/lib/server/chatrooms/chatroom-helpers.ts +3 -0
- package/src/lib/server/chats/chat-session-service.ts +4 -0
- package/src/lib/server/connectors/session.ts +2 -0
- package/src/lib/server/context-manager.ts +1 -0
- package/src/lib/server/provider-health.ts +4 -2
- package/src/lib/server/provider-model-discovery.test.ts +1 -1
- package/src/lib/server/provider-model-discovery.ts +1 -1
- package/src/lib/server/runtime/daemon-state/core.ts +2 -2
- package/src/lib/server/session-reset-policy.ts +2 -0
- package/src/lib/server/session-tools/context.ts +2 -2
- package/src/lib/server/session-tools/delegate-droid.test.ts +24 -0
- package/src/lib/server/session-tools/delegate.ts +105 -12
- package/src/lib/server/session-tools/index.ts +3 -2
- package/src/lib/server/session-tools/session-info.ts +1 -0
- package/src/lib/server/storage-normalization.ts +3 -0
- package/src/lib/server/tool-aliases.ts +1 -1
- package/src/lib/server/tool-capability-policy.ts +2 -1
- package/src/lib/setup-defaults.ts +21 -0
- package/src/types/misc.ts +1 -1
- package/src/types/provider.ts +1 -1
- package/src/types/session.ts +3 -0
|
@@ -25,7 +25,7 @@ import { markProviderFailure, markProviderSuccess } from '../provider-health'
|
|
|
25
25
|
import { loadRuntimeSettings } from '../runtime/runtime-settings'
|
|
26
26
|
import { getSessionDepth } from '../agents/subagent-runtime'
|
|
27
27
|
|
|
28
|
-
const DELEGATE_BACKEND_ORDER: DelegateBackend[] = ['claude', 'codex', 'opencode', 'gemini', 'copilot', 'cursor', 'qwen']
|
|
28
|
+
const DELEGATE_BACKEND_ORDER: DelegateBackend[] = ['claude', 'codex', 'opencode', 'gemini', 'copilot', 'droid', 'cursor', 'qwen']
|
|
29
29
|
|
|
30
30
|
interface DelegateContext {
|
|
31
31
|
id?: string
|
|
@@ -34,8 +34,8 @@ interface DelegateContext {
|
|
|
34
34
|
jobId?: string | null
|
|
35
35
|
cwd?: string
|
|
36
36
|
claudeTimeoutMs?: number
|
|
37
|
-
readStoredDelegateResumeId?: (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen') => string | null
|
|
38
|
-
persistDelegateResumeId?: (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen', id: string | null | undefined) => void
|
|
37
|
+
readStoredDelegateResumeId?: (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen') => string | null
|
|
38
|
+
persistDelegateResumeId?: (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen', id: string | null | undefined) => void
|
|
39
39
|
ctx?: {
|
|
40
40
|
delegationEnabled?: boolean
|
|
41
41
|
delegationTargetMode?: 'all' | 'selected'
|
|
@@ -48,7 +48,7 @@ interface DelegateContext {
|
|
|
48
48
|
hasTool?: (name: string) => boolean
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
type DelegateBackend = 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen'
|
|
51
|
+
type DelegateBackend = 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen'
|
|
52
52
|
|
|
53
53
|
interface DelegateRuntimeState {
|
|
54
54
|
child?: ChildProcess | null
|
|
@@ -129,10 +129,11 @@ function buildDelegateResumePatch(bctx: DelegateContext) {
|
|
|
129
129
|
opencode: bctx.readStoredDelegateResumeId?.('opencode') || null,
|
|
130
130
|
gemini: bctx.readStoredDelegateResumeId?.('gemini') || null,
|
|
131
131
|
copilot: bctx.readStoredDelegateResumeId?.('copilot') || null,
|
|
132
|
+
droid: bctx.readStoredDelegateResumeId?.('droid') || null,
|
|
132
133
|
cursor: bctx.readStoredDelegateResumeId?.('cursor') || null,
|
|
133
134
|
qwen: bctx.readStoredDelegateResumeId?.('qwen') || null,
|
|
134
135
|
}
|
|
135
|
-
const resumeId = resumeIds.claudeCode || resumeIds.codex || resumeIds.opencode || resumeIds.gemini || resumeIds.copilot || resumeIds.cursor || resumeIds.qwen || null
|
|
136
|
+
const resumeId = resumeIds.claudeCode || resumeIds.codex || resumeIds.opencode || resumeIds.gemini || resumeIds.copilot || resumeIds.droid || resumeIds.cursor || resumeIds.qwen || null
|
|
136
137
|
return { resumeIds, resumeId }
|
|
137
138
|
}
|
|
138
139
|
|
|
@@ -144,6 +145,7 @@ function coerceDelegateBackend(value: unknown): DelegateBackend | null {
|
|
|
144
145
|
if (['opencode', 'open code', 'open-code', 'open_code'].includes(normalized)) return 'opencode'
|
|
145
146
|
if (['gemini', 'gemini cli', 'gemini-cli', 'gemini_cli'].includes(normalized)) return 'gemini'
|
|
146
147
|
if (['copilot', 'copilot cli', 'copilot-cli', 'copilot_cli', 'github copilot'].includes(normalized)) return 'copilot'
|
|
148
|
+
if (['droid', 'droid cli', 'droid-cli', 'droid_cli', 'factory', 'factory droid', 'factory-droid', 'factory_droid'].includes(normalized)) return 'droid'
|
|
147
149
|
if (['cursor', 'cursor cli', 'cursor-cli', 'cursor_cli', 'cursor-agent'].includes(normalized)) return 'cursor'
|
|
148
150
|
if (['qwen', 'qwen code', 'qwen-code', 'qwen_code', 'qwen-code-cli', 'qwen_code_cli'].includes(normalized)) return 'qwen'
|
|
149
151
|
return null
|
|
@@ -340,21 +342,22 @@ function coerceOptionalBool(value: unknown): boolean | null {
|
|
|
340
342
|
}
|
|
341
343
|
|
|
342
344
|
function resumeStorageKeyForBackend(
|
|
343
|
-
backend: 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen',
|
|
344
|
-
): 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen' {
|
|
345
|
+
backend: 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen',
|
|
346
|
+
): 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen' {
|
|
345
347
|
if (backend === 'claude') return 'claudeCode'
|
|
346
348
|
if (backend === 'codex') return 'codex'
|
|
347
349
|
if (backend === 'opencode') return 'opencode'
|
|
348
350
|
if (backend === 'gemini') return 'gemini'
|
|
349
351
|
if (backend === 'copilot') return 'copilot'
|
|
352
|
+
if (backend === 'droid') return 'droid'
|
|
350
353
|
if (backend === 'cursor') return 'cursor'
|
|
351
354
|
return 'qwen'
|
|
352
355
|
}
|
|
353
356
|
|
|
354
357
|
export function resolveDelegateResumeConfig(
|
|
355
358
|
normalized: Record<string, unknown>,
|
|
356
|
-
backend: 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen',
|
|
357
|
-
bctx: { readStoredDelegateResumeId?: (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen') => string | null },
|
|
359
|
+
backend: 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen',
|
|
360
|
+
bctx: { readStoredDelegateResumeId?: (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen') => string | null },
|
|
358
361
|
): { resume: boolean; resumeId: string } {
|
|
359
362
|
const explicitResumeId = typeof normalized.resumeId === 'string' ? normalized.resumeId.trim() : ''
|
|
360
363
|
if (explicitResumeId) return { resume: true, resumeId: explicitResumeId }
|
|
@@ -429,6 +432,11 @@ const DELEGATE_BACKEND_ADAPTERS: Record<DelegateBackend, DelegateBackendAdapter>
|
|
|
429
432
|
binaryName: 'copilot',
|
|
430
433
|
run: runCopilotDelegate,
|
|
431
434
|
},
|
|
435
|
+
droid: {
|
|
436
|
+
backend: 'droid',
|
|
437
|
+
binaryName: 'droid',
|
|
438
|
+
run: runDroidDelegate,
|
|
439
|
+
},
|
|
432
440
|
cursor: {
|
|
433
441
|
backend: 'cursor',
|
|
434
442
|
binaryName: 'cursor-agent',
|
|
@@ -459,6 +467,7 @@ function providerIdForBackend(backend: DelegateBackend): string {
|
|
|
459
467
|
if (backend === 'opencode') return 'opencode-cli'
|
|
460
468
|
if (backend === 'gemini') return 'gemini-cli'
|
|
461
469
|
if (backend === 'copilot') return 'copilot-cli'
|
|
470
|
+
if (backend === 'droid') return 'droid-cli'
|
|
462
471
|
if (backend === 'cursor') return 'cursor-cli'
|
|
463
472
|
return 'qwen-code-cli'
|
|
464
473
|
}
|
|
@@ -983,6 +992,90 @@ async function runGeminiDelegate(binary: string, task: string, resume: boolean,
|
|
|
983
992
|
}
|
|
984
993
|
}
|
|
985
994
|
|
|
995
|
+
async function runDroidDelegate(binary: string, task: string, resume: boolean, resumeId: string, bctx: DelegateContext, runtime?: DelegateRuntimeState): Promise<DelegateBackendResult> {
|
|
996
|
+
try {
|
|
997
|
+
const env = buildCliEnv()
|
|
998
|
+
const auth = probeCliAuth(binary, 'droid', env, bctx.cwd)
|
|
999
|
+
if (!auth.authenticated) {
|
|
1000
|
+
return buildDelegateFailure('droid', auth.errorMessage || 'Factory Droid CLI is not authenticated.', 'auth')
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const storedResumeId = bctx.readStoredDelegateResumeId?.('droid')
|
|
1004
|
+
const resumeIdToUse = resumeId?.trim() || (resume ? storedResumeId : null)
|
|
1005
|
+
|
|
1006
|
+
return await new Promise<DelegateBackendResult>((resolve) => {
|
|
1007
|
+
const args = ['exec', task, '--output-format', 'stream-json', '--auto', 'low']
|
|
1008
|
+
if (resumeIdToUse) args.push('-s', resumeIdToUse)
|
|
1009
|
+
|
|
1010
|
+
const child = spawn(binary, args, { cwd: bctx.cwd, env, stdio: ['ignore', 'pipe', 'pipe'] })
|
|
1011
|
+
bindDelegateRuntime(runtime, child)
|
|
1012
|
+
let stdoutBuf = ''
|
|
1013
|
+
let stderrBuf = ''
|
|
1014
|
+
let responseText = ''
|
|
1015
|
+
let discoveredId: string | null = null
|
|
1016
|
+
let settled = false
|
|
1017
|
+
|
|
1018
|
+
const finish = (result: DelegateBackendResult) => {
|
|
1019
|
+
if (settled) return
|
|
1020
|
+
settled = true
|
|
1021
|
+
resolve(result)
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
const timeoutHandle = setTimeout(() => {
|
|
1025
|
+
try { child.kill('SIGTERM') } catch { /* ignore */ }
|
|
1026
|
+
}, bctx.claudeTimeoutMs || 300000)
|
|
1027
|
+
|
|
1028
|
+
child.stdout?.on('data', (chunk) => {
|
|
1029
|
+
stdoutBuf += chunk.toString()
|
|
1030
|
+
const lines = stdoutBuf.split('\n')
|
|
1031
|
+
stdoutBuf = lines.pop() || ''
|
|
1032
|
+
for (const line of lines) {
|
|
1033
|
+
const trimmed = line.trim()
|
|
1034
|
+
if (!trimmed) continue
|
|
1035
|
+
try {
|
|
1036
|
+
const ev = JSON.parse(trimmed) as Record<string, unknown>
|
|
1037
|
+
const sid = typeof ev.session_id === 'string'
|
|
1038
|
+
? ev.session_id
|
|
1039
|
+
: typeof ev.sessionId === 'string'
|
|
1040
|
+
? ev.sessionId
|
|
1041
|
+
: null
|
|
1042
|
+
if (sid) discoveredId = sid
|
|
1043
|
+
const text = parseCursorOutputText(ev)
|
|
1044
|
+
if (text) {
|
|
1045
|
+
if (String(ev.type || '').includes('result') || String(ev.type || '').includes('completed')) responseText = text
|
|
1046
|
+
else responseText += text
|
|
1047
|
+
}
|
|
1048
|
+
} catch {
|
|
1049
|
+
responseText += `${line}\n`
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
})
|
|
1053
|
+
|
|
1054
|
+
child.stderr?.on('data', (chunk) => {
|
|
1055
|
+
stderrBuf += chunk.toString()
|
|
1056
|
+
if (stderrBuf.length > 16_000) stderrBuf = stderrBuf.slice(-16_000)
|
|
1057
|
+
})
|
|
1058
|
+
|
|
1059
|
+
child.on('close', (code, signal) => {
|
|
1060
|
+
clearTimeout(timeoutHandle)
|
|
1061
|
+
if (discoveredId) bctx.persistDelegateResumeId?.('droid', discoveredId)
|
|
1062
|
+
const output = responseText.trim()
|
|
1063
|
+
if (output) return finish(buildDelegateSuccess('droid', output))
|
|
1064
|
+
const stderr = stderrBuf.trim()
|
|
1065
|
+
if (stderr) return finish(buildDelegateFailure('droid', stderr))
|
|
1066
|
+
return finish(buildDelegateFailure('droid', `Droid exited with code ${code ?? 'unknown'}${signal ? ` (${signal})` : ''}.`, 'runtime'))
|
|
1067
|
+
})
|
|
1068
|
+
|
|
1069
|
+
child.on('error', (err) => {
|
|
1070
|
+
clearTimeout(timeoutHandle)
|
|
1071
|
+
finish(buildDelegateFailure('droid', err.message, 'spawn'))
|
|
1072
|
+
})
|
|
1073
|
+
})
|
|
1074
|
+
} catch (err: unknown) {
|
|
1075
|
+
return buildDelegateFailure('droid', errorMessage(err), 'runtime')
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
986
1079
|
async function runCopilotDelegate(binary: string, task: string, resume: boolean, resumeId: string, bctx: DelegateContext, runtime?: DelegateRuntimeState): Promise<DelegateBackendResult> {
|
|
987
1080
|
try {
|
|
988
1081
|
const env = buildCliEnv()
|
|
@@ -1304,19 +1397,19 @@ const DelegateExtension: Extension = {
|
|
|
1304
1397
|
name: 'Core Delegate',
|
|
1305
1398
|
description: 'Delegate complex multi-file tasks to specialized CLI backends or other agents.',
|
|
1306
1399
|
hooks: {
|
|
1307
|
-
getCapabilityDescription: () => 'I can hand off coding work to Claude Code, Codex, OpenCode, Gemini CLI, Cursor CLI, or Qwen Code CLI (`delegate`) for file creation, refactoring, debugging, code generation, and multi-file edits. Resume IDs may come back via `[delegate_meta]`.',
|
|
1400
|
+
getCapabilityDescription: () => 'I can hand off coding work to Claude Code, Codex, OpenCode, Gemini CLI, Copilot CLI, Factory Droid CLI, Cursor CLI, or Qwen Code CLI (`delegate`) for file creation, refactoring, debugging, code generation, and multi-file edits. Resume IDs may come back via `[delegate_meta]`.',
|
|
1308
1401
|
getOperatingGuidance: () => ['CRITICAL: `execute_command` (not delegation) for running servers, installs, scripts. Delegation sessions end and kill processes.', 'Delegate for code tasks: writing/creating files, refactors, debugging, generation, test suites, data exports to files.'],
|
|
1309
1402
|
} as ExtensionHooks,
|
|
1310
1403
|
tools: [
|
|
1311
1404
|
{
|
|
1312
1405
|
name: 'delegate',
|
|
1313
|
-
description: 'Delegate to a specialized backend (Claude, Codex, OpenCode, Gemini, Cursor, Qwen) for code tasks: writing files, refactoring, debugging, code generation, and multi-file edits. Supports background jobs with action=status|list|wait|cancel.',
|
|
1406
|
+
description: 'Delegate to a specialized backend (Claude, Codex, OpenCode, Gemini, Copilot, Droid, Cursor, Qwen) for code tasks: writing files, refactoring, debugging, code generation, and multi-file edits. Supports background jobs with action=status|list|wait|cancel.',
|
|
1314
1407
|
parameters: {
|
|
1315
1408
|
type: 'object',
|
|
1316
1409
|
properties: {
|
|
1317
1410
|
action: { type: 'string', enum: ['start', 'status', 'list', 'wait', 'cancel'] },
|
|
1318
1411
|
task: { type: 'string' },
|
|
1319
|
-
backend: { type: 'string', enum: ['claude', 'codex', 'opencode', 'gemini', 'copilot', 'cursor', 'qwen'] },
|
|
1412
|
+
backend: { type: 'string', enum: ['claude', 'codex', 'opencode', 'gemini', 'copilot', 'droid', 'cursor', 'qwen'] },
|
|
1320
1413
|
resume: { type: 'boolean' },
|
|
1321
1414
|
resumeId: { type: 'string', description: 'Optional explicit session/thread ID to resume' },
|
|
1322
1415
|
jobId: { type: 'string' },
|
|
@@ -76,6 +76,7 @@ const DELEGATION_TOOL_NAMES = new Set([
|
|
|
76
76
|
'delegate_to_opencode_cli',
|
|
77
77
|
'delegate_to_gemini_cli',
|
|
78
78
|
'delegate_to_copilot_cli',
|
|
79
|
+
'delegate_to_droid_cli',
|
|
79
80
|
'delegate_to_cursor_cli',
|
|
80
81
|
'delegate_to_qwen_code_cli',
|
|
81
82
|
])
|
|
@@ -122,14 +123,14 @@ export async function buildSessionTools(cwd: string, enabledExtensions: string[]
|
|
|
122
123
|
return loadSession(ctx.sessionId)
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
const readStoredDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen'): string | null => {
|
|
126
|
+
const readStoredDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen'): string | null => {
|
|
126
127
|
const session = resolveCurrentSession()
|
|
127
128
|
if (!session?.delegateResumeIds || typeof session.delegateResumeIds !== 'object') return null
|
|
128
129
|
const raw = session.delegateResumeIds[key]
|
|
129
130
|
return typeof raw === 'string' && raw.trim() ? raw.trim() : null
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
const persistDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen', resumeId: string | null | undefined): void => {
|
|
133
|
+
const persistDelegateResumeId = (key: 'claudeCode' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen', resumeId: string | null | undefined): void => {
|
|
133
134
|
const normalized = typeof resumeId === 'string' ? resumeId.trim() : ''
|
|
134
135
|
if (!normalized || !ctx?.sessionId) return
|
|
135
136
|
patchSession(ctx.sessionId, (target) => {
|
|
@@ -50,6 +50,7 @@ function normalizeRuntimeExtensionId(extensionId: string): string {
|
|
|
50
50
|
if (normalized === 'delegate_to_opencode_cli' || normalized === 'opencode_cli') return 'opencode_cli'
|
|
51
51
|
if (normalized === 'delegate_to_gemini_cli' || normalized === 'gemini_cli') return 'gemini_cli'
|
|
52
52
|
if (normalized === 'delegate_to_copilot_cli' || normalized === 'copilot_cli') return 'copilot_cli'
|
|
53
|
+
if (normalized === 'delegate_to_droid_cli' || normalized === 'droid_cli') return 'droid_cli'
|
|
53
54
|
if (normalized === 'delegate_to_cursor_cli' || normalized === 'cursor_cli') return 'cursor_cli'
|
|
54
55
|
if (normalized === 'delegate_to_qwen_code_cli' || normalized === 'qwen_code_cli') return 'qwen_code_cli'
|
|
55
56
|
if (['session_info', 'sessions_tool', 'whoami_tool', 'search_history_tool'].includes(normalized)) return 'manage_sessions'
|
|
@@ -649,6 +649,7 @@ function normalizeStoredRecordInner(
|
|
|
649
649
|
if (session.geminiSessionId === undefined) session.geminiSessionId = null
|
|
650
650
|
// Default copilotSessionId for new field
|
|
651
651
|
if (session.copilotSessionId === undefined) session.copilotSessionId = null
|
|
652
|
+
if (session.droidSessionId === undefined) session.droidSessionId = null
|
|
652
653
|
if (session.cursorSessionId === undefined) session.cursorSessionId = null
|
|
653
654
|
if (session.qwenSessionId === undefined) session.qwenSessionId = null
|
|
654
655
|
if (session.acpSessionId === undefined) session.acpSessionId = null
|
|
@@ -659,12 +660,14 @@ function normalizeStoredRecordInner(
|
|
|
659
660
|
opencode: null,
|
|
660
661
|
gemini: null,
|
|
661
662
|
copilot: null,
|
|
663
|
+
droid: null,
|
|
662
664
|
cursor: null,
|
|
663
665
|
qwen: null,
|
|
664
666
|
}
|
|
665
667
|
} else {
|
|
666
668
|
const resumeIds = session.delegateResumeIds as Record<string, unknown>
|
|
667
669
|
if (resumeIds.copilot === undefined) resumeIds.copilot = null
|
|
670
|
+
if (resumeIds.droid === undefined) resumeIds.droid = null
|
|
668
671
|
if (resumeIds.cursor === undefined) resumeIds.cursor = null
|
|
669
672
|
if (resumeIds.qwen === undefined) resumeIds.qwen = null
|
|
670
673
|
}
|
|
@@ -5,7 +5,7 @@ const EXTENSION_ALIAS_GROUPS: string[][] = [
|
|
|
5
5
|
['edit_file'],
|
|
6
6
|
['web', 'web_search', 'web_fetch', 'http_request', 'http'],
|
|
7
7
|
['browser', 'openclaw_browser'],
|
|
8
|
-
['delegate', 'claude_code', 'codex_cli', 'opencode_cli', 'gemini_cli', 'copilot_cli', 'cursor_cli', 'qwen_code_cli', 'delegate_to_claude_code', 'delegate_to_codex_cli', 'delegate_to_opencode_cli', 'delegate_to_gemini_cli', 'delegate_to_copilot_cli', 'delegate_to_cursor_cli', 'delegate_to_qwen_code_cli'],
|
|
8
|
+
['delegate', 'claude_code', 'codex_cli', 'opencode_cli', 'gemini_cli', 'copilot_cli', 'droid_cli', 'cursor_cli', 'qwen_code_cli', 'delegate_to_claude_code', 'delegate_to_codex_cli', 'delegate_to_opencode_cli', 'delegate_to_gemini_cli', 'delegate_to_copilot_cli', 'delegate_to_droid_cli', 'delegate_to_cursor_cli', 'delegate_to_qwen_code_cli'],
|
|
9
9
|
['manage_platform'],
|
|
10
10
|
['manage_agents'],
|
|
11
11
|
['manage_projects'],
|
|
@@ -53,12 +53,13 @@ const TOOL_DESCRIPTORS: Record<string, ToolDescriptor> = {
|
|
|
53
53
|
web_search: { categories: ['network'], concreteTools: ['web_search'] },
|
|
54
54
|
web_fetch: { categories: ['network'], concreteTools: ['web_fetch'] },
|
|
55
55
|
browser: { categories: ['browser', 'network'], concreteTools: ['browser', 'openclaw_browser'] },
|
|
56
|
-
delegate: { categories: ['delegation', 'execution'], concreteTools: ['delegate', 'delegate_to_claude_code', 'delegate_to_codex_cli', 'delegate_to_opencode_cli', 'delegate_to_gemini_cli', 'delegate_to_copilot_cli', 'delegate_to_cursor_cli', 'delegate_to_qwen_code_cli'] },
|
|
56
|
+
delegate: { categories: ['delegation', 'execution'], concreteTools: ['delegate', 'delegate_to_claude_code', 'delegate_to_codex_cli', 'delegate_to_opencode_cli', 'delegate_to_gemini_cli', 'delegate_to_copilot_cli', 'delegate_to_droid_cli', 'delegate_to_cursor_cli', 'delegate_to_qwen_code_cli'] },
|
|
57
57
|
claude_code: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_claude_code'] },
|
|
58
58
|
codex_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_codex_cli'] },
|
|
59
59
|
opencode_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_opencode_cli'] },
|
|
60
60
|
gemini_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_gemini_cli'] },
|
|
61
61
|
copilot_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_copilot_cli'] },
|
|
62
|
+
droid_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_droid_cli'] },
|
|
62
63
|
cursor_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_cursor_cli'] },
|
|
63
64
|
qwen_code_cli: { categories: ['delegation', 'execution'], concreteTools: ['delegate_to_qwen_code_cli'] },
|
|
64
65
|
memory: { categories: ['memory'], concreteTools: ['memory', 'memory_tool', 'memory_search', 'memory_get', 'memory_store', 'memory_update', 'context_status', 'context_summarize'] },
|
|
@@ -9,6 +9,7 @@ export type SetupProvider =
|
|
|
9
9
|
| 'opencode-cli'
|
|
10
10
|
| 'gemini-cli'
|
|
11
11
|
| 'copilot-cli'
|
|
12
|
+
| 'droid-cli'
|
|
12
13
|
| 'cursor-cli'
|
|
13
14
|
| 'qwen-code-cli'
|
|
14
15
|
| 'goose'
|
|
@@ -97,6 +98,19 @@ export const SETUP_PROVIDERS: SetupProviderOption[] = [
|
|
|
97
98
|
badge: 'CLI',
|
|
98
99
|
icon: 'P',
|
|
99
100
|
},
|
|
101
|
+
{
|
|
102
|
+
id: 'droid-cli',
|
|
103
|
+
name: 'Factory Droid CLI',
|
|
104
|
+
description: 'Factory.ai’s terminal coding agent with headless exec mode, session resume, and autonomy controls.',
|
|
105
|
+
requiresKey: false,
|
|
106
|
+
supportsEndpoint: false,
|
|
107
|
+
optionalKey: true,
|
|
108
|
+
keyUrl: 'https://app.factory.ai/settings/api-keys',
|
|
109
|
+
keyLabel: 'app.factory.ai',
|
|
110
|
+
keyPlaceholder: 'FACTORY_API_KEY (optional if signed in via `droid`)',
|
|
111
|
+
badge: 'CLI',
|
|
112
|
+
icon: 'F',
|
|
113
|
+
},
|
|
100
114
|
{
|
|
101
115
|
id: 'cursor-cli',
|
|
102
116
|
name: 'Cursor Agent CLI',
|
|
@@ -743,6 +757,13 @@ export const DEFAULT_AGENTS: Record<SetupProvider, DefaultAgentConfig> = {
|
|
|
743
757
|
model: 'claude-sonnet-4-5',
|
|
744
758
|
tools: STARTER_AGENT_TOOLS,
|
|
745
759
|
},
|
|
760
|
+
'droid-cli': {
|
|
761
|
+
name: 'Factory Droid',
|
|
762
|
+
description: 'A helpful assistant powered by Factory Droid CLI.',
|
|
763
|
+
systemPrompt: SWARMCLAW_ASSISTANT_PROMPT,
|
|
764
|
+
model: 'default',
|
|
765
|
+
tools: STARTER_AGENT_TOOLS,
|
|
766
|
+
},
|
|
746
767
|
'cursor-cli': {
|
|
747
768
|
name: 'Cursor CLI',
|
|
748
769
|
description: 'A helpful assistant powered by Cursor Agent CLI.',
|
package/src/types/misc.ts
CHANGED
|
@@ -387,7 +387,7 @@ export interface DelegationJobRecord {
|
|
|
387
387
|
id: string
|
|
388
388
|
kind: DelegationJobKind
|
|
389
389
|
status: DelegationJobStatus
|
|
390
|
-
backend?: 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'cursor' | 'qwen' | null
|
|
390
|
+
backend?: 'claude' | 'codex' | 'opencode' | 'gemini' | 'copilot' | 'droid' | 'cursor' | 'qwen' | null
|
|
391
391
|
parentSessionId?: string | null
|
|
392
392
|
childSessionId?: string | null
|
|
393
393
|
agentId?: string | null
|
package/src/types/provider.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ProviderType = 'claude-cli' | 'codex-cli' | 'opencode-cli' | 'gemini-cli' | 'copilot-cli' | 'cursor-cli' | 'qwen-code-cli' | 'goose' | 'openai' | 'openrouter' | 'ollama' | 'anthropic' | 'openclaw' | 'hermes' | 'google' | 'deepseek' | 'groq' | 'together' | 'mistral' | 'xai' | 'fireworks' | 'nebius' | 'deepinfra'
|
|
1
|
+
export type ProviderType = 'claude-cli' | 'codex-cli' | 'opencode-cli' | 'gemini-cli' | 'copilot-cli' | 'droid-cli' | 'cursor-cli' | 'qwen-code-cli' | 'goose' | 'openai' | 'openrouter' | 'ollama' | 'anthropic' | 'openclaw' | 'hermes' | 'google' | 'deepseek' | 'groq' | 'together' | 'mistral' | 'xai' | 'fireworks' | 'nebius' | 'deepinfra'
|
|
2
2
|
export type ProviderId = ProviderType | (string & {})
|
|
3
3
|
|
|
4
4
|
export interface ProviderInfo {
|
package/src/types/session.ts
CHANGED
|
@@ -71,6 +71,7 @@ export interface Session {
|
|
|
71
71
|
opencodeSessionId?: string | null
|
|
72
72
|
geminiSessionId?: string | null
|
|
73
73
|
copilotSessionId?: string | null
|
|
74
|
+
droidSessionId?: string | null
|
|
74
75
|
cursorSessionId?: string | null
|
|
75
76
|
qwenSessionId?: string | null
|
|
76
77
|
acpSessionId?: string | null
|
|
@@ -80,6 +81,7 @@ export interface Session {
|
|
|
80
81
|
opencode?: string | null
|
|
81
82
|
gemini?: string | null
|
|
82
83
|
copilot?: string | null
|
|
84
|
+
droid?: string | null
|
|
83
85
|
cursor?: string | null
|
|
84
86
|
qwen?: string | null
|
|
85
87
|
}
|
|
@@ -206,6 +208,7 @@ export type SessionTool =
|
|
|
206
208
|
| 'opencode_cli'
|
|
207
209
|
| 'gemini_cli'
|
|
208
210
|
| 'copilot_cli'
|
|
211
|
+
| 'droid_cli'
|
|
209
212
|
| 'cursor_cli'
|
|
210
213
|
| 'qwen_code_cli'
|
|
211
214
|
| 'web_search'
|