understudy 0.4.0__tar.gz → 0.6.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 (68) hide show
  1. understudy-0.6.0/LICENSE +21 -0
  2. {understudy-0.4.0 → understudy-0.6.0}/PKG-INFO +52 -24
  3. {understudy-0.4.0 → understudy-0.6.0}/README.md +41 -7
  4. understudy-0.6.0/pyproject.toml +207 -0
  5. understudy-0.6.0/pyproject.toml.orig +151 -0
  6. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/__init__.py +135 -51
  7. understudy-0.6.0/src/understudy/adk/__init__.py +426 -0
  8. understudy-0.6.0/src/understudy/adk/instrumentation.py +65 -0
  9. understudy-0.6.0/src/understudy/agentic/__init__.py +53 -0
  10. understudy-0.6.0/src/understudy/agentic/check.py +209 -0
  11. understudy-0.6.0/src/understudy/agentic/metrics.py +171 -0
  12. understudy-0.6.0/src/understudy/agentic/models.py +276 -0
  13. understudy-0.6.0/src/understudy/agentic/runner.py +160 -0
  14. understudy-0.6.0/src/understudy/assertions.py +44 -0
  15. understudy-0.6.0/src/understudy/batch.py +54 -0
  16. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/check.py +97 -49
  17. understudy-0.6.0/src/understudy/cli.py +1557 -0
  18. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/compare.py +6 -1
  19. understudy-0.6.0/src/understudy/diff.py +241 -0
  20. understudy-0.6.0/src/understudy/execution.py +320 -0
  21. understudy-0.6.0/src/understudy/http/__init__.py +369 -0
  22. understudy-0.6.0/src/understudy/instrumentation.py +39 -0
  23. understudy-0.6.0/src/understudy/judge_backends.py +150 -0
  24. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/judges.py +77 -24
  25. understudy-0.6.0/src/understudy/langchain/__init__.py +35 -0
  26. understudy-0.6.0/src/understudy/langchain/middleware.py +51 -0
  27. understudy-0.6.0/src/understudy/langgraph/__init__.py +448 -0
  28. understudy-0.6.0/src/understudy/langgraph/instrumentation.py +58 -0
  29. understudy-0.6.0/src/understudy/langgraph/tools.py +77 -0
  30. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/metrics/builtins.py +25 -9
  31. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/metrics/registry.py +7 -7
  32. understudy-0.6.0/src/understudy/mocks.py +105 -0
  33. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/models.py +70 -15
  34. understudy-0.6.0/src/understudy/py.typed +0 -0
  35. understudy-0.6.0/src/understudy/pytest_plugin.py +181 -0
  36. understudy-0.6.0/src/understudy/replay.py +199 -0
  37. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/reports.py +23 -9
  38. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/runner.py +99 -51
  39. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/server/__init__.py +3 -2
  40. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/server/sessions.py +18 -18
  41. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/server/ui_simulator.py +19 -8
  42. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/simulator.py +4 -5
  43. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/storage.py +283 -220
  44. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/suite.py +103 -65
  45. understudy-0.6.0/src/understudy/templates/init/conftest.py.template +70 -0
  46. understudy-0.6.0/src/understudy/templates/init/example_scene.yaml +36 -0
  47. understudy-0.6.0/src/understudy/templates/init/test_agent.py.template +43 -0
  48. understudy-0.6.0/src/understudy/templates/init/understudy.yaml.template +16 -0
  49. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/templates/run_detail.html +25 -2
  50. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/trace.py +55 -6
  51. understudy-0.6.0/src/understudy/validation.py +167 -0
  52. understudy-0.4.0/pyproject.toml +0 -70
  53. understudy-0.4.0/src/understudy/adk/__init__.py +0 -254
  54. understudy-0.4.0/src/understudy/cli.py +0 -837
  55. understudy-0.4.0/src/understudy/http/__init__.py +0 -346
  56. understudy-0.4.0/src/understudy/langgraph/__init__.py +0 -162
  57. understudy-0.4.0/src/understudy/langgraph/tools.py +0 -100
  58. understudy-0.4.0/src/understudy/mocks.py +0 -56
  59. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/metrics/__init__.py +0 -0
  60. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/metrics/templates/clarity.jinja +0 -0
  61. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/metrics/templates/policy_compliance.jinja +0 -0
  62. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/metrics/templates/tone_empathy.jinja +0 -0
  63. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/prompts/__init__.py +4 -4
  64. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/prompts/rubrics.py +0 -0
  65. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/server/models.py +0 -0
  66. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/templates/base.html +0 -0
  67. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/templates/comparison.html +0 -0
  68. {understudy-0.4.0 → understudy-0.6.0}/src/understudy/templates/index.html +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gaurav Sood
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,35 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: understudy
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary: Simulation and trace-based evaluation for agentic systems
5
5
  Keywords: agent,evaluation,simulation,testing,llm
