Skip to content

Commit ae3e260

Browse files
authored
Setup basic github actions and cleaning up pyproject.toml (#64)
* adding a cleaner version of pyproject.toml * modifying elrons pr to run with uv on many py versions * moving things into a workflows folder * removing py 3.9 * fixing pre-commit issues in all files * adding uv.lock * small change * adding ollama and tests * small change * small change * disabling ollama tests for now cause they are taking too long * removing ollama and llm tests for now * moving docling to it's own group
1 parent 77d2f08 commit ae3e260

15 files changed

+2702
-2592
lines changed

.github/workflows/quality.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Verify Code Quality
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref_name }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
quality:
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 30
17+
strategy:
18+
matrix:
19+
python-version: ['3.10', '3.11', '3.12'] # Need to add 3.13 once we resolve outlines issues.
20+
steps:
21+
- uses: actions/checkout@v4
22+
- name: Install uv and set the python version
23+
uses: astral-sh/setup-uv@v5
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
enable-cache: true
27+
- name: pre-commit cache key
28+
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> "$GITHUB_ENV"
29+
- uses: actions/cache@v4
30+
with:
31+
path: ~/.cache/pre-commit
32+
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
33+
- name: Install dependencies
34+
run: uv sync --frozen --all-extras
35+
- name: Check style and run tests
36+
run: pre-commit run --all-files
37+
- name: Send failure message
38+
if: failure() # This step will only run if a previous step failed
39+
run: echo "The quality verification failed. Please run precommit "

docs/dev/constrained_decoding.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The `m` framework currently uses the `format` argument to pydantic schemas, **ou
1010

1111
> If a keyword had meaning across multiple types of backends, and if it means the same thing in all of those backends but has different names, then we use the `@@@`-style args so that the user can pass these args across all backends in the same way. Otherwise, the arguments in model_args are passed along verbatim.
1212
13-
This argues for `@@@format@@@` as opposed to a dedicated `format` option in the method signature. Or, in the alternative, for an entir re-think of ModelArgs.
13+
This argues for `@@@format@@@` as opposed to a dedicated `format` option in the method signature. Or, in the alternative, for an entire re-think of ModelArgs.
1414

1515
## Integration with grammar-targeted LLMs
1616

docs/examples/notebooks/compositionality_with_generative_slots.ipynb

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{
@@ -76,15 +81,18 @@
7681
"source": [
7782
"from mellea import generative\n",
7883
"\n",
84+
"\n",
7985
"# The Summarizer Library\n",
8086
"@generative\n",
8187
"def summarize_meeting(transcript: str) -> str:\n",
8288
" \"\"\"Summarize the meeting transcript into a concise paragraph of main points.\"\"\"\n",
8389
"\n",
90+
"\n",
8491
"@generative\n",
8592
"def summarize_contract(contract_text: str) -> str:\n",
8693
" \"\"\"Produce a natural language summary of contract obligations and risks.\"\"\"\n",
8794
"\n",
95+
"\n",
8896
"@generative\n",
8997
"def summarize_short_story(story: str) -> str:\n",
9098
" \"\"\"Summarize a short story, with one paragraph on plot and one paragraph on braod themes.\"\"\""
@@ -109,10 +117,12 @@
109117
"def propose_business_decision(summary: str) -> str:\n",
110118
" \"\"\"Given a structured summary with clear recommendations, propose a business decision.\"\"\"\n",
111119
"\n",
120+
"\n",
112121
"@generative\n",
113122
"def generate_risk_mitigation(summary: str) -> str:\n",
114123
" \"\"\"If the summary contains risk elements, propose mitigation strategies.\"\"\"\n",
115124
"\n",
125+
"\n",
116126
"@generative\n",
117127
"def generate_novel_recommendations(summary: str) -> str:\n",
118128
" \"\"\"Provide a list of novel recommendations that are similar in plot or theme to the short story summary.\"\"\""
@@ -135,16 +145,19 @@
135145
"outputs": [],
136146
"source": [
137147
"# Compose the libraries.\n",
138-
"from typing import Literal # noqa: E402\n",
148+
"from typing import Literal\n",
149+
"\n",
139150
"\n",
140151
"@generative\n",
141152
"def has_structured_conclusion(summary: str) -> Literal[\"yes\", \"no\"]:\n",
142153
" \"\"\"Determine whether the summary contains a clearly marked conclusion or recommendation.\"\"\"\n",
143154
"\n",
155+
"\n",
144156
"@generative\n",
145157
"def contains_actionable_risks(summary: str) -> Literal[\"yes\", \"no\"]:\n",
146158
" \"\"\"Check whether the summary contains references to business risks or exposure.\"\"\"\n",
147159
"\n",
160+
"\n",
148161
"@generative\n",
149162
"def has_theme_and_plot(summary: str) -> Literal[\"yes\", \"no\"]:\n",
150163
" \"\"\"Check whether the summary contains both a plot and thematic elements.\"\"\""
@@ -166,7 +179,7 @@
166179
},
167180
"outputs": [],
168181
"source": [
169-
"from mellea import start_session # noqa: E402\n",
182+
"from mellea import start_session\n",
170183
"\n",
171184
"m = start_session()"
172185
]

docs/examples/notebooks/context_example.ipynb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{
@@ -80,6 +85,7 @@
8085
"outputs": [],
8186
"source": [
8287
"from mellea import LinearContext, start_session\n",
88+
"\n",
8389
"m = start_session(ctx=LinearContext())\n",
8490
"m.chat(\"Make up a math problem.\")\n",
8591
"m.chat(\"Solve your math problem.\")\n",

docs/examples/notebooks/document_mobject.ipynb

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{
@@ -77,6 +82,7 @@
7782
"outputs": [],
7883
"source": [
7984
"from mellea.stdlib.docs.richdocument import RichDocument\n",
85+
"\n",
8086
"rd = RichDocument.from_document_file(\"https://arxiv.org/pdf/1906.04043\")"
8187
]
8288
},
@@ -96,7 +102,8 @@
96102
},
97103
"outputs": [],
98104
"source": [
99-
"from mellea.stdlib.docs.richdocument import Table # noqa: E402\n",
105+
"from mellea.stdlib.docs.richdocument import Table\n",
106+
"\n",
100107
"table1: Table = rd.get_tables()[0]\n",
101108
"print(table1.to_markdown())"
102109
]
@@ -119,8 +126,9 @@
119126
},
120127
"outputs": [],
121128
"source": [
122-
"from mellea import start_session # noqa: E402\n",
123-
"from mellea.backends.types import ModelOption # noqa: E402\n",
129+
"from mellea import start_session\n",
130+
"from mellea.backends.types import ModelOption\n",
131+
"\n",
124132
"m = start_session()\n",
125133
"for seed in [x * 12 for x in range(5)]:\n",
126134
" table2 = m.transform(\n",

docs/examples/notebooks/example.ipynb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{
@@ -77,6 +82,7 @@
7782
"outputs": [],
7883
"source": [
7984
"import mellea\n",
85+
"\n",
8086
"m = mellea.start_session()"
8187
]
8288
},

docs/examples/notebooks/instruct_validate_repair.ipynb

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{
@@ -66,9 +71,9 @@
6671
"source": [
6772
"## Import Mellea and Specify Requirements\n",
6873
"We create 3 requirements:\n",
69-
"- 1st requirement (r1) will be validated by LLM-as-a-judge on the output of the instruction. This is the default behavior.\n",
70-
"- 2nd requirement (r2) uses a function that takes the output of a sampling step and returns a boolean value indicating successful or unsuccessful validation. While the validation_fn parameter requires to run validation on the full session context, Mellea provides a wrapper for simpler validation functions (simple_validate(fn: Callable[[str], bool])) that take the output string and return a boolean as seen in this case.\n",
71-
"- 3rd requirement is a check(). Checks are only used for validation, not for generation. Checks aim to avoid the \"do not think about B\" effect that often primes models (and humans) to do the opposite and \"think\" about B."
74+
"- First requirement (r1) will be validated by LLM-as-a-judge on the output of the instruction. This is the default behavior.\n",
75+
"- Second requirement (r2) uses a function that takes the output of a sampling step and returns a boolean value indicating successful or unsuccessful validation. While the validation_fn parameter requires to run validation on the full session context, Mellea provides a wrapper for simpler validation functions (simple_validate(fn: Callable[[str], bool])) that take the output string and return a boolean as seen in this case.\n",
76+
"- Third requirement is a check(). Checks are only used for validation, not for generation. Checks aim to avoid the \"do not think about B\" effect that often primes models (and humans) to do the opposite and \"think\" about B."
7277
]
7378
},
7479
{
@@ -79,9 +84,10 @@
7984
},
8085
"outputs": [],
8186
"source": [
87+
"import mellea\n",
8288
"from mellea.stdlib.requirement import check, req, simple_validate\n",
83-
"import mellea # noqa: E402\n",
84-
"from mellea.stdlib.sampling import RejectionSamplingStrategy # noqa: E402\n",
89+
"from mellea.stdlib.sampling import RejectionSamplingStrategy\n",
90+
"\n",
8591
"requirements = [\n",
8692
" req(\"The email should have a salutation\"), # == r1\n",
8793
" req(\n",

docs/examples/notebooks/m_serve_example.ipynb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{

docs/examples/notebooks/mcp_example.ipynb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,13 @@
3535
"!uv pip install mcp -q\n",
3636
"\n",
3737
"from IPython.display import HTML, display\n",
38-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
39-
"get_ipython().events.register('pre_run_cell',set_css)"
38+
"\n",
39+
"\n",
40+
"def set_css():\n",
41+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
42+
"\n",
43+
"\n",
44+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
4045
]
4146
},
4247
{
@@ -76,6 +81,7 @@
7681
"outputs": [],
7782
"source": [
7883
"from mcp.server.fastmcp import FastMCP\n",
84+
"\n",
7985
"from mellea import MelleaSession\n",
8086
"from mellea.backends import model_ids\n",
8187
"from mellea.backends.ollama import OllamaModelBackend\n",
@@ -100,6 +106,7 @@
100106
"source": [
101107
"mcp = FastMCP(\"Demo\")\n",
102108
"\n",
109+
"\n",
103110
"@mcp.tool()\n",
104111
"def write_a_poem(word_limit: int) -> str:\n",
105112
" \"\"\"Write a poem with a word limit.\"\"\"\n",
@@ -116,10 +123,11 @@
116123
" assert isinstance(res, ModelOutputThunk)\n",
117124
" return str(res.value)\n",
118125
"\n",
126+
"\n",
119127
"@mcp.resource(\"greeting://{name}\")\n",
120128
"def get_greeting(name: str) -> str:\n",
121129
" \"\"\"Get a personalized greeting\"\"\"\n",
122-
" return f\"Hello, {name}!\" "
130+
" return f\"Hello, {name}!\""
123131
]
124132
}
125133
],

docs/examples/notebooks/model_options_example.ipynb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
},
88
"source": [
99
"# Model Options Example\n",
10-
"This Jupyter notebook runs on Colab and demostrates specifying model options"
10+
"This Jupyter notebook runs on Colab and demonstrates specifying model options"
1111
]
1212
},
1313
{
@@ -33,8 +33,13 @@
3333
"!nohup ollama serve >/dev/null 2>&1 &\n",
3434
"\n",
3535
"from IPython.display import HTML, display\n",
36-
"def set_css(): display(HTML('\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n'))\n",
37-
"get_ipython().events.register('pre_run_cell',set_css)"
36+
"\n",
37+
"\n",
38+
"def set_css():\n",
39+
" display(HTML(\"\\n<style>\\n pre{\\n white-space: pre-wrap;\\n}\\n</style>\\n\"))\n",
40+
"\n",
41+
"\n",
42+
"get_ipython().events.register(\"pre_run_cell\", set_css)"
3843
]
3944
},
4045
{

0 commit comments

Comments
 (0)