Skip to content
jeff.support.message-triagev1.4.0

Shared inbox triage

Classifies an inbox message, determines the required action and urgency, and selects the responsible team using your message categories, routing table and rules.

Open in playground

Example

Context

recipient
name: Lena Brandt address: lena.brandt@hollowayarch.example role: Office manager organisation: Holloway Architects
message_kinds
invoice: A supplier's bill or a question about one booking: Meeting room, travel or event bookings it_problem: Something broken with computers, phones or the network newsletter: Bulk mail and marketing
routing_table
- {"key":"finance","name":"Finance team","address":"finance@hollowayarch.example","topics":"Supplier invoices, payments, expenses"} - {"key":"it","name":"IT support","address":"it@hollowayarch.example","topics":"Computers, phones, printers, network and accounts"}
routing_rules
- Anything about a client project's fees goes to the partner on the project, never to finance.
now
Monday 2 November 2026, 09:40

Input

channel: email from: billing@greenleafplants.example to: lena.brandt@hollowayarch.example cc: received: Monday 2 November 2026, 08:55 subject: Invoice GL-5520 for October plant care body: Hello Lena, please find attached our invoice GL-5520 for October's plant care at your Bristol office, 240.00. Could you arrange payment within 30 days? Kind regards, Greenleaf Plants

Answer (JSON)
value forward, confidence 0.99
Top options
  1. forward 0.99
  2. do_task 0.007
  3. fyi_only 0.001

A supplier's invoice belongs to the finance team, who are not yet on the email, so the action is forward.

Open in playground

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.support.message-triage.action_needed", context={        "recipient": {            "name": "Lena Brandt",            "address": "lena.brandt@hollowayarch.example",            "role": "Office manager",            "organisation": "Holloway Architects",        },        "message_kinds": {            "invoice": "A supplier's bill or a question about one",            "booking": "Meeting room, travel or event bookings",            "it_problem": "Something broken with computers, phones or the network",            "newsletter": "Bulk mail and marketing",        },        "routing_table": [            {                "key": "finance",                "name": "Finance team",                "address": "finance@hollowayarch.example",                "topics": "Supplier invoices, payments, expenses",            },            {                "key": "it",                "name": "IT support",                "address": "it@hollowayarch.example",                "topics": "Computers, phones, printers, network and accounts",            },        ],        "routing_rules": [            "Anything about a client project's fees goes to the partner on the project, never to finance.",        ],        "now": "Monday 2 November 2026, 09:40",    })     decision = decide({        "channel": "email",        "from": "billing@greenleafplants.example",        "to": "lena.brandt@hollowayarch.example",        "cc": "",        "received": "Monday 2 November 2026, 08:55",        "subject": "Invoice GL-5520 for October plant care",        "body": "Hello Lena, please find attached our invoice GL-5520 for October's plant care at your Bristol office, 240.00. Could you arrange payment within 30 days? Kind regards, Greenleaf Plants",    })     print(decision.value, decision.confidence)

