shareAI-lab / shareAI-lab/learn-claude-code
s09: select_relevant_memories 的 "recent" 拼接顺序与切片不合理,不是真正的最近 2k 上下文
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 77.2k
- Forks
- 12.4k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 6
Description
问题
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" 是尾部,不是头部。
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in s09_memory/code.py at recent_user_text, especially lines 251-261, and inspect how user messages are collected, joined, and sliced. Verify the chosen behavior with short and long recent turns; done means the returned context preserves chronological order and includes the tail of the most recent 4000 characters.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- ai
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100