Merge remote-tracking branch 'upstream/main'

This commit is contained in:
github-actions[bot]
2026-07-28 15:13:54 +00:00
14 changed files with 53 additions and 55 deletions
+1 -3
View File
@@ -232,10 +232,8 @@ register_hook("Stop", summary_hook)
# agent_loop — same as s04 + nag reminder counter
# ═══════════════════════════════════════════════════════════
rounds_since_todo = 0
def agent_loop(messages: list):
global rounds_since_todo
rounds_since_todo = 0
while True:
# s05: nag reminder — inject if model hasn't updated todos for 3 rounds
if rounds_since_todo >= 3 and messages:
+1 -3
View File
@@ -312,10 +312,8 @@ register_hook("Stop", summary_hook)
# agent_loop — same as s05 + nag reminder, task auto-dispatches
# ═══════════════════════════════════════════════════════════
rounds_since_todo = 0
def agent_loop(messages: list):
global rounds_since_todo
rounds_since_todo = 0
while True:
# s05: nag reminder
if rounds_since_todo >= 3 and messages:
+1 -3
View File
@@ -356,10 +356,8 @@ register_hook("Stop", summary_hook)
# agent_loop — same as s05-s06 + nag reminder
# ═══════════════════════════════════════════════════════════
rounds_since_todo = 0
def agent_loop(messages: list):
global rounds_since_todo
rounds_since_todo = 0
while True:
if rounds_since_todo >= 3 and messages:
messages.append({"role": "user",
+1 -1
View File
@@ -136,7 +136,7 @@ def compact_history(messages):
Sometimes the API still returns `prompt_too_long` (413) — when context grows faster than compression triggers.
This triggers **reactive_compact**: more aggressive than compact_history, it retreats from the tail, but still avoids leaving an orphaned `tool_result`.
This triggers **reactive_compact**: more aggressive than compact_history in trigger (emergency response to a 413 error), but more conservative in what it removes, keeping ~5 recent messages and only summarizing earlier history. Still avoids an orphaned `tool_result`.
```python
def reactive_compact(messages):
+1 -1
View File
@@ -136,7 +136,7 @@ def compact_history(messages):
API がまだ `prompt_too_long`(413)を返すことがある。コンテキストの増加速度が圧縮のトリガー速度を上回る場合。
この時 **reactive_compact** がトリガーされるcompact_history よりもさらに積極的だが、末尾を残す際も孤立した `tool_result` を残さないようする。
この時 **reactive_compact** がトリガーされる。トリガー方式は compact_history より積極的(413 エラー後の緊急対応)だが、圧縮方針はより温和で、末尾約 5 件のメッセージを保持し、早期の履歴だけを要約する。孤立した `tool_result` を残さないよう配慮する。
```python
def reactive_compact(messages):
+1 -1
View File
@@ -136,7 +136,7 @@ def compact_history(messages):
有时候 API 还是返回 `prompt_too_long`(413),上下文增长速度快于压缩触发速度时。
这时触发 **reactive_compact**:比 compact_history 更激进,从尾部回退,但仍要避免留下孤立 `tool_result`
这时触发 **reactive_compact**触发方式比 compact_history 更激进(API 报错后的应急手段),但压缩策略更温和,保留最近约 5 条原始消息,只总结较早历史。同样避免留下孤立 `tool_result`
```python
def reactive_compact(messages):
+6 -5
View File
@@ -68,9 +68,6 @@ Split the monolithic string into a dictionary, each key is a topic:
```python
PROMPT_SECTIONS = {
"identity": "You are a coding agent. Act, don't explain.",
"tools": "Available tools: bash, read_file, write_file.",
"workspace": f"Working directory: {WORKDIR}",
"memory": "Relevant memories are injected below when available.",
}
```
@@ -86,8 +83,12 @@ def assemble_system_prompt(context: dict) -> str:
# Always loaded
sections.append(PROMPT_SECTIONS["identity"])
sections.append(PROMPT_SECTIONS["tools"])
sections.append(PROMPT_SECTIONS["workspace"])
# Dynamic — tools and workspace from context
tools = ", ".join(context.get("enabled_tools", []))
if tools:
sections.append(f"Available tools: {tools}.")
sections.append(f"Working directory: {context.get("workspace", WORKDIR)}")
# On-demand — based on real state, not keywords
memories = context.get("memories", "")
+6 -5
View File
@@ -68,9 +68,6 @@ s10 は prompt アセンブリ機構に焦点を当てる。s08-s09 の能力を
```python
PROMPT_SECTIONS = {
"identity": "You are a coding agent. Act, don't explain.",
"tools": "Available tools: bash, read_file, write_file.",
"workspace": f"Working directory: {WORKDIR}",
"memory": "Relevant memories are injected below when available.",
}
```
@@ -86,8 +83,12 @@ def assemble_system_prompt(context: dict) -> str:
# 常にロード
sections.append(PROMPT_SECTIONS["identity"])
sections.append(PROMPT_SECTIONS["tools"])
sections.append(PROMPT_SECTIONS["workspace"])
# context から動的に tools と workspace を取得
tools = ", ".join(context.get("enabled_tools", []))
if tools:
sections.append(f"Available tools: {tools}.")
sections.append(f"Working directory: {context.get("workspace", WORKDIR)}")
# オンデマンド — 実際の状態に基づく、キーワードではない
memories = context.get("memories", "")
+6 -5
View File
@@ -68,9 +68,6 @@ s10 聚焦 prompt 组装机制。以 s08-s09 的能力为背景,但不重复
```python
PROMPT_SECTIONS = {
"identity": "You are a coding agent. Act, don't explain.",
"tools": "Available tools: bash, read_file, write_file.",
"workspace": f"Working directory: {WORKDIR}",
"memory": "Relevant memories are injected below when available.",
}
```
@@ -86,8 +83,12 @@ def assemble_system_prompt(context: dict) -> str:
# 始终加载
sections.append(PROMPT_SECTIONS["identity"])
sections.append(PROMPT_SECTIONS["tools"])
sections.append(PROMPT_SECTIONS["workspace"])
# 从 context 动态获取 tools 和 workspace
tools = ", ".join(context.get("enabled_tools", []))
if tools:
sections.append(f"Available tools: {tools}.")
sections.append(f"Working directory: {context.get("workspace", WORKDIR)}")
# 按需加载 — 基于真实状态,不是关键词
memories = context.get("memories", "")
+7 -6
View File
@@ -41,9 +41,6 @@ MODEL = os.environ["MODEL_ID"]
PROMPT_SECTIONS = {
"identity": "You are a coding agent. Act, don't explain.",
"tools": "Available tools: bash, read_file, write_file.",
"workspace": f"Working directory: {WORKDIR}",
"memory": "Relevant memories are injected below when available.",
}
@@ -51,10 +48,14 @@ def assemble_system_prompt(context: dict) -> str:
"""Select and join prompt sections based on current context."""
sections = []
# Always loaded — identity, tools, workspace
# Always loaded — identity
sections.append(PROMPT_SECTIONS["identity"])
sections.append(PROMPT_SECTIONS["tools"])
sections.append(PROMPT_SECTIONS["workspace"])
# Dynamic — tools and workspace from context
tools = ", ".join(context.get("enabled_tools", []))
if tools:
sections.append(f"Available tools: {tools}.")
sections.append(f"Working directory: {context.get("workspace", WORKDIR)}")
# Conditional — memory loaded when MEMORY.md exists and has content
memories = context.get("memories", "")
+4 -4
View File
@@ -272,10 +272,10 @@ def agent_loop(messages: list, context: dict):
# ── LLM call: with_retry handles 429/529, outer handles rest ──
try:
response = with_retry(
lambda mt=max_tokens, mdl=state.current_model:
client.messages.create(
model=mdl, system=system, messages=messages,
tools=TOOLS, max_tokens=mt),
lambda: client.messages.create(
model=state.current_model, system=system,
messages=messages, tools=TOOLS,
max_tokens=max_tokens),
state)
except Exception as e:
# Path 2: prompt_too_long -> reactive compact (once)
+6 -6
View File
@@ -195,15 +195,15 @@ Two teammates claim and work in parallel. Lead only creates tasks and spawns tea
| Component | Before (s16) | After (s17) |
|-----------|-------------|-------------|
| Task assignment | Lead manually assigns | Teammates auto-claim (can_start checks deps) |
| Teammate state | WORK or exit | WORK → IDLE (60s poll) → SHUTDOWN |
| Teammate state | WORK → IDLE (1s inbox poll) → WORK / SHUTDOWN | WORK → IDLE (5s inbox + task board poll, 60s timeout) → WORK / SHUTDOWN |
| claim_task | No owner check | Rejects tasks that already have an owner |
| IDLE phase shutdown | Doesn't handle shutdown_request | Dispatches shutdown immediately and exits |
| Lead inbox | Prints only, not in context | consume_lead_inbox injects into history |
| New functions | | idle_poll, scan_unclaimed_tasks, consume_lead_inbox |
| IDLE phase shutdown | Exits after receiving shutdown_request | Dispatches shutdown immediately and exits |
| Lead inbox | consume_lead_inbox routes protocol responses and injects into context | Reuses consume_lead_inbox mechanism |
| New functions | consume_lead_inbox already exists | idle_poll, scan_unclaimed_tasks (reuses consume_lead_inbox) |
| Identity persistence | System prompt only | Auto re-inject after compression |
| Lead tools | 14 (s16) | 14 (unchanged) |
| Lead tools | 14 | 14 (unchanged) |
| Teammate tools | 5 | 8 (+ list_tasks, claim_task, complete_task) |
| Teammate exit | Exit after task done | Exit only after 60s idle timeout |
| Teammate exit | WORK ends → enters IDLE, waits for shutdown_request (no timeout) | Exits after 60s idle timeout or receiving shutdown_request |
---
+6 -6
View File
@@ -195,15 +195,15 @@ if len(messages) <= 3:
| コンポーネント | 変更前 (s16) | 変更後 (s17) |
|--------------|------------|------------|
| タスク割り当て | Lead が手動 assign | チームメイトが自動認領(can_start で依存確認) |
| チームメイト状態 | WORK または終了 | WORK → IDLE(60s ポーリング) → SHUTDOWN |
| チームメイト状態 | WORK → IDLE(1s 間隔で inbox をポーリング)→ WORK / SHUTDOWN | WORK → IDLE5s 間隔で inbox + タスクボードをポーリング、60s タイムアウト)→ WORK / SHUTDOWN |
| claim_task | owner チェックなし | 既に owner があるタスクを拒否 |
| IDLE フェーズシャットダウン | shutdown_request を処理しない | 即座にシャットダウンをディスパッチして終了 |
| Lead inbox | 印刷のみ、コンテキストに入らない | consume_lead_inbox で history に注入 |
| 新規関数 | | idle_poll, scan_unclaimed_tasks, consume_lead_inbox |
| IDLE フェーズシャットダウン | shutdown_request を受信後に終了 | 即座にシャットダウンをディスパッチして終了 |
| Lead inbox | consume_lead_inbox がプロトコル応答をルーティングしコンテキストに入 | consume_lead_inbox 機構を踏襲 |
| 新規関数 | consume_lead_inbox は既存 | idle_poll, scan_unclaimed_tasksconsume_lead_inbox を踏襲) |
| 身份保持 | system prompt のみ | 圧縮後に自動再注入 |
| Lead ツール | 14 (s16) | 14(変更なし) |
| Lead ツール | 14 | 14(変更なし) |
| チームメイトツール | 5 | 8+ list_tasks, claim_task, complete_task |
| チームメイト終了条件 | タスク完了後即終了 | 60s アイドルタイムアウト後のみ終了 |
| チームメイト終了条件 | WORK 完了後 IDLE に入り、shutdown_request を待って終了(タイムアウトなし) | 60s アイドルタイムアウトまたは shutdown_request 受信で終了 |
---
+6 -6
View File
@@ -195,15 +195,15 @@ if len(messages) <= 3:
| 组件 | 之前 (s16) | 之后 (s17) |
|------|-----------|-----------|
| 任务分配 | Lead 手动 assign | 队友自动认领(can_start 检查依赖) |
| 队友状态 | WORK 或退出 | WORK → IDLE(轮询 60s SHUTDOWN |
| 队友状态 | WORK → IDLE(每 1s 轮询 inbox)→ WORK / SHUTDOWN | WORK → IDLE(每 5s 轮询 inbox + 任务板,60s 超时)→ WORK / SHUTDOWN |
| claim_task | 无 owner 检查 | 拒绝已有 owner 的任务 |
| IDLE 阶段关机 | 不处理 shutdown_request | 直接 dispatch shutdown 并退出 |
| Lead inbox | 只打印,不进上下文 | consume_lead_inbox 统一注入 history |
| 新函数 | | idle_poll, scan_unclaimed_tasks, consume_lead_inbox |
| IDLE 阶段关机 | 收到 shutdown_request 后退出 | 直接 dispatch shutdown 并退出 |
| Lead inbox | consume_lead_inbox 路由协议响应并注入上下文 | 沿用 consume_lead_inbox 机制 |
| 新函数 | 已有 consume_lead_inbox | idle_poll, scan_unclaimed_tasks(沿用 consume_lead_inbox |
| 身份保持 | 仅 system prompt | 压缩后自动重注入 |
| Lead 工具 | 14 (s16) | 14(不变) |
| Lead 工具 | 14 | 14(不变) |
| 队友工具 | 5 | 8+ list_tasks, claim_task, complete_task |
| 队友退出条件 | 完成任务即退出 | 60s 无新任务才退出 |
| 队友退出条件 | WORK 完进入 IDLE,等待 shutdown_request 后退出(无超时) | 60s 无新任务或收到 shutdown_request 后退出 |
---