s09: select_relevant_memories 的 "recent" 拼接顺序与切片不合理,不是真正的最近 2k 上下文
Maintainer thường phản hồi trong vòng 15 ngày
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 78/100
Hướng nghiên cứu
Bắt đầu trong s09_memory/code.py tại recent_user_text, đặc biệt là các dòng 251-261, và kiểm tra cách các tin nhắn của người dùng được thu thập, nối lại và cắt. Xác minh hành vi đã chọn với các lượt gần đây ngắn và dài; hoàn tất khi context được trả về giữ nguyên thứ tự thời gian và bao gồm phần cuối của 4000 ký tự gần đây nhất.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
问题
s09_memory/code.py:251-261 recent_user_text returns a string claiming to be the most recent user context, but the join + slice order produces an unintuitive result.
def recent_user_text(messages: list, max_turns: int = 3) -> str:
turns = []
for message in reversed(messages):
if message.get("role") != "user":
continue
text = message_text(message).strip()
if text:
turns.append(text)
if len(turns) == max_turns:
break
return "\n".join(reversed(turns))[:4000]
Actual behavior
reversed(messages)walks backwards;turnsaccumulates up tomax_turns=3user texts inturns = [latest, prev, prev2]order.reversed(turns)then flips it back to[prev2, prev, latest].- Joined with
\n, sliced to head 4000 chars.
Consequences:
- If the latest user turn is short (e.g. "ok"), the head-4000 fills with older turns and the latest one is pushed past the slice window — the most relevant signal is dropped.
- If the latest turn is long, older turns are pushed out entirely and the function degrades to "use only the latest turn" — but that intent is not expressed in the code.
- The function is named
recent_user_textbut the implementation is "oldest of the recent few, then head-slice". Order is non-obvious.
Expected behavior
recent_user_text should mean "the last N characters of the most recent user context, in chronological order". A minimal fix:
def recent_user_text(messages: list, max_chars: int = 4000) -> str:
chunks = []
for message in messages:
if message.get("role") != "user":
continue
text = message_text(message).strip()
if text:
chunks.append(text)
joined = "\n".join(chunks)
return joined[-max_chars:] if len(joined) > max_chars else joined
Or, if preserving the per-turn walk is desired, take only the tail of the result rather than the head:
result = "\n".join(reversed(turns))
return result[-4000:] if len(result) > 4000 else result
Either is fine — the important thing is that the slice direction matches the name: "recent" means tail, not head.
中文版本
问题
s09_memory/code.py:251-261 recent_user_text 的字面意思虽然是"最近的用户文本",但 join + 切片的顺序让它产出一个反直觉的结果。
```python
def recent_user_text(messages: list, max_turns: int = 3) -> str:
turns = []
for message in reversed(messages):
if message.get("role") != "user":
continue
text = message_text(message).strip()
if text:
turns.append(text)
if len(turns) == max_turns:
break
return "\n".join(reversed(turns))[:4000]
```
实际行为
- `reversed(messages)` 从末尾向前扫描,收集最多 3 条 user 文本,此时 `turns` 顺序为 `[最新, 次新, 更旧]`。
- `reversed(turns)` 又翻回 `[更旧, 次新, 最新]`。
- 用 `\n` 拼接后取头 4000 字符。
带来的问题:
- 如果最新那条很短(比如 "ok"),头 4000 字符会被更旧的消息灌满,最新那条反而被切掉——最该被命中的信号反而丢
- 如果最新那条够长,前面的消息直接被挤出窗口,函数退化成"只用最新一条"——这个意图代码里没体现
- 函数名叫 `recent_user_text`,实现却是"最近几条里最旧的先出现 + 头切",顺序含义不明
期望行为
`recent_user_text` 应该是"按时间正序排列后,取末尾 N 个字符"。最小修复:
```python
def recent_user_text(messages: list, max_chars: int = 4000) -> str:
chunks = []
for message in messages:
if message.get("role") != "user":
continue
text = message_text(message).strip()
if text:
chunks.append(text)
joined = "\n".join(chunks)
return joined[-max_chars:] if len(joined) > max_chars else joined
```
或者保留逐条遍历的写法,但把切片方向反过来:
```python
result = "\n".join(reversed(turns))
return result[-4000:] if len(result) > 4000 else result
```
任选其一即可,关键是切片方向跟函数名一致——"recent" 是尾部,不是头部。
- Ngôn ngữ chính
- Python
- Star
- 79.5k
- Fork
- 12.7k
- Merge trung bình
- 11 ngày 19 giờ
- Pull request đã merge (30 ngày)
- 5
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của shareAI-lab/learn-claude-code
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
shareAI-lab/learn-claude-code#583 ·
Maintainer thường phản hồi trong vòng 15 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
shareAI-lab/learn-claude-code#528 ·
Maintainer thường phản hồi trong vòng 15 ngày
-
s17: IDLE teammates cannot resume their own in-progress tasksCó thể đã có người làm @hichipli đã nhận 61 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
shareAI-lab/learn-claude-code#519 ·
Maintainer thường phản hồi trong vòng 15 ngày
-
plan_approval_response 不会唤醒 idle teammateCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
shareAI-lab/learn-claude-code#455 ·
Maintainer thường phản hồi trong vòng 15 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 52/100
shareAI-lab/learn-claude-code#605 ·
Maintainer thường phản hồi trong vòng 15 ngày
Tất cả issue của shareAI-lab/learn-claude-code
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
BCDA-APS/polar-bits#93 ·
-
infer_audio_type only recognises one MPEG Layer III frame header, so most MP3 files are rejectedCó thể đã có người làm @Steve-20-ai đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[BUG] - ssh_config `Match tagged` statement always appliesCó thể đã có người làm @AtharvRG đã nhận hôm nay. Đang mởBug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
paramiko/paramiko#2715 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 9 ngày
-
auto-rejected intake mcp-intake needs-salvage priority:high type:feature
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
Ikalus1988/MisakaNet#4221 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày