Agent next-step selection
Determines what an agent should do after a tool returns a result: continue, retry, change approach, stop or hand over to a person.
Example
Context
- app
- Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices and clients and emails invoices on request.
- today
- Monday 2 November 2026
- tools
- - find_invoice: finds the studio's invoice for a client and month - send_invoice: emails an invoice to a recipient, with optional copies
- retry_limit
- Retry a failed call at most 3 times.
- goal
- Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.
- plan
- - 1. Find the October invoice for Orbit Print (done) - 2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (current step) - 3. Tell the user it was sent (still to do)
- steps_so_far
- - {"call":{"tool":"find_invoice","arguments":{"client":"Orbit Print","month":"2026-10"}},"result":{"invoice_id":"INV-2026-0412","total":2350,"status":"unpaid"}}
- latest_call
- tool: send_invoice arguments: {"invoice_id":"INV-2026-0412","to":"accounts@orbitprint.example","cc":["sam@pinecrest.example"]} attempt: 1
Input
status: error code: 503 message: Mail service temporarily unavailable, please try again in a few seconds.
- Answer (JSON)
- value retry, confidence 1
- Top options
- retry 1
- continue 0
- escalate 0
The mail service failed with a temporary error on the first attempt, so the agent should retry.
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.agents.after-result.next", context={ "app": "Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices and clients and emails invoices on request.", "today": "Monday 2 November 2026", "tools": [ "find_invoice: finds the studio's invoice for a client and month", "send_invoice: emails an invoice to a recipient, with optional copies", ], "retry_limit": "Retry a failed call at most 3 times.", "goal": "Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.", "plan": [ "1. Find the October invoice for Orbit Print (done)", "2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (current step)", "3. Tell the user it was sent (still to do)", ], "steps_so_far": [ { "call": { "tool": "find_invoice", "arguments": { "client": "Orbit Print", "month": "2026-10", }, }, "result": { "invoice_id": "INV-2026-0412", "total": 2350, "status": "unpaid", }, }, ], "latest_call": { "tool": "send_invoice", "arguments": { "invoice_id": "INV-2026-0412", "to": "accounts@orbitprint.example", "cc": [ "sam@pinecrest.example", ], }, "attempt": 1, }, }) decision = decide({ "status": "error", "code": 503, "message": "Mail service temporarily unavailable, please try again in a few seconds.", }) print(decision.value, decision.confidence)
More examples
Invoice found, email still to sendanswer continue · confidence 1
Context
- app
- Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.
- today
- Monday 2 November 2026
- tools
- - find_invoice: finds the studio's invoice for a client and month - send_invoice: emails an invoice to a recipient, with optional copies
- retry_limit
- Retry a failed call at most 3 times.
- goal
- Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.
- plan
- - 1. Find the October invoice for Orbit Print (current step) - 2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (still to do) - 3. Tell the user it was sent (still to do)
- steps_so_far
- latest_call
- tool: find_invoice arguments: {"client":"Orbit Print","month":"2026-10"} attempt: 1
Input
status: ok data: {"invoice_id":"INV-2026-0412","total":2350,"status":"unpaid"}
- Answer (JSON)
- value continue, confidence 1
- Top options
- continue 1
- change_approach 0
- retry 0
The invoice was found and sending it is still to do, so the agent should
continue.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.agents.after-result.next", context={ "app": "Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.", "today": "Monday 2 November 2026", "tools": [ "find_invoice: finds the studio's invoice for a client and month", "send_invoice: emails an invoice to a recipient, with optional copies", ], "retry_limit": "Retry a failed call at most 3 times.", "goal": "Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.", "plan": [ "1. Find the October invoice for Orbit Print (current step)", "2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (still to do)", "3. Tell the user it was sent (still to do)", ], "steps_so_far": [], "latest_call": { "tool": "find_invoice", "arguments": { "client": "Orbit Print", "month": "2026-10", }, "attempt": 1, }, }) decision = decide({ "status": "ok", "data": { "invoice_id": "INV-2026-0412", "total": 2350, "status": "unpaid", }, }) print(decision.value, decision.confidence)
Month written in a format the tool refusesanswer change_approach · confidence 1
Context
- app
- Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.
- today
- Monday 2 November 2026
- tools
- - find_invoice: finds the studio's invoice for a client and month - send_invoice: emails an invoice to a recipient, with optional copies
- retry_limit
- Retry a failed call at most 3 times.
- goal
- Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.
- plan
- - 1. Find the October invoice for Orbit Print (current step) - 2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (still to do) - 3. Tell the user it was sent (still to do)
- steps_so_far
- latest_call
- tool: find_invoice arguments: {"client":"Orbit Print","month":"October"} attempt: 1
Input
status: error code: 400 message: Invalid month "October": use the form YYYY-MM, for example 2026-10.
- Answer (JSON)
- value change_approach, confidence 1
- Top options
- change_approach 1
- stop 0
- continue 0
The tool refused the month because the agent wrote it in the wrong form, so the agent must
change_approachand fix the call.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.agents.after-result.next", context={ "app": "Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.", "today": "Monday 2 November 2026", "tools": [ "find_invoice: finds the studio's invoice for a client and month", "send_invoice: emails an invoice to a recipient, with optional copies", ], "retry_limit": "Retry a failed call at most 3 times.", "goal": "Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.", "plan": [ "1. Find the October invoice for Orbit Print (current step)", "2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (still to do)", "3. Tell the user it was sent (still to do)", ], "steps_so_far": [], "latest_call": { "tool": "find_invoice", "arguments": { "client": "Orbit Print", "month": "October", }, "attempt": 1, }, }) decision = decide({ "status": "error", "code": 400, "message": "Invalid month \"October\": use the form YYYY-MM, for example 2026-10.", }) print(decision.value, decision.confidence)
Last step of the plan workedanswer stop · confidence 1
Context
- app
- Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.
- today
- Monday 2 November 2026
- tools
- - find_invoice: finds the studio's invoice for a client and month - send_invoice: emails an invoice to a recipient, with optional copies
- retry_limit
- Retry a failed call at most 3 times.
- goal
- Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.
- plan
- - 1. Find the October invoice for Orbit Print (done) - 2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (current step)
- steps_so_far
- - {"call":{"tool":"find_invoice","arguments":{"client":"Orbit Print","month":"2026-10"}},"result":{"invoice_id":"INV-2026-0412","total":2350,"status":"unpaid"}}
- latest_call
- tool: send_invoice arguments: {"invoice_id":"INV-2026-0412","to":"accounts@orbitprint.example","cc":["sam@pinecrest.example"]} attempt: 1
Input
status: ok data: {"status":"sent","message_id":"m-77120"}
- Answer (JSON)
- value stop, confidence 1
- Top options
- stop 1
- retry 0
- change_approach 0
The email went out and it was the plan's last step, so the agent should
stopand report back.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.agents.after-result.next", context={ "app": "Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.", "today": "Monday 2 November 2026", "tools": [ "find_invoice: finds the studio's invoice for a client and month", "send_invoice: emails an invoice to a recipient, with optional copies", ], "retry_limit": "Retry a failed call at most 3 times.", "goal": "Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.", "plan": [ "1. Find the October invoice for Orbit Print (done)", "2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (current step)", ], "steps_so_far": [ { "call": { "tool": "find_invoice", "arguments": { "client": "Orbit Print", "month": "2026-10", }, }, "result": { "invoice_id": "INV-2026-0412", "total": 2350, "status": "unpaid", }, }, ], "latest_call": { "tool": "send_invoice", "arguments": { "invoice_id": "INV-2026-0412", "to": "accounts@orbitprint.example", "cc": [ "sam@pinecrest.example", ], }, "attempt": 1, }, }) decision = decide({ "status": "ok", "data": { "status": "sent", "message_id": "m-77120", }, }) print(decision.value, decision.confidence)
Mail account signed outanswer escalate · confidence 1
Context
- app
- Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.
- today
- Monday 2 November 2026
- tools
- - find_invoice: finds the studio's invoice for a client and month - send_invoice: emails an invoice to a recipient, with optional copies
- retry_limit
- Retry a failed call at most 3 times.
- goal
- Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.
- plan
- - 1. Find the October invoice for Orbit Print (done) - 2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (current step) - 3. Tell the user it was sent (still to do)
- steps_so_far
- - {"call":{"tool":"find_invoice","arguments":{"client":"Orbit Print","month":"2026-10"}},"result":{"invoice_id":"INV-2026-0412","total":2350,"status":"unpaid"}}
- latest_call
- tool: send_invoice arguments: {"invoice_id":"INV-2026-0412","to":"accounts@orbitprint.example","cc":["sam@pinecrest.example"]} attempt: 1
Input
status: error code: 401 message: The studio's mail account login has expired. The account owner must sign in again in Settings before mail can be sent.
- Answer (JSON)
- value escalate, confidence 1
- Top options
- escalate 1
- retry 0
- change_approach 0
The mail account's login has expired and only its owner can sign in again, so the agent must
escalate.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.agents.after-result.next", context={ "app": "Pinecrest Books, a bookkeeping assistant for a small design studio. It keeps the studio's invoices, clients and supplier bills, emails invoices and pays bills on request.", "today": "Monday 2 November 2026", "tools": [ "find_invoice: finds the studio's invoice for a client and month", "send_invoice: emails an invoice to a recipient, with optional copies", ], "retry_limit": "Retry a failed call at most 3 times.", "goal": "Send the October invoice for Orbit Print to accounts@orbitprint.example and copy me.", "plan": [ "1. Find the October invoice for Orbit Print (done)", "2. Email it to accounts@orbitprint.example with a copy to sam@pinecrest.example (current step)", "3. Tell the user it was sent (still to do)", ], "steps_so_far": [ { "call": { "tool": "find_invoice", "arguments": { "client": "Orbit Print", "month": "2026-10", }, }, "result": { "invoice_id": "INV-2026-0412", "total": 2350, "status": "unpaid", }, }, ], "latest_call": { "tool": "send_invoice", "arguments": { "invoice_id": "INV-2026-0412", "to": "accounts@orbitprint.example", "cc": [ "sam@pinecrest.example", ], }, "attempt": 1, }, }) decision = decide({ "status": "error", "code": 401, "message": "The studio's mail account login has expired. The account owner must sign in again in Settings before mail can be sent.", }) print(decision.value, decision.confidence)
Use when
- Your agent needs to choose its next step after each tool result.
- Failed or stalled runs should be referred to a person.
Avoid when
- You need to select a specific tool; use Agent tool selection from a menu.
Context and input
| Field | Kind | Description |
|---|---|---|
latest_result | input | The result of the latest call, as the tool returned it (a success with data, or an error with a status and message). |
app | context | The application the agent works in: its name and a description of what it does and for whom. |
today | context | Today's date, written out (for example 'Wednesday 23 June 2027'). |
tools | context | The tools the agent can call, a list of 'name: what it does'. |
retry_limit | context | The app's rule for retrying a failed call, as a sentence (for example 'Retry a failed call at most 3 times'). |
goal | context | What the user asked the agent to achieve, in the user's words. |
plan | context | The agent's plan, a list of numbered steps each marked done, current step or still to do. |
steps_so_far | context | The calls the agent has made so far, each with its call (tool and arguments) and its result. |
latest_call | context | The call just made: tool, arguments and the attempt number. |
Functions
| Key | Interface | Instructions | Labels |
|---|---|---|---|
| next | classify | Given the agent's goal, its plan and the latest tool result, what should the agent do next? continue: the latest call worked and steps of the plan remain, or it returned only part of a list and the goal needs the rest (fetch the next part). retry: the call failed for a temporary reason (a timeout, the service unavailable, a rate limit with a short wait) and the attempts so far are fewer than the retry limit; make the same call again. change_approach: the call cannot succeed as it was made because of the agent's own mistake (a value in the wrong format or not allowed, an id or name that differs from the one in the goal, a search spelled differently from the goal); correct the call or use another tool. stop: report back to the user: the goal is now done (the last step of the plan worked, or the result itself answers the goal), or it cannot be done (the record in the goal does not exist, or the request was refused for a reason no retry or other tool can change). escalate: a person must act: permission denied, login expired, approval needed, or a temporary failure has already used every allowed retry. | change_approach, continue, escalate, retry, stop |
How it was measured
Test accuracy: the share of test rows whose top answer was right.
- 100.0% on the in-house test (2,000 rows). in-house: same generator as the training data
- 100.0% on a second in-house test of unseen cases. 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 |
|---|---|---|---|---|
| next | 99.95% | 100.0% | 0.70 | 2,000 |
Base: Jeff v1.4. Adapter trained: 25 October 2026.
Base
jeff-base v1.4
Call it
jeff.agents.after-result.next, 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.agents.after-result.next", context={ "app": "<app>", "today": "<today>", "tools": "<tools>", "retry_limit": "<retry_limit>", "goal": "<goal>", "plan": "<plan>", "steps_so_far": "<steps_so_far>", "latest_call": "<latest_call>", }) decision = decide("<latest_result>") print(decision.value, decision.confidence)
Download
Weights: mstrasser/jeff-adapter-after-result (v1.4)
Licence: Apache-2.0