#!/usr/bin/env python3"""notes_pack.py — 参照メモをセクション単位でバイト予算内に詰める"""import reimport sysfrom pathlib import PathHEADING = re.compile(r"^##\s+(.+)$")def split_sections(text: str): """先頭の前文と ## 単位の節に分解する""" lines = text.splitlines(keepends=True) preamble, sections = [], [] current = None for line in lines: m = HEADING.match(line) if m: if current: sections.append(current) current = {"title": m.group(1).strip(), "body": [line]} elif current: current["body"].append(line) else: preamble.append(line) if current: sections.append(current) for s in sections: s["text"] = "".join(s["body"]) s["bytes"] = len(s["text"].encode("utf-8")) return "".join(preamble), sectionsdef pack(path: Path, budget: int, keep_titles=()): text = path.read_text(encoding="utf-8") preamble, sections = split_sections(text) out, used, dropped = [], len(preamble.encode("utf-8")), [] # ① 明示的に必須と指定された節を先に確保する pinned = [s for s in sections if any(k in s["title"] for k in keep_titles)] rest = [s for s in sections if s not in pinned] for s in pinned + rest: if used + s["bytes"] <= budget: out.append(s) used += s["bytes"] else: dropped.append(s["title"]) # ② 途中で切らず、節ごと落とす body = preamble + "".join(s["text"] for s in out) return body, used, droppedif __name__ == "__main__": src = Path(sys.argv[1]) budget = int(sys.argv[2]) if len(sys.argv) > 2 else 20000 keep = sys.argv[3].split(",") if len(sys.argv) > 3 else [] body, used, dropped = pack(src, budget, keep) sys.stdout.write(body) # ③ 落とした節は必ず stderr に出す(沈黙させない) if dropped: sys.stderr.write( f"[notes_pack] {src.name}: {used}/{budget} bytes, " f"dropped {len(dropped)} sections: {', '.join(dropped[:5])}\n" )
予算そのものは、渡す先の窓ではなく本題の指示を基準に決めました。私は「参照メモの合計が指示文の3倍を超えたら予算を絞る」という目安を使っています。参照が指示を圧倒すると、エージェントは資料の要約に流れて、依頼した作業の優先順位を落とします。長い添付が本題を薄める現象は長い PDF を読み飛ばす問題と引用を強制する検証ゲートで扱われているものと同じ構図で、渡し方の側から見ると「入れすぎない予算」がその第一の対策になります。