fix: skip auto-processing for self-assigned tasks (taken via tool call)

When agent takes a task via take_task tool in conversation, the
task.assigned event is now skipped (no duplicate in_progress→in_review).
This commit is contained in:
Markov 2026-02-24 11:45:11 +01:00
parent 9d897621a7
commit e58c39dc0c
3 changed files with 13 additions and 0 deletions

View File

@ -16,6 +16,8 @@ export class EventRouter {
private log = logger.child({ component: 'event-router' }); private log = logger.child({ component: 'event-router' });
private activeTasks = 0; private activeTasks = 0;
private trackerTools: ToolDefinition[]; private trackerTools: ToolDefinition[];
/** Tasks taken via tool call (agent already knows about them — skip auto-processing) */
private selfAssignedTasks = new Set<string>();
constructor( constructor(
private config: AgentConfig, private config: AgentConfig,
private client: TrackerClient, private client: TrackerClient,
@ -24,6 +26,7 @@ export class EventRouter {
this.trackerTools = createTrackerTools({ this.trackerTools = createTrackerTools({
trackerClient: client, trackerClient: client,
agentSlug: config.slug, agentSlug: config.slug,
selfAssignedTasks: this.selfAssignedTasks,
}); });
this.log.info({ toolCount: this.trackerTools.length }, 'Tracker tools registered'); this.log.info({ toolCount: this.trackerTools.length }, 'Tracker tools registered');
} }
@ -61,6 +64,13 @@ export class EventRouter {
return; return;
} }
// Skip if agent took this task itself via tool call (already in conversation context)
if (this.selfAssignedTasks.has(task.id)) {
this.selfAssignedTasks.delete(task.id);
this.log.info('│ TASK %s self-assigned via tool, skipping auto-processing', task.key);
return;
}
if (this.activeTasks >= this.config.maxConcurrentTasks) { if (this.activeTasks >= this.config.maxConcurrentTasks) {
this.log.warn({ taskId: task.id, activeTasks: this.activeTasks }, 'Max concurrent tasks reached, skipping'); this.log.warn({ taskId: task.id, activeTasks: this.activeTasks }, 'Max concurrent tasks reached, skipping');
return; return;

View File

@ -100,6 +100,7 @@ export function createTaskTools(ctx: ToolContext): ToolDefinition<any>[] {
description: 'Take a task for yourself (atomically assign to this agent). Task must be in backlog or todo status.', description: 'Take a task for yourself (atomically assign to this agent). Task must be in backlog or todo status.',
parameters: TakeTaskParams, parameters: TakeTaskParams,
async execute(_id: string, params: any) { async execute(_id: string, params: any) {
ctx.selfAssignedTasks.add(params.task_id);
await ctx.trackerClient.takeTask(params.task_id, ctx.agentSlug); await ctx.trackerClient.takeTask(params.task_id, ctx.agentSlug);
return ok(`Task ${params.task_id} taken by ${ctx.agentSlug}`); return ok(`Task ${params.task_id} taken by ${ctx.agentSlug}`);
}, },

View File

@ -4,4 +4,6 @@ import type { TrackerClient } from '../tracker/client.js';
export interface ToolContext { export interface ToolContext {
trackerClient: TrackerClient; trackerClient: TrackerClient;
agentSlug: string; agentSlug: string;
/** Track tasks taken via tool call — prevents duplicate auto-processing */
selfAssignedTasks: Set<string>;
} }