6
6
  Author: Gaurav Sood
7
7
  License-Expression: MIT
8
+ License-File: LICENSE
8
9
  Classifier: Development Status :: 3 - Alpha
9
10
  Classifier: Intended Audience :: Developers
10
- Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
14
15
  Classifier: Topic :: Software Development :: Testing
15
16
  Requires-Dist: pydantic>=2.0
16
17
  Requires-Dist: pyyaml>=6.0
17
18
  Requires-Dist: litellm>=1.50
18
- Requires-Dist: google-adk>=1.0 ; extra == 'adk'
19
+ Requires-Dist: google-adk>=2.11 ; extra == 'adk'
19
20
  Requires-Dist: python-dotenv>=1.0 ; extra == 'adk'
20
- Requires-Dist: understudy[adk,http,langgraph,server,reports] ; extra == 'all'
21
- Requires-Dist: understudy[all,docs] ; extra == 'dev'
22
- Requires-Dist: pytest>=8.0 ; extra == 'dev'
23
- Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
24
- Requires-Dist: pytest-cov>=4.0 ; extra == 'dev'
25
- Requires-Dist: ruff>=0.4 ; extra == 'dev'
26
- Requires-Dist: sphinx>=7.0 ; extra == 'docs'
27
- Requires-Dist: furo>=2024.0 ; extra == 'docs'
28
- Requires-Dist: myst-parser>=3.0 ; extra == 'docs'
29
- Requires-Dist: sphinx-autodoc-typehints>=2.0 ; extra == 'docs'
21
+ Requires-Dist: understudy[adk,http,langgraph,langchain,server,reports] ; extra == 'all'
30
22
  Requires-Dist: httpx>=0.27 ; extra == 'http'
31
- Requires-Dist: langgraph>=0.2 ; extra == 'langgraph'
32
- Requires-Dist: langchain-core>=0.3 ; extra == 'langgraph'
23
+ Requires-Dist: langchain>=1.4.4 ; extra == 'langchain'
24
+ Requires-Dist: langgraph>=1.2.14 ; extra == 'langchain'
25
+ Requires-Dist: langchain-core>=1.6.9 ; extra == 'langchain'
26
+ Requires-Dist: langgraph>=1.2.14 ; extra == 'langgraph'
27
+ Requires-Dist: langchain-core>=1.6.9 ; extra == 'langgraph'
33
28
  Requires-Dist: langchain-openai>=0.3 ; extra == 'langgraph'
34
29
  Requires-Dist: jinja2>=3.0 ; extra == 'reports'
35
30
  Requires-Dist: click>=8.0 ; extra == 'reports'
@@ -42,9 +37,8 @@ Project-URL: Repository, https://github.com/gojiplus/understudy
42
37
  Project-URL: Issues, https://github.com/gojiplus/understudy/issues
43
38
  Provides-Extra: adk
44
39
  Provides-Extra: all
45
- Provides-Extra: dev
46
- Provides-Extra: docs
47
40
  Provides-Extra: http
41
+ Provides-Extra: langchain
48
42
  Provides-Extra: langgraph
49
43
  Provides-Extra: reports
50
44
  Provides-Extra: server
@@ -65,22 +59,50 @@ Understudy is a scenario-driven testing framework for AI agents that simulates r
65
59
 
66
60
  Testing with understudy is **4 steps**:
67
61
 
68
- 1. **Wrap your agent** — Adapt your agent (ADK, LangGraph, HTTP) to understudy's interface
62
+ 1. **Wrap your agent** — Adapt your agent (ADK, LangGraph, LangChain, HTTP) to understudy's interface
69
63
  2. **Mock your tools** — Register handlers that return test data instead of calling real services
