Merge pull request #314 from builderz-labs/fix/task-dispatch-agent-id
fix(tasks): use gateway agent ID instead of display name for dispatch
This commit is contained in:
commit
14890e7630
|
|
@ -66,7 +66,7 @@
|
||||||
"vitest": "^2.1.5"
|
"vitest": "^2.1.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "22.x || 24.x"
|
"node": ">=22"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"openclaw",
|
"openclaw",
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const SUPPORTED_NODE_MAJORS = [22, 24]
|
const MIN_NODE_MAJOR = 22
|
||||||
|
|
||||||
const current = process.versions.node
|
const current = process.versions.node
|
||||||
const currentMajor = Number.parseInt(current.split('.')[0] || '', 10)
|
const currentMajor = Number.parseInt(current.split('.')[0] || '', 10)
|
||||||
|
|
||||||
if (!SUPPORTED_NODE_MAJORS.includes(currentMajor)) {
|
if (currentMajor < MIN_NODE_MAJOR) {
|
||||||
const supported = SUPPORTED_NODE_MAJORS.map((major) => `${major}.x`).join(' or ')
|
|
||||||
console.error(
|
console.error(
|
||||||
[
|
[
|
||||||
`error: Mission Control supports Node ${supported}, but found ${current}.`,
|
`error: Mission Control requires Node ${MIN_NODE_MAJOR} or later, but found ${current}.`,
|
||||||
'use `nvm use 22` (recommended LTS) or `nvm use 24` before installing, building, or starting the app.',
|
'use `nvm use 22` (recommended LTS) or any later version before installing, building, or starting the app.',
|
||||||
].join('\n')
|
].join('\n')
|
||||||
)
|
)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,25 @@ interface DispatchableTask {
|
||||||
workspace_id: number
|
workspace_id: number
|
||||||
agent_name: string
|
agent_name: string
|
||||||
agent_id: number
|
agent_id: number
|
||||||
|
agent_config: string | null
|
||||||
ticket_prefix: string | null
|
ticket_prefix: string | null
|
||||||
project_ticket_no: number | null
|
project_ticket_no: number | null
|
||||||
project_id: number | null
|
project_id: number | null
|
||||||
tags?: string[]
|
tags?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Extract the gateway agent identifier from the agent's config JSON.
|
||||||
|
* Falls back to agent_name (display name) if openclawId is not set. */
|
||||||
|
function resolveGatewayAgentId(task: DispatchableTask): string {
|
||||||
|
if (task.agent_config) {
|
||||||
|
try {
|
||||||
|
const cfg = JSON.parse(task.agent_config)
|
||||||
|
if (typeof cfg.openclawId === 'string' && cfg.openclawId) return cfg.openclawId
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
return task.agent_name
|
||||||
|
}
|
||||||
|
|
||||||
function buildTaskPrompt(task: DispatchableTask, rejectionFeedback?: string | null): string {
|
function buildTaskPrompt(task: DispatchableTask, rejectionFeedback?: string | null): string {
|
||||||
const ticket = task.ticket_prefix && task.project_ticket_no
|
const ticket = task.ticket_prefix && task.project_ticket_no
|
||||||
? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
|
? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
|
||||||
|
|
@ -94,11 +107,22 @@ interface ReviewableTask {
|
||||||
description: string | null
|
description: string | null
|
||||||
resolution: string | null
|
resolution: string | null
|
||||||
assigned_to: string | null
|
assigned_to: string | null
|
||||||
|
agent_config: string | null
|
||||||
workspace_id: number
|
workspace_id: number
|
||||||
ticket_prefix: string | null
|
ticket_prefix: string | null
|
||||||
project_ticket_no: number | null
|
project_ticket_no: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveGatewayAgentIdForReview(task: ReviewableTask): string {
|
||||||
|
if (task.agent_config) {
|
||||||
|
try {
|
||||||
|
const cfg = JSON.parse(task.agent_config)
|
||||||
|
if (typeof cfg.openclawId === 'string' && cfg.openclawId) return cfg.openclawId
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
return task.assigned_to || 'jarv'
|
||||||
|
}
|
||||||
|
|
||||||
function buildReviewPrompt(task: ReviewableTask): string {
|
function buildReviewPrompt(task: ReviewableTask): string {
|
||||||
const ticket = task.ticket_prefix && task.project_ticket_no
|
const ticket = task.ticket_prefix && task.project_ticket_no
|
||||||
? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
|
? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
|
||||||
|
|
@ -154,9 +178,10 @@ export async function runAegisReviews(): Promise<{ ok: boolean; message: string
|
||||||
|
|
||||||
const tasks = db.prepare(`
|
const tasks = db.prepare(`
|
||||||
SELECT t.id, t.title, t.description, t.resolution, t.assigned_to, t.workspace_id,
|
SELECT t.id, t.title, t.description, t.resolution, t.assigned_to, t.workspace_id,
|
||||||
p.ticket_prefix, t.project_ticket_no
|
p.ticket_prefix, t.project_ticket_no, a.config as agent_config
|
||||||
FROM tasks t
|
FROM tasks t
|
||||||
LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
|
LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
|
||||||
|
LEFT JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
|
||||||
WHERE t.status = 'review'
|
WHERE t.status = 'review'
|
||||||
ORDER BY t.updated_at ASC
|
ORDER BY t.updated_at ASC
|
||||||
LIMIT 3
|
LIMIT 3
|
||||||
|
|
@ -181,8 +206,8 @@ export async function runAegisReviews(): Promise<{ ok: boolean; message: string
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const prompt = buildReviewPrompt(task)
|
const prompt = buildReviewPrompt(task)
|
||||||
// Use the assigned agent or fall back to a default reviewer agent
|
// Resolve the gateway agent ID from config, falling back to assigned_to or default
|
||||||
const reviewAgent = task.assigned_to || 'jarv'
|
const reviewAgent = resolveGatewayAgentIdForReview(task)
|
||||||
|
|
||||||
const invokeParams = {
|
const invokeParams = {
|
||||||
message: prompt,
|
message: prompt,
|
||||||
|
|
@ -290,7 +315,7 @@ export async function dispatchAssignedTasks(): Promise<{ ok: boolean; message: s
|
||||||
const db = getDatabase()
|
const db = getDatabase()
|
||||||
|
|
||||||
const tasks = db.prepare(`
|
const tasks = db.prepare(`
|
||||||
SELECT t.*, a.name as agent_name, a.id as agent_id,
|
SELECT t.*, a.name as agent_name, a.id as agent_id, a.config as agent_config,
|
||||||
p.ticket_prefix, t.project_ticket_no
|
p.ticket_prefix, t.project_ticket_no
|
||||||
FROM tasks t
|
FROM tasks t
|
||||||
JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
|
JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
|
||||||
|
|
@ -350,9 +375,10 @@ export async function dispatchAssignedTasks(): Promise<{ ok: boolean; message: s
|
||||||
const prompt = buildTaskPrompt(task, rejectionFeedback)
|
const prompt = buildTaskPrompt(task, rejectionFeedback)
|
||||||
|
|
||||||
// Step 1: Invoke via gateway
|
// Step 1: Invoke via gateway
|
||||||
|
const gatewayAgentId = resolveGatewayAgentId(task)
|
||||||
const invokeParams = {
|
const invokeParams = {
|
||||||
message: prompt,
|
message: prompt,
|
||||||
agentId: task.agent_name,
|
agentId: gatewayAgentId,
|
||||||
idempotencyKey: `task-dispatch-${task.id}-${Date.now()}`,
|
idempotencyKey: `task-dispatch-${task.id}-${Date.now()}`,
|
||||||
deliver: false,
|
deliver: false,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue