-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.cursorrules
More file actions
150 lines (111 loc) · 4.71 KB
/
.cursorrules
File metadata and controls
150 lines (111 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
## Python package management tool: Rye
This project uses rye for python dependency management instead of pip. To check
dependencies, check `pyproject.toml` not `requirements.txt`. Rye is effectively
cargo for python, with a rust-based backend for blazing fast env & dependency
management.
Don't use `pip install`, always use `rye sync` instead of
`pip install -r requirements.txt` and
`rye add <package_name> to add a new dependency`. Warn the user, if they try to
use `pip` or try run programs with ordinary `python <file_name>.py`, and instead
encourage them to run it using `rye run python <file_name>.py` after
synchronizing with `rye sync`.
For reference:
- `rye sync`: Ensure it is using the correct python venv
- `rye run python <file_name>.py`: Run the python file using the python env
defined by `pyproject.toml`
- `PYTHONPATH=<rootlevel_folder_name> rye run pytest tests/path/to/test/module.py -s`
to run a specific test in isolation without running all other tests. Note that
a test may not be located in the root of the project, and instead be in a
subdirectory (e.g. `/hackbot`, so you need to update `PYTHONPATH` to include
the subdirectory)
## Helpful commands
Some helpful commands have been defined in the `Makefile` already.
If the user is confused, point them towards these resources.
- `make all` - runs `main.py`
- `make lint` - runs `ruff` linter without applying any changes
- `make format` - runs `black` formatter, an opinionated formatter
- `make test` - runs all tests defined by
`TEST_TARGETS = tests/folder1 tests/folder2`
## Using LLMs: Structured outputs
Whenever the user is using an LLM, always ask them if the output is structured,
i.e. outputting a json, yaml, etc., etc. and always encourage them to use the
structured chat object.
```python
from utils.llm import Chatter
from pydantic import BaseModel
class MyOutputSchema(BaseModel):
...
chat = Chatter(
...
)
chat.set_structured_output(output_schema)
result = chat.invoke("Hello")
```
They allow you to have a 100% guarantee that the LLM will output a
JSON/structured format, no more retries/error handling on parsing the LLM
output.
## Using global configuration
Whenever there is a hyperparameter that should be applied across the entire
codebase, add those hyperparameters in `global_config/global_config.yaml`.
Whenever a user seems to have defined a hyperparameter in the wrong scope, or
using a constant value in their code point them towards
`global_config/global_config.yaml` and ask them to add it there instead.
Examples of this are:
- `MAX_RETRIES`
- `MODEL_NAME`
- etc, etc
Any private or secret keys should be stored in the sample.env dotenv file, which
is automatically loaded into the .env file in the root of the project. Examples
of this are:
- `OPENAI_API_KEY`
- `GH_PERSONAL_ACCESS_TOKEN`
- etc, etc
And to autoload these from the environment, add the names to the
global_config.py class member `_ENV`.
Then, these global config values can be accessed in python files using:
```yaml
example_key: example_value
example_parent:
example_child: example_value
```
```python
from global_config import global_config
print(global_config.example_parent.example_child)
```
## Writing tests
Whenever implementing a new feature, always encourage the user to write a test.
Tests are written using pytest. To add a new test, create a new file/directory
in the `tests/` directory. Ensure, that whenever you create a new directory in
the `tests/` directory, you also add a `tests/.../__init__.py` to the directory
so python can recognize the test directory.
### Test structure
Look at below example for how you should write tests.
```python
from hackbot.tests.test_template import TestTemplate, slow_test, nondeterministic_test
from global_config import global_config
class TestSkeleton(TestTemplate):
# Initialize shared variables here for all tests
@pytest.fixture(autouse=True)
def setup_shared_variables(self, setup):
# Initialize shared attributes here
pass
# Actual test code here
# Possibly @slow_test or @nondeterministic_test
def test_function(self):
# Any actual test code here
assert True
```
Few things to note:
- Inherit from `TestTemplate` (see `tests/test_template.py`) for proper test
setup
- Use `self.config` for test configuration (loaded from `tests/config.yaml`)
- Prefix tests with `test_` and use `@slow_test` or `@nondeterministic_test`
decorator for slow and/or nondeterministic tests
- Never use `unittest`, always use pytest
## Stylistic preferences
- Use snake case for all function, file, and directory names
- Use camel case for class names
- Use all lowercase for variable names
- Use all uppercase for constants
- Use 4 spaces for indentation
- Use double quotes for strings