Document section classification
Identifies the type of document section a passage belongs to, using your list of section types and descriptions. Returns none when no type fits.
Example
Context
- document
- An installation services agreement between a home energy installer and a housing developer.
Input
Either party may end this agreement on 60 days' written notice. If the developer ends it, any invoices then unpaid fall due at once.
Labels (the options)
- scope
- What work the installer will do, and where
- payment
- Prices, invoicing and when payment is due
- termination
- How and when either party may end the agreement
- liability
- Who is responsible for loss or damage, and the limits
- none
- None of these sections
- Answer (JSON)
- value termination, confidence 1
- Top options
- termination 1
- payment 0
- none 0
The passage is about ending the agreement, so it comes from the termination section.
import os import jeff with jeff.Jeff.remote("https://api.jeffhub.ai", token=os.environ["JEFF_API_KEY"], timeout_s=30) as client: decide = client.function("jeff.retrieval.section-id.section", context={ "document": "An installation services agreement between a home energy installer and a housing developer.", }, labels={ "scope": "What work the installer will do, and where", "payment": "Prices, invoicing and when payment is due", "termination": "How and when either party may end the agreement", "liability": "Who is responsible for loss or damage, and the limits", "none": "None of these sections", }) decision = decide("Either party may end this agreement on 60 days' written notice. If the developer ends it, any invoices then unpaid fall due at once.") print(decision.value, decision.confidence)
More examples
When invoices fall dueanswer payment · confidence 1
Context
- document
- An installation services agreement between a home energy installer and a housing developer.
Input
The installer will invoice the developer at the end of each month for the units installed in that month. Each invoice is payable within 30 days of its date.
Labels (the options)
- scope
- What work the installer will do, and where
- payment
- Prices, invoicing and when payment is due
- termination
- How and when either party may end the agreement
- liability
- Who is responsible for loss or damage, and the limits
- none
- None of these sections
- Answer (JSON)
- value payment, confidence 1
- Top options
- payment 1
- none 0
- scope 0
The passage says when the installer invoices and when invoices fall due, so it comes from the
paymentsection.import os import jeff with jeff.Jeff.remote("https://api.jeffhub.ai", token=os.environ["JEFF_API_KEY"], timeout_s=30) as client: decide = client.function("jeff.retrieval.section-id.section", context={ "document": "An installation services agreement between a home energy installer and a housing developer.", }, labels={ "scope": "What work the installer will do, and where", "payment": "Prices, invoicing and when payment is due", "termination": "How and when either party may end the agreement", "liability": "Who is responsible for loss or damage, and the limits", "none": "None of these sections", }) decision = decide("The installer will invoice the developer at the end of each month for the units installed in that month. Each invoice is payable within 30 days of its date.") print(decision.value, decision.confidence)
Which homes the installer fitsanswer scope · confidence 0.927
Context
- document
- An installation services agreement between a home energy installer and a housing developer.
Input
The installer will supply and fit one Aster 2 heat pump in each of the 48 homes on the Mill Brook site, plots 1 to 48, and commission each unit.
Labels (the options)
- scope
- What work the installer will do, and where
- payment
- Prices, invoicing and when payment is due
- termination
- How and when either party may end the agreement
- liability
- Who is responsible for loss or damage, and the limits
- none
- None of these sections
- Answer (JSON)
- value scope, confidence 0.927
- Top options
- scope 0.927
- none 0.073
- payment 0
The passage says which homes the installer fits and what it does there, so it comes from the
scopesection.import os import jeff with jeff.Jeff.remote("https://api.jeffhub.ai", token=os.environ["JEFF_API_KEY"], timeout_s=30) as client: decide = client.function("jeff.retrieval.section-id.section", context={ "document": "An installation services agreement between a home energy installer and a housing developer.", }, labels={ "scope": "What work the installer will do, and where", "payment": "Prices, invoicing and when payment is due", "termination": "How and when either party may end the agreement", "liability": "Who is responsible for loss or damage, and the limits", "none": "None of these sections", }) decision = decide("The installer will supply and fit one Aster 2 heat pump in each of the 48 homes on the Mill Brook site, plots 1 to 48, and commission each unit.") print(decision.value, decision.confidence)
Cap on the installer's liabilityanswer liability · confidence 1
Context
- document
- An installation services agreement between a home energy installer and a housing developer.
Input
The installer's total liability for any loss or damage arising under this agreement is limited to the price of the units installed in the 12 months before the claim.
Labels (the options)
- scope
- What work the installer will do, and where
- payment
- Prices, invoicing and when payment is due
- termination
- How and when either party may end the agreement
- liability
- Who is responsible for loss or damage, and the limits
- none
- None of these sections
- Answer (JSON)
- value liability, confidence 1
- Top options
- liability 1
- payment 0
- none 0
The passage limits the installer's liability for loss or damage, so it comes from the
liabilitysection.import os import jeff with jeff.Jeff.remote("https://api.jeffhub.ai", token=os.environ["JEFF_API_KEY"], timeout_s=30) as client: decide = client.function("jeff.retrieval.section-id.section", context={ "document": "An installation services agreement between a home energy installer and a housing developer.", }, labels={ "scope": "What work the installer will do, and where", "payment": "Prices, invoicing and when payment is due", "termination": "How and when either party may end the agreement", "liability": "Who is responsible for loss or damage, and the limits", "none": "None of these sections", }) decision = decide("The installer's total liability for any loss or damage arising under this agreement is limited to the price of the units installed in the 12 months before the claim.") print(decision.value, decision.confidence)
Signatures and dateanswer none · confidence 1
Context
- document
- An installation services agreement between a home energy installer and a housing developer.
Input
Signed for and on behalf of Fenwick Home Energy Ltd: R. Fenwick, Director. Signed for and on behalf of Ashgrove Homes Ltd: P. Mensah, Director. Date: 2 November 2026.
Labels (the options)
- scope
- What work the installer will do, and where
- payment
- Prices, invoicing and when payment is due
- termination
- How and when either party may end the agreement
- liability
- Who is responsible for loss or damage, and the limits
- none
- None of these sections
- Answer (JSON)
- value none, confidence 1
- Top options
- none 1
- termination 0
- liability 0
The signature block serves none of the listed sections, so the answer is
none.import os import jeff with jeff.Jeff.remote("https://api.jeffhub.ai", token=os.environ["JEFF_API_KEY"], timeout_s=30) as client: decide = client.function("jeff.retrieval.section-id.section", context={ "document": "An installation services agreement between a home energy installer and a housing developer.", }, labels={ "scope": "What work the installer will do, and where", "payment": "Prices, invoicing and when payment is due", "termination": "How and when either party may end the agreement", "liability": "Who is responsible for loss or damage, and the limits", "none": "None of these sections", }) decision = decide("Signed for and on behalf of Fenwick Home Energy Ltd: R. Fenwick, Director. Signed for and on behalf of Ashgrove Homes Ltd: P. Mensah, Director. Date: 2 November 2026.") print(decision.value, decision.confidence)
Use when
- You have split documents into passages and need to classify each passage by section type.
Avoid when
- Your documents already have reliable headings that code can read directly.
Context and input
| Field | Kind | Description |
|---|---|---|
passage | input | The passage's text. |
document | context | What the document is: its kind and parties, one line. |
Functions
| Key | Interface | Instructions | Labels |
|---|---|---|---|
| section | classify | Which section of the document is this passage from? Choose the section kind whose main purpose the passage serves, using the descriptions. Judge by its content, not by topics it mentions in passing: a termination clause that mentions unpaid fees is still about termination. Headings may be missing, numbered or worded differently from the section names. none: the passage serves none of the listed section kinds (for example a kind of section that is not on the list), even when a listed kind is similar. | from the caller |
How it was measured
Test accuracy: the share of test rows whose top answer was right.
- 90.9% on CUAD, a public benchmark of real contract paragraphs (1,168 rows). public benchmark
- 99.8% on the in-house test (2,000 rows). in-house: same generator as the training data
- 99.6% on the in-house test in domains never seen in training (2,000 rows). in-house: same generator as the training data
When confident
From the calibration set: at or above the threshold confidence, how often the answer is right, and how often the adapter is that confident. Below it, escalate.
| Function | Right when confident | Confident on | Threshold | Calibration rows |
|---|---|---|---|---|
| section | 99.8% | 100.0% | 0.53 | 2,000 |
Caveats
- The CUAD rows were kept only where an LLM agreed with the label, which removes the hardest real passages.
Base: Jeff v1.4. Adapter trained: 25 October 2026.
Base
jeff-base v1.4
Call it
jeff.retrieval.section-id.section, with placeholders for its input and context.
import os import jeff with jeff.Jeff.remote("https://api.jeffhub.ai", token=os.environ["JEFF_API_KEY"], timeout_s=30) as client: decide = client.function("jeff.retrieval.section-id.section", context={ "document": "<document>", }) decision = decide("<passage>") print(decision.value, decision.confidence)
Download
Weights: mstrasser/jeff-adapter-section-id (v1.4)
Licence: Apache-2.0