workflow-ai 1.0.7 → 1.0.8

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.
@@ -233,6 +233,12 @@ pipeline:
233
233
  agent: qwen-code
234
234
  fallback_agent: kilo-deepseek
235
235
  skill: execute-task
236
+ counter: task_attempts
237
+ agent_by_attempt:
238
+ 1: qwen-code
239
+ 2: claude-sonnet
240
+ 3: claude-opus
241
+ 4: kilo-deepseek
236
242
  goto:
237
243
  default:
238
244
  stage: move-to-review
@@ -275,6 +281,7 @@ pipeline:
275
281
  agent: claude-sonnet
276
282
  fallback_agent: qwen-code
277
283
  skill: review-result
284
+ counter: task_attempts
278
285
  goto:
279
286
  passed:
280
287
  stage: move-ticket
@@ -294,19 +301,19 @@ pipeline:
294
301
  # -------------------------------------------------------------------------
295
302
  # 4b. increment-task-attempts
296
303
  # Отдельный стейдж обновления счётчика попыток выполнения тикета.
297
- # При достижении max — блокирует тикет. Иначе — возвращает в очередь.
304
+ # При достижении max — блокирует тикет. Иначе — отправляет на доработку.
305
+ # Проверка лимита происходит ДО повторного execute-task.
298
306
  # -------------------------------------------------------------------------
299
307
  increment-task-attempts:
300
308
  description: "Обновить счётчик попыток выполнения тикета"
301
309
  type: update-counter
302
310
  counter: task_attempts
303
- max: 3
311
+ max: 6
304
312
  goto:
305
313
  default:
306
- stage: move-ticket
314
+ stage: execute-task
307
315
  params:
308
316
  ticket_id: "$context.ticket_id"
309
- target: ready
310
317
  max_reached:
311
318
  stage: move-ticket
312
319
  params:
@@ -366,7 +373,7 @@ pipeline:
366
373
  description: "Обновить счётчик итераций анализа плана"
367
374
  type: update-counter
368
375
  counter: plan_iterations
369
- max: 3
376
+ max: 2
370
377
  goto:
371
378
  default:
372
379
  stage: decompose-gaps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workflow-ai",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "AI Agent Workflow Coordinator — kanban-based pipeline for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
package/src/runner.mjs CHANGED
@@ -681,7 +681,17 @@ class StageExecutor {
681
681
  throw new Error(`Stage not found: ${stageId}`);
682
682
  }
683
683
 
684
- const agentId = stage.agent;
684
+ // Выбираем агента: если есть agent_by_attempt и счётчик — ротация по попыткам
685
+ let agentId = stage.agent;
686
+ if (stage.agent_by_attempt && stage.counter) {
687
+ const attempt = this.counters[stage.counter] || 0;
688
+ if (stage.agent_by_attempt[attempt]) {
689
+ agentId = stage.agent_by_attempt[attempt];
690
+ if (this.logger) {
691
+ this.logger.info(`Agent rotation: attempt ${attempt} → ${agentId}`, stageId);
692
+ }
693
+ }
694
+ }
685
695
  const agent = this.pipeline.agents[agentId];
686
696
  if (!agent) {
687
697
  throw new Error(`Agent not found: ${agentId}`);
@@ -1157,41 +1167,6 @@ class PipelineRunner {
1157
1167
  this.updateContext(transition.params, result.result);
1158
1168
  }
1159
1169
 
1160
- // Проверяем retry-логику с agent_by_attempt
1161
- if (transition.agent_by_attempt && stage.counter) {
1162
- const attempt = this.counters[stage.counter] || 1;
1163
- const maxAttempts = transition.max || 3;
1164
-
1165
- if (attempt < maxAttempts) {
1166
- // Ещё есть попытки — переходим на указанный stage с переопределением агента
1167
- const nextStage = transition.stage || stageId;
1168
- const overrideAgent = transition.agent_by_attempt[attempt];
1169
-
1170
- if (overrideAgent) {
1171
- // Переопределяем агента для следующей попытки
1172
- stage.agent = overrideAgent;
1173
- this.logger.info(`Retry attempt ${attempt}: overriding agent to ${overrideAgent}`, stageId);
1174
- }
1175
-
1176
- this.logger.retry(stageId, attempt, maxAttempts);
1177
- this.logger.gotoTransition(stageId, nextStage, status, transition.params);
1178
- return nextStage;
1179
- } else {
1180
- // Попытки исчерпаны — переходим на on_max
1181
- this.logger.info(`Max attempts (${maxAttempts}) reached for ${stageId}`, stageId);
1182
- this.logger.retry(stageId, attempt, maxAttempts);
1183
-
1184
- if (transition.on_max) {
1185
- if (transition.on_max.params) {
1186
- this.updateContext(transition.on_max.params, result.result);
1187
- }
1188
- const nextStage = transition.on_max.stage || 'end';
1189
- this.logger.gotoTransition(stageId, nextStage, status, transition.on_max.params);
1190
- return nextStage;
1191
- }
1192
- }
1193
- }
1194
-
1195
1170
  const nextStage = transition.stage || 'end';
1196
1171
  this.logger.gotoTransition(stageId, nextStage, status, transition.params);
1197
1172
  return nextStage;