pyagent-studio 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. pyagent_studio-0.1.0/.gitignore +18 -0
  2. pyagent_studio-0.1.0/PKG-INFO +140 -0
  3. pyagent_studio-0.1.0/README.md +110 -0
  4. pyagent_studio-0.1.0/pyproject.toml +43 -0
  5. pyagent_studio-0.1.0/src/pyagent_studio/__init__.py +14 -0
  6. pyagent_studio-0.1.0/src/pyagent_studio/app.py +84 -0
  7. pyagent_studio-0.1.0/src/pyagent_studio/cli.py +30 -0
  8. pyagent_studio-0.1.0/src/pyagent_studio/py.typed +0 -0
  9. pyagent_studio-0.1.0/src/pyagent_studio/screens/__init__.py +22 -0
  10. pyagent_studio-0.1.0/src/pyagent_studio/screens/cost.py +33 -0
  11. pyagent_studio-0.1.0/src/pyagent_studio/screens/dashboard.py +55 -0
  12. pyagent_studio-0.1.0/src/pyagent_studio/screens/editor.py +64 -0
  13. pyagent_studio-0.1.0/src/pyagent_studio/screens/governance.py +77 -0
  14. pyagent_studio-0.1.0/src/pyagent_studio/screens/graph.py +42 -0
  15. pyagent_studio-0.1.0/src/pyagent_studio/screens/simulation.py +64 -0
  16. pyagent_studio-0.1.0/src/pyagent_studio/screens/traces.py +43 -0
  17. pyagent_studio-0.1.0/src/pyagent_studio/services/__init__.py +13 -0
  18. pyagent_studio-0.1.0/src/pyagent_studio/services/blueprint_service.py +115 -0
  19. pyagent_studio-0.1.0/src/pyagent_studio/services/governance_service.py +105 -0
  20. pyagent_studio-0.1.0/src/pyagent_studio/services/simulation_service.py +109 -0
  21. pyagent_studio-0.1.0/src/pyagent_studio/services/trace_service.py +115 -0
  22. pyagent_studio-0.1.0/src/pyagent_studio/widgets/__init__.py +23 -0
  23. pyagent_studio-0.1.0/src/pyagent_studio/widgets/agent_card.py +40 -0
  24. pyagent_studio-0.1.0/src/pyagent_studio/widgets/blueprint_tree.py +73 -0
  25. pyagent_studio-0.1.0/src/pyagent_studio/widgets/cost_chart.py +40 -0
  26. pyagent_studio-0.1.0/src/pyagent_studio/widgets/diff_view.py +50 -0
  27. pyagent_studio-0.1.0/src/pyagent_studio/widgets/trace_table.py +29 -0
  28. pyagent_studio-0.1.0/src/pyagent_studio/widgets/validation_log.py +28 -0
  29. pyagent_studio-0.1.0/tests/__init__.py +0 -0
  30. pyagent_studio-0.1.0/tests/test_services.py +160 -0
