Fix problemas detectados en evaluación: historial, prompting, artifacts
1. Task history preserva key_data estructurado (recordNums, sectionIds, moduleIds, pages) extraído de las tool executions reales — el modelo retiene contexto entre tasks sin re-consultar. 2. Coder system prompt mejorado: instrucciones explícitas sobre qué tool usar para cada operación (create_module vs create_or_update_record), consultar knowledge base antes de actuar, y reutilizar key_data del historial. 3. Eliminado artifact_memory y working_context del coder context_sections — ya no son necesarios con conversación real. Reduce acumulación de artifacts en el context. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -398,6 +398,20 @@ class ContextEngine:
|
||||
lines.append(f" Result: {summary}")
|
||||
if facts:
|
||||
lines.append(f" Facts: {'; '.join(facts[:5])}")
|
||||
# Key structured data (recordNums, sectionIds, etc.)
|
||||
key_data = entry.get("key_data", {})
|
||||
if key_data:
|
||||
kd_parts = []
|
||||
for table, nums in key_data.get("tables", {}).items():
|
||||
kd_parts.append(f"{table}: records {nums}")
|
||||
for page, num in key_data.get("pages", {}).items():
|
||||
kd_parts.append(f"page '{page}' = record {num}")
|
||||
if key_data.get("sections"):
|
||||
kd_parts.append(f"sections: {key_data['sections']}")
|
||||
if key_data.get("modules"):
|
||||
kd_parts.append(f"modules: {key_data['modules']}")
|
||||
if kd_parts:
|
||||
lines.append(f" Key data: {'; '.join(kd_parts)}")
|
||||
review = entry.get("review", "")
|
||||
if review:
|
||||
lines.append(f" Review: {review[:100]}")
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
from ...models.agent import AgentProfile, AgentRole
|
||||
from .base import BaseAgent
|
||||
|
||||
CODER_SYSTEM_PROMPT = """Eres un Agente Programador. Tu rol es ejecutar tareas de implementación usando las herramientas disponibles.
|
||||
CODER_SYSTEM_PROMPT = """Eres un Agente Programador de Acai CMS. Tu rol es ejecutar tareas de implementación usando las herramientas MCP disponibles.
|
||||
|
||||
## Instrucciones
|
||||
- Concéntrate en la descripción del paso actual.
|
||||
@@ -16,9 +16,17 @@ CODER_SYSTEM_PROMPT = """Eres un Agente Programador. Tu rol es ejecutar tareas d
|
||||
- Responde SIEMPRE en español.
|
||||
|
||||
## Uso de herramientas
|
||||
- Usa herramientas cuando necesites leer archivos, escribir código o ejecutar comandos.
|
||||
- Los resultados de herramientas se te presentarán resumidos — no verás la salida cruda.
|
||||
- Si necesitas más detalle de un resultado, solicita rehidratación.
|
||||
- CONSULTA la Knowledge Base ANTES de actuar — tiene la referencia completa de tools y flujos de trabajo.
|
||||
- Para CREAR MÓDULOS usa `create_module` (crea archivos en filesystem), NUNCA `create_or_update_record` en tabla modulos.
|
||||
- Para GESTIONAR REGISTROS de tablas (apartados, travesias, etc.) usa `create_or_update_record`.
|
||||
- Para ESCRIBIR ARCHIVOS usa `acai_write` o `acai_line_replace`.
|
||||
- Tras crear un módulo, SIEMPRE sigue el flujo: create_module → add_module_to_record → set_module_config_vars.
|
||||
- tableName siempre SIN prefijo cms_ (ej: apartados, NO cms_apartados).
|
||||
- La primary key es siempre `num`, nunca `id`.
|
||||
|
||||
## Datos del historial
|
||||
- Si el historial de sesión incluye Key Data con recordNums o sectionIds, ÚSALOS directamente sin re-consultar.
|
||||
- Ejemplo: si el historial dice "pages: Inicio = record 2", usa recordNum=2 para la portada.
|
||||
"""
|
||||
|
||||
|
||||
@@ -35,8 +43,6 @@ def create_coder_profile() -> AgentProfile:
|
||||
"project_profile",
|
||||
"knowledge_base",
|
||||
"task_state",
|
||||
"artifact_memory",
|
||||
"working_context",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -296,12 +296,16 @@ class OrchestratorEngine:
|
||||
for step in task.plan:
|
||||
tools_used.update(step.tools_used)
|
||||
|
||||
# Extract key structured data from tool executions
|
||||
key_data = self._extract_key_data_from_results(results)
|
||||
|
||||
history_entry = {
|
||||
"task_id": task.task_id,
|
||||
"objective": task.objective,
|
||||
"status": task.status.value,
|
||||
"steps": len(task.plan),
|
||||
"facts": task.facts_extracted[-10:],
|
||||
"key_data": key_data,
|
||||
"tools_used": list(tools_used)[:10],
|
||||
"artifacts_count": len(task_artifacts),
|
||||
"summary": "; ".join(step_summaries)[:300],
|
||||
@@ -327,6 +331,73 @@ class OrchestratorEngine:
|
||||
task.task_id, len(task.facts_extracted), len(tools_used), len(task_artifacts),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _extract_key_data_from_results(results: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
"""Extract structured data from tool executions for task history.
|
||||
|
||||
Preserves key identifiers (recordNum, sectionId, tableName, moduleId)
|
||||
so the model retains context across tasks without re-querying.
|
||||
"""
|
||||
key_data: dict[str, Any] = {}
|
||||
seen_tables: dict[str, list[int]] = {} # tableName -> recordNums
|
||||
seen_sections: list[str] = []
|
||||
seen_modules: list[str] = []
|
||||
seen_pages: dict[str, int] = {} # page name/url -> recordNum
|
||||
|
||||
for result in results:
|
||||
for te in result.get("tool_executions", []):
|
||||
args = te.arguments
|
||||
name = te.tool_name
|
||||
|
||||
# Track table + record relationships
|
||||
table = args.get("tableName", "")
|
||||
record = args.get("recordNum")
|
||||
if table and record:
|
||||
record_int = int(record) if str(record).isdigit() else None
|
||||
if record_int and table not in seen_tables:
|
||||
seen_tables[table] = []
|
||||
if record_int and record_int not in seen_tables.get(table, []):
|
||||
seen_tables[table].append(record_int)
|
||||
|
||||
# Track section IDs
|
||||
section = args.get("sectionId", "")
|
||||
if section and section not in seen_sections:
|
||||
seen_sections.append(section)
|
||||
|
||||
# Track modules
|
||||
module = args.get("moduleId", "") or args.get("moduleName", "")
|
||||
if module and module not in seen_modules:
|
||||
seen_modules.append(module)
|
||||
|
||||
# Extract page info from raw output (enlace, name)
|
||||
if te.raw_output and "enlace" in te.raw_output:
|
||||
try:
|
||||
import json as _json
|
||||
# Try to parse structured data from output
|
||||
for line in te.raw_output.splitlines():
|
||||
line = line.strip()
|
||||
if line.startswith("{"):
|
||||
try:
|
||||
data = _json.loads(line)
|
||||
if "enlace" in data and "num" in data:
|
||||
page_key = data.get("name", data["enlace"])
|
||||
seen_pages[page_key] = int(data["num"])
|
||||
except _json.JSONDecodeError:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if seen_tables:
|
||||
key_data["tables"] = {t: nums[:10] for t, nums in seen_tables.items()}
|
||||
if seen_sections:
|
||||
key_data["sections"] = seen_sections[:20]
|
||||
if seen_modules:
|
||||
key_data["modules"] = seen_modules[:20]
|
||||
if seen_pages:
|
||||
key_data["pages"] = dict(list(seen_pages.items())[:20])
|
||||
|
||||
return key_data
|
||||
|
||||
def _maybe_compact_previous_steps(
|
||||
self, task: TaskState, current_index: int
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user