rebase
This commit is contained in:
146
app/engine/tools/schema_tools.py
Normal file
146
app/engine/tools/schema_tools.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""Schema tools for world_editor — add/modify/remove entity types and fields."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from app.engine.tools.base import Tool, ToolContext, ToolResult
|
||||
|
||||
|
||||
def _find_schema(world_schemas: list[dict], type_name: str) -> dict | None:
|
||||
for s in world_schemas:
|
||||
if s.get("type") == type_name:
|
||||
return s
|
||||
return None
|
||||
|
||||
|
||||
class SchemaAddTypeTool(Tool):
|
||||
name = "schema_add_type"
|
||||
category = "schema"
|
||||
stages = {"world_builder", "world_editor"}
|
||||
description = "Add a new entity type to world.schemas."
|
||||
parameters_schema = {
|
||||
"type": "object",
|
||||
"required": ["type", "verbose", "plural", "properties"],
|
||||
"properties": {
|
||||
"type": {"type": "string", "pattern": "^[a-z][a-z0-9_]*$"},
|
||||
"verbose": {"type": "string"},
|
||||
"plural": {"type": "string"},
|
||||
"properties": {"type": "array", "items": {"type": "object"}},
|
||||
},
|
||||
}
|
||||
|
||||
async def execute(self, arguments: dict[str, Any], ctx: ToolContext) -> ToolResult:
|
||||
type_name = arguments.get("type")
|
||||
schemas = list(ctx.world.schemas or [])
|
||||
if _find_schema(schemas, type_name):
|
||||
return ToolResult(
|
||||
ok=False, error_code="name_conflict",
|
||||
error_message=f"Type {type_name!r} already exists",
|
||||
)
|
||||
schemas.append({
|
||||
"type": type_name,
|
||||
"verbose": arguments.get("verbose"),
|
||||
"plural": arguments.get("plural"),
|
||||
"properties": arguments.get("properties") or [],
|
||||
})
|
||||
ctx.world.schemas = schemas
|
||||
await ctx.db.flush()
|
||||
return ToolResult(ok=True, data={"type": type_name}, message=f"Type {type_name!r} added")
|
||||
|
||||
|
||||
class SchemaAddFieldTool(Tool):
|
||||
name = "schema_add_field"
|
||||
category = "schema"
|
||||
stages = {"world_builder", "world_editor"}
|
||||
description = "Add a field to an existing entity type."
|
||||
parameters_schema = {
|
||||
"type": "object",
|
||||
"required": ["entity_type", "field"],
|
||||
"properties": {
|
||||
"entity_type": {"type": "string"},
|
||||
"field": {"type": "object"},
|
||||
},
|
||||
}
|
||||
|
||||
async def execute(self, arguments: dict[str, Any], ctx: ToolContext) -> ToolResult:
|
||||
et = arguments.get("entity_type")
|
||||
field = arguments.get("field") or {}
|
||||
schemas = list(ctx.world.schemas or [])
|
||||
s = _find_schema(schemas, et)
|
||||
if s is None:
|
||||
return ToolResult(ok=False, error_code="not_found",
|
||||
error_message=f"Type {et!r} not found")
|
||||
props = list(s.get("properties") or [])
|
||||
if any(p.get("name") == field.get("name") for p in props):
|
||||
return ToolResult(ok=False, error_code="name_conflict",
|
||||
error_message=f"Field {field.get('name')!r} already exists")
|
||||
props.append(field)
|
||||
s["properties"] = props
|
||||
ctx.world.schemas = schemas
|
||||
await ctx.db.flush()
|
||||
return ToolResult(ok=True, data={"type": et, "field": field.get("name")},
|
||||
message=f"Field added to {et!r}")
|
||||
|
||||
|
||||
class SchemaRemoveFieldTool(Tool):
|
||||
name = "schema_remove_field"
|
||||
category = "schema"
|
||||
stages = {"world_builder", "world_editor"}
|
||||
description = "Remove a field from an entity type."
|
||||
parameters_schema = {
|
||||
"type": "object",
|
||||
"required": ["entity_type", "field_name"],
|
||||
"properties": {
|
||||
"entity_type": {"type": "string"},
|
||||
"field_name": {"type": "string"},
|
||||
},
|
||||
}
|
||||
|
||||
async def execute(self, arguments: dict[str, Any], ctx: ToolContext) -> ToolResult:
|
||||
et = arguments.get("entity_type")
|
||||
fn = arguments.get("field_name")
|
||||
schemas = list(ctx.world.schemas or [])
|
||||
s = _find_schema(schemas, et)
|
||||
if s is None:
|
||||
return ToolResult(ok=False, error_code="not_found",
|
||||
error_message=f"Type {et!r} not found")
|
||||
props = [p for p in (s.get("properties") or []) if p.get("name") != fn]
|
||||
s["properties"] = props
|
||||
ctx.world.schemas = schemas
|
||||
await ctx.db.flush()
|
||||
return ToolResult(ok=True, data={"removed": fn}, message=f"Field {fn!r} removed from {et!r}")
|
||||
|
||||
|
||||
class SchemaModifyFieldTool(Tool):
|
||||
name = "schema_modify_field"
|
||||
category = "schema"
|
||||
stages = {"world_builder", "world_editor"}
|
||||
description = "Modify an existing field of an entity type."
|
||||
parameters_schema = {
|
||||
"type": "object",
|
||||
"required": ["entity_type", "field_name", "changes"],
|
||||
"properties": {
|
||||
"entity_type": {"type": "string"},
|
||||
"field_name": {"type": "string"},
|
||||
"changes": {"type": "object"},
|
||||
},
|
||||
}
|
||||
|
||||
async def execute(self, arguments: dict[str, Any], ctx: ToolContext) -> ToolResult:
|
||||
et = arguments.get("entity_type")
|
||||
fn = arguments.get("field_name")
|
||||
changes = arguments.get("changes") or {}
|
||||
schemas = list(ctx.world.schemas or [])
|
||||
s = _find_schema(schemas, et)
|
||||
if s is None:
|
||||
return ToolResult(ok=False, error_code="not_found",
|
||||
error_message=f"Type {et!r} not found")
|
||||
for p in (s.get("properties") or []):
|
||||
if p.get("name") == fn:
|
||||
p.update(changes)
|
||||
ctx.world.schemas = schemas
|
||||
await ctx.db.flush()
|
||||
return ToolResult(ok=True, data=p, message=f"Field {fn!r} modified")
|
||||
return ToolResult(ok=False, error_code="not_found",
|
||||
error_message=f"Field {fn!r} not found in {et!r}")
|
||||
Reference in New Issue
Block a user