@@ -0,0 +1,18 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .pytest_cache/
14
+ .coverage
15
+ htmlcov/
16
+ site/
17
+ .env
18
+ *.log
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyagent-studio
3
+ Version: 0.1.0
4
+ Summary: Terminal-based interactive workbench for designing, simulating, and debugging agent systems
5
+ Project-URL: Homepage, https://pyagent.org
6
+ Project-URL: Repository, https://github.com/pyagent-core/pyagent
7
+ Project-URL: Documentation, https://pyagent.org
8
+ Author-email: PyAgent Team <team@pyagent.org>
9
+ License: MIT
10
+ Keywords: LLM,TUI,agents,studio,textual,workbench
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: click>=8.1
21
+ Requires-Dist: pyagent-blueprint>=0.1.0
22
+ Requires-Dist: pyagent-trace>=0.1.0
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
25
+ Requires-Dist: pytest>=8.0; extra == 'dev'
26
+ Requires-Dist: textual-dev>=1.0; extra == 'dev'
27
+ Provides-Extra: tui
28
+ Requires-Dist: textual>=3.0; extra == 'tui'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # pyagent-studio
32
+
33
+ **Terminal-based interactive workbench** for designing, simulating, debugging, and governing multi-agent LLM systems. Built with [Textual](https://textual.textualize.io/) for a rich TUI experience.
34
+
35
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](../../LICENSE)
36
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
37
+
38
+ ## Install
39
+
40
+ ```bash
41
+ pip install pyagent-studio[tui] # Full TUI (requires textual)
42
+ pip install pyagent-studio # Services only (no TUI)
43
+ ```
44
+
45
+ Depends on: `pyagent-blueprint`, `pyagent-trace`, `click`.
46
+
47
+ ## Quick Start
48
+
49
+ ```bash
50
+ # Launch with a blueprint
51
+ pyagent-studio blueprint.yaml
52
+
53
+ # Or launch and browse discovered blueprints
54
+ pyagent-studio
55
+ ```
56
+
57
+ ## Screens
58
+
59
+ ### Dashboard
60
+ List discovered YAML blueprints, view validation status, agent/workflow counts.
61
+
62
+ ```
63
+ ┌─────────────────────────────────────────────────────────────┐
64
+ │ PyAgent Studio — Dashboard │
65
+ ├─────────────────────────────────────────────────────────────┤
66
+ │ File │ Name │ Agents │ Status │
67
+ │ customer_support.yaml │ customer-support │ 3 │ ✓ Valid │
68
+ │ research_agent.yaml │ research-agent │ 2 │ ✓ Valid │
69
+ └─────────────────────────────────────────────────────────────┘
70
+ ```
71
+
72
+ ### Editor
73
+ YAML editing with live validation panel showing Pydantic errors as you type.
74
+
75
+ ### Graph
76
+ ASCII-rendered workflow DAG showing agents as boxes and edges as pattern connections.
77
+
78
+ ### Simulation
79
+ Run blueprints with MockLLM (no API keys needed), stream results with timing and token counts.
80
+
81
+ ### Traces
82
+ Browse recorded trace spans from `pyagent-trace` Recorder JSONL files.
83
+
84
+ ### Cost
85
+ Cost breakdown tables by pattern, agent, and model with bar chart visualization.
86
+
87
+ ### Governance
88
+ Validation issues, compliance scoring (% of checks passing), and semantic diff between blueprint versions.
89
+
90
+ ## Key Bindings
91
+
92
+ | Key | Action |
93
+ |-----|--------|
94
+ | `Tab` / `Shift+Tab` | Switch screens |
95
+ | `q` | Quit |
96
+ | `Ctrl+S` | Save blueprint |
97
+ | `Ctrl+V` | Validate |
98
+ | `Ctrl+R` | Render graph |
99
+ | `Ctrl+T` | Run simulation |
100
+ | `Ctrl+D` | Show diff |
101
+
102
+ ## Services (Headless API)
103
+
104
+ Use the services layer without the TUI for scripting and CI:
105
+
106
+ ```python
107
+ from pyagent_studio import BlueprintService, SimulationService, GovernanceService
108
+
109
+ # Load and validate
110
+ svc = BlueprintService()
111
+ spec = svc.load("blueprint.yaml")
112
+ issues = svc.validate()
113
+ print(svc.summary())
114
+
115
+ # Run simulation
116
+ import asyncio
117
+ sim = SimulationService()
118
+ result = asyncio.run(sim.run(spec, "support", "I can't see my invoice"))
119
+ print(result.output)
120
+
121
+ # Governance
122
+ gov = GovernanceService()
123
+ report = gov.check_compliance(spec)
124
+ print(gov.format_report(report))
125
+ ```
126
+
127
+ ### TraceService
128
+
129
+ ```python
130
+ from pyagent_studio import TraceService
131
+
132
+ traces = TraceService()
133
+ spans = traces.load("traces.jsonl")
134
+ llm_calls = traces.query(event_type="llm_call")
135
+ print(traces.summary())
136
+ ```
137
+
138
+ ## Full Documentation
139
+
140
+ See [pyagent.dev](https://pyagent.dev) for full API reference and integration guides.
@@ -0,0 +1,110 @@
1
+ # pyagent-studio
2
+
3
+ **Terminal-based interactive workbench** for designing, simulating, debugging, and governing multi-agent LLM systems. Built with [Textual](https://textual.textualize.io/) for a rich TUI experience.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](../../LICENSE)
6
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ pip install pyagent-studio[tui] # Full TUI (requires textual)
12
+ pip install pyagent-studio # Services only (no TUI)
13
+ ```
14
+
15
+ Depends on: `pyagent-blueprint`, `pyagent-trace`, `click`.
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Launch with a blueprint
21
+ pyagent-studio blueprint.yaml
22
+
23
+ # Or launch and browse discovered blueprints
24
+ pyagent-studio
25
+ ```
26
+
27
+ ## Screens
28
+
29
+ ### Dashboard
30
+ List discovered YAML blueprints, view validation status, agent/workflow counts.
31
+
32
+ ```
33
+ ┌─────────────────────────────────────────────────────────────┐
34
+ │ PyAgent Studio — Dashboard │
35
+ ├─────────────────────────────────────────────────────────────┤
36
+ │ File │ Name │ Agents │ Status │
37
+ │ customer_support.yaml │ customer-support │ 3 │ ✓ Valid │
38
+ │ research_agent.yaml │ research-agent │ 2 │ ✓ Valid │
39
+ └─────────────────────────────────────────────────────────────┘
40
+ ```
41
+
42
+ ### Editor
43
+ YAML editing with live validation panel showing Pydantic errors as you type.
44
+
45
+ ### Graph
46
+ ASCII-rendered workflow DAG showing agents as boxes and edges as pattern connections.
47
+
48
+ ### Simulation
49
+ Run blueprints with MockLLM (no API keys needed), stream results with timing and token counts.
50
+
51
+ ### Traces
52
+ Browse recorded trace spans from `pyagent-trace` Recorder JSONL files.
53
+
54
+ ### Cost
55
+ Cost breakdown tables by pattern, agent, and model with bar chart visualization.
56
+
57
+ ### Governance
58
+ Validation issues, compliance scoring (% of checks passing), and semantic diff between blueprint versions.
59
+
60
+ ## Key Bindings
61
+
62
+ | Key | Action |
63
+ |-----|--------|
64
+ | `Tab` / `Shift+Tab` | Switch screens |
65
+ | `q` | Quit |
66
+ | `Ctrl+S` | Save blueprint |
67
+ | `Ctrl+V` | Validate |
68
+ | `Ctrl+R` | Render graph |
69
+ | `Ctrl+T` | Run simulation |
70
+ | `Ctrl+D` | Show diff |
71
+
72
+ ## Services (Headless API)
73
+
74
+ Use the services layer without the TUI for scripting and CI:
75
+
76
+ ```python
77
+ from pyagent_studio import BlueprintService, SimulationService, GovernanceService
78
+
79
+ # Load and validate
80
+ svc = BlueprintService()
81
+ spec = svc.load("blueprint.yaml")
82
+ issues = svc.validate()
83
+ print(svc.summary())
84
+
85
+ # Run simulation
86
+ import asyncio
87
+ sim = SimulationService()
88
+ result = asyncio.run(sim.run(spec, "support", "I can't see my invoice"))
89
+ print(result.output)
90
+
91
+ # Governance
92
+ gov = GovernanceService()
93
+ report = gov.check_compliance(spec)
94
+ print(gov.format_report(report))
95
+ ```
96
+
97
+ ### TraceService
98
+
99
+ ```python
100
+ from pyagent_studio import TraceService
101
+
102
+ traces = TraceService()
103
+ spans = traces.load("traces.jsonl")
104
+ llm_calls = traces.query(event_type="llm_call")
105
+ print(traces.summary())
106
+ ```
107
+
108
+ ## Full Documentation
109
+
110
+ See [pyagent.dev](https://pyagent.dev) for full API reference and integration guides.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pyagent-studio"
7
+ version = "0.1.0"
8
+ description = "Terminal-based interactive workbench for designing, simulating, and debugging agent systems"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = {text = "MIT"}
12
+ authors = [{name = "PyAgent Team", email = "team@pyagent.org"}]
13
+ keywords = ["agents", "TUI", "studio", "LLM", "textual", "workbench"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
+ "Typing :: Typed",
23
+ ]
24
+ dependencies = [
25
+ "pyagent-blueprint>=0.1.0",
26
+ "pyagent-trace>=0.1.0",
27
+ "click>=8.1",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://pyagent.org"
32
+ Repository = "https://github.com/pyagent-core/pyagent"
33
+ Documentation = "https://pyagent.org"
34
+
35
+ [project.optional-dependencies]
36
+ tui = ["textual>=3.0"]
37
+ dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "textual-dev>=1.0"]
38
+
39
+ [project.scripts]
40
+ pyagent-studio = "pyagent_studio.cli:main"
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/pyagent_studio"]
@@ -0,0 +1,14 @@
1
+ """PyAgent Studio — terminal-based interactive workbench for agent systems."""
2
+
3
+ from pyagent_studio.services.blueprint_service import BlueprintService
4
+ from pyagent_studio.services.governance_service import GovernanceService
5
+ from pyagent_studio.services.simulation_service import SimulationService
6
+ from pyagent_studio.services.trace_service import TraceService
7
+
8
+ __all__ = [
9
+ "BlueprintService",
10
+ "GovernanceService",
11
+ "SimulationService",
12
+ "TraceService",
13
+ ]
14
+ __version__ = "0.1.0"
@@ -0,0 +1,84 @@
1
+ """StudioApp: main Textual application with screen routing."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from textual.app import App, ComposeResult
6
+ from textual.widgets import Footer, Header, TabbedContent, TabPane
7
+
8
+ from pyagent_blueprint.schema import BlueprintSpec
9
+ from pyagent_studio.services.blueprint_service import BlueprintService
10
+
11
+
12
+ class StudioApp(App):
13
+ """PyAgent Studio — terminal-based interactive workbench.
14
+
15
+ Launch via: ``pyagent-studio [blueprint.yaml]``
16
+ """
17
+
18
+ TITLE = "PyAgent Studio"
19
+ CSS = """
20
+ TabbedContent {
21
+ height: 1fr;
22
+ }
23
+ """
24
+ BINDINGS = [
25
+ ("q", "quit", "Quit"),
26
+ ("ctrl+s", "save", "Save"),
27
+ ("ctrl+v", "validate", "Validate"),
28
+ ("ctrl+r", "render", "Render Graph"),
29
+ ("ctrl+t", "simulate", "Simulate"),
30
+ ("ctrl+d", "diff", "Diff"),
31
+ ]
32
+
33
+ def __init__(self, blueprint_path: str | None = None, **kwargs) -> None:
34
+ super().__init__(**kwargs)
35
+ self._blueprint_path = blueprint_path
36
+ self._service = BlueprintService()
37
+ self._spec: BlueprintSpec | None = None
38
+
39
+ def compose(self) -> ComposeResult:
40
+ yield Header()
41
+ with TabbedContent():
42
+ with TabPane("Dashboard", id="tab-dashboard"):
43
+ from textual.widgets import Static
44
+ yield Static("[bold]Dashboard[/bold]\n\nLoad a blueprint to get started.")
45
+ with TabPane("Editor", id="tab-editor"):
46
+ from textual.widgets import Static
47
+ yield Static("Editor — use Ctrl+V to validate")
48
+ with TabPane("Graph", id="tab-graph"):
49
+ from textual.widgets import Static
50
+ yield Static("Graph — load a blueprint first")
51
+ with TabPane("Simulation", id="tab-sim"):
52
+ from textual.widgets import Static
53
+ yield Static("Simulation — load a blueprint first")
54
+ with TabPane("Traces", id="tab-traces"):
55
+ from textual.widgets import Static
56
+ yield Static("Traces — no trace file loaded")
57
+ with TabPane("Cost", id="tab-cost"):
58
+ from textual.widgets import Static
59
+ yield Static("Cost — no data available")
60
+ with TabPane("Governance", id="tab-gov"):
61
+ from textual.widgets import Static
62
+ yield Static("Governance — load a blueprint first")
63
+ yield Footer()
64
+
65
+ def on_mount(self) -> None:
66
+ if self._blueprint_path:
67
+ try:
68
+ self._spec = self._service.load(self._blueprint_path)
69
+ self.notify(f"Loaded: {self._spec.metadata.name}")
70
+ except Exception as exc:
71
+ self.notify(f"Load error: {exc}", severity="error")
72
+
73
+ def action_quit(self) -> None:
74
+ self.exit()
75
+
76
+ def action_validate(self) -> None:
77
+ if self._spec is None:
78
+ self.notify("No blueprint loaded", severity="warning")
79
+ return
80
+ issues = self._service.validate()
81
+ if issues:
82
+ self.notify(f"{len(issues)} validation issue(s) found", severity="warning")
83
+ else:
84
+ self.notify("Blueprint is valid ✓")
@@ -0,0 +1,30 @@
1
+ """CLI entry point: pyagent-studio [blueprint.yaml]."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+
8
+ @click.command()
9
+ @click.argument("blueprint", required=False, default=None, type=click.Path())
10
+ def main(blueprint: str | None) -> None:
11
+ """Launch PyAgent Studio — interactive agent system workbench.
12
+
13
+ Optionally pass a blueprint YAML file to load on startup.
14
+ """
15
+ try:
16
+ from pyagent_studio.app import StudioApp
17
+ except ImportError:
18
+ click.echo(
19
+ "Error: textual is not installed. "
20
+ "Install with: pip install pyagent-studio[tui]",
21
+ err=True,
22
+ )
23
+ raise SystemExit(1)
24
+
25
+ app = StudioApp(blueprint_path=blueprint)
26
+ app.run()
27
+
28
+
29
+ if __name__ == "__main__":
30
+ main()
File without changes
@@ -0,0 +1,22 @@
1
+ """Studio screens — Textual Screen subclasses for each TUI view."""
2
+
3
+ try:
4
+ from pyagent_studio.screens.dashboard import DashboardScreen
5
+ from pyagent_studio.screens.editor import EditorScreen
6
+ from pyagent_studio.screens.graph import GraphScreen
7
+ from pyagent_studio.screens.simulation import SimulationScreen
8
+ from pyagent_studio.screens.traces import TracesScreen
9
+ from pyagent_studio.screens.cost import CostScreen
10
+ from pyagent_studio.screens.governance import GovernanceScreen
11
+
12
+ __all__ = [
13
+ "CostScreen",
14
+ "DashboardScreen",
15
+ "EditorScreen",
16
+ "GovernanceScreen",
17
+ "GraphScreen",
18
+ "SimulationScreen",
19
+ "TracesScreen",
20
+ ]
21
+ except ImportError:
22
+ __all__ = []
@@ -0,0 +1,33 @@
1
+ """CostScreen: cost breakdown tables by pattern/agent/model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from textual.app import ComposeResult
6
+ from textual.screen import Screen
7
+ from textual.widgets import Footer, Header, Static
8
+
9
+ from pyagent_studio.widgets.cost_chart import CostChart
10
+
11
+
12
+ class CostScreen(Screen):
13
+ """Display cost breakdown for agent system runs."""
14
+
15
+ BINDINGS = [("q", "quit", "Quit")]
16
+
17
+ def __init__(self, costs: dict[str, float] | None = None, **kwargs) -> None:
18
+ super().__init__(**kwargs)
19
+ self._costs = costs
20
+
21
+ def compose(self) -> ComposeResult:
22
+ yield Header()
23
+ yield Static("[bold]Cost Analysis[/bold]", id="title")
24
+ yield CostChart(id="cost-chart")
25
+ yield Footer()
26
+
27
+ def on_mount(self) -> None:
28
+ if self._costs:
29
+ chart = self.query_one("#cost-chart", CostChart)
30
+ chart.load_data(self._costs)
31
+
32
+ def action_quit(self) -> None:
33
+ self.app.exit()
@@ -0,0 +1,55 @@
1
+ """DashboardScreen: list blueprints, health summary, quick actions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from textual.app import ComposeResult
6
+ from textual.screen import Screen
7
+ from textual.widgets import DataTable, Footer, Header, Static
8
+
9
+ from pyagent_studio.services.blueprint_service import BlueprintService
10
+
11
+
12
+ class DashboardScreen(Screen):
13
+ """Main dashboard showing discovered blueprints and their status."""
14
+
15
+ BINDINGS = [
16
+ ("n", "new_blueprint", "New"),
17
+ ("enter", "open_blueprint", "Open"),
18
+ ("q", "quit", "Quit"),
19
+ ]
20
+
21
+ def __init__(self, service: BlueprintService | None = None, **kwargs) -> None:
22
+ super().__init__(**kwargs)
23
+ self._service = service or BlueprintService()
24
+
25
+ def compose(self) -> ComposeResult:
26
+ yield Header()
27
+ yield Static("[bold]PyAgent Studio — Dashboard[/bold]", id="title")
28
+ yield DataTable(id="blueprint-list")
29
+ yield Footer()
30
+
31
+ def on_mount(self) -> None:
32
+ table = self.query_one("#blueprint-list", DataTable)
33
+ table.add_columns("File", "Name", "Agents", "Workflows", "Status")
34
+ self._refresh_list(table)
35
+
36
+ def _refresh_list(self, table: DataTable) -> None:
37
+ """Discover and list blueprints."""
38
+ table.clear()
39
+ for path in self._service.discover_blueprints():
40
+ try:
41
+ spec = self._service.load(path)
42
+ issues = self._service.validate()
43
+ status = "✓ Valid" if not issues else f"✗ {len(issues)} issue(s)"
44
+ table.add_row(
45
+ str(path.name),
46
+ spec.metadata.name,
47
+ str(len(spec.agents)),
48
+ str(len(spec.workflows)),
49
+ status,
50
+ )
51
+ except Exception:
52
+ table.add_row(str(path.name), "?", "?", "?", "✗ Load error")
53
+
54
+ def action_quit(self) -> None:
55
+ self.app.exit()
@@ -0,0 +1,64 @@
1
+ """EditorScreen: YAML editing with live validation panel."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from textual.app import ComposeResult
6
+ from textual.containers import Horizontal
7
+ from textual.screen import Screen
8
+ from textual.widgets import Footer, Header, TextArea
9
+
10
+ from pyagent_studio.widgets.validation_log import ValidationLog
11
+
12
+
13
+ class EditorScreen(Screen):
14
+ """YAML editor with live validation sidebar."""
15
+
16
+ BINDINGS = [
17
+ ("ctrl+s", "save", "Save"),
18
+ ("ctrl+v", "validate", "Validate"),
19
+ ("q", "quit", "Quit"),
20
+ ]
21
+
22
+ DEFAULT_CSS = """
23
+ EditorScreen Horizontal {
24
+ height: 1fr;
25
+ }
26
+ EditorScreen TextArea {
27
+ width: 2fr;
28
+ }
29
+ EditorScreen ValidationLog {
30
+ width: 1fr;
31
+ border-left: solid green;
32
+ }
33
+ """
34
+
35
+ def __init__(self, content: str = "", **kwargs) -> None:
36
+ super().__init__(**kwargs)
37
+ self._content = content
38
+
39
+ def compose(self) -> ComposeResult:
40
+ yield Header()
41
+ with Horizontal():
42
+ yield TextArea(self._content, language="yaml", id="editor")
43
+ yield ValidationLog(id="validation-log")
44
+ yield Footer()
45
+
46
+ def action_validate(self) -> None:
47
+ """Validate current editor content."""
48
+ from pyagent_blueprint import BlueprintValidator, load_blueprint_from_str
49
+ from pyagent_blueprint.loader import BlueprintLoadError
50
+
51
+ editor = self.query_one("#editor", TextArea)
52
+ log = self.query_one("#validation-log", ValidationLog)
53
+
54
+ try:
55
+ spec = load_blueprint_from_str(editor.text)
56
+ validator = BlueprintValidator()
57
+ issues = validator.validate(spec)
58
+ log.load_issues(issues)
59
+ except (BlueprintLoadError, Exception) as exc:
60
+ log.clear()
61
+ log.write(f"[red]Parse error: {exc}[/red]")
62
+
63
+ def action_quit(self) -> None:
64
+ self.app.exit()