diff --git a/README.md b/README.md
index 45f1e8e77..18712d3fe 100644
--- a/README.md
+++ b/README.md
@@ -39,12 +39,17 @@ with structured, maintainable, robust, and efficient AI workflows.
## Getting Started
+
+You can get started with a local install, or by using Colab notebooks.
+
+### Getting Started with Local Infernece
+
Install with pip:
```bash
-uv pip install .
+uv pip install mellea
```
> [!NOTE]
@@ -69,6 +74,23 @@ Then run it:
uv run --with mellea docs/examples/tutorial/example.py
```
+### Get Started with Colab
+
+| Notebook | Try in Colab | Goal |
+|----------|--------------|------|
+| Hello, World |
| Quick‑start demo |
+| Simple Email |
| Using the `m.instruct` primitive |
+| Instruct-Validate-Repair |
| Introduces our first generative programming design pattern |
+| Model Options |
| Demonstrates how to pass model options through to backends |
+| Sentiment Classifier |
| Introduces the `@generative` decorator |
+| Managing Context |
| Shows how to construct and manage context in a `MelleaSession` |
+| Generative OOP |
| Demonstrates object-oriented generative programming in Mellea |
+| Rich Documents |
| A generative program that uses Docling to work with rich-text documents |
+| Composing Generative Functions |
| Demonstrates contract-oriented programming in Mellea |
+| `m serve` |
| Serve a generative program as an openai-compatible model endpoint |
+| MCP |
| Mellea + MCP |
+
+
### Installing from source
Fork and clone the repositoy:
@@ -99,7 +121,7 @@ pre-commit install
Mellea supports validation of generation results through a **instruct-validate-repair** pattern.
Below, the request for *"Write an email.."* is constrained by the requirements of *"be formal"* and *"Use 'Dear interns' as greeting."*.
-Using a simple rejection sampling strategy, the request is send up to three (loop_budget) times to the model and
+Using a simple rejection sampling strategy, the request is sent up to three (loop_budget) times to the model and
the output is checked against the constraints using (in this case) LLM-as-a-judge.
@@ -114,7 +136,7 @@ from mellea.stdlib.sampling import RejectionSamplingStrategy
# create a session with Mistral running on Ollama
m = MelleaSession(
backend=OllamaModelBackend(
- model_id=model_ids.MISTRALAI_MISTRAL_0_3_7b,
+ model_id=model_ids.MISTRALAI_MISTRAL_0_3_7B,
model_options={ModelOption.MAX_NEW_TOKENS: 300},
)
)
@@ -133,11 +155,11 @@ print(f"***** email ****\n{str(email_v1)}\n*******")
## Getting Started with Generative Slots
-Generative slots allow to define functions without implementing them.
-By using the `@generative` decorator, the function gets converted into an LLM function.
-The example below, is a minimal version of writing a sentiment classification function
-using Mellea's generative slots and a local LLM.
-
+Generative slots allow you to define functions without implementing them.
+The `@generative` decorator marks a function as one that should be interpreted by querying an LLM.
+The example below demonstrates how an LLM's sentiment classification
+capability can be wrapped up as a function using Mellea's generative slots and
+a local LLM.
```python
diff --git a/docs/examples/notebooks/compositionality_with_generative_slots.ipynb b/docs/examples/notebooks/compositionality_with_generative_slots.ipynb
new file mode 100644
index 000000000..9c1d06c6c
--- /dev/null
+++ b/docs/examples/notebooks/compositionality_with_generative_slots.ipynb
@@ -0,0 +1,309 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Compositionality with Generative Slots\n",
+ "This Jupyter notebook runs on Colab demonstrates GEnerative Slots, a function whose implementation is provided by an LLM. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Create Summarizer Library\n",
+ "Form a Summarizer library that contains a set of functions for summarizing various types of documents."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mellea import generative\n",
+ "\n",
+ "# The Summarizer Library\n",
+ "@generative\n",
+ "def summarize_meeting(transcript: str) -> str:\n",
+ " \"\"\"Summarize the meeting transcript into a concise paragraph of main points.\"\"\"\n",
+ "\n",
+ "@generative\n",
+ "def summarize_contract(contract_text: str) -> str:\n",
+ " \"\"\"Produce a natural language summary of contract obligations and risks.\"\"\"\n",
+ "\n",
+ "@generative\n",
+ "def summarize_short_story(story: str) -> str:\n",
+ " \"\"\"Summarize a short story, with one paragraph on plot and one paragraph on braod themes.\"\"\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create Decision Aide Library\n",
+ "Form a Decision Aides library that aids in decision making for particular situations."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# The Decision Aides Library\n",
+ "@generative\n",
+ "def propose_business_decision(summary: str) -> str:\n",
+ " \"\"\"Given a structured summary with clear recommendations, propose a business decision.\"\"\"\n",
+ "\n",
+ "@generative\n",
+ "def generate_risk_mitigation(summary: str) -> str:\n",
+ " \"\"\"If the summary contains risk elements, propose mitigation strategies.\"\"\"\n",
+ "\n",
+ "@generative\n",
+ "def generate_novel_recommendations(summary: str) -> str:\n",
+ " \"\"\"Provide a list of novel recommendations that are similar in plot or theme to the short story summary.\"\"\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Specify Contract Functions\n",
+ "To help us compose these libraries, we introduce a set of contracts that gate function composition and then use those contracts to short-circuit non-sensical compositions of library components:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "P1-mChhly4Ow"
+ },
+ "outputs": [],
+ "source": [
+ "# Compose the libraries.\n",
+ "from typing import Literal # noqa: E402\n",
+ "\n",
+ "@generative\n",
+ "def has_structured_conclusion(summary: str) -> Literal[\"yes\", \"no\"]:\n",
+ " \"\"\"Determine whether the summary contains a clearly marked conclusion or recommendation.\"\"\"\n",
+ "\n",
+ "@generative\n",
+ "def contains_actionable_risks(summary: str) -> Literal[\"yes\", \"no\"]:\n",
+ " \"\"\"Check whether the summary contains references to business risks or exposure.\"\"\"\n",
+ "\n",
+ "@generative\n",
+ "def has_theme_and_plot(summary: str) -> Literal[\"yes\", \"no\"]:\n",
+ " \"\"\"Check whether the summary contains both a plot and thematic elements.\"\"\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Start a Mellea Session\n",
+ "We initialize a backend running Ollama using the granite3.3-chat model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "-0GPZ3_ty4Ow"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea import start_session # noqa: E402\n",
+ "\n",
+ "m = start_session()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Provide a meeting transcript with sample data."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "AQGDkbeby4Ox"
+ },
+ "outputs": [],
+ "source": [
+ "transcript = \"\"\"Meeting Transcript: Market Risk Review -- Self-Sealing Stembolts Division\n",
+ "Date: December 1, 3125\n",
+ "Attendees:\n",
+ "\n",
+ "Karen Rojas, VP of Product Strategy\n",
+ "\n",
+ "Derek Madsen, Director of Global Procurement\n",
+ "\n",
+ "Felicia Zheng, Head of Market Research\n",
+ "\n",
+ "Tom Vega, CFO\n",
+ "\n",
+ "Luis Tran, Engineering Liaison\n",
+ "\n",
+ "Karen Rojas:\n",
+ "Thanks, everyone, for making time on short notice. As you've all seen, we've got three converging market risks we need to address: tariffs on micro-carburetors, increased adoption of the self-interlocking leafscrew, and, believe it or not, the \"hipsterfication\" of the construction industry. I need all on deck and let's not waste time. Derek, start.\n",
+ "\n",
+ "Derek Madsen:\n",
+ "Right. As of Monday, the 25% tariff on micro-carburetors sourced from the Pan-Alpha Centauri confederacy is active. We tried to pre-purchase a three-month buffer, but after that, our unit cost rises by $1.72. That's a 9% increase in the BOM cost of our core model 440 stembolt. Unless we find alternative suppliers or pass on the cost, we're eating into our already narrow margin.\n",
+ "\n",
+ "Tom Vega:\n",
+ "We cannot absorb that without consequences. If we pass the cost downstream, we risk losing key mid-tier OEM clients. And with the market already sniffing around leafscrew alternatives, this makes us more vulnerable.\n",
+ "\n",
+ "Karen:\n",
+ "Lets pause there. Felicia, give us the quick-and-dirty on the leafscrew.\n",
+ "\n",
+ "Felicia Zheng:\n",
+ "It's ugly. Sales of the self-interlocking leafscrew—particularly in modular and prefab construction—are up 38% year-over-year. It's not quite a full substitute for our self-sealing stembolts, but they are close enough in function that some contractors are making the switch. Their appeal? No micro-carburetors, lower unit complexity, and easier training for install crews. We estimate we've lost about 12% of our industrial segment to the switch in the last two quarters.\n",
+ "\n",
+ "Karen:\n",
+ "Engineering, Luis; your take on how real that risk is?\n",
+ "\n",
+ "Luis Tran:\n",
+ "Technically, leafscrews are not as robust under high-vibration loads. But here's the thing: most of the modular prefab sites don not need that level of tolerance. If the design spec calls for durability over 10 years, we win. But for projects looking to move fast and hit 5-year lifespans? The leafscrew wins on simplicity and cost.\n",
+ "\n",
+ "Tom:\n",
+ "So they're eating into our low-end. That's our volume base.\n",
+ "\n",
+ "Karen:\n",
+ "Exactly. Now let's talk about this last one: the “hipsterfication” of construction. Felicia?\n",
+ "\n",
+ "Felicia:\n",
+ "So this is wild. We're seeing a cultural shift in boutique and residential construction—especially in markets like Beckley, West Sullivan, parts of Osborne County, where clients are requesting \"authentic\" manual fasteners. They want hand-sealed bolts, visible threads, even mismatched patinas. It's an aesthetic thing. Function is almost secondary. Our old manual-seal line from the 3180s? People are hunting them down on auction sites.\n",
+ "\n",
+ "Tom:\n",
+ "Well, I'm glad I don't have to live in the big cities... nothing like this would ever happen in downt-to-earth places Brooklyn, Portland, or Austin.\n",
+ "\n",
+ "Luis:\n",
+ "We literally got a request from a design-build firm in Keough asking if we had any bolts “pre-distressed.”\n",
+ "\n",
+ "Karen:\n",
+ "Can we spin this?\n",
+ "\n",
+ "Tom:\n",
+ "If we keep our vintage tooling and market it right, maybe. But that's niche. It won't offset losses in industrial and prefab.\n",
+ "\n",
+ "Karen:\n",
+ "Not yet. But we may need to reframe it as a prestige line—low volume, high margin. Okay, action items. Derek, map alternative micro-carburetor sources. Felicia, get me a forecast on leafscrew erosion by sector. Luis, feasibility of reviving manual seal production. Tom, let's scenario-plan cost pass-through vs. feature-based differentiation.\n",
+ "\n",
+ "Let's reconvene next week with hard numbers. Thanks, all.\"\"\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Summarize the Meeting\n",
+ "Use the contracts to short-circuit non-sensical compositions of library components."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "mV-zS1wDy4Oz"
+ },
+ "outputs": [],
+ "source": [
+ "summary = summarize_meeting(m, transcript=transcript)\n",
+ "\n",
+ "if contains_actionable_risks(m, summary=summary) == \"yes\":\n",
+ " mitigation = generate_risk_mitigation(m, summary=summary)\n",
+ " print(f\"Mitigation: {mitigation}\")\n",
+ "else:\n",
+ " print(\"Summary does not contain actionable risks.\")\n",
+ "if has_structured_conclusion(m, summary=summary) == \"yes\":\n",
+ " decision = propose_business_decision(m, summary=summary)\n",
+ " print(f\"Decision: {decision}\")\n",
+ "else:\n",
+ " print(\"Summary lacks a structured conclusion.\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/context_example.ipynb b/docs/examples/notebooks/context_example.ipynb
new file mode 100644
index 000000000..82e05eab3
--- /dev/null
+++ b/docs/examples/notebooks/context_example.ipynb
@@ -0,0 +1,116 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Context Example\n",
+ "This Jupyter notebook runs on Colab and demonstrates context management."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Start a Session with LinearContext\n",
+ "\n",
+ "Up to this point we have used SimpleContext, a context manager that resets the chat message history on each model call. That is, the model's context is entirely determined by the current Component. \n",
+ "\n",
+ "Mellea also provides a LinearContext, which behaves like a chat history. We will use the LinearContext to interact with cat hmodels:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "z7FVCBTRwgNC"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea import LinearContext, start_session\n",
+ "m = start_session(ctx=LinearContext())\n",
+ "m.chat(\"Make up a math problem.\")\n",
+ "m.chat(\"Solve your math problem.\")\n",
+ "print(m.ctx.last_output())\n",
+ "print(m.ctx.last_turn())"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/document_mobject.ipynb b/docs/examples/notebooks/document_mobject.ipynb
new file mode 100644
index 000000000..501a50baa
--- /dev/null
+++ b/docs/examples/notebooks/document_mobject.ipynb
@@ -0,0 +1,171 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Document MObject Example\n",
+ "This Jupyter notebook runs on Colab after adding HF_TOKEN as secret to Colab."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Create a RichDocument\n",
+ "Let's create a RichDocument from an arxiv paper, which loads the PDF file and parses it with the Docling parser into an intermediate representation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "3j-Se7PpfMqV"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea.stdlib.docs.richdocument import RichDocument\n",
+ "rd = RichDocument.from_document_file(\"https://arxiv.org/pdf/1906.04043\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Extract a Table from the Document\n",
+ "We can extract some document content, e.g. the first table:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "kcBb3g_BfMqV"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea.stdlib.docs.richdocument import Table # noqa: E402\n",
+ "table1: Table = rd.get_tables()[0]\n",
+ "print(table1.to_markdown())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "qGPC471ufMqW"
+ },
+ "source": [
+ "## Work with the Table Object\n",
+ "The Table object is Mellea-ready and can be used immediately with LLMs. In this example, table1 is transformed to have an extra column \"Model\" which contains the model string from the Feature column or \"None\" if there is none."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "aHI3E7G9fMqX"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea import start_session # noqa: E402\n",
+ "from mellea.backends.types import ModelOption # noqa: E402\n",
+ "m = start_session()\n",
+ "for seed in [x * 12 for x in range(5)]:\n",
+ " table2 = m.transform(\n",
+ " table1,\n",
+ " \"Add a column 'Model' that extracts which model was used or 'None' if none.\",\n",
+ " model_options={ModelOption.SEED: seed},\n",
+ " )\n",
+ " if isinstance(table2, Table):\n",
+ " print(table2.to_markdown())\n",
+ " break\n",
+ " else:\n",
+ " print(\"==== TRYING AGAIN after non-useful output.====\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The model has fulfilled the task and coming back with a parsable syntax. You could now call (e.g. m.query(table2, \"Are there any GPT models referenced?\")) or continue transformation (e.g. m.transform(table2, \"Transpose the table.\"))."
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/example.ipynb b/docs/examples/notebooks/example.ipynb
new file mode 100644
index 000000000..ebae1bc0c
--- /dev/null
+++ b/docs/examples/notebooks/example.ipynb
@@ -0,0 +1,127 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Simple Example\n",
+ "This Jupyter notebook runs on Colab and shows a simple example of Generative Code."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Start a Session\n",
+ "We initialize a backend running Ollama using the granite3.3-chat model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Jt3UC-Sa0djY"
+ },
+ "outputs": [],
+ "source": [
+ "import mellea\n",
+ "m = mellea.start_session()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We then ask the model to generate an output telling us Mellea is working."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Jt3UC-Sa0djY"
+ },
+ "outputs": [],
+ "source": [
+ "print(m.chat(\"What is the etymology of mellea?\").content)"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/instruct_validate_repair.ipynb b/docs/examples/notebooks/instruct_validate_repair.ipynb
new file mode 100644
index 000000000..589eb0d28
--- /dev/null
+++ b/docs/examples/notebooks/instruct_validate_repair.ipynb
@@ -0,0 +1,177 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Instruct Validate Repair\n",
+ "This Jupyter notebook runs the instruct-validate-repair pattern on Colab."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Specify Requirements\n",
+ "We create 3 requirements:\n",
+ "- 1st requirement (r1) will be validated by LLM-as-a-judge on the output of the instruction. This is the default behavior.\n",
+ "- 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",
+ "- 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."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "2qrMw-ZyN8hz"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea.stdlib.requirement import check, req, simple_validate\n",
+ "import mellea # noqa: E402\n",
+ "from mellea.stdlib.sampling import RejectionSamplingStrategy # noqa: E402\n",
+ "requirements = [\n",
+ " req(\"The email should have a salutation\"), # == r1\n",
+ " req(\n",
+ " \"Use only lower-case letters\",\n",
+ " validation_fn=simple_validate(lambda x: x.lower() == x),\n",
+ " ), # == r2\n",
+ " check(\"Do not mention purple elephants.\"), # == r3\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create Email Function with Instruct Validate Repair\n",
+ "We bring it together with a function using the instruct-validate-repair pattern."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "YJUWV2AKN8h0"
+ },
+ "outputs": [],
+ "source": [
+ "def write_email(m: mellea.MelleaSession, name: str, notes: str) -> str:\n",
+ " email_candidate = m.instruct(\n",
+ " \"Write an email to {{name}} using the notes following: {{notes}}.\",\n",
+ " requirements=requirements,\n",
+ " strategy=RejectionSamplingStrategy(loop_budget=5),\n",
+ " user_variables={\"name\": name, \"notes\": notes},\n",
+ " return_sampling_results=True,\n",
+ " )\n",
+ " if email_candidate.success:\n",
+ " return str(email_candidate.result)\n",
+ " else:\n",
+ " return email_candidate.sample_generations[0].value"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We initialize a backend and request an email to be written."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Hd3p2BgDN8h0"
+ },
+ "outputs": [],
+ "source": [
+ "m = mellea.start_session()\n",
+ "print(\n",
+ " write_email(\n",
+ " m,\n",
+ " \"Olivia\",\n",
+ " \"Olivia helped the lab over the last few weeks by organizing intern events, advertising the speaker series, and handling issues with snack delivery.\",\n",
+ " )\n",
+ ")"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "machine_shape": "hm",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/m_serve_example.ipynb b/docs/examples/notebooks/m_serve_example.ipynb
new file mode 100644
index 000000000..c7216d706
--- /dev/null
+++ b/docs/examples/notebooks/m_serve_example.ipynb
@@ -0,0 +1,156 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# M Serve Example\n",
+ "This Jupyter notebook runs M Serve on Colab."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Getting Started with Mellea\n",
+ "This Jupyter notebook runs on Colab and runs the first piece of generative code."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Start a Session\n",
+ "We initialize a backend and specify the context."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from typing import Any\n",
+ "\n",
+ "import mellea\n",
+ "from cli.serve.models import ChatMessage\n",
+ "from mellea.stdlib.base import LinearContext, ModelOutputThunk\n",
+ "from mellea.stdlib.requirement import Requirement, simple_validate\n",
+ "from mellea.stdlib.sampling import RejectionSamplingStrategy, SamplingResult\n",
+ "\n",
+ "session = mellea.start_session(ctx=LinearContext())\n",
+ "\n",
+ "\n",
+ "def validate_hi_bob(email: str) -> bool:\n",
+ " return email.startswith(\"Hi Bob!\")\n",
+ "\n",
+ "\n",
+ "def validate_email_len(email: str) -> bool:\n",
+ " return len(email) < 50\n",
+ "\n",
+ "\n",
+ "def serve(\n",
+ " input: list[ChatMessage],\n",
+ " requirements: list[str] | None = None,\n",
+ " model_options: None | dict = None,\n",
+ ") -> ModelOutputThunk | SamplingResult:\n",
+ " \"\"\"Takes a prompt as input and runs it through an M program.\"\"\"\n",
+ " requirements = requirements if requirements else []\n",
+ " message = input[-1].content\n",
+ " reqs = [\n",
+ " Requirement(\n",
+ " \"Keep this under 50 words\",\n",
+ " validation_fn=simple_validate(validate_email_len),\n",
+ " ),\n",
+ " Requirement(\n",
+ " \"Add a 'Hi Bob!' at the top of the output\",\n",
+ " validation_fn=simple_validate(validate_hi_bob),\n",
+ " ),\n",
+ " *requirements,\n",
+ " ]\n",
+ "\n",
+ " result = session.instruct(\n",
+ " description=message, # type: ignore\n",
+ " requirements=reqs, # type: ignore\n",
+ " strategy=RejectionSamplingStrategy(loop_budget=3),\n",
+ " model_options=model_options,\n",
+ " )\n",
+ " return result"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/mcp_example.ipynb b/docs/examples/notebooks/mcp_example.ipynb
new file mode 100644
index 000000000..c41b6f487
--- /dev/null
+++ b/docs/examples/notebooks/mcp_example.ipynb
@@ -0,0 +1,145 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Model Context Protocol (MCP) Server Example \n",
+ "This Jupyter notebook runs on Colab and demonstrates a MCP server running Mellea. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and MCP Server"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mcp.server.fastmcp import FastMCP\n",
+ "from mellea import MelleaSession\n",
+ "from mellea.backends import model_ids\n",
+ "from mellea.backends.ollama import OllamaModelBackend\n",
+ "from mellea.stdlib.base import ModelOutputThunk\n",
+ "from mellea.stdlib.requirement import Requirement, simple_validate\n",
+ "from mellea.stdlib.sampling import RejectionSamplingStrategy"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create an MCP Server\n",
+ "Run MCP debug UI with: `uv run mcp dev docs/examples/mcp/mcp_example.py`. We can wrap a simple mcp server around a program and use the server as-is. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "mcp = FastMCP(\"Demo\")\n",
+ "\n",
+ "@mcp.tool()\n",
+ "def write_a_poem(word_limit: int) -> str:\n",
+ " \"\"\"Write a poem with a word limit.\"\"\"\n",
+ " m = MelleaSession(OllamaModelBackend(model_ids.QWEN3_8B))\n",
+ " wl_req = Requirement(\n",
+ " f\"Use only {word_limit} words.\",\n",
+ " validation_fn=simple_validate(lambda x: len(x.split(\" \")) < word_limit),\n",
+ " )\n",
+ " res = m.instruct(\n",
+ " \"Write a poem\",\n",
+ " requirements=[wl_req],\n",
+ " strategy=RejectionSamplingStrategy(loop_budget=4),\n",
+ " )\n",
+ " assert isinstance(res, ModelOutputThunk)\n",
+ " return str(res.value)\n",
+ "\n",
+ "@mcp.resource(\"greeting://{name}\")\n",
+ "def get_greeting(name: str) -> str:\n",
+ " \"\"\"Get a personalized greeting\"\"\"\n",
+ " return f\"Hello, {name}!\" "
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/model_options_example.ipynb b/docs/examples/notebooks/model_options_example.ipynb
new file mode 100644
index 000000000..b17fd0786
--- /dev/null
+++ b/docs/examples/notebooks/model_options_example.ipynb
@@ -0,0 +1,156 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Model Options Example\n",
+ "This Jupyter notebook runs on Colab and demostrates specifying model options"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Start a Session\n",
+ "We initialize a backend running Ollama using the granite3.3-chat model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "DM6s856Nar-1"
+ },
+ "outputs": [],
+ "source": [
+ "import mellea\n",
+ "from mellea.backends import model_ids\n",
+ "from mellea.backends.ollama import OllamaModelBackend\n",
+ "from mellea.backends.types import ModelOption"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Spefify Options on Backend Initialization\n",
+ "You can add any key-value option pair supported by the backend to the model_options dictionary, and those options are passed along to the inference engine (even if a Mellea-specific ModelOption is defined for that option). This means you can safely copy over model option parameters from exiting codebases as-is:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "WVavhJ-uar-1"
+ },
+ "outputs": [],
+ "source": [
+ "m = mellea.MelleaSession(\n",
+ " backend=OllamaModelBackend(\n",
+ " model_id=model_ids.IBM_GRANITE_3_2_8B, model_options={ModelOption.SEED: 42}\n",
+ " )\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Specify Options on a Mellea Call\n",
+ "Options specified here will update previously specified model options for this call only."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "ishXXO9Far-2"
+ },
+ "outputs": [],
+ "source": [
+ "answer = m.instruct(\n",
+ " \"What is 2x2?\", model_options={\"temperature\": 0.5, \"num_predict\": 5}\n",
+ ")\n",
+ "print(str(answer))"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/sentiment_classifier.ipynb b/docs/examples/notebooks/sentiment_classifier.ipynb
new file mode 100644
index 000000000..4e4a2e86b
--- /dev/null
+++ b/docs/examples/notebooks/sentiment_classifier.ipynb
@@ -0,0 +1,134 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Sentiment Classifier Example\n",
+ "This notebook runs on Colab to show an example of sentiment classification."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Create a Classification Function\n",
+ "We initialize a backend running Ollama using the granite3.3-chat model and create a generative function for sentiment classification."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "SyVjDmyHcwxM"
+ },
+ "outputs": [],
+ "source": [
+ "from typing import Literal\n",
+ "from mellea import generative, start_session\n",
+ "@generative\n",
+ "def classify_sentiment(text: str) -> Literal[\"positive\", \"negative\"]:\n",
+ " \"\"\"Classify the sentiment of the input text as 'positive' or 'negative'.\"\"\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Start a Session and Request Classification"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "ZGz3X8GncwxN"
+ },
+ "outputs": [],
+ "source": [
+ "m = start_session()\n",
+ "sentiment = classify_sentiment(m, text=\"I love this!\")\n",
+ "print(\"Output sentiment is:\", sentiment)"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/simple_email.ipynb b/docs/examples/notebooks/simple_email.ipynb
new file mode 100644
index 000000000..0de34384e
--- /dev/null
+++ b/docs/examples/notebooks/simple_email.ipynb
@@ -0,0 +1,247 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Simple Email\n",
+ "This Jupyter notebook runs on Colab and demonstrates composing a simple email."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Import Mellea and Start a Session\n",
+ "We initialize a backend running Ollama using the granite3.3-chat model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "nlcQhqVB0djX"
+ },
+ "outputs": [],
+ "source": [
+ "import mellea\n",
+ "m = mellea.start_session()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Basic Email\n",
+ "We make a simple email request."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Jt3UC-Sa0djY"
+ },
+ "outputs": [],
+ "source": [
+ "email = m.instruct(\"Write an email inviting interns to an office party at 3:30pm.\")\n",
+ "print(str(email))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Email Function with User Variables\n",
+ "We wrap this call into a function with some arguments."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "YQMLMA6L0djZ"
+ },
+ "outputs": [],
+ "source": [
+ "def write_email(m: mellea.MelleaSession, name: str, notes: str) -> str:\n",
+ " email = m.instruct(\n",
+ " \"Write an email to {{name}} using the notes following: {{notes}}.\",\n",
+ " user_variables={\"name\": name, \"notes\": notes},\n",
+ " )\n",
+ " return email.value # str(email) also works.\n",
+ "print(\n",
+ " write_email(\n",
+ " m,\n",
+ " \"Olivia\",\n",
+ " \"Olivia helped the lab over the last few weeks by organizing intern events, advertising the speaker series, and handling issues with snack delivery.\",\n",
+ " )\n",
+ ") "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "3grQLU580dja"
+ },
+ "source": [
+ "## Email with Requirements\n",
+ "Suppose we want to ensure that the email has a salutation and contains only lower-case letters.\n",
+ "We capture these post-conditions by specifying requirements on the m.instruct call."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "xQmvHSfX0dja"
+ },
+ "outputs": [],
+ "source": [
+ "def write_email_with_requirements(\n",
+ " m: mellea.MelleaSession, name: str, notes: str\n",
+ ") -> str:\n",
+ " email = m.instruct(\n",
+ " \"Write an email to {{name}} using the notes following: {{notes}}.\",\n",
+ " requirements=[\n",
+ " \"The email should have a salutation\",\n",
+ " \"Use only lower-case letters\",\n",
+ " ],\n",
+ " user_variables={\"name\": name, \"notes\": notes},\n",
+ " )\n",
+ " return str(email)\n",
+ "print(\n",
+ " write_email_with_requirements(\n",
+ " m,\n",
+ " name=\"Olivia\",\n",
+ " notes=\"Olivia helped the lab over the last few weeks by organizing intern events, advertising the speaker series, and handling issues with snack delivery.\",\n",
+ " )\n",
+ ") "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "U5BQleHA0dja"
+ },
+ "source": [
+ "## Email with Rejection Sampling\n",
+ "We add two requirements to the instruction which will be added to the model request. \n",
+ "But we don't check yet if these requirements are satisfied, we add a strategy for validating the requirements.\n",
+ "\n",
+ "This sampling strategy (RejectionSamplingStrategy()) checks if all requirements are met and if any requirement fails, the sampling strategy will sample a new email from the LLM."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "z24yoz3D0dja"
+ },
+ "outputs": [],
+ "source": [
+ "from mellea.stdlib.sampling import RejectionSamplingStrategy # noqa: E402\n",
+ "def write_email_with_strategy(m: mellea.MelleaSession, name: str, notes: str) -> str:\n",
+ " email_candidate = m.instruct(\n",
+ " \"Write an email to {{name}} using the notes following: {{notes}}.\",\n",
+ " requirements=[\n",
+ " \"The email should have a salutation\",\n",
+ " \"Use only lower-case letters\",\n",
+ " ],\n",
+ " strategy=RejectionSamplingStrategy(loop_budget=5),\n",
+ " user_variables={\"name\": name, \"notes\": notes},\n",
+ " return_sampling_results=True,\n",
+ " )\n",
+ " if email_candidate.success:\n",
+ " return str(email_candidate.result)\n",
+ " else:\n",
+ " print(\"Expect sub-par result.\")\n",
+ " return email_candidate.sample_generations[0].value\n",
+ "print(\n",
+ " write_email_with_strategy(\n",
+ " m,\n",
+ " \"Olivia\",\n",
+ " \"Olivia helped the lab over the last few weeks by organizing intern events, advertising the speaker series, and handling issues with snack delivery.\",\n",
+ " )\n",
+ ") "
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/examples/notebooks/table_mobject.ipynb b/docs/examples/notebooks/table_mobject.ipynb
new file mode 100644
index 000000000..a4bca0a86
--- /dev/null
+++ b/docs/examples/notebooks/table_mobject.ipynb
@@ -0,0 +1,150 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "IByYhgKy9WCo"
+ },
+ "source": [
+ "# Table MObject Example\n",
+ "This notebook runs on Colab and demostrates the MObject pattern with a table example."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZIu6B1Ht927Z"
+ },
+ "source": [
+ "## Install Ollama\n",
+ "\n",
+ "Before we get started with Mellea, we download and install ollama."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "VDaTfltQY3Fl"
+ },
+ "outputs": [],
+ "source": [
+ "!curl -fsSL https://ollama.com/install.sh | sh\n",
+ "!nohup ollama serve &"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "jEl3nAk696mI"
+ },
+ "source": [
+ "## Install Mellea\n",
+ "We run `uv pip install .` to install Mellea."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "9EurAUSz_1yl"
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "!git clone https://github.com/generative-computing/mellea.git --quiet\n",
+ "os.chdir(\"mellea\")\n",
+ "!uv pip install . -qq"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "NU7bZqKA0djW"
+ },
+ "source": [
+ "## Create Table MObject\n",
+ "Use the @mify decorator to transform MyCompanyDatabase into an MObject."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "2w_qWagm3gDa"
+ },
+ "outputs": [],
+ "source": [
+ "from io import StringIO\n",
+ "import pandas\n",
+ "import mellea\n",
+ "from mellea.stdlib.mify import MifiedProtocol, mify\n",
+ "\n",
+ "@mify(fields_include={\"table\"}, template=\"{{ table }}\")\n",
+ "class MyCompanyDatabase:\n",
+ " table: str = \"\"\"| Store | Sales |\n",
+ " | ---------- | ------- |\n",
+ " | Northeast | $250 |\n",
+ " | Southeast | $80 |\n",
+ " | Midwest | $420 |\"\"\"\n",
+ " def transpose(self):\n",
+ " pandas.read_csv(\n",
+ " StringIO(self.table),\n",
+ " sep=\"|\",\n",
+ " skipinitialspace=True,\n",
+ " header=0,\n",
+ " index_col=False,\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Ask Questions about the Table\n",
+ "Initialize a backend running Ollama and use the LLM to answer questions about the table."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "tLrGT6iT3gDa"
+ },
+ "outputs": [],
+ "source": [
+ "m = mellea.start_session()\n",
+ "db = MyCompanyDatabase()\n",
+ "assert isinstance(db, MifiedProtocol)\n",
+ "answer = m.query(db, \"What were sales for the Northeast branch this month?\")\n",
+ "print(str(answer))"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}