update
This commit is contained in:
@@ -597,6 +597,32 @@ def _sink_json(result, path: Path, schema):
|
||||
return val
|
||||
|
||||
|
||||
def _sink_subs(result, path: Path):
|
||||
"""Finder reply as TEXT (marker format), persisted to `path` for audit/diagnosis.
|
||||
File fallback: a tool-capable agent (thema web mode) that wrote the file despite the
|
||||
text instruction still counts — same tolerance as _sink_or_file."""
|
||||
text = _reply_text(result).strip()
|
||||
d = _parse_subblocks(text)
|
||||
if d:
|
||||
atomic_write_text(path, text)
|
||||
return d
|
||||
return _parse_subblocks(_read(path)) or None
|
||||
|
||||
|
||||
def _finder_material(folder, sources: list[str] | None, queries: list[str]) -> tuple[str, str, str]:
|
||||
"""→ (material, backing, caps) for the Subblock-Research prompt. uni/projekt: corpus
|
||||
excerpts INLINE — the finder had neither path nor excerpts and hunted the material per
|
||||
call via glob/grep/bash (measured: 3–13 tool rounds, 52–141 s vs 15–35 s single-shot).
|
||||
thema (or excerpt miss): web research as before, fail-open."""
|
||||
ev = _evidence_pack(folder, sources, queries) if folder else ""
|
||||
if ev:
|
||||
material = "\n" + _prompt("Blocks-Source-Inline", excerpts=ev) + "\n"
|
||||
backing = ("Backed by the SOURCE EXCERPTS above, not invented — leave out any "
|
||||
"sub-point the excerpts do not support.")
|
||||
return material, backing, "none"
|
||||
return "", "Backed, not invented. Verify uncertain points via web search.", ("files" if folder else "full")
|
||||
|
||||
|
||||
def _build_research_prompt(topic: str, out_path: Path, instructions: str, type: str, folder: Path | None, fokus: str = "", section: str = "") -> str:
|
||||
if section:
|
||||
# Section mode (uni/projekt): text directly in the prompt → small context, no file reading.
|
||||
@@ -760,15 +786,15 @@ async def _subblocks_block(ctx: GenContext, set_p, files: dict, entries: dict, i
|
||||
return ("\n\nBEREITS ERFASST — liste diese NICHT erneut. Finde nur, was FEHLT:\n" + "\n".join(known))
|
||||
|
||||
# ONE finder round (3 slots, quorum 2) → count of NEW sub norms; None = no result/cancel.
|
||||
async def _one_round(label, subset, assignment, paths, keys, known, extra_instr):
|
||||
async def _one_round(label, subset, assignment, paths, keys, known, extra_instr, material, backing, round_caps):
|
||||
chunk_idx = _title_index({num: title_by_num[num] for num in subset})
|
||||
for p in paths:
|
||||
p.unlink(missing_ok=True)
|
||||
slots = [{
|
||||
"key": k,
|
||||
"prompt": _prompt("Subblock-Research", topic=topic, assignment=assignment, known=known, out_path=p, extra=_extra(extra_instr)),
|
||||
"role": "quick", "capabilities": caps,
|
||||
"payload": (lambda result, p=p: _parse_subblocks(_read(p)) or None),
|
||||
"prompt": _prompt("Subblock-Research", topic=topic, assignment=assignment, known=known, material=material, backing=backing, extra=_extra(extra_instr)),
|
||||
"role": "quick", "capabilities": round_caps,
|
||||
"payload": (lambda result, p=p: _sink_subs(result, p)),
|
||||
} for k, p in zip(keys, paths)]
|
||||
agent_texts = await _race(topic, label, slots, 2, _timeout("subblock", len(subset)), provider, cancelled=is_cancelled, grace=CONSENSUS_GRACE)
|
||||
if is_cancelled() or not agent_texts:
|
||||
@@ -818,6 +844,10 @@ async def _subblocks_block(ctx: GenContext, set_p, files: dict, entries: dict, i
|
||||
# Phase "Subblocks find": per package loop until 0 new subs / time cap.
|
||||
async def _find(c, chunk):
|
||||
assignment = "\n".join(f"- {entries[num]}" for num in chunk)
|
||||
# Material once per package (excerpts are round-invariant; one query per block
|
||||
# keeps the coverage guarantee of _evidence_pack).
|
||||
material, backing, round_caps = await asyncio.to_thread(
|
||||
_finder_material, folder, sources, [str(entries[num]) for num in chunk])
|
||||
start = time.monotonic()
|
||||
round_n = 0
|
||||
while not is_cancelled():
|
||||
@@ -825,7 +855,7 @@ async def _subblocks_block(ctx: GenContext, set_p, files: dict, entries: dict, i
|
||||
bekannt = await _known_block(chunk) if round_n > 1 else ""
|
||||
paths = [work_dir / f"subblock-c{c}-r{round_n}-{i}.md" for i in (1, 2, 3)]
|
||||
keys = [f"blocks-{topic}-{ns}subblock-c{c}-r{round_n}-{i}" for i in (1, 2, 3)]
|
||||
new = await _one_round(f"{lbl}Subblocks package {c} R{round_n}", chunk, assignment, paths, keys, bekannt, instructions)
|
||||
new = await _one_round(f"{lbl}Subblocks package {c} R{round_n}", chunk, assignment, paths, keys, bekannt, instructions, material, backing, round_caps)
|
||||
if new is None:
|
||||
if is_cancelled():
|
||||
return False
|
||||
@@ -1067,9 +1097,11 @@ async def _subblocks_block(ctx: GenContext, set_p, files: dict, entries: dict, i
|
||||
focus = (instructions + "\n\nDieser Block hat bisher nur sehr wenige belegte "
|
||||
"Subbausteine. Suche gezielt nach WEITEREN belegbaren Kernaspekten, die "
|
||||
"oben fehlen. Nimm NUR auf, was die Quellen wirklich hergeben — nicht aufblähen.")
|
||||
material, backing, round_caps = await asyncio.to_thread(
|
||||
_finder_material, folder, sources, [str(entries[num]) for num in lacking])
|
||||
paths = [work_dir / f"subblock-x{k}-c{c}-{i}.md" for i in (1, 2, 3)]
|
||||
keys = [f"blocks-{topic}-{ns}subblock-x{k}-c{c}-{i}" for i in (1, 2, 3)]
|
||||
new = await _one_round(f"{lbl}Subblocks catch-up {c} X{k}", lacking, assignment, paths, keys, known, focus)
|
||||
new = await _one_round(f"{lbl}Subblocks catch-up {c} X{k}", lacking, assignment, paths, keys, known, focus, material, backing, round_caps)
|
||||
if not new:
|
||||
return
|
||||
await _select(lacking, keep_consensus=True)
|
||||
@@ -1412,12 +1444,14 @@ async def _luecken_runde(ctx: GenContext, files: dict, title: str, luecken: list
|
||||
"Aspekten des Blocks — nichts anderes:\n" + "\n".join(f"- {l}" for l in luecken))
|
||||
known = ("\n\nBEREITS ERFASST — liste diese NICHT erneut:\n"
|
||||
+ "\n".join(f"- {s}" for s in have)) if have else ""
|
||||
material, backing, caps = await asyncio.to_thread(
|
||||
_finder_material, folder, sources, [title] + list(luecken))
|
||||
paths = [work_dir / f"luecken-{ns}r1-{i}.md" for i in (1, 2, 3)]
|
||||
slots = [{
|
||||
"key": f"blocks-{topic}-{ns}luecken-r1-{i}",
|
||||
"prompt": _prompt("Subblock-Research", topic=topic, assignment=f"- {title}", known=known, out_path=p, extra=_extra(focus)),
|
||||
"role": "quick", "capabilities": "files" if folder else "full",
|
||||
"payload": (lambda result, p=p: _parse_subblocks(_read(p)) or None),
|
||||
"prompt": _prompt("Subblock-Research", topic=topic, assignment=f"- {title}", known=known, material=material, backing=backing, extra=_extra(focus)),
|
||||
"role": "quick", "capabilities": caps,
|
||||
"payload": (lambda result, p=p: _sink_subs(result, p)),
|
||||
} for i, p in zip((1, 2, 3), paths)]
|
||||
agent_texts = await _race(topic, f"{lbl}Lücken-Nachfass", slots, 2,
|
||||
_timeout("subblock", 1), provider, cancelled=is_cancelled, grace=CONSENSUS_GRACE)
|
||||
|
||||
Reference in New Issue
Block a user