70
64
  3. **Write scenes** — YAML files defining what the simulated user wants and what you expect
71
65
  4. **Run and assert** — Execute simulations, check traces, generate reports
72
66
 
73
67
  The key insight: **assert against the trace, not the prose**. Don't check what the agent said—check what it did (tool calls).
74
68
 
69
+ ## Two Evaluation Paradigms
70
+
71
+ ### Conversational Agent Evaluation
72
+ Simulate multi-turn conversations with personas to test dialog agents.
73
+ - Use case: Customer service bots, assistants, chatbots
74
+ - Assert on tool calls: `trace.called("tool_name")`
75
+
76
+ ### Agentic Flow Evaluation
77
+ Evaluate autonomous agents executing multi-step tasks.
78
+ - Use case: Code agents, research agents, task automation
79
+ - Assert on actions: `trace.performed("action")`
80
+
81
+ See [examples/README.md](https://github.com/gojiplus/understudy/blob/main/examples/README.md) for complete examples of both paradigms.
82
+
75
83
  **See real examples:**
76
- - [Example scene](https://github.com/gojiplus/understudy/blob/main/example/scenes/return_eligible_backpack.yaml) — YAML defining a test scenario
77
- - [ADK test file](https://github.com/gojiplus/understudy/blob/main/example/adk/test_returns.py) — pytest assertions against traces
78
- - [LangGraph test file](https://github.com/gojiplus/understudy/blob/main/example/langgraph/test_returns.py) — same tests, different framework
84
+ - [Example scene](https://github.com/gojiplus/understudy/blob/main/examples/scenes/return_eligible_backpack.yaml) — YAML defining a test scenario
85
+ - [ADK test file](https://github.com/gojiplus/understudy/blob/main/examples/adk/test_adk_returns.py) — pytest assertions against traces
86
+ - [LangGraph test file](https://github.com/gojiplus/understudy/blob/main/examples/langgraph/test_langgraph_returns.py) — same tests, different framework
87
+ - [Agentic test file](https://github.com/gojiplus/understudy/blob/main/examples/agentic/test_agentic.py) — agentic flow evaluation
88
+ - [Agentic scene](https://github.com/gojiplus/understudy/blob/main/examples/agentic_scenes/code_review_task.yaml) — task-based scenario
89
+ - [Example report](https://htmlpreview.github.io/?https://github.com/gojiplus/understudy/blob/main/examples/langgraph/report/index.html) — HTML report with metrics and transcripts
90
+
91
+ ## State injection and next-turn tests
92
+
93
+ Restore a completed checkpoint, inject synthetic history/state, or replay through
94
+ exchange X, then execute and assert only against exchange X+1. ADK and LangGraph
95
+ support isolated checkpoint forks; `LangChainApp` builds an instrumented LangChain
96
+ agent with tool middleware. Traces retain nested invocation identities.
97
+
98
+ See the [state-testing guide](https://gojiplus.github.io/understudy/state-testing.html)
99
+ for `run_turn`, `replay_to`, scoped tool mocks, pytest fixtures, CLI commands, and
100
+ framework-specific restoration limits.
79
101
 
80
102
  ## Installation
81
103
 
82
104
  ```bash
83
- pip install understudy[all]
105
+ pip install "understudy[all]"
84
106
  ```
85
107
 
86
108
  ## Quick Start
@@ -103,9 +125,15 @@ from understudy.mocks import MockToolkit
103
125
 
104
126
  mocks = MockToolkit()
105
127
 
128
+
106
129
  @mocks.handle("lookup_order")
107
130
  def lookup_order(order_id: str) -> dict:
108
- return {"order_id": order_id, "items": [...], "status": "delivered"}
131
+ return {
132
+ "order_id": order_id,
133
+ "items": [{"sku": "BACKPACK-01", "quantity": 1}],
134
+ "status": "delivered",
135
+ }
136
+
109
137
 
110
138
  @mocks.handle("create_return")
111
139
  def create_return(order_id: str, item_sku: str, reason: str) -> dict:
@@ -282,7 +310,7 @@ assert result.score == 1
282
310
  Built-in rubrics:
283
311
 
284
312
  ```python
285
- from understudy.judges import (
313
+ from understudy.prompts import (
286
314
  TOOL_USAGE_CORRECTNESS,
287
315
  POLICY_COMPLIANCE,
288
316
  TONE_EMPATHY,
@@ -13,22 +13,50 @@ Understudy is a scenario-driven testing framework for AI agents that simulates r
13
13
 
14
14
  Testing with understudy is **4 steps**:
15
15
 
16
- 1. **Wrap your agent** — Adapt your agent (ADK, LangGraph, HTTP) to understudy's interface
16
+ 1. **Wrap your agent** — Adapt your agent (ADK, LangGraph, LangChain, HTTP) to understudy's interface
17
17
  2. **Mock your tools** — Register handlers that return test data instead of calling real services
18
18
  3. **Write scenes** — YAML files defining what the simulated user wants and what you expect
19
19
  4. **Run and assert** — Execute simulations, check traces, generate reports
20
20
 
21
21
  The key insight: **assert against the trace, not the prose**. Don't check what the agent said—check what it did (tool calls).
22
22
 
23
+ ## Two Evaluation Paradigms
24
+
25
+ ### Conversational Agent Evaluation
26
+ Simulate multi-turn conversations with personas to test dialog agents.
27
+ - Use case: Customer service bots, assistants, chatbots
28
+ - Assert on tool calls: `trace.called("tool_name")`
29
+
30
+ ### Agentic Flow Evaluation
31
+ Evaluate autonomous agents executing multi-step tasks.
32
+ - Use case: Code agents, research agents, task automation
33
+ - Assert on actions: `trace.performed("action")`
34
+
35
+ See [examples/README.md](https://github.com/gojiplus/understudy/blob/main/examples/README.md) for complete examples of both paradigms.
36
+
23
37
  **See real examples:**
24
- - [Example scene](https://github.com/gojiplus/understudy/blob/main/example/scenes/return_eligible_backpack.yaml) — YAML defining a test scenario
25
- - [ADK test file](https://github.com/gojiplus/understudy/blob/main/example/adk/test_returns.py) — pytest assertions against traces
26
- - [LangGraph test file](https://github.com/gojiplus/understudy/blob/main/example/langgraph/test_returns.py) — same tests, different framework
38
+ - [Example scene](https://github.com/gojiplus/understudy/blob/main/examples/scenes/return_eligible_backpack.yaml) — YAML defining a test scenario
39
+ - [ADK test file](https://github.com/gojiplus/understudy/blob/main/examples/adk/test_adk_returns.py) — pytest assertions against traces
40
+ - [LangGraph test file](https://github.com/gojiplus/understudy/blob/main/examples/langgraph/test_langgraph_returns.py) — same tests, different framework
41
+ - [Agentic test file](https://github.com/gojiplus/understudy/blob/main/examples/agentic/test_agentic.py) — agentic flow evaluation
42
+ - [Agentic scene](https://github.com/gojiplus/understudy/blob/main/examples/agentic_scenes/code_review_task.yaml) — task-based scenario
43
+ - [Example report](https://htmlpreview.github.io/?https://github.com/gojiplus/understudy/blob/main/examples/langgraph/report/index.html) — HTML report with metrics and transcripts
44
+
45
+ ## State injection and next-turn tests
46
+
47
+ Restore a completed checkpoint, inject synthetic history/state, or replay through
48
+ exchange X, then execute and assert only against exchange X+1. ADK and LangGraph
49
+ support isolated checkpoint forks; `LangChainApp` builds an instrumented LangChain
50
+ agent with tool middleware. Traces retain nested invocation identities.
51
+
52
+ See the [state-testing guide](https://gojiplus.github.io/understudy/state-testing.html)
53
+ for `run_turn`, `replay_to`, scoped tool mocks, pytest fixtures, CLI commands, and
54
+ framework-specific restoration limits.
27
55
 
28
56
  ## Installation
29
57
 
30
58
  ```bash
31
- pip install understudy[all]
59
+ pip install "understudy[all]"
32
60
  ```
33
61
 
34
62
  ## Quick Start
@@ -51,9 +79,15 @@ from understudy.mocks import MockToolkit
51
79
 
52
80
  mocks = MockToolkit()
53
81
 
82
+
54
83
  @mocks.handle("lookup_order")
55
84
  def lookup_order(order_id: str) -> dict:
56
- return {"order_id": order_id, "items": [...], "status": "delivered"}
85
+ return {
86
+ "order_id": order_id,
87
+ "items": [{"sku": "BACKPACK-01", "quantity": 1}],
88
+ "status": "delivered",
89
+ }
90
+
57
91
 
58
92
  @mocks.handle("create_return")
59
93
  def create_return(order_id: str, item_sku: str, reason: str) -> dict:
@@ -230,7 +264,7 @@ assert result.score == 1
230
264
  Built-in rubrics:
231
265
 
232
266
  ```python
233
- from understudy.judges import (
267
+ from understudy.prompts import (
234
268
  TOOL_USAGE_CORRECTNESS,
235
269
  POLICY_COMPLIANCE,
236
270
  TONE_EMPATHY,
@@ -0,0 +1,207 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.12.5,<0.13"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "understudy"
7
+ version = "0.6.0"
8
+ description = "Simulation and trace-based evaluation for agentic systems"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.12"
13
+ keywords = [
14
+ "agent",
15
+ "evaluation",
16
+ "simulation",
17
+ "testing",
18
+ "llm",
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 3 - Alpha",
22
+ "Intended Audience :: Developers",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
27
+ "Topic :: Software Development :: Testing",
28
+ ]
29
+ dependencies = [
30
+ "pydantic>=2.0",
31
+ "pyyaml>=6.0",
32
+ "litellm>=1.50",
33
+ ]
34
+
35
+ [[project.authors]]
36
+ name = "Gaurav Sood"
37
+
38
+ [project.optional-dependencies]
39
+ adk = [
40
+ "google-adk>=2.11",
41
+ "python-dotenv>=1.0",
42
+ ]
43
+ http = ["httpx>=0.27"]
44
+ langgraph = [
45
+ "langgraph>=1.2.14",
46
+ "langchain-core>=1.6.9",
47
+ "langchain-openai>=0.3",
48
+ ]
49
+ server = [
50
+ "fastapi>=0.115",
51
+ "uvicorn>=0.32",
52
+ ]
53
+ reports = [
54
+ "jinja2>=3.0",
55
+ "click>=8.0",
56
+ ]
57
+ all = ["understudy[adk,http,langgraph,langchain,server,reports]"]
58
+ langchain = [
59
+ "langchain>=1.4.4",
60
+ "langgraph>=1.2.14",
61
+ "langchain-core>=1.6.9",
62
+ ]
63
+
64
+ [project.scripts]
65
+ understudy = "understudy.cli:main"
66
+
67
+ [project.entry-points.pytest11]
68
+ understudy = "understudy.pytest_plugin"
69
+
70
+ [project.urls]
71
+ Homepage = "https://github.com/gojiplus/understudy"
72
+ Documentation = "https://gojiplus.github.io/understudy"
73
+ Repository = "https://github.com/gojiplus/understudy"
74
+ Issues = "https://github.com/gojiplus/understudy/issues"
75
+
76
+ [tool.ruff]
77
+ line-length = 88
78
+ target-version = "py312"
79
+
80
+ [tool.ruff.lint]
81
+ external = ["DOC"]
82
+ select = [
83
+ "E",
84
+ "W",
85
+ "F",
86
+ "I",
87
+ "B",
88
+ "C4",
89
+ "UP",
90
+ "N",
91
+ "D",
92
+ "S",
93
+ "SIM",
94
+ "T20",
95
+ "PT",
96
+ "RUF",
97
+ "PTH",
98
+ "RET",
99
+ "PIE",
100
+ "FURB",
101
+ "PERF",
102
+ "DTZ",
103
+ "LOG",
104
+ "G",
105
+ "TC",
106
+ "FLY",
107
+ "RSE",
108
+ "SLOT",
109
+ "FA",
110
+ "A",
111
+ "EXE",
112
+ "ICN",
113
+ "PGH",
114
+ "PLE",
115
+ "ARG",
116
+ "SLF",
117
+ ]
118
+ ignore = [
119
+ "D203",
120
+ "D213",
121
+ "W191",
122
+ "D206",
123
+ "D300",
124
+ ]
125
+
126
+ [tool.ruff.lint.pydocstyle]
127
+ convention = "google"
128
+
129
+ [tool.ruff.lint.per-file-ignores]
130
+ "tests/**" = [
131
+ "S101",
132
+ "D",
133
+ "ARG",
134
+ "SLF",
135
+ "S108",
136
+ ]
137
+ "docs/**" = ["D"]
138
+ "examples/**" = [
139
+ "S101",
140
+ "T20",
141
+ "D",
142
+ "ARG",
143
+ "A002",
144
+ ]
145
+ "src/understudy/server/models.py" = ["N815"]
146
+
147
+ [tool.pytest.ini_options]
148
+ testpaths = ["tests"]
149
+ asyncio_mode = "auto"
150
+ minversion = "6"
151
+ log_level = "INFO"
152
+ xfail_strict = true
153
+ filterwarnings = ["error"]
154
+ addopts = [
155
+ "--strict-config",
156
+ "--strict-markers",
157
+ "-ra",
158
+ ]
159
+
160
+ [tool.coverage.run]
161
+ source = ["src/understudy"]
162
+ branch = true
163
+
164
+ [tool.coverage.report]
165
+ show_missing = true
166
+ fail_under = 80
167
+
168
+ [tool.pyright]
169
+ include = ["src"]
170
+ typeCheckingMode = "standard"
171
+
172
+ [tool.pydoclint]
173
+ style = "google"
174
+ arg-type-hints-in-docstring = false
175
+ check-return-types = false
176
+ check-class-attributes = false
177
+ allow-init-docstring = true
178
+ exclude = '\.venv|tests|docs'
179
+
180
+ [tool.codespell]
181
+ builtin = "clear,rare,en-GB_to_en-US"
182
+
183
+ [dependency-groups]
184
+ docs = [
185
+ "sphinx>=7.0",
186
+ "furo>=2024.0",
187
+ "myst-parser>=3.0",
188
+ "sphinx-autodoc-typehints>=2.0",
189
+ "sphinx-copybutton",
190
+ "py-canon @ git+https://github.com/gojiplus/py-canon@v1",
191
+ ]
192
+ test = [
193
+ "pytest>=8.0",
194
+ "pytest-asyncio>=0.23",
195
+ "pytest-cov>=4.0",
196
+ "httpx2>=2.12",
197
+ ]
198
+ dev = [
199
+ "pytest>=8.0",
200
+ "pytest-asyncio>=0.23",
201
+ "pytest-cov>=4.0",
202
+ "ruff>=0.4",
203
+ { include-group = "test" },
204
+ { include-group = "docs" },
205
+ "pyright>=1.1.390",
206
+ "pydoclint>=0.5",
207
+ ]
@@ -0,0 +1,151 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.12.5,<0.13"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "understudy"
7
+ version = "0.6.0"
8
+ description = "Simulation and trace-based evaluation for agentic systems"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.12"
13
+ authors = [
14
+ { name = "Gaurav Sood" },
15
+ ]
16
+ keywords = ["agent", "evaluation", "simulation", "testing", "llm"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ "Topic :: Software Development :: Testing",
25
+ ]
26
+ dependencies = [
27
+ "pydantic>=2.0",
28
+ "pyyaml>=6.0",
29
+ "litellm>=1.50",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ adk = ["google-adk>=2.11", "python-dotenv>=1.0"]
34
+ http = ["httpx>=0.27"]
35
+ langgraph = ["langgraph>=1.2.14", "langchain-core>=1.6.9", "langchain-openai>=0.3"]
36
+ server = ["fastapi>=0.115", "uvicorn>=0.32"]
37
+ reports = ["jinja2>=3.0", "click>=8.0"]
38
+ all = ["understudy[adk,http,langgraph,langchain,server,reports]"]
39
+ langchain = [
40
+ "langchain>=1.4.4",
41
+ "langgraph>=1.2.14",
42
+ "langchain-core>=1.6.9",
43
+ ]
44
+
45
+ [project.scripts]
46
+ understudy = "understudy.cli:main"
47
+
48
+ [project.entry-points.pytest11]
49
+ understudy = "understudy.pytest_plugin"
50
+
51
+ [project.urls]
52
+ Homepage = "https://github.com/gojiplus/understudy"
53
+ Documentation = "https://gojiplus.github.io/understudy"
54
+ Repository = "https://github.com/gojiplus/understudy"
55
+ Issues = "https://github.com/gojiplus/understudy/issues"
56
+
57
+ [tool.ruff]
58
+ line-length = 88
59
+ target-version = "py312"
60
+
61
+ [tool.ruff.lint]
62
+ external = ["DOC"]
63
+ select = [
64
+ "E", "W", "F", "I", "B", "C4", "UP", "N", "D", "S", "SIM", "T20", "PT", "RUF",
65
+ "PTH", "RET", "PIE", "FURB", "PERF", "DTZ", "LOG", "G", "TC", "FLY",
66
+ "RSE", "SLOT", "FA", "A", "EXE", "ICN", "PGH", "PLE", "ARG", "SLF",
67
+ ]
68
+ # D203/D213: the google convention the fleet standard picks. W191/D206/D300:
69
+ # ruff's own docs list these as always incompatible with `ruff format`, which
70
+ # the standard also runs.
71
+ ignore = ["D203", "D213", "W191", "D206", "D300"]
72
+
73
+ [tool.ruff.lint.pydocstyle]
74
+ convention = "google"
75
+
76
+ [tool.ruff.lint.per-file-ignores]
77
+ # S108: "/tmp/..." strings in tests are inert fixture data, never opened.
78
+ "tests/**" = ["S101", "D", "ARG", "SLF", "S108"]
79
+ "docs/**" = ["D"]
80
+ # Runnable demo scripts: asserts and prints are their idiom, unused callback
81
+ # arguments mirror the framework signatures they demonstrate, and mock tool
82
+ # handlers must reuse the tool's own argument names (`format` included)
83
+ # because mocks are invoked with keyword arguments from the scene.
84
+ "examples/**" = ["S101", "T20", "D", "ARG", "A002"]
85
+ # Request/response models mirror the UI client's camelCase wire schema.
86
+ "src/understudy/server/models.py" = ["N815"]
87
+
88
+ [tool.pytest.ini_options]
89
+ testpaths = ["tests"]
90
+ asyncio_mode = "auto"
91
+ minversion = "6"
92
+ log_level = "INFO"
93
+ xfail_strict = true
94
+ filterwarnings = ["error"]
95
+ addopts = ["--strict-config", "--strict-markers", "-ra"]
96
+
97
+ [tool.coverage.run]
98
+ source = ["src/understudy"]
99
+ branch = true
100
+
101
+ [tool.coverage.report]
102
+ show_missing = true
103
+ fail_under = 80
104
+
105
+ [tool.pyright]
106
+ include = ["src"]
107
+ typeCheckingMode = "standard"
108
+
109
+ [tool.pydoclint]
110
+ style = "google"
111
+ arg-type-hints-in-docstring = false
112
+ check-return-types = false
113
+ check-class-attributes = false
114
+ allow-init-docstring = true
115
+ exclude = '\.venv|tests|docs'
116
+
117
+ [dependency-groups]
118
+ # Development concerns, not user-facing optional features -- extras are for
119
+ # what a consumer might install, and nobody installs understudy to build its
120
+ # docs. CI syncs `--all-extras --all-groups`.
121
+ docs = [
122
+ "sphinx>=7.0",
123
+ "furo>=2024.0",
124
+ "myst-parser>=3.0",
125
+ "sphinx-autodoc-typehints>=2.0",
126
+ "sphinx-copybutton",
127
+ "py-canon @ git+https://github.com/gojiplus/py-canon@v1",
128
+ ]
129
+ test = [
130
+ "pytest>=8.0",
131
+ "pytest-asyncio>=0.23",
132
+ "pytest-cov>=4.0",
133
+ # starlette's TestClient (reached through fastapi.testclient) warns that
134
+ # driving it with httpx is deprecated and names httpx2 as the replacement.
135
+ # Under filterwarnings = ["error"] that notice fails collection of
136
+ # tests/test_server.py outright.
137
+ "httpx2>=2.12",
138
+ ]
139
+ dev = [
140
+ "pytest>=8.0",
141
+ "pytest-asyncio>=0.23",
142
+ "pytest-cov>=4.0",
143
+ "ruff>=0.4",
144
+ { include-group = "test" },
145
+ { include-group = "docs" },
146
+ "pyright>=1.1.390",
147
+ "pydoclint>=0.5",
148
+ ]
149
+
150
+ [tool.codespell]
151
+ builtin = "clear,rare,en-GB_to_en-US"