Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,24 @@


def build_entity_context(entity: Entity) -> EntitySQLContext:
"""Convert an Entity SDK object to schema + derived query patterns."""
"""Convert an Entity SDK object to schema + derived query patterns.

Auto-added system/audit fields (Id, CreateTime, UpdateTime, CreatedBy,
UpdatedBy) are surfaced in the schema, tagged ``system`` via
:attr:`FieldSchema.is_system_field`, but are always excluded from the
derived query patterns so the examples reference only business fields.
"""
field_schemas: list[FieldSchema] = []
# Query patterns are derived from business fields only — system fields,
# even when surfaced in the schema, must never drive an example query.
business_field_names: list[str] = []
numeric_field: str | None = None
text_field: str | None = None

for field in entity.fields or []:
if field.is_hidden_field or field.is_system_field:
if field.is_hidden_field:
continue
is_system = field.is_system_field
type_name = field.sql_type.name if field.sql_type else "unknown"
fs = FieldSchema(
name=field.name,
Expand All @@ -45,15 +55,19 @@ def build_entity_context(entity: Entity) -> EntitySQLContext:
is_required=field.is_required,
is_unique=field.is_unique,
nullable=not field.is_required,
is_system_field=is_system,
)
field_schemas.append(fs)

if is_system:
continue
business_field_names.append(fs.name)
if not numeric_field and fs.is_numeric:
numeric_field = fs.name
if not text_field and fs.is_text:
text_field = fs.name

field_names = [f.name for f in field_schemas]
field_names = business_field_names
table = entity.name

group_field = text_field or (field_names[0] if field_names else "Category")
Expand Down Expand Up @@ -172,11 +186,11 @@ def format_sql_context(ctx: SQLContext) -> str:
if entity.description:
lines.append(f"_{entity.description}_")
lines.append("")
lines.append("| Field | Type |")
lines.append("|-------|------|")

lines.append("| Field | Type | Description |")
lines.append("|-------|------|-------------|")
for field in entity.fields:
lines.append(f"| {field.name} | {field.display_type} |")
desc = (field.description or "").replace("|", r"\|").replace("\n", " ")
lines.append(f"| {field.name} | {field.display_type} | {desc} |")

lines.append("")

Expand Down
3 changes: 3 additions & 0 deletions src/uipath_langchain/agent/tools/datafabric_tool/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ class FieldSchema(BaseModel):
is_required: bool = False
is_unique: bool = False
nullable: bool = True
is_system_field: bool = False

@property
def display_type(self) -> str:
"""Type string with modifiers for markdown display."""
modifiers = []
if self.is_required:
modifiers.append("required")
if self.is_system_field:
modifiers.append("system")
if modifiers:
return f"{self.type}, {', '.join(modifiers)}"
return self.type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
customer_name, order_date, etc.
e. Double-check: does every field in your SELECT directly appear in the \
answer the user expects?
f. SYSTEM / AUDIT FIELDS — the schema may include auto-added system fields \
tagged ``system`` (e.g. a record identifier or created/updated bookkeeping \
columns). Use field names and descriptions to decide which field the question \
refers to; when a business (non-system) field overlaps a system field's \
concept and it is unclear which to use — prefer the BUSINESS field.
4. WHERE FILTERS — What predicates belong in WHERE? What are the exact values \
to filter on?
5. VALUE RESOLUTION — Before finalising any equality / IN filter on a textual \
Expand Down
52 changes: 50 additions & 2 deletions tests/agent/tools/test_datafabric_prompt_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def _fake_field(**overrides):
return SimpleNamespace(
defaults = dict(
name="status",
display_name="Status",
sql_type=SimpleNamespace(name="varchar"),
Expand All @@ -19,8 +19,9 @@ def _fake_field(**overrides):
is_unique=False,
is_hidden_field=False,
is_system_field=False,
**overrides,
)
defaults.update(overrides)
return SimpleNamespace(**defaults)


def _fake_entity(*fields, **overrides):
Expand Down Expand Up @@ -57,3 +58,50 @@ def test_build_includes_domain_guidance_in_rendered_prompt():

assert "## Domain Guidance" in prompt
assert "Use business-friendly ticket language." in prompt


def _system_field(name, type_name="datetimeoffset", **overrides):
"""A fake auto-added system/audit field (Id, CreateTime, ...)."""
return _fake_field(
name=name,
display_name=name,
sql_type=SimpleNamespace(name=type_name),
description="System built-in field",
is_system_field=True,
allowed_values=None,
examples=None,
good_for_aggregation=False,
good_for_grouping=False,
good_for_filtering=False,
**overrides,
)


def test_surfaces_tagged_system_fields_with_descriptions():
"""System fields are surfaced, tagged ``system``, in a Description-column table."""
entity = _fake_entity(
_fake_field(name="status"),
_system_field("CreateTime"),
_system_field("CreatedBy", type_name="uniqueidentifier"),
)
prompt = build([entity])

assert "| Field | Type | Description |" in prompt
assert "| CreateTime | datetimeoffset, system |" in prompt
assert "System built-in field" in prompt
# system/audit field-selection guidance is part of the prompt
assert "SYSTEM / AUDIT FIELDS" in prompt


def test_query_patterns_exclude_system_fields():
"""Surfaced system fields must never drive the derived query patterns."""
entity = _fake_entity(
_fake_field(name="status"),
_system_field("CreateTime"),
_system_field("Id", type_name="uniqueidentifier"),
)
prompt = build([entity])

patterns_block = prompt.split("Query Patterns for Ticket", 1)[1]
assert "CreateTime" not in patterns_block
assert "Id" not in patterns_block
Loading