More examples

  • Broken printer, who deals with itanswer it · confidence 0.965

    Context

    recipient
    name: Lena Brandt address: lena.brandt@hollowayarch.example role: Office manager organisation: Holloway Architects
    message_kinds
    invoice: A supplier's bill or a question about one booking: Meeting room, travel or event bookings it_problem: Something broken with computers, phones or the network newsletter: Bulk mail and marketing
    routing_table
    - {"key":"finance","name":"Finance team","address":"finance@hollowayarch.example","topics":"Supplier invoices, payments, expenses"} - {"key":"it","name":"IT support","address":"it@hollowayarch.example","topics":"Computers, phones, printers, network and accounts"}
    routing_rules
    - Anything about a client project's fees goes to the partner on the project, never to finance.
    now
    Monday 2 November 2026, 09:40

    Input

    channel: email from: tom.reyes@hollowayarch.example to: lena.brandt@hollowayarch.example cc: received: Monday 2 November 2026, 09:31 subject: Printer on the second floor body: Hi Lena, the big printer on the second floor shows "fuser error" and won't print anything. Who can fix it? Tom

    Labels (the options)

    finance
    Finance team (supplier invoices, payments, expenses)
    it
    IT support (computers, phones, printers, network and accounts)
    self
    Lena Brandt deals with it herself
    Answer (JSON)
    value it, confidence 0.965
    Top options
    1. it 0.965
    2. self 0.03
    3. finance 0.005

    A broken printer is on IT support's list of topics, so the message goes to it.

    Open in playground

    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.support.message-triage.route_to", context={        "recipient": {            "name": "Lena Brandt",            "address": "lena.brandt@hollowayarch.example",            "role": "Office manager",            "organisation": "Holloway Architects",        },        "message_kinds": {            "invoice": "A supplier's bill or a question about one",            "booking": "Meeting room, travel or event bookings",            "it_problem": "Something broken with computers, phones or the network",            "newsletter": "Bulk mail and marketing",        },        "routing_table": [            {                "key": "finance",                "name": "Finance team",                "address": "finance@hollowayarch.example",                "topics": "Supplier invoices, payments, expenses",            },            {                "key": "it",                "name": "IT support",                "address": "it@hollowayarch.example",                "topics": "Computers, phones, printers, network and accounts",            },        ],        "routing_rules": [            "Anything about a client project's fees goes to the partner on the project, never to finance.",        ],        "now": "Monday 2 November 2026, 09:40",    }, labels={        "finance": "Finance team (supplier invoices, payments, expenses)",        "it": "IT support (computers, phones, printers, network and accounts)",        "self": "Lena Brandt deals with it herself",    })     decision = decide({        "channel": "email",        "from": "tom.reyes@hollowayarch.example",        "to": "lena.brandt@hollowayarch.example",        "cc": "",        "received": "Monday 2 November 2026, 09:31",        "subject": "Printer on the second floor",        "body": "Hi Lena, the big printer on the second floor shows \"fuser error\" and won't print anything. Who can fix it? Tom",    })     print(decision.value, decision.confidence)
  • Meeting room request, sorted by kindanswer booking · confidence 0.999

    Context

    recipient
    name: Lena Brandt address: lena.brandt@hollowayarch.example role: Office manager organisation: Holloway Architects
    message_kinds
    invoice: A supplier's bill or a question about one booking: Meeting room, travel or event bookings it_problem: Something broken with computers, phones or the network newsletter: Bulk mail and marketing
    routing_table
    - {"key":"finance","name":"Finance team","address":"finance@hollowayarch.example","topics":"Supplier invoices, payments, expenses"} - {"key":"it","name":"IT support","address":"it@hollowayarch.example","topics":"Computers, phones, printers, network and accounts"}
    routing_rules
    - Anything about a client project's fees goes to the partner on the project, never to finance.
    now
    Monday 2 November 2026, 09:40

    Input

    channel: email from: ada.mensah@hollowayarch.example to: lena.brandt@hollowayarch.example cc: received: Monday 2 November 2026, 09:12 subject: Room for Thursday body: Morning Lena, could you book the big meeting room for Thursday from 2 to 4 pm? I have the Ashgrove Homes team coming in. Thanks, Ada

    Labels (the options)

    invoice
    A supplier's bill or a question about one
    booking
    Meeting room, travel or event bookings
    it_problem
    Something broken with computers, phones or the network
    newsletter
    Bulk mail and marketing
    Answer (JSON)
    value booking, confidence 0.999
    Top options
    1. booking 0.999
    2. invoice 0
    3. newsletter 0

    A request to book the meeting room is, on the office manager's own list, a booking.

    Open in playground

    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.support.message-triage.intent", context={        "recipient": {            "name": "Lena Brandt",            "address": "lena.brandt@hollowayarch.example",            "role": "Office manager",            "organisation": "Holloway Architects",        },        "message_kinds": {            "invoice": "A supplier's bill or a question about one",            "booking": "Meeting room, travel or event bookings",            "it_problem": "Something broken with computers, phones or the network",            "newsletter": "Bulk mail and marketing",        },        "routing_table": [            {                "key": "finance",                "name": "Finance team",                "address": "finance@hollowayarch.example",                "topics": "Supplier invoices, payments, expenses",            },            {                "key": "it",                "name": "IT support",                "address": "it@hollowayarch.example",                "topics": "Computers, phones, printers, network and accounts",            },        ],        "routing_rules": [            "Anything about a client project's fees goes to the partner on the project, never to finance.",        ],        "now": "Monday 2 November 2026, 09:40",    }, labels={        "invoice": "A supplier's bill or a question about one",        "booking": "Meeting room, travel or event bookings",        "it_problem": "Something broken with computers, phones or the network",        "newsletter": "Bulk mail and marketing",    })     decision = decide({        "channel": "email",        "from": "ada.mensah@hollowayarch.example",        "to": "lena.brandt@hollowayarch.example",        "cc": "",        "received": "Monday 2 November 2026, 09:12",        "subject": "Room for Thursday",        "body": "Morning Lena, could you book the big meeting room for Thursday from 2 to 4 pm? I have the Ashgrove Homes team coming in. Thanks, Ada",    })     print(decision.value, decision.confidence)
  • Shared drive down before an 11:00 deadlineanswer now · confidence 0.941

    Context

    recipient
    name: Lena Brandt address: lena.brandt@hollowayarch.example role: Office manager organisation: Holloway Architects
    message_kinds
    invoice: A supplier's bill or a question about one booking: Meeting room, travel or event bookings it_problem: Something broken with computers, phones or the network newsletter: Bulk mail and marketing
    routing_table
    - {"key":"finance","name":"Finance team","address":"finance@hollowayarch.example","topics":"Supplier invoices, payments, expenses"} - {"key":"it","name":"IT support","address":"it@hollowayarch.example","topics":"Computers, phones, printers, network and accounts"}
    routing_rules
    - Anything about a client project's fees goes to the partner on the project, never to finance.
    now
    Monday 2 November 2026, 09:40

    Input

    channel: email from: ada.mensah@hollowayarch.example to: lena.brandt@hollowayarch.example cc: it@hollowayarch.example received: Monday 2 November 2026, 09:35 subject: Can't reach the project drive body: Lena, nobody on the third floor can open the project drive. We have to send the Mill Brook drawings to the client by 11:00 this morning. Ada

    Answer (JSON)
    value now, confidence 0.941
    Top options
    1. now 0.941
    2. no_deadline 0.047
    3. today 0.006

    The shared drive is down and the drawings are due within two hours, so the urgency is now.

    Open in playground

    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.support.message-triage.urgency", context={        "recipient": {            "name": "Lena Brandt",            "address": "lena.brandt@hollowayarch.example",            "role": "Office manager",            "organisation": "Holloway Architects",        },        "message_kinds": {            "invoice": "A supplier's bill or a question about one",            "booking": "Meeting room, travel or event bookings",            "it_problem": "Something broken with computers, phones or the network",            "newsletter": "Bulk mail and marketing",        },        "routing_table": [            {                "key": "finance",                "name": "Finance team",                "address": "finance@hollowayarch.example",                "topics": "Supplier invoices, payments, expenses",            },            {                "key": "it",                "name": "IT support",                "address": "it@hollowayarch.example",                "topics": "Computers, phones, printers, network and accounts",            },        ],        "routing_rules": [            "Anything about a client project's fees goes to the partner on the project, never to finance.",        ],        "now": "Monday 2 November 2026, 09:40",    })     decision = decide({        "channel": "email",        "from": "ada.mensah@hollowayarch.example",        "to": "lena.brandt@hollowayarch.example",        "cc": "it@hollowayarch.example",        "received": "Monday 2 November 2026, 09:35",        "subject": "Can't reach the project drive",        "body": "Lena, nobody on the third floor can open the project drive. We have to send the Mill Brook drawings to the client by 11:00 this morning. Ada",    })     print(decision.value, decision.confidence)
  • Fake parcel notice in the inboxanswer ignore_spam · confidence 0.995

    Context

    recipient
    name: Lena Brandt address: lena.brandt@hollowayarch.example role: Office manager organisation: Holloway Architects
    message_kinds
    invoice: A supplier's bill or a question about one booking: Meeting room, travel or event bookings it_problem: Something broken with computers, phones or the network newsletter: Bulk mail and marketing
    routing_table
    - {"key":"finance","name":"Finance team","address":"finance@hollowayarch.example","topics":"Supplier invoices, payments, expenses"} - {"key":"it","name":"IT support","address":"it@hollowayarch.example","topics":"Computers, phones, printers, network and accounts"}
    routing_rules
    - Anything about a client project's fees goes to the partner on the project, never to finance.
    now
    Monday 2 November 2026, 09:40

    Input

    channel: email from: delivery-notice@parcel-track-help.example to: lena.brandt@hollowayarch.example cc: received: Monday 2 November 2026, 07:58 subject: Your parcel is on hold body: We tried to deliver your parcel but customs fees of 2.99 are unpaid. Pay within 12 hours at http://parcel-track-help.example/pay or your parcel will be returned.

    Answer (JSON)
    value ignore_spam, confidence 0.995
    Top options
    1. ignore_spam 0.995
    2. forward 0.003
    3. fyi_only 0.001

    A parcel notice asking for a small fee through an unknown link is a scam, so the action is ignore_spam.

    Open in playground

    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.support.message-triage.action_needed", context={        "recipient": {            "name": "Lena Brandt",            "address": "lena.brandt@hollowayarch.example",            "role": "Office manager",            "organisation": "Holloway Architects",        },        "message_kinds": {            "invoice": "A supplier's bill or a question about one",            "booking": "Meeting room, travel or event bookings",            "it_problem": "Something broken with computers, phones or the network",            "newsletter": "Bulk mail and marketing",        },        "routing_table": [            {                "key": "finance",                "name": "Finance team",                "address": "finance@hollowayarch.example",                "topics": "Supplier invoices, payments, expenses",            },            {                "key": "it",                "name": "IT support",                "address": "it@hollowayarch.example",                "topics": "Computers, phones, printers, network and accounts",            },        ],        "routing_rules": [            "Anything about a client project's fees goes to the partner on the project, never to finance.",        ],        "now": "Monday 2 November 2026, 09:40",    })     decision = decide({        "channel": "email",        "from": "delivery-notice@parcel-track-help.example",        "to": "lena.brandt@hollowayarch.example",        "cc": "",        "received": "Monday 2 November 2026, 07:58",        "subject": "Your parcel is on hold",        "body": "We tried to deliver your parcel but customs fees of 2.99 are unpaid. Pay within 12 hours at http://parcel-track-help.example/pay or your parcel will be returned.",    })     print(decision.value, decision.confidence)

Use when

  • A shared inbox receives different types of messages, and you can define its categories, teams and handling rules.

Avoid when

  • You need to write a reply; this adapter only classifies and routes the message.

Context and input

FieldKindDescription
message
inputThe newest message: an object with channel, from, to, cc, received, subject and body (it may quote or forward earlier messages).
recipient
contextWhose inbox it is: an object with the recipient's name, address, role and organisation.
message_kinds
contextThe recipient's own sorting list: an object of message kind -> description.
routing_table
contextWho handles what: a list of entries, each with key, name, address and the topics it handles.
routing_rules
contextRules that override the routing table, a list of sentences.
now
contextThe current date and time (for example 'Monday 8 February 2027, 12:15').

Functions

KeyInterfaceInstructionsLabels
route_torouteWho should deal with this message? Choose the routing table entry whose responsibilities cover the topic of the newest message (for a forwarded message, the forwarded content), or self if it is a topic the recipient deals with personally. A routing rule that matches the message overrides the topic. Choose the entry that should deal with it even if it is already in the To or Cc, or if the message only informs.from the caller
action_neededclassifyWhat must the recipient do with this message? Go by the newest message. ignore_spam: unsolicited bulk advertising, a scam or a phishing attempt, whatever it claims. Otherwise first decide who deals with it (the routing table entry for its topic, unless a routing rule matches the message, or the recipient for topics they deal with). If that is a team or person in the routing table: forward when they are not already in the To or Cc of the message, fyi_only when they are. If it is the recipient: fyi_only when the message only informs and asks nothing; reply when the sender needs only a written answer, decision or confirmation; do_task when the recipient must do something beyond writing an answer, such as preparing or sending a document, changing a booking or record, fixing something, or approving or paying in a system.do_task, forward, fyi_only, ignore_spam, reply
intentclassifyWhich kind of message is this, using the recipient's own sorting list (the options)? Judge the newest message; earlier messages in the thread are context only. For a forwarded message, judge the forwarded content that is being passed on. Go by what the message actually asks or says, not by its subject line, which may be out of date or misleading.from the caller
urgencyclassifyHow soon must this message be acted on, judged against the current date and time given? now: something is broken, stopped or blocked right now, or the action is needed within the next two hours. today: needed before the end of today but more than two hours from now. this_week: needed after today and within the next seven days. no_deadline: no deadline stated or implied, or the deadline is more than seven days away. Spam, and messages that only inform and ask nothing of anyone, are no_deadline. A request addressed to someone else keeps its own deadline. Go by the facts: a polite or relaxed tone does not lower urgency, and words like 'urgent' in a subject line or a disclaimer do not raise it.no_deadline, now, this_week, today

How it was measured

Test accuracy: the share of test rows whose top answer was right.

  • 98.0% on CLINC150, a public intent benchmark (it asks the intent question only) (1,000 rows). public benchmark
  • 96.7% on the in-house test (2,000 rows). in-house: same generator as the training data
  • 97.0% on the in-house test in domain families 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.

FunctionRight when confidentConfident onThresholdCalibration rows
route_to96.9%100.0%0.50520
action_needed95.2%100.0%0.50540
intent95.4%100.0%0.44540
urgency98.3%100.0%0.49400

Caveats

  • Training and test rows were kept only where a blind LLM check agreed with the label, so these scores are probably inflated.

Base: Jeff v1.4. Adapter trained: 25 October 2026.

Base

jeff-base v1.4

Call it

jeff.support.message-triage.route_to, 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.support.message-triage.route_to", context={        "recipient": "<recipient>",        "message_kinds": "<message_kinds>",        "routing_table": "<routing_table>",        "routing_rules": "<routing_rules>",        "now": "<now>",    })     decision = decide("<message>")     print(decision.value, decision.confidence)

Download

Weights: mstrasser/jeff-adapter-message-triage (v1.4)

Licence: Apache-2.0