mirror of
https://github.com/NVIDIA-NeMo/DataDesigner
synced 2026-05-24 09:48:29 +00:00
* feat: add agent introspection cli * refactor: remove agent cli schema version * refactor: omit missing builder docstrings from context * refactor: tighten agent cli contract * feat: add schema_text() to ConfigBase for human-readable field summaries ConfigBase.schema_text() returns a concise text representation including the class docstring summary, field names, types, defaults, and descriptions. Field descriptions added to column config types to surface through this method. * refactor: flatten agent CLI into plain functions with text output mode Delete AgentController class and agent_command_defs module. Move all logic into agent_introspection (data) and agent_text_formatter (display) as plain functions. Add --json flag so commands default to human-readable text using schema_text(), with JSON as opt-in. Unify _emit helper, remove include_docstrings parameter, deduplicate catalog calls, and fix N+1 discover_family_types in get_family_schemas. * fix: port stale controller tests and consolidate command descriptions Port test_agent_controller.py to use plain functions instead of deleted AgentController. Extract AGENT_COMMANDS constant as single source for operation descriptions, syncing with main.py help strings. * style: fix ruff formatting in agent_introspection * refactor: centralize agent command definitions Extract AGENT_COMMANDS into agent_command_defs.py so main.py and agent_introspection.py share a single source for command names, help text, and metadata. The new module has no heavy dependencies, keeping --help latency unaffected. * fix: handle default_factory and empty providers in schema_text and introspection - schema_text() now detects default_factory fields and renders e.g. "list()" instead of leaking PydanticUndefined - Guard against IndexError when provider registry has an empty providers list - Add 15 edge-case tests for schema_text covering default_factory, enum defaults, None defaults, scalar defaults, descriptions, and docstrings * refactor: remove JSON output mode from agent CLI commands Text-only output simplifies the interface. Structured output can be added back trivially since the functions already return dicts. * docs: update schema_text docstring to reflect agent focus * fix: include builder section and import_path in agent text output - format_context_text now renders a ## Builder section - format_types_text now includes import_path column in tables * refactor: drop import_path from types tables All config objects are imported via dd.<ClassName>, so the full import path is redundant noise in agent output. * docs: add family definition and import hint to context output * refactor: rename Types section to Families, drop redundant "types" from sub-headers * fix: coerce None to empty string in table cells row.get(col, '') returns None when the key exists with value None, causing str(None) to render "None" in the output. Use `or ''` instead. * refactor: move agent controller tests to utils as introspection integration tests There is no controller layer — these tests exercise functions in agent_introspection.py, so they belong in tests/cli/utils/. * fix: only coerce None to empty string in table cells, not False The previous `or ''` pattern treated all falsy values (including False) as empty. Use an explicit None check so booleans render correctly. * style: address review nits from nabin - Add explicit parentheses to and/or precedence in _build_agent_lazy_group - Rename loop variable l to line in test_schema_text - Move get_family_schema import to module level in test_agent_text_formatter * fix: improve schema_text Literal display, builder signature quotes, and docstring parsing - _format_annotation now renders Literal['value'] instead of bare Literal - _format_signature strips quotes from stringified annotations caused by `from __future__ import annotations` - _get_docstring_summary stops at any Google-style section header, not just Attributes:
65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from typer.testing import CliRunner
|
|
|
|
from data_designer.cli.main import app
|
|
|
|
_PATCH = "data_designer.cli.commands.agent"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"args,data_fn,format_fn,expected_text",
|
|
[
|
|
(["agent", "context"], "get_context", "format_context_text", "Data Designer"),
|
|
(["agent", "types", "columns"], "get_types", "format_types_text", "columns"),
|
|
(["agent", "builder"], "get_builder_api", "format_builder_text", "Builder:"),
|
|
(["agent", "state", "model-aliases"], "get_model_aliases_state", "format_model_aliases_text", "model aliases"),
|
|
(
|
|
["agent", "state", "persona-datasets"],
|
|
"get_persona_datasets_state",
|
|
"format_persona_datasets_text",
|
|
"persona",
|
|
),
|
|
],
|
|
ids=["context", "types", "builder", "model-aliases", "persona-datasets"],
|
|
)
|
|
def test_commands_default_text_mode(args: list[str], data_fn: str, format_fn: str, expected_text: str) -> None:
|
|
runner = CliRunner()
|
|
with (
|
|
patch(f"{_PATCH}.{data_fn}", return_value={"stub": True}) as mock_get,
|
|
patch(f"{_PATCH}.{format_fn}", return_value=expected_text),
|
|
):
|
|
result = runner.invoke(app, args)
|
|
|
|
assert result.exit_code == 0
|
|
assert expected_text in result.output
|
|
mock_get.assert_called_once()
|
|
|
|
|
|
def test_schema_command_default_outputs_text() -> None:
|
|
runner = CliRunner()
|
|
with (
|
|
patch(f"{_PATCH}.get_schema", return_value={"type_name": "llm-text", "schema": {}}),
|
|
patch(f"{_PATCH}.format_schema_text", return_value="# llm-text\n{}"),
|
|
):
|
|
result = runner.invoke(app, ["agent", "schema", "columns", "llm-text"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "llm-text" in result.output
|
|
|
|
|
|
def test_error_outputs_message_to_stderr() -> None:
|
|
runner = CliRunner()
|
|
with patch(f"{_PATCH}.get_schema", side_effect=ValueError("boom")):
|
|
result = runner.invoke(app, ["agent", "schema", "columns", "missing"])
|
|
|
|
assert result.exit_code == 1
|
|
assert result.stdout == ""
|
|
assert "internal_error" in result.stderr
|
|
assert "boom" in result.stderr
|