workflow-ai 1.0.21 → 1.0.23
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.
package/configs/pipeline.yaml
CHANGED
|
@@ -285,10 +285,10 @@ pipeline:
|
|
|
285
285
|
# docs: qwen-code
|
|
286
286
|
admin: kilo-minimax
|
|
287
287
|
agent_by_attempt:
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
288
|
+
2: qwen-code
|
|
289
|
+
3: claude-sonnet
|
|
290
|
+
4: claude-opus
|
|
291
|
+
5: kilo-deepseek
|
|
292
292
|
goto:
|
|
293
293
|
default:
|
|
294
294
|
stage: move-to-review
|
|
@@ -482,6 +482,6 @@ pipeline:
|
|
|
482
482
|
# ===========================================================================
|
|
483
483
|
execution:
|
|
484
484
|
max_steps: 1500
|
|
485
|
-
delay_between_stages:
|
|
485
|
+
delay_between_stages: 5
|
|
486
486
|
timeout_per_stage: 1800
|
|
487
487
|
log_file: ".workflow/logs/pipeline.log"
|
package/package.json
CHANGED
package/src/lib/utils.mjs
CHANGED
|
@@ -117,10 +117,16 @@ export function getLastReviewStatus(content) {
|
|
|
117
117
|
if (!content) return null;
|
|
118
118
|
|
|
119
119
|
// Находим секцию "## Ревью" — захватываем всё до следующего заголовка ## или конца файла
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
120
|
+
const headerIdx = content.search(/^##\s*Ревью\s*$/m);
|
|
121
|
+
if (headerIdx === -1) return null;
|
|
122
122
|
|
|
123
|
-
const
|
|
123
|
+
const bodyStart = content.indexOf('\n', headerIdx);
|
|
124
|
+
if (bodyStart === -1) return null;
|
|
125
|
+
|
|
126
|
+
const nextH2 = content.indexOf('\n## ', bodyStart);
|
|
127
|
+
const reviewSection = (nextH2 === -1
|
|
128
|
+
? content.slice(bodyStart + 1)
|
|
129
|
+
: content.slice(bodyStart + 1, nextH2)).trim();
|
|
124
130
|
if (!reviewSection) return null;
|
|
125
131
|
|
|
126
132
|
// Пробуем распарсить табличный формат
|
package/src/runner.mjs
CHANGED
|
@@ -725,28 +725,24 @@ class StageExecutor {
|
|
|
725
725
|
}
|
|
726
726
|
|
|
727
727
|
// Выбираем агента по приоритету:
|
|
728
|
-
// 1.
|
|
729
|
-
// 2.
|
|
728
|
+
// 1. attempt=1 → agent_by_type[task_type] (первая попытка — по типу задачи)
|
|
729
|
+
// 2. attempt>1 → agent_by_attempt[counter] (повторные попытки — ротация)
|
|
730
730
|
// 3. stage.agent — явно указанный агент stage
|
|
731
731
|
// 4. default_agent — глобальный дефолт
|
|
732
732
|
let agentId = stage.agent || this.pipeline.default_agent;
|
|
733
|
+
const attempt = (stage.counter && this.counters[stage.counter]) || 0;
|
|
733
734
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (stage.agent_by_type && this.context.task_type) {
|
|
735
|
+
if (attempt <= 1 && stage.agent_by_type && this.context.task_type) {
|
|
736
|
+
// Первая попытка: выбор по типу задачи
|
|
737
737
|
const taskType = this.context.task_type;
|
|
738
738
|
if (stage.agent_by_type[taskType]) {
|
|
739
|
-
|
|
739
|
+
agentId = stage.agent_by_type[taskType];
|
|
740
740
|
if (this.logger) {
|
|
741
|
-
this.logger.info(`Agent by type: task_type="${taskType}" → ${
|
|
741
|
+
this.logger.info(`Agent by type: task_type="${taskType}" → ${agentId}`, stageId);
|
|
742
742
|
}
|
|
743
|
-
agentId = typeBasedAgent;
|
|
744
743
|
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// Приоритет 2: agent_by_attempt (ротация по попыткам) — перекрывает agent_by_type
|
|
748
|
-
if (stage.agent_by_attempt && stage.counter) {
|
|
749
|
-
const attempt = this.counters[stage.counter] || 0;
|
|
744
|
+
} else if (stage.agent_by_attempt && attempt > 1) {
|
|
745
|
+
// Повторные попытки: ротация по agent_by_attempt
|
|
750
746
|
if (stage.agent_by_attempt[attempt]) {
|
|
751
747
|
agentId = stage.agent_by_attempt[attempt];
|
|
752
748
|
if (this.logger) {
|
|
@@ -17,6 +17,21 @@ description: Проверить актуальность тикета перед
|
|
|
17
17
|
|
|
18
18
|
## Шаги проверки
|
|
19
19
|
|
|
20
|
+
### 0. Быстрый выход по существующему ревью
|
|
21
|
+
|
|
22
|
+
**До любых проверок** найди в тикете секцию `## Ревью`.
|
|
23
|
+
|
|
24
|
+
Если последняя запись имеет статус `⏭ skipped` — тикет уже был проверен и пропущен. **Повторно проверять НЕ НАДО**, новую запись skipped добавлять НЕ НАДО. Немедленно верни:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
---RESULT---
|
|
28
|
+
status: irrelevant
|
|
29
|
+
reason: already_skipped
|
|
30
|
+
---RESULT---
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Если последней записи нет или статус другой — переходи к шагу 1.
|
|
34
|
+
|
|
20
35
|
### 1. Прочитать тикет
|
|
21
36
|
|
|
22
37
|
**ОБЯЗАТЕЛЬНО:** Используй `ticket_id` из секции Context промпта.
|
|
@@ -86,7 +101,7 @@ description: Проверить актуальность тикета перед
|
|
|
86
101
|
Формат записи:
|
|
87
102
|
|
|
88
103
|
```
|
|
89
|
-
| {текущая дата} |
|
|
104
|
+
| {текущая дата} | ⏭️ skipped | {причина irrelevant: plan_inactive / dod_completed / dependencies_inactive} |
|
|
90
105
|
```
|
|
91
106
|
|
|
92
107
|
Пример:
|
|
@@ -96,7 +111,7 @@ description: Проверить актуальность тикета перед
|
|
|
96
111
|
|
|
97
112
|
| Дата | Статус | Самари |
|
|
98
113
|
|------|--------|--------|
|
|
99
|
-
| 2026-03-10 |
|
|
114
|
+
| 2026-03-10 | ⏭️ skipped | DoD уже выполнен, тикет неактуален |
|
|
100
115
|
```
|
|
101
116
|
|
|
102
117
|
Это единственная допустимая запись в файл — только добавление строки в таблицу ревью.
|
|
@@ -83,6 +83,8 @@ ID тикета передаётся в промпте как `ticket_id` в с
|
|
|
83
83
|
|
|
84
84
|
### 4. Сформировать вердикт
|
|
85
85
|
|
|
86
|
+
> **ВАЖНО:** Review-result НИКОГДА не пишет статус `skipped`. Допустимы только `passed` или `failed`. Статус `skipped` — прерогатива check-relevance.
|
|
87
|
+
|
|
86
88
|
Возвращать структурированный результат строго в одном из двух форматов:
|
|
87
89
|
|
|
88
90
|
> **КРИТИЧНО**: `status` принимает ТОЛЬКО два значения: `passed` или `failed`.
|