Nyk commited on
Commit
8965499
·
1 Parent(s): 234a2ac

fix(tasks): use gateway agent ID instead of display name for dispatch

Browse files

Task dispatch and Aegis review were sending `agents.name` (the display
name) as `agentId` to the gateway. When `identity.name` differs from
the gateway agent `id`, the gateway rejects the call with
"unknown agent id".

Now extracts `openclawId` from the agent's config JSON (set during
agent sync) and uses that for gateway invocations, falling back to
the display name for backwards compatibility.

Closes #310

Files changed (1) hide show
  1. src/lib/task-dispatch.ts +31 -5
src/lib/task-dispatch.ts CHANGED
@@ -13,12 +13,25 @@ interface DispatchableTask {
13
  workspace_id: number
14
  agent_name: string
15
  agent_id: number
 
16
  ticket_prefix: string | null
17
  project_ticket_no: number | null
18
  project_id: number | null
19
  tags?: string[]
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  function buildTaskPrompt(task: DispatchableTask, rejectionFeedback?: string | null): string {
23
  const ticket = task.ticket_prefix && task.project_ticket_no
24
  ? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
@@ -94,11 +107,22 @@ interface ReviewableTask {
94
  description: string | null
95
  resolution: string | null
96
  assigned_to: string | null
 
97
  workspace_id: number
98
  ticket_prefix: string | null
99
  project_ticket_no: number | null
100
  }
101
 
 
 
 
 
 
 
 
 
 
 
102
  function buildReviewPrompt(task: ReviewableTask): string {
103
  const ticket = task.ticket_prefix && task.project_ticket_no
104
  ? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
@@ -154,9 +178,10 @@ export async function runAegisReviews(): Promise<{ ok: boolean; message: string
154
 
155
  const tasks = db.prepare(`
156
  SELECT t.id, t.title, t.description, t.resolution, t.assigned_to, t.workspace_id,
157
- p.ticket_prefix, t.project_ticket_no
158
  FROM tasks t
159
  LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
 
160
  WHERE t.status = 'review'
161
  ORDER BY t.updated_at ASC
162
  LIMIT 3
@@ -181,8 +206,8 @@ export async function runAegisReviews(): Promise<{ ok: boolean; message: string
181
 
182
  try {
183
  const prompt = buildReviewPrompt(task)
184
- // Use the assigned agent or fall back to a default reviewer agent
185
- const reviewAgent = task.assigned_to || 'jarv'
186
 
187
  const invokeParams = {
188
  message: prompt,
@@ -290,7 +315,7 @@ export async function dispatchAssignedTasks(): Promise<{ ok: boolean; message: s
290
  const db = getDatabase()
291
 
292
  const tasks = db.prepare(`
293
- SELECT t.*, a.name as agent_name, a.id as agent_id,
294
  p.ticket_prefix, t.project_ticket_no
295
  FROM tasks t
296
  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
350
  const prompt = buildTaskPrompt(task, rejectionFeedback)
351
 
352
  // Step 1: Invoke via gateway
 
353
  const invokeParams = {
354
  message: prompt,
355
- agentId: task.agent_name,
356
  idempotencyKey: `task-dispatch-${task.id}-${Date.now()}`,
357
  deliver: false,
358
  }
 
13
  workspace_id: number
14
  agent_name: string
15
  agent_id: number
16
+ agent_config: string | null
17
  ticket_prefix: string | null
18
  project_ticket_no: number | null
19
  project_id: number | null
20
  tags?: string[]
21
  }
22
 
23
+ /** Extract the gateway agent identifier from the agent's config JSON.
24
+ * Falls back to agent_name (display name) if openclawId is not set. */
25
+ function resolveGatewayAgentId(task: DispatchableTask): string {
26
+ if (task.agent_config) {
27
+ try {
28
+ const cfg = JSON.parse(task.agent_config)
29
+ if (typeof cfg.openclawId === 'string' && cfg.openclawId) return cfg.openclawId
30
+ } catch { /* ignore */ }
31
+ }
32
+ return task.agent_name
33
+ }
34
+
35
  function buildTaskPrompt(task: DispatchableTask, rejectionFeedback?: string | null): string {
36
  const ticket = task.ticket_prefix && task.project_ticket_no
37
  ? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
 
107
  description: string | null
108
  resolution: string | null
109
  assigned_to: string | null
110
+ agent_config: string | null
111
  workspace_id: number
112
  ticket_prefix: string | null
113
  project_ticket_no: number | null
114
  }
115
 
116
+ function resolveGatewayAgentIdForReview(task: ReviewableTask): string {
117
+ if (task.agent_config) {
118
+ try {
119
+ const cfg = JSON.parse(task.agent_config)
120
+ if (typeof cfg.openclawId === 'string' && cfg.openclawId) return cfg.openclawId
121
+ } catch { /* ignore */ }
122
+ }
123
+ return task.assigned_to || 'jarv'
124
+ }
125
+
126
  function buildReviewPrompt(task: ReviewableTask): string {
127
  const ticket = task.ticket_prefix && task.project_ticket_no
128
  ? `${task.ticket_prefix}-${String(task.project_ticket_no).padStart(3, '0')}`
 
178
 
179
  const tasks = db.prepare(`
180
  SELECT t.id, t.title, t.description, t.resolution, t.assigned_to, t.workspace_id,
181
+ p.ticket_prefix, t.project_ticket_no, a.config as agent_config
182
  FROM tasks t
183
  LEFT JOIN projects p ON p.id = t.project_id AND p.workspace_id = t.workspace_id
184
+ LEFT JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
185
  WHERE t.status = 'review'
186
  ORDER BY t.updated_at ASC
187
  LIMIT 3
 
206
 
207
  try {
208
  const prompt = buildReviewPrompt(task)
209
+ // Resolve the gateway agent ID from config, falling back to assigned_to or default
210
+ const reviewAgent = resolveGatewayAgentIdForReview(task)
211
 
212
  const invokeParams = {
213
  message: prompt,
 
315
  const db = getDatabase()
316
 
317
  const tasks = db.prepare(`
318
+ SELECT t.*, a.name as agent_name, a.id as agent_id, a.config as agent_config,
319
  p.ticket_prefix, t.project_ticket_no
320
  FROM tasks t
321
  JOIN agents a ON a.name = t.assigned_to AND a.workspace_id = t.workspace_id
 
375
  const prompt = buildTaskPrompt(task, rejectionFeedback)
376
 
377
  // Step 1: Invoke via gateway
378
+ const gatewayAgentId = resolveGatewayAgentId(task)
379
  const invokeParams = {
380
  message: prompt,
381
+ agentId: gatewayAgentId,
382
  idempotencyKey: `task-dispatch-${task.id}-${Date.now()}`,
383
  deliver: false,
384
  }