Recipe catalog / followup-timing
Recognize requested follow-up timing
When does the sender want another contact, if any?
You need to distinguish immediate contact, a later time, an event condition, and no follow-up request.
Explore this recipe interactively ยท Source and implementation guide
Use followup-timing 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 { followupTiming } from 'jev-recipes/followup-timing';
const result = await followupTiming({
"message": "Please check back after our finance team approves the budget.",
"minConfidence": 0.8
});
console.log(result);
Input contract
| Field | Type | Needed |
|---|---|---|
| message | string | Required |
| context | string | Optional |
| minConfidence | number | Optional |
Full input and result schemas
{
"input": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"message": {
"type": "string"
},
"context": {
"type": "string"
},
"minConfidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"message"
]
},
"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": [
"now",
"later",
"after_event",
"not_requested",
"declined",
"unclear"
]
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"probabilities": {
"type": "object",
"propertyNames": {
"type": "string",
"enum": [
"now",
"later",
"after_event",
"not_requested",
"declined",
"unclear"
]
},
"additionalProperties": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"required": [
"now",
"later",
"after_event",
"not_requested",
"declined",
"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 followup-timing.
{
"model": "demo-fixture",
"usage": {
"input_tokens": 0,
"output_tokens": 0
},
"status": "ready",
"verdict": "after_event",
"confidence": 0.93,
"probabilities": {
"now": 0.01,
"later": 0.02,
"after_event": 0.93,
"not_requested": 0.01,
"declined": 0.01,
"unclear": 0.02
}
}
Evaluation evidence
jev-1.13.0 / 2026-09-27 / 40 held-out cases
Scoring revision 1.
37 ready decisions, with 100% accuracy among those decisions.
95% case-level interval: 91% to 100%. Related synthetic cases are correlated.
Measured on these synthetic cases
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
- Does not extract dates, time zones, or event identifiers and does not schedule contact.
- A timing request does not override stored contact preferences or establish permission to contact.
- Missing references, unresolved alternatives, and conflicting timing instructions require review.
Related recipes
- response-needed: Use response-needed to decide whether the current message needs a reply.
- contact-opt-out: Use contact-opt-out for the scope of a request to stop future contact.
- callback-responsibility: Use callback-responsibility to identify who should initiate a call.