Recipe catalog / text-block-role
Identify a text block’s structure
Is extracted text a heading, body paragraph, list item, code, table, caption, formula, or other block?
You have already extracted a text block but its structural markup is missing.
Explore this recipe interactively · Source and implementation guide
Use text-block-role in TypeScript
Install with npm install jev-recipes. Requires Node.js 22.9 or newer and ES modules. Set TYPESAFE_API_KEY in your server environment for live calls, which send input to TypeSafe and use API quota. See the installation guide.
import { textBlockRole } from 'jev-recipes/text-block-role';
const result = await textBlockRole({
"text": "Installation",
"after": "Run npm install to add the package.",
"minConfidence": 0.8
});
console.log(result);
Input contract
| Field | Type | Needed |
|---|---|---|
| text | string | Required |
| before | string | Optional |
| after | string | Optional |
| context | string | Optional |
| minConfidence | number | Optional |
Full input and result schemas
{
"input": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"text": {
"type": "string"
},
"before": {
"type": "string"
},
"after": {
"type": "string"
},
"context": {
"type": "string"
},
"minConfidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"text"
]
},
"result": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"model": {
"type": "string"
},
"usage": {
"type": "object",
"properties": {
"input_tokens": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"output_tokens": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"input_tokens",
"output_tokens"
],
"additionalProperties": false
},
"status": {
"type": "string",
"enum": [
"ready",
"review"
]
},
"verdict": {
"type": "string",
"enum": [
"heading",
"body",
"list_item",
"code",
"table",
"caption",
"formula",
"other",
"unclear"
]
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"probabilities": {
"type": "object",
"propertyNames": {
"type": "string",
"enum": [
"heading",
"body",
"list_item",
"code",
"table",
"caption",
"formula",
"other",
"unclear"
]
},
"additionalProperties": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"required": [
"heading",
"body",
"list_item",
"code",
"table",
"caption",
"formula",
"other",
"unclear"
]
}
},
"required": [
"model",
"usage",
"status",
"verdict",
"confidence",
"probabilities"
],
"additionalProperties": false
}
}Saved example result
This hand-authored response demonstrates the contract. It is not a model accuracy measurement. Run it without an API key: npx jev-recipes demo text-block-role.
{
"model": "demo-fixture",
"usage": {
"input_tokens": 0,
"output_tokens": 0
},
"status": "ready",
"verdict": "heading",
"confidence": 0.94,
"probabilities": {
"heading": 0.94,
"body": 0.04,
"list_item": 0,
"code": 0,
"table": 0,
"caption": 0,
"formula": 0,
"other": 0,
"unclear": 0.02
}
}
Evaluation evidence
typesafe-ai/jev / 2026-09-27 / 189 held-out cases
Scoring revision 1.
136 ready decisions, with 90% accuracy among those decisions.
95% case-level interval: 76% to 87%. Related synthetic cases are correlated.
Experimental: declared document acceptance policy not met
This measurement uses an earlier or unverified recipe or evaluator version. Rerun with the current recipe and evaluator before treating these numbers as current.
Use the evaluation guide to measure this decision on your own labeled cases.
Limitations
- Classifies supplied text only; it does not read PDFs, perform OCR, recover missing text, or determine reading order.
- Native tags take precedence. Preserve every block when reviewing uncertain structure.
- Experimental until independent document-level evaluation meets the published acceptance criteria.
Related recipes
- document-role: Use document-role for the purpose of an entire document.
- context-role: Use context-role for the contribution a passage makes to a question.
- paragraph-boundary: Use paragraph-boundary to decide whether adjacent fragments belong to one paragraph.