Rifqi Hafizuddin Claude Opus 5.5 commited on
Commit ·
863bf8e
1
Parent(s): 5595f0e
[NOTICKET] fix(planner): a failed plan is not a data gap (P0-9)
Browse filesTaskList._exhausted (private attr, not in the model's schema) marks a plan
that failed validation on every attempt; the coordinator shows its own text
without the data-gap lead. New EN/ID texts (register "Anda"): the plan failed
its checks, which does not mean the data is missing; ask more specifically.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/agents/planner/schemas.py
CHANGED
|
@@ -13,7 +13,7 @@ from __future__ import annotations
|
|
| 13 |
import re
|
| 14 |
from typing import Any, Literal
|
| 15 |
|
| 16 |
-
from pydantic import BaseModel, Field
|
| 17 |
|
| 18 |
from ..scope.models import ScopeChange
|
| 19 |
|
|
@@ -55,6 +55,11 @@ class Task(BaseModel):
|
|
| 55 |
|
| 56 |
|
| 57 |
class TaskList(BaseModel):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
plan_id: str
|
| 59 |
goal_restated: str
|
| 60 |
assumptions: list[str] = Field(default_factory=list)
|
|
|
|
| 13 |
import re
|
| 14 |
from typing import Any, Literal
|
| 15 |
|
| 16 |
+
from pydantic import BaseModel, Field, PrivateAttr
|
| 17 |
|
| 18 |
from ..scope.models import ScopeChange
|
| 19 |
|
|
|
|
| 55 |
|
| 56 |
|
| 57 |
class TaskList(BaseModel):
|
| 58 |
+
# Set by PlannerService when every attempt failed validation (audit P0-9): the
|
| 59 |
+
# answer then says the PLAN failed, not that the data lacks the measure. Private,
|
| 60 |
+
# so it is not in the structured-output schema the model fills.
|
| 61 |
+
_exhausted: bool = PrivateAttr(default=False)
|
| 62 |
+
|
| 63 |
plan_id: str
|
| 64 |
goal_restated: str
|
| 65 |
assumptions: list[str] = Field(default_factory=list)
|
src/agents/planner/service.py
CHANGED
|
@@ -263,12 +263,14 @@ class PlannerService:
|
|
| 263 |
attempts=self._max_retries,
|
| 264 |
errors=previous_errors,
|
| 265 |
)
|
| 266 |
-
|
| 267 |
plan_id=context.project_id,
|
| 268 |
goal_restated=query,
|
| 269 |
tasks=[],
|
| 270 |
infeasible_reason=_exhausted_reason(reply_language),
|
| 271 |
)
|
|
|
|
|
|
|
| 272 |
|
| 273 |
|
| 274 |
async def plan_analysis(
|
|
@@ -306,17 +308,21 @@ def _schema_error(exc: Exception) -> str:
|
|
| 306 |
#: What the user sees when the planner could not build a valid plan. Deliberately
|
| 307 |
#: says what happened in THEIR terms and does not quote the validator: they cannot
|
| 308 |
#: act on "not a declared foreign key", and it is not their problem.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
_EXHAUSTED_EN = (
|
| 310 |
-
"I
|
| 311 |
-
"
|
| 312 |
-
"
|
| 313 |
-
"
|
| 314 |
)
|
| 315 |
_EXHAUSTED_ID = (
|
| 316 |
-
"Saya belum
|
| 317 |
-
"
|
| 318 |
-
"
|
| 319 |
-
"
|
| 320 |
)
|
| 321 |
|
| 322 |
|
|
|
|
| 263 |
attempts=self._max_retries,
|
| 264 |
errors=previous_errors,
|
| 265 |
)
|
| 266 |
+
exhausted = TaskList(
|
| 267 |
plan_id=context.project_id,
|
| 268 |
goal_restated=query,
|
| 269 |
tasks=[],
|
| 270 |
infeasible_reason=_exhausted_reason(reply_language),
|
| 271 |
)
|
| 272 |
+
exhausted._exhausted = True
|
| 273 |
+
return exhausted
|
| 274 |
|
| 275 |
|
| 276 |
async def plan_analysis(
|
|
|
|
| 308 |
#: What the user sees when the planner could not build a valid plan. Deliberately
|
| 309 |
#: says what happened in THEIR terms and does not quote the validator: they cannot
|
| 310 |
#: act on "not a declared foreign key", and it is not their problem.
|
| 311 |
+
# Audit P0-9 (2026-11-03): these used to blame the data ("the measure may not be in
|
| 312 |
+
# the catalog") and were shown under the data-gap lead, so a chart request right after
|
| 313 |
+
# the user SAW the data read as "the data cannot answer" twice. Exhaustion means the
|
| 314 |
+
# plan failed its own checks — say that. Indonesian register: "Anda" (decision D2).
|
| 315 |
_EXHAUSTED_EN = (
|
| 316 |
+
"I couldn't put together a working analysis for that question — my plan kept "
|
| 317 |
+
"failing its own checks. That does not mean the data is missing. Please ask again "
|
| 318 |
+
"more specifically (name the measure, the period and the unit or site), or split "
|
| 319 |
+
"it into two questions."
|
| 320 |
)
|
| 321 |
_EXHAUSTED_ID = (
|
| 322 |
+
"Saya belum berhasil menyusun analisis untuk pertanyaan itu — setelah beberapa kali "
|
| 323 |
+
"mencoba, rencana analisisnya masih gagal pemeriksaan internal. Ini tidak berarti "
|
| 324 |
+
"datanya tidak ada. Silakan ajukan lagi dengan lebih spesifik (sebutkan ukuran, "
|
| 325 |
+
"periode, dan unit atau site-nya), atau pecah menjadi dua pertanyaan."
|
| 326 |
)
|
| 327 |
|
| 328 |
|