mirror of
https://github.com/Ryder-Sun/Meldwork.git
synced 2026-11-07 06:56:03 -10:00
280 lines
8.4 KiB
JavaScript
280 lines
8.4 KiB
JavaScript
const path = require('node:path')
|
|
|
|
const CODEX_SANDBOXES = new Set(['read-only', 'workspace-write'])
|
|
const IMAGE_ATTACHMENT_LIMITS = Object.freeze({
|
|
codex: 4,
|
|
hermes: 1,
|
|
opencode: 4,
|
|
})
|
|
|
|
function codexSandbox(requested) {
|
|
if (requested != null) {
|
|
if (!CODEX_SANDBOXES.has(requested)) throw new Error('CODEX_SANDBOX_UNSUPPORTED')
|
|
return requested
|
|
}
|
|
const configured = process.env.MELDWORK_CODEX_SANDBOX || 'read-only'
|
|
return CODEX_SANDBOXES.has(configured) ? configured : 'read-only'
|
|
}
|
|
|
|
function imageAttachmentLimit(kind) {
|
|
return IMAGE_ATTACHMENT_LIMITS[kind] || 0
|
|
}
|
|
|
|
function attachmentPaths(kind, value) {
|
|
if (value == null) return []
|
|
if (!Array.isArray(value)) throw new Error('LOCAL_ATTACHMENT_REFERENCE_INVALID')
|
|
const limit = imageAttachmentLimit(kind)
|
|
if (value.length && !limit) throw new Error('LOCAL_AGENT_IMAGE_UNSUPPORTED')
|
|
if (value.length > limit) throw new Error('LOCAL_AGENT_IMAGE_LIMIT')
|
|
const normalized = value.map((filename) => {
|
|
if (typeof filename !== 'string' || !filename || filename.length > 4096
|
|
|| !path.isAbsolute(filename) || /[\u0000-\u001f\u007f]/.test(filename)) {
|
|
throw new Error('LOCAL_ATTACHMENT_REFERENCE_INVALID')
|
|
}
|
|
return path.normalize(filename)
|
|
})
|
|
if (new Set(normalized).size !== normalized.length) {
|
|
throw new Error('LOCAL_ATTACHMENT_REFERENCE_INVALID')
|
|
}
|
|
return normalized
|
|
}
|
|
|
|
function invocation(kind, executable, workdir, sessionRef = '', options = {}) {
|
|
const attachments = attachmentPaths(kind, options.attachments)
|
|
if (kind === 'codex') {
|
|
const sandbox = codexSandbox(options.sandbox)
|
|
const imageArgs = attachments.flatMap(filename => ['--image', filename])
|
|
if (sessionRef) {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'exec', 'resume', '--json', '--skip-git-repo-check',
|
|
'-c', `sandbox_mode="${sandbox}"`, ...imageArgs, sessionRef, '-',
|
|
],
|
|
stdin: true,
|
|
}
|
|
}
|
|
return {
|
|
command: executable,
|
|
args: ['exec', '--json', '--skip-git-repo-check', '--sandbox',
|
|
sandbox, '-C', workdir, ...imageArgs, '-'],
|
|
stdin: true,
|
|
}
|
|
}
|
|
if (kind === 'hermes') {
|
|
const legacySessionRef = options.sessionTransport === 'acp' ? '' : sessionRef
|
|
const useAcp = options.invocationTransport !== 'legacy'
|
|
&& !attachments.length
|
|
&& options.hermesAcpAvailable !== false
|
|
&& (!sessionRef || options.sessionTransport === 'acp')
|
|
if (useAcp) {
|
|
return {
|
|
command: executable,
|
|
args: ['acp'],
|
|
acpMode: options.sandbox === 'workspace-write' ? 'accept_edits' : 'default',
|
|
eventTransport: 'acp',
|
|
fallbackTransport: 'legacy',
|
|
fallbackSessionPolicy: 'invalidate',
|
|
}
|
|
}
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'chat',
|
|
'--quiet',
|
|
...(options.sandbox === 'workspace-write' ? ['--yolo'] : []),
|
|
...(options.provider?.id ? ['--provider', options.provider.id] : []),
|
|
...(options.provider?.model ? ['--model', options.provider.model] : []),
|
|
...(legacySessionRef ? ['--resume', legacySessionRef] : []),
|
|
...(attachments[0] ? ['--image', attachments[0]] : []),
|
|
'--query',
|
|
],
|
|
promptArg: true,
|
|
eventTransport: 'legacy',
|
|
}
|
|
}
|
|
if (kind === 'openclaw') {
|
|
if (options.invocationTransport !== 'legacy') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--no-color', '--log-level', 'info',
|
|
'acp',
|
|
...(sessionRef ? ['--session', sessionRef] : []),
|
|
'--no-prefix-cwd',
|
|
'--verbose',
|
|
],
|
|
eventTransport: 'acp',
|
|
acpSessionStrategy: 'new',
|
|
publicSessionRef: sessionRef,
|
|
openClawGateway: true,
|
|
fallbackTransport: 'legacy',
|
|
fallbackSessionPolicy: 'preserve',
|
|
}
|
|
}
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'agent', '--local', '--agent', 'main',
|
|
...(sessionRef ? ['--session-key', sessionRef] : []),
|
|
'--message',
|
|
],
|
|
suffixArgs: ['--json'],
|
|
promptArg: true,
|
|
eventTransport: 'legacy',
|
|
}
|
|
}
|
|
if (kind === 'workbuddy') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--print',
|
|
'--output-format', 'stream-json',
|
|
'--include-partial-messages',
|
|
'--permission-mode', options.sandbox === 'workspace-write' ? 'acceptEdits' : 'plan',
|
|
'--max-turns', '20',
|
|
...(sessionRef ? ['--resume', sessionRef] : []),
|
|
],
|
|
promptArg: true,
|
|
eventTransport: 'stream-json',
|
|
}
|
|
}
|
|
if (kind === 'pi') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--mode', 'json',
|
|
...(options.sandbox === 'workspace-write'
|
|
? []
|
|
: ['--tools', 'read,grep,find,ls']),
|
|
...(options.provider?.id ? ['--provider', options.provider.id] : []),
|
|
...(options.provider?.model ? ['--model', options.provider.model] : []),
|
|
...(sessionRef ? ['--session-id', sessionRef] : []),
|
|
'-p',
|
|
],
|
|
promptArg: true,
|
|
eventTransport: 'pi-json-events',
|
|
}
|
|
}
|
|
if (kind === 'kimi') {
|
|
if (options.sandbox !== 'workspace-write') {
|
|
return {
|
|
command: executable,
|
|
args: ['acp'],
|
|
acpMode: 'plan',
|
|
eventTransport: 'acp',
|
|
}
|
|
}
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--output-format', 'stream-json',
|
|
'--auto',
|
|
...(sessionRef ? ['--session', sessionRef] : []),
|
|
'--prompt',
|
|
],
|
|
promptArg: true,
|
|
eventTransport: 'stream-json',
|
|
}
|
|
}
|
|
if (kind === 'mimo') {
|
|
if (options.invocationTransport !== 'json') {
|
|
return {
|
|
command: executable,
|
|
args: ['acp', '--pure', '--cwd', workdir],
|
|
acpMode: options.sandbox === 'workspace-write' ? 'build' : 'plan',
|
|
eventTransport: 'acp',
|
|
fallbackTransport: 'json',
|
|
fallbackSessionPolicy: 'preserve',
|
|
}
|
|
}
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'run', '--pure', '--agent', options.sandbox === 'workspace-write' ? 'build' : 'plan',
|
|
'--format', 'json', '--dir', workdir,
|
|
...(sessionRef ? ['--session', sessionRef] : []),
|
|
],
|
|
promptArg: true,
|
|
}
|
|
}
|
|
if (kind === 'claude') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--print',
|
|
'--output-format', 'stream-json',
|
|
'--include-partial-messages',
|
|
'--verbose',
|
|
'--permission-mode', options.sandbox === 'workspace-write' ? 'acceptEdits' : 'plan',
|
|
...(sessionRef ? ['--resume', sessionRef] : []),
|
|
],
|
|
promptArg: true,
|
|
}
|
|
}
|
|
if (kind === 'qwen') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--output-format', 'stream-json',
|
|
'--include-partial-messages',
|
|
'--approval-mode', options.sandbox === 'workspace-write' ? 'auto-edit' : 'plan',
|
|
...(options.provider?.id === 'openai' ? ['--auth-type', 'openai'] : []),
|
|
...(options.provider?.model ? ['--model', options.provider.model] : []),
|
|
...(sessionRef ? ['--resume', sessionRef] : []),
|
|
],
|
|
promptArg: true,
|
|
}
|
|
}
|
|
if (kind === 'gemini') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'--output-format', 'stream-json',
|
|
'--approval-mode', options.sandbox === 'workspace-write' ? 'auto_edit' : 'plan',
|
|
...(sessionRef ? ['--resume', sessionRef] : []),
|
|
'--prompt',
|
|
],
|
|
promptArg: true,
|
|
}
|
|
}
|
|
if (kind === 'opencode') {
|
|
if (!attachments.length && options.invocationTransport !== 'json') {
|
|
return {
|
|
command: executable,
|
|
args: ['acp', '--pure', '--cwd', workdir],
|
|
acpMode: options.sandbox === 'workspace-write' ? 'build' : 'plan',
|
|
eventTransport: 'acp',
|
|
fallbackTransport: 'json',
|
|
fallbackSessionPolicy: 'preserve',
|
|
}
|
|
}
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'run', '--format', 'json',
|
|
'--agent', options.sandbox === 'workspace-write' ? 'build' : 'plan',
|
|
...(sessionRef ? ['--session', sessionRef] : []),
|
|
...attachments.flatMap(filename => ['--file', filename]),
|
|
],
|
|
promptArg: true,
|
|
}
|
|
}
|
|
if (kind === 'opencodereview') {
|
|
return {
|
|
command: executable,
|
|
args: [
|
|
'review', '--audience', 'agent', '--format', 'json', '--repo', workdir,
|
|
'--background',
|
|
],
|
|
promptArg: true,
|
|
}
|
|
}
|
|
throw new Error('LOCAL_AGENT_KIND_UNSUPPORTED')
|
|
}
|
|
|
|
module.exports = {
|
|
imageAttachmentLimit,
|
|
invocation,
|
|
}
|