Agent tool selection from a menu
Selects the next tool from a menu included in the request, using the conversation for context. Can also indicate that no tool is needed or that the user must supply missing information.
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
- def find_invoice(client: str, month: str) -> dict: """Finds the studio's invoice for a client and month.""" def send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict: """Emails an invoice to a recipient, with optional copies.""" def create_invoice(client: str, items: list[dict]) -> dict: """Creates a new draft invoice."""
- conversation
- - {"role":"user","content":"Morning! Can you send the October invoice for Orbit Print?"} - {"role":"assistant","content":"I found it, INV-2026-0412 for 2,350.00, still unpaid. Who at Orbit Print should receive it?"}
Input
Send it to their accounts address, accounts@orbitprint.example, and copy me.
Labels (the options)
- find_invoice
- Finds the studio's invoice for a client and month.
- send_invoice
- Emails an invoice to a recipient, with optional copies.
- create_invoice
- Creates a new draft invoice.
- none
- No tool is needed, or no tool on the menu can do what the user asks.
- ask_user
- A tool fits, but a required detail is missing and the agent must ask the user.
- Answer (JSON)
- value send_invoice, confidence 0.998
- Top options
- send_invoice 0.998
- ask_user 0.002
- find_invoice 0
The user has given the last detail the agent needed, so the next tool to call is send_invoice.
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.tool-route.tool", 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": "def find_invoice(client: str, month: str) -> dict:\n \"\"\"Finds the studio's invoice for a client and month.\"\"\"\ndef send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict:\n \"\"\"Emails an invoice to a recipient, with optional copies.\"\"\"\ndef create_invoice(client: str, items: list[dict]) -> dict:\n \"\"\"Creates a new draft invoice.\"\"\"", "conversation": [ { "role": "user", "content": "Morning! Can you send the October invoice for Orbit Print?", }, { "role": "assistant", "content": "I found it, INV-2026-0412 for 2,350.00, still unpaid. Who at Orbit Print should receive it?", }, ], }, labels={ "find_invoice": "Finds the studio's invoice for a client and month.", "send_invoice": "Emails an invoice to a recipient, with optional copies.", "create_invoice": "Creates a new draft invoice.", "none": "No tool is needed, or no tool on the menu can do what the user asks.", "ask_user": "A tool fits, but a required detail is missing and the agent must ask the user.", }) decision = decide("Send it to their accounts address, accounts@orbitprint.example, and copy me.") print(decision.value, decision.confidence)
More examples
Look up an invoiceanswer find_invoice · confidence 0.811
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
- def find_invoice(client: str, month: str) -> dict: """Finds the studio's invoice for a client and month.""" def send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict: """Emails an invoice to a recipient, with optional copies.""" def create_invoice(client: str, items: list[dict]) -> dict: """Creates a new draft invoice."""
- conversation
Input
How much did we bill Moss & Gale in September 2026?
Labels (the options)
- find_invoice
- Finds the studio's invoice for a client and month.
- send_invoice
- Emails an invoice to a recipient, with optional copies.
- create_invoice
- Creates a new draft invoice.
- none
- No tool is needed, or no tool on the menu can do what the user asks.
- ask_user
- A tool fits, but a required detail is missing and the agent must ask the user.
- Answer (JSON)
- value find_invoice, confidence 0.811
- Top options
- find_invoice 0.811
- none 0.166
- ask_user 0.018
The user asks what was billed to a client in a given month, so the tool to call is
find_invoice.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.tool-route.tool", 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": "def find_invoice(client: str, month: str) -> dict:\n \"\"\"Finds the studio's invoice for a client and month.\"\"\"\ndef send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict:\n \"\"\"Emails an invoice to a recipient, with optional copies.\"\"\"\ndef create_invoice(client: str, items: list[dict]) -> dict:\n \"\"\"Creates a new draft invoice.\"\"\"", "conversation": [], }, labels={ "find_invoice": "Finds the studio's invoice for a client and month.", "send_invoice": "Emails an invoice to a recipient, with optional copies.", "create_invoice": "Creates a new draft invoice.", "none": "No tool is needed, or no tool on the menu can do what the user asks.", "ask_user": "A tool fits, but a required detail is missing and the agent must ask the user.", }) decision = decide("How much did we bill Moss & Gale in September 2026?") print(decision.value, decision.confidence)
Send an invoice, but which one?answer ask_user · confidence 0.991
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
- def find_invoice(client: str, month: str) -> dict: """Finds the studio's invoice for a client and month.""" def send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict: """Emails an invoice to a recipient, with optional copies.""" def create_invoice(client: str, items: list[dict]) -> dict: """Creates a new draft invoice."""
- conversation
Input
Send the invoice to the client, please.
Labels (the options)
- find_invoice
- Finds the studio's invoice for a client and month.
- send_invoice
- Emails an invoice to a recipient, with optional copies.
- create_invoice
- Creates a new draft invoice.
- none
- No tool is needed, or no tool on the menu can do what the user asks.
- ask_user
- A tool fits, but a required detail is missing and the agent must ask the user.
- Answer (JSON)
- value ask_user, confidence 0.991
- Top options
- ask_user 0.991
- send_invoice 0.004
- find_invoice 0.002
The user wants an invoice sent but names neither the invoice nor the client, so the agent must
ask_user.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.tool-route.tool", 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": "def find_invoice(client: str, month: str) -> dict:\n \"\"\"Finds the studio's invoice for a client and month.\"\"\"\ndef send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict:\n \"\"\"Emails an invoice to a recipient, with optional copies.\"\"\"\ndef create_invoice(client: str, items: list[dict]) -> dict:\n \"\"\"Creates a new draft invoice.\"\"\"", "conversation": [], }, labels={ "find_invoice": "Finds the studio's invoice for a client and month.", "send_invoice": "Emails an invoice to a recipient, with optional copies.", "create_invoice": "Creates a new draft invoice.", "none": "No tool is needed, or no tool on the menu can do what the user asks.", "ask_user": "A tool fits, but a required detail is missing and the agent must ask the user.", }) decision = decide("Send the invoice to the client, please.") print(decision.value, decision.confidence)
The user says thanksanswer none · 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
- def find_invoice(client: str, month: str) -> dict: """Finds the studio's invoice for a client and month.""" def send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict: """Emails an invoice to a recipient, with optional copies.""" def create_invoice(client: str, items: list[dict]) -> dict: """Creates a new draft invoice."""
- conversation
- - {"role":"user","content":"Send the October invoice for Orbit Print to accounts@orbitprint.example."} - {"role":"assistant","content":"Done, INV-2026-0412 has been sent to accounts@orbitprint.example."}
Input
Perfect, thank you!
Labels (the options)
- find_invoice
- Finds the studio's invoice for a client and month.
- send_invoice
- Emails an invoice to a recipient, with optional copies.
- create_invoice
- Creates a new draft invoice.
- none
- No tool is needed, or no tool on the menu can do what the user asks.
- ask_user
- A tool fits, but a required detail is missing and the agent must ask the user.
- Answer (JSON)
- value none, confidence 1
- Top options
- none 1
- ask_user 0
- send_invoice 0
The user is only saying thank you, so no tool is needed and 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.agents.tool-route.tool", 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": "def find_invoice(client: str, month: str) -> dict:\n \"\"\"Finds the studio's invoice for a client and month.\"\"\"\ndef send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict:\n \"\"\"Emails an invoice to a recipient, with optional copies.\"\"\"\ndef create_invoice(client: str, items: list[dict]) -> dict:\n \"\"\"Creates a new draft invoice.\"\"\"", "conversation": [ { "role": "user", "content": "Send the October invoice for Orbit Print to accounts@orbitprint.example.", }, { "role": "assistant", "content": "Done, INV-2026-0412 has been sent to accounts@orbitprint.example.", }, ], }, labels={ "find_invoice": "Finds the studio's invoice for a client and month.", "send_invoice": "Emails an invoice to a recipient, with optional copies.", "create_invoice": "Creates a new draft invoice.", "none": "No tool is needed, or no tool on the menu can do what the user asks.", "ask_user": "A tool fits, but a required detail is missing and the agent must ask the user.", }) decision = decide("Perfect, thank you!") print(decision.value, decision.confidence)
Draft a new invoice with its itemsanswer create_invoice · confidence 0.821
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
- def find_invoice(client: str, month: str) -> dict: """Finds the studio's invoice for a client and month.""" def send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict: """Emails an invoice to a recipient, with optional copies.""" def create_invoice(client: str, items: list[dict]) -> dict: """Creates a new draft invoice."""
- conversation
Input
Make a new invoice for Harbour Lane Cafe for the menu design, 2 days at 450.00 a day.
Labels (the options)
- find_invoice
- Finds the studio's invoice for a client and month.
- send_invoice
- Emails an invoice to a recipient, with optional copies.
- create_invoice
- Creates a new draft invoice.
- none
- No tool is needed, or no tool on the menu can do what the user asks.
- ask_user
- A tool fits, but a required detail is missing and the agent must ask the user.
- Answer (JSON)
- value create_invoice, confidence 0.821
- Top options
- create_invoice 0.821
- ask_user 0.168
- none 0.006
The user gives the client, the work and the price for a new invoice, so the tool to call is
create_invoice.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.tool-route.tool", 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": "def find_invoice(client: str, month: str) -> dict:\n \"\"\"Finds the studio's invoice for a client and month.\"\"\"\ndef send_invoice(invoice_id: str, to: str, cc: list[str] = []) -> dict:\n \"\"\"Emails an invoice to a recipient, with optional copies.\"\"\"\ndef create_invoice(client: str, items: list[dict]) -> dict:\n \"\"\"Creates a new draft invoice.\"\"\"", "conversation": [], }, labels={ "find_invoice": "Finds the studio's invoice for a client and month.", "send_invoice": "Emails an invoice to a recipient, with optional copies.", "create_invoice": "Creates a new draft invoice.", "none": "No tool is needed, or no tool on the menu can do what the user asks.", "ask_user": "A tool fits, but a required detail is missing and the agent must ask the user.", }) decision = decide("Make a new invoice for Harbour Lane Cafe for the menu design, 2 days at 450.00 a day.") print(decision.value, decision.confidence)
Use when
- Your tool menu is supplied as text, function signatures or schemas in the request.
- You need a tool-selection decision with a probability.
Avoid when
- You need to generate tool arguments; this adapter selects a tool without constructing the call.
Context and input
| Field | Kind | Description |
|---|---|---|
request | input | The user's latest 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 tool menu, in any common format (Python signatures, JSON schemas and so on). |
conversation | context | The conversation so far, a list of messages (user, assistant, tool calls and tool results). |
Functions
| Key | Interface | Instructions | Labels |
|---|---|---|---|
| tool | route | What should the agent do next with the user's latest message? Choose the tool on the menu that should be called now when that tool can do what the user asks and the request and the conversation give every detail it requires (details the agent can take from earlier in the conversation count). Choose none when no tool is needed or none fits: the user is chatting or thanking, asks something the conversation already answers, or asks for something no tool on the menu can do. Choose ask_user when a tool fits but a required detail is missing and cannot be taken from the conversation, or when the request could mean two different records or actions and the agent must ask which. Read the tool names and descriptions carefully: similar tools do different things. | from the caller |
How it was measured
Test accuracy: the share of test rows whose top answer was right.
- 71.6% on When2Call, a public function-calling benchmark (questions and tools from the Berkeley Function Calling Leaderboard) (3,646 rows). public benchmark
- 98.2% on the in-house test (2,000 rows). in-house: same generator as the training data
- 96.7% on a second in-house test of unseen cases (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 |
|---|---|---|---|---|
| tool | 98.5% | 100.0% | 0.41 | 2,000 |
Base: Jeff v1.4. Adapter trained: 25 October 2026.
Base
jeff-base v1.4
Call it
jeff.agents.tool-route.tool, 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.tool-route.tool", context={ "app": "<app>", "today": "<today>", "tools": "<tools>", "conversation": "<conversation>", }) decision = decide("<request>") print(decision.value, decision.confidence)
Download
Weights: mstrasser/jeff-adapter-tool-route (v1.4)
Licence: Apache-2.0