understudy 0.5.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 (67) hide show
  1. understudy-0.6.0/LICENSE +21 -0
  2. {understudy-0.5.0 → understudy-0.6.0}/PKG-INFO +34 -23
  3. {understudy-0.5.0 → understudy-0.6.0}/README.md +23 -6
  4. understudy-0.6.0/pyproject.toml +207 -0
  5. understudy-0.6.0/pyproject.toml.orig +151 -0
  6. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/__init__.py +105 -75
  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.5.0 → understudy-0.6.0}/src/understudy/agentic/check.py +14 -3
  10. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/agentic/metrics.py +1 -0
  11. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/agentic/models.py +32 -20
  12. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/agentic/runner.py +24 -14
  13. understudy-0.6.0/src/understudy/assertions.py +44 -0
  14. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/batch.py +7 -6
  15. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/check.py +44 -13
  16. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/cli.py +209 -50
  17. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/compare.py +6 -1
  18. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/diff.py +23 -15
  19. understudy-0.6.0/src/understudy/execution.py +320 -0
  20. understudy-0.6.0/src/understudy/http/__init__.py +369 -0
  21. understudy-0.6.0/src/understudy/instrumentation.py +39 -0
  22. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/judge_backends.py +7 -4
  23. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/judges.py +8 -2
  24. understudy-0.6.0/src/understudy/langchain/__init__.py +35 -0
  25. understudy-0.6.0/src/understudy/langchain/middleware.py +51 -0
  26. understudy-0.6.0/src/understudy/langgraph/__init__.py +448 -0
  27. understudy-0.6.0/src/understudy/langgraph/instrumentation.py +58 -0
  28. understudy-0.6.0/src/understudy/langgraph/tools.py +77 -0
  29. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/metrics/builtins.py +25 -9
  30. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/metrics/registry.py +7 -7
  31. understudy-0.6.0/src/understudy/mocks.py +105 -0
  32. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/models.py +31 -15
  33. understudy-0.6.0/src/understudy/py.typed +0 -0
  34. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/pytest_plugin.py +16 -56
  35. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/replay.py +9 -6
  36. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/reports.py +23 -9
  37. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/runner.py +46 -19
  38. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/server/__init__.py +3 -2
  39. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/server/sessions.py +18 -18
  40. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/server/ui_simulator.py +19 -8
  41. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/simulator.py +4 -5
  42. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/storage.py +35 -17
  43. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/suite.py +43 -10
  44. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/run_detail.html +25 -2
  45. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/trace.py +55 -6
  46. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/validation.py +38 -44
  47. understudy-0.5.0/pyproject.toml +0 -73
  48. understudy-0.5.0/src/understudy/adk/__init__.py +0 -254
  49. understudy-0.5.0/src/understudy/http/__init__.py +0 -346
  50. understudy-0.5.0/src/understudy/langgraph/__init__.py +0 -162
  51. understudy-0.5.0/src/understudy/langgraph/tools.py +0 -100
  52. understudy-0.5.0/src/understudy/mocks.py +0 -56
  53. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/agentic/__init__.py +0 -0
  54. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/metrics/__init__.py +0 -0
  55. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/metrics/templates/clarity.jinja +0 -0
  56. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/metrics/templates/policy_compliance.jinja +0 -0
  57. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/metrics/templates/tone_empathy.jinja +0 -0
  58. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/prompts/__init__.py +4 -4
  59. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/prompts/rubrics.py +0 -0
  60. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/server/models.py +0 -0
  61. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/base.html +0 -0
  62. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/comparison.html +0 -0
  63. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/index.html +0 -0
  64. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/init/conftest.py.template +0 -0
  65. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/init/example_scene.yaml +0 -0
  66. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/init/test_agent.py.template +0 -0
  67. {understudy-0.5.0 → understudy-0.6.0}/src/understudy/templates/init/understudy.yaml.template +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.5.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,7 +59,7 @@ 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
@@ -75,7 +69,7 @@ The key insight: **assert against the trace, not the prose**. Don't check what t
75
69
  ## Two Evaluation Paradigms
76
70
 
77
71
  ### Conversational Agent Evaluation
78
- Simulate multi-turn conversations with personas to test dialogue agents.
72
+ Simulate multi-turn conversations with personas to test dialog agents.
79
73
  - Use case: Customer service bots, assistants, chatbots
80
74
  - Assert on tool calls: `trace.called("tool_name")`
81
75
 
@@ -84,7 +78,7 @@ Evaluate autonomous agents executing multi-step tasks.
84
78
  - Use case: Code agents, research agents, task automation
85
79
  - Assert on actions: `trace.performed("action")`
86
80
 
87
- See [examples/README.md](examples/README.md) for complete examples of both paradigms.
81
+ See [examples/README.md](https://github.com/gojiplus/understudy/blob/main/examples/README.md) for complete examples of both paradigms.
88
82
 
89
83
  **See real examples:**
90
84
  - [Example scene](https://github.com/gojiplus/understudy/blob/main/examples/scenes/return_eligible_backpack.yaml) — YAML defining a test scenario
@@ -94,10 +88,21 @@ See [examples/README.md](examples/README.md) for complete examples of both parad
94
88
  - [Agentic scene](https://github.com/gojiplus/understudy/blob/main/examples/agentic_scenes/code_review_task.yaml) — task-based scenario
95
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
96
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.
101
+
97
102
  ## Installation
98
103
 
99
104
  ```bash
100
- pip install understudy[all]
105
+ pip install "understudy[all]"
101
106
  ```
102
107
 
103
108
  ## Quick Start
@@ -120,9 +125,15 @@ from understudy.mocks import MockToolkit
120
125
 
121
126
  mocks = MockToolkit()
122
127
 
128
+
123
129
  @mocks.handle("lookup_order")
124
130
  def lookup_order(order_id: str) -> dict:
125
- 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
+
126
137
 
127
138
  @mocks.handle("create_return")
128
139
  def create_return(order_id: str, item_sku: str, reason: str) -> dict:
@@ -299,7 +310,7 @@ assert result.score == 1
299
310
  Built-in rubrics:
300
311
 
301
312
  ```python
302
- from understudy.judges import (
313
+ from understudy.prompts import (
303
314
  TOOL_USAGE_CORRECTNESS,
304
315
  POLICY_COMPLIANCE,
305
316
  TONE_EMPATHY,
@@ -13,7 +13,7 @@ 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
@@ -23,7 +23,7 @@ The key insight: **assert against the trace, not the prose**. Don't check what t
23
23
  ## Two Evaluation Paradigms
24
24
 
25
25
  ### Conversational Agent Evaluation
26
- Simulate multi-turn conversations with personas to test dialogue agents.
26
+ Simulate multi-turn conversations with personas to test dialog agents.
27
27
  - Use case: Customer service bots, assistants, chatbots
28
28
  - Assert on tool calls: `trace.called("tool_name")`
29
29
 
@@ -32,7 +32,7 @@ Evaluate autonomous agents executing multi-step tasks.
32
32
  - Use case: Code agents, research agents, task automation
33
33
  - Assert on actions: `trace.performed("action")`
34
34
 
35
- See [examples/README.md](examples/README.md) for complete examples of both paradigms.
35
+ See [examples/README.md](https://github.com/gojiplus/understudy/blob/main/examples/README.md) for complete examples of both paradigms.
36
36
 
37
37
  **See real examples:**
38
38
  - [Example scene](https://github.com/gojiplus/understudy/blob/main/examples/scenes/return_eligible_backpack.yaml) — YAML defining a test scenario
@@ -42,10 +42,21 @@ See [examples/README.md](examples/README.md) for complete examples of both parad
42
42
  - [Agentic scene](https://github.com/gojiplus/understudy/blob/main/examples/agentic_scenes/code_review_task.yaml) — task-based scenario
43
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
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.
55
+
45
56
  ## Installation
46
57
 
47
58
  ```bash
48
- pip install understudy[all]
59
+ pip install "understudy[all]"
49
60
  ```
50
61
 
51
62
  ## Quick Start
@@ -68,9 +79,15 @@ from understudy.mocks import MockToolkit
68
79
 
69
80
  mocks = MockToolkit()
70
81
 
82
+
71
83
  @mocks.handle("lookup_order")
72
84
  def lookup_order(order_id: str) -> dict:
73
- 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
+
74
91
 
75
92
  @mocks.handle("create_return")
76
93
  def create_return(order_id: str, item_sku: str, reason: str) -> dict:
@@ -247,7 +264,7 @@ assert result.score == 1
247
264
  Built-in rubrics:
248
265
 
249
266
  ```python
250
- from understudy.judges import (
267
+ from understudy.prompts import (
251
268
  TOOL_USAGE_CORRECTNESS,
252
269
  POLICY_COMPLIANCE,
253
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"