feat: strengthen validation logic when loading
This commit is contained in:
@@ -35,15 +35,8 @@ def _build_appendices() -> str:
|
||||
# Shared appendices — appended to every coding node's system prompt.
|
||||
_appendices = _build_appendices()
|
||||
|
||||
# GCU first-class section (when GCU is enabled).
|
||||
# Placed prominently in the main prompt body, not as an appendix.
|
||||
_gcu_building_section = (
|
||||
("\n\n# GCU Nodes — Browser Automation\n\n" + _gcu_guide)
|
||||
if _is_gcu_enabled() and _gcu_guide
|
||||
else ""
|
||||
)
|
||||
|
||||
_gcu_planning_section = (
|
||||
# GCU guide — shared between planning and building via _shared_building_knowledge.
|
||||
_gcu_section = (
|
||||
("\n\n# GCU Nodes — Browser Automation\n\n" + _gcu_guide)
|
||||
if _is_gcu_enabled() and _gcu_guide
|
||||
else ""
|
||||
@@ -166,7 +159,7 @@ generate a clickable file URI for the user
|
||||
|
||||
IMPORTANT: Do NOT tell workers to use read_file, write_file, edit_file, \
|
||||
search_files, or list_directory — those are YOUR tools, not theirs.
|
||||
"""
|
||||
""" + _gcu_section
|
||||
|
||||
_planning_knowledge = """\
|
||||
**A responsible engineer doesn't jump into building. First, \
|
||||
@@ -1020,7 +1013,6 @@ queen_node = NodeSpec(
|
||||
_queen_identity_building
|
||||
+ _queen_style
|
||||
+ _package_builder_knowledge
|
||||
+ _gcu_building_section # GCU as first-class citizen (not appendix)
|
||||
+ _queen_tools_docs
|
||||
+ _queen_behavior
|
||||
+ _queen_phase_7
|
||||
@@ -1062,6 +1054,5 @@ __all__ = [
|
||||
"_building_knowledge",
|
||||
"_package_builder_knowledge",
|
||||
"_appendices",
|
||||
"_gcu_building_section",
|
||||
"_gcu_planning_section",
|
||||
"_gcu_section",
|
||||
]
|
||||
|
||||
@@ -41,8 +41,6 @@ async def create_queen(
|
||||
_QUEEN_STAGING_TOOLS,
|
||||
_appendices,
|
||||
_building_knowledge,
|
||||
_gcu_building_section,
|
||||
_gcu_planning_section,
|
||||
_planning_knowledge,
|
||||
_shared_building_knowledge,
|
||||
_queen_behavior_always,
|
||||
@@ -156,7 +154,6 @@ async def create_queen(
|
||||
+ _queen_behavior_always
|
||||
+ _queen_behavior_planning
|
||||
+ _planning_knowledge
|
||||
+ _gcu_planning_section
|
||||
+ worker_identity
|
||||
)
|
||||
phase_state.prompt_planning = _queen_identity_planning + _planning_body
|
||||
@@ -168,7 +165,6 @@ async def create_queen(
|
||||
+ _queen_behavior_always
|
||||
+ _queen_behavior_building
|
||||
+ _building_knowledge
|
||||
+ _gcu_building_section
|
||||
+ _queen_phase_7
|
||||
+ _appendices
|
||||
+ worker_identity
|
||||
|
||||
@@ -1623,7 +1623,39 @@ def register_queen_lifecycle_tools(
|
||||
)
|
||||
info = updated_session.worker_info
|
||||
|
||||
# Switch to staging phase after successful load
|
||||
# Validate that all tools declared by nodes are registered
|
||||
loaded_runtime = _get_runtime()
|
||||
if loaded_runtime is not None:
|
||||
available_tool_names = {t.name for t in loaded_runtime._tools}
|
||||
missing_by_node: dict[str, list[str]] = {}
|
||||
for node in loaded_runtime.graph.nodes:
|
||||
if node.tools:
|
||||
missing = set(node.tools) - available_tool_names
|
||||
if missing:
|
||||
missing_by_node[f"{node.name} (id={node.id})"] = sorted(
|
||||
missing
|
||||
)
|
||||
if missing_by_node:
|
||||
# Unload the broken worker
|
||||
try:
|
||||
await session_manager.unload_worker(manager_session_id)
|
||||
except Exception:
|
||||
pass
|
||||
details = "; ".join(
|
||||
f"Node '{k}' missing {v}"
|
||||
for k, v in missing_by_node.items()
|
||||
)
|
||||
return json.dumps(
|
||||
{
|
||||
"error": (
|
||||
f"Tool validation failed: {details}. "
|
||||
"Fix node tool declarations or add the missing "
|
||||
"tools, then try loading again."
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Switch to staging phase after successful load + validation
|
||||
if phase_state is not None:
|
||||
await phase_state.switch_to_staging()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user