Агент, который сам ищет себе работу
«The agent finds work itself.» Не нужно назначать задачи — агент сам берёт их из доски.
От «разбуженного» к «ищущему работу»
Teammate из s09/s10 пассивен: кто-то отправляет сообщение в inbox — тогда начинает работать; завершает — переходит в idle, ждёт следующего пробуждения.
Autonomous teammate из s11 активен: даже без работы он не остаётся полностью бездействующим — каждые 5 секунд сканирует директорию .tasks/. Видит незанятую задачу — вызывает claim_task, берётся за работу.
Жизненный цикл teammate:
+-------+
| spawn |
+---+---+
|
v
+-------+
| WORK | <-- цикл LLM + tool_use
+---+---+
|
| stop_reason != tool_use OR tool_use("idle")
v
+-------+
| IDLE | опрос каждые 5с, всего 12 раз = таймаут 60с
+---+---+
|
+--> есть новые сообщения в inbox? → возобновить WORK
|
+--> сканирует .tasks/, находит незанятую → claim → возобновить WORK
|
+--> 60с прошло без событий → status = shutdown, поток завершается
Auto-claim · «взять заказ» с доски задач
Ключевая функция:
def scan_unclaimed_tasks() -> list: unclaimed = [] for f in sorted(TASKS_DIR.glob("task_*.json")): task = json.loads(f.read_text()) if (task.get("status") == "pending" and not task.get("owner") and not task.get("blockedBy")): unclaimed.append(task) return unclaimed
Три фильтра = pending + нет owner + нет blockedBy. Все три обязательны.
Само действие claim защищено локом (_claim_lock), чтобы два агента, одновременно увидевшие одну незанятую задачу, не взяли её оба — лок перечитывает задачу, проверяет, что owner ещё пустой, затем атомарно записывает «in_progress» и owner на диск.
Симуляция: несколько агентов одновременно сканируют доску задач
3 teammate в состоянии idle, 3 задачи ждут. Нажмите «следующий опрос» и наблюдайте, кто первым возьмёт задачу (по алфавиту).
Identity reinjection · помнит ли агент себя после сжатия?
В s06 auto_compact заменяет messages на summary. Autonomous agent легко работает несколько часов и попадает под сжатие — после которого модель не знает, как её зовут и какова её роль.
Решение s11: при claim новой задачи, если len(messages) ≤ 3 (признак недавнего сжатия), автоматически вставляем identity-блок в начало:
if len(messages) <= 3: messages.insert(0, { "role": "user", "content": f"<identity>You are 'alice', role: coder, team: my-team. Continue your work.</identity>", }) messages.insert(1, {"role":"assistant", "content": f"I am alice. Continuing."})
Этот паттерн называется identity reinjection — искусственно сконструированный диалоговый раунд «говорит модели, кто она», возвращая ей ощущение роли.