Spaces:
Sleeping
Sleeping
fix: fast 3-agent web demo (Surveyor->Planner->Formatter, ~60s) (#12)
Browse filesResearch loop without real SecondLayer tool access takes 10+ minutes
per iteration (Researcher hallucinates, Reviewer reviews hallucinations).
Web demo now runs Survey+Plan+Format for ~60-90s response time.
Full 15-iteration pipeline remains available via CLI.
Co-authored-by: overthelex <mcvovkes@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -32,71 +32,28 @@ def has_api_keys() -> bool:
|
|
| 32 |
|
| 33 |
|
| 34 |
async def _run_pipeline(question: str):
|
| 35 |
-
"""Run
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
from lmaf.core.config import Config
|
| 37 |
from lmaf.engine import LMAF
|
| 38 |
-
from lmaf.state.research_state import CritiqueStatus
|
| 39 |
|
| 40 |
config = Config.from_env()
|
| 41 |
-
config.max_iterations = 2
|
| 42 |
-
config.critic_every_n = 2
|
| 43 |
lmaf = LMAF(question, config)
|
| 44 |
|
| 45 |
-
yield "Surveyor: аналізую правовий ландшафт..."
|
| 46 |
await lmaf.surveyor.run(lmaf.state)
|
| 47 |
-
lmaf._loop.survey_done = True
|
| 48 |
if lmaf.state.survey_summary:
|
| 49 |
-
yield f"**
|
| 50 |
|
| 51 |
-
yield "Planner: розробляю стратегію дослідження..."
|
| 52 |
await lmaf.planner.run(lmaf.state)
|
| 53 |
-
lmaf._loop.plan_done = True
|
| 54 |
if lmaf.state.strategy.approach:
|
| 55 |
-
yield f"**
|
| 56 |
-
|
| 57 |
-
for iteration in range(1, config.max_iterations + 1):
|
| 58 |
-
lmaf.state.iteration = iteration
|
| 59 |
-
|
| 60 |
-
yield f"Ітерація {iteration}: Orchestrator вирішує наступний крок..."
|
| 61 |
-
orch_result = await lmaf.orchestrator.run(lmaf.state)
|
| 62 |
-
|
| 63 |
-
if not orch_result.success:
|
| 64 |
-
if lmaf._loop.consecutive_failures >= config.max_consecutive_failures:
|
| 65 |
-
yield "Занадто багато послідовних помилок, зупиняюсь."
|
| 66 |
-
break
|
| 67 |
-
continue
|
| 68 |
-
|
| 69 |
-
yield "Researcher: шукаю судову практику та законодавство..."
|
| 70 |
-
agent_result = await lmaf.researcher.run(
|
| 71 |
-
lmaf.state, task_description=orch_result.summary
|
| 72 |
-
)
|
| 73 |
-
if agent_result.success:
|
| 74 |
-
yield f"**Знайдено**: {agent_result.summary[:200]}"
|
| 75 |
|
| 76 |
-
|
| 77 |
-
await lmaf.reviewer.run(lmaf.state)
|
| 78 |
-
|
| 79 |
-
if iteration % config.critic_every_n == 0:
|
| 80 |
-
yield "Critic: аудит стратегії та повноти аналізу..."
|
| 81 |
-
critic_result = await lmaf.critic.run(lmaf.state)
|
| 82 |
-
lmaf._loop.last_critic_iteration = iteration
|
| 83 |
-
|
| 84 |
-
for critique in lmaf.state.active_critiques():
|
| 85 |
-
if critique.type == "strategy":
|
| 86 |
-
await lmaf.planner.run(
|
| 87 |
-
lmaf.state, revision_critique=critique.details
|
| 88 |
-
)
|
| 89 |
-
critique.status = CritiqueStatus.RESOLVED
|
| 90 |
-
|
| 91 |
-
if "можна завершувати: True" in critic_result.summary:
|
| 92 |
-
yield "Critic схвалив -- формую консультацію."
|
| 93 |
-
break
|
| 94 |
-
|
| 95 |
-
if not lmaf.state.open_questions() and not lmaf.state.active_critiques():
|
| 96 |
-
yield "Всі питання вирішено -- формую консультацію."
|
| 97 |
-
break
|
| 98 |
-
|
| 99 |
-
yield "Formatter: оформлюю фінальну консультацію..."
|
| 100 |
await lmaf.formatter.run(lmaf.state)
|
| 101 |
|
| 102 |
yield lmaf.state.answer or "Не вдалося сформувати відповідь."
|
|
@@ -117,15 +74,9 @@ async def stream_chat(message: str, history: list[dict]):
|
|
| 117 |
return
|
| 118 |
|
| 119 |
accumulated = ""
|
| 120 |
-
status_prefixes = (
|
| 121 |
-
"Surveyor", "Planner", "Ітерація", "Researcher",
|
| 122 |
-
"Reviewer", "Critic", "Formatter", "Всі", "Занадто",
|
| 123 |
-
)
|
| 124 |
async for update in _run_pipeline(message):
|
| 125 |
-
if update.startswith("**")
|
| 126 |
accumulated += f"\n\n{update}"
|
| 127 |
-
elif update.startswith(status_prefixes):
|
| 128 |
-
accumulated += f"\n\n__{update}__"
|
| 129 |
else:
|
| 130 |
accumulated = update
|
| 131 |
yield accumulated
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
async def _run_pipeline(question: str):
|
| 35 |
+
"""Run a fast 3-agent pipeline for the web demo.
|
| 36 |
+
|
| 37 |
+
Full research loop (15 iterations) is available via the CLI.
|
| 38 |
+
The web demo runs: Surveyor -> Planner -> Formatter (~60-90s).
|
| 39 |
+
"""
|
| 40 |
from lmaf.core.config import Config
|
| 41 |
from lmaf.engine import LMAF
|
|
|
|
| 42 |
|
| 43 |
config = Config.from_env()
|
|
|
|
|
|
|
| 44 |
lmaf = LMAF(question, config)
|
| 45 |
|
| 46 |
+
yield "**Surveyor**: аналізую правовий ландшафт..."
|
| 47 |
await lmaf.surveyor.run(lmaf.state)
|
|
|
|
| 48 |
if lmaf.state.survey_summary:
|
| 49 |
+
yield f"**Surveyor**: {lmaf.state.survey_summary[:400]}"
|
| 50 |
|
| 51 |
+
yield "**Planner**: розробляю стратегію дослідження..."
|
| 52 |
await lmaf.planner.run(lmaf.state)
|
|
|
|
| 53 |
if lmaf.state.strategy.approach:
|
| 54 |
+
yield f"**Planner**: {lmaf.state.strategy.approach[:400]}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
+
yield "**Formatter**: оформлюю консультацію..."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
await lmaf.formatter.run(lmaf.state)
|
| 58 |
|
| 59 |
yield lmaf.state.answer or "Не вдалося сформувати відповідь."
|
|
|
|
| 74 |
return
|
| 75 |
|
| 76 |
accumulated = ""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
async for update in _run_pipeline(message):
|
| 78 |
+
if update.startswith("**"):
|
| 79 |
accumulated += f"\n\n{update}"
|
|
|
|
|
|
|
| 80 |
else:
|
| 81 |
accumulated = update
|
| 82 |
yield accumulated
|