AI Knowledge & Logic

Human-in-the-Loop Decisions

Ask a teammate for a decision while the bot keeps the conversation, then let the bot continue from the recorded outcome.

Human decision requests let the bot ask your team for a specific decision without handing over the whole conversation. An agent sees a card in the Octocom conversation, chooses an option, and can provide a reason or other detail. The bot is then triggered to read that decision and continue helping the customer.

Use this for an exchange exception, a review of damage evidence, or another decision that needs human judgment while the bot can still handle the customer-facing follow-up.

Decision request or full handoff?

Human decision requestFull handoff
What the human doesAnswers a specific question on a cardTakes over the conversation
Who handles the customerThe bot retains the conversationA human agent
What happens after the decisionA new bot turn checks the result and follows the workflowThe conversation remains handed off
How to use itCustom Python actions using the helpers belowtransferConversation or hand_off_conversation

Creating a decision request does not itself hand off or assign the conversation. Your team needs a process for finding and answering these cards. Use Human Escalation when the customer needs a person to take over instead.

How it works

  1. The bot calls a custom action that registers a decision request.
  2. The action returns immediately with the request's status. Python does not stay running while a human decides.
  3. Following your workflow instructions, the bot tells the customer it has submitted the request and will follow up. The helper does not send this message itself.
  4. The Octocom dashboard shows an internal Action requested card with the summary, supporting information, and decision buttons. In the conversation timeline, it is positioned after the next bot message following the request, normally the announcement. The customer does not see the card.
  5. An agent chooses an option and supplies any required text. The card displays the recorded decision and inputs.
  6. Resolving the request triggers a new bot turn, whether the decision was approval, rejection, or another option. The bot is instructed to call the matching check action, read the outcome, and continue according to your workflow.

The continuation is a new bot turn, not a resumption of the original Python function. Clicking Approve records approval; it does not itself issue a refund, create an exchange, or run the next business operation. Those steps belong in your configured actions and workflow.

Set up an exchange review

Create two custom Python actions: one to request the review and one to check its result. Both helpers are built in and require no imports.

1. Create the request action

Name the action requestExchangeReview. Give it a required string argument named orderId, and describe it as submitting an exchange for human review without performing the exchange.

def execute_action(context):
    order_id = context["args"]["orderId"]
    return request_human_decision(
        context,
        key=f"exchange_review:{order_id}",
        summary=f"Review exchange request for order {order_id}",
        decisions=[
            {"key": "approve", "label": "Approve exchange"},
            {
                "key": "reject",
                "label": "Reject exchange",
                "input": {
                    "label": "Reason",
                    "type": "text",
                    "required": True,
                },
            },
        ],
        info={"Order": str(order_id)},
    )

The summary is the question your agent sees. info adds read-only context. The decisions list defines the buttons; labels are for the agent, while keys such as approve are the values your workflow receives. A decision can ask for one text input, optionally required.

2. Create the check action

Name this action checkExchangeReview, also with a required string argument named orderId. Describe it as reading the review's status, chosen decision, and any explanation from the reviewer.

def execute_action(context):
    order_id = context["args"]["orderId"]
    return get_human_decision_result(
        context,
        key=f"exchange_review:{order_id}",
    )

The two actions must use exactly the same request key for the same review.

3. Enable both actions in a workflow

Actions are only available to the bot when an active workflow enables them. Enable both requestExchangeReview and checkExchangeReview, plus any separate action needed to perform an approved exchange.

Example workflow instructions:

When an exchange requires human review, collect the order ID and the information needed by the reviewer, then call requestExchangeReview.

If the result is pending, tell the customer the request has been submitted for review and that you will follow up. Do not claim it is approved or perform the exchange yet.

When notified that the human review is resolved, call checkExchangeReview for the same order. Always read the recorded result before deciding what to do next.

If the decision is approve, follow the approved exchange process using the configured exchange action. Confirm completion only after that action succeeds. If the decision is reject, explain the result using the reviewer's reason and offer the alternatives allowed by our policy.

If the check still returns pending, do not claim there is a decision. If it returns none, no request was found for that key; check the order ID before submitting a request.

If a business operation requires approval, its Python action should also verify the recorded decision before making changes. Make that operation safe to retry so a repeated bot turn cannot create a duplicate exchange.

Helper reference

request_human_decision

request_human_decision(context, key, summary, decisions, info=None)
ParameterMeaning
contextThe custom action's context, including the current conversation
keyA stable identifier within the conversation, between 1 and 100 characters
summaryA non-empty description of what the agent needs to decide
decisionsOne or more options with a key, label, and optional input
infoOptional dictionary of read-only context fields shown on the card

Calling this helper again with the same conversation and key returns the existing request, including an already-resolved result. It does not reset the request or replace its summary, buttons, or information. Use a different key for a genuinely new review, such as a second review round; do not generate a fresh key on every retry.

get_human_decision_result

get_human_decision_result(context, key)

Returns the current state for that conversation and key. It only reads the request; it does not create or resolve one.

StatusMeaning
pendingA request exists and is waiting for a human decision
resolvedRead decision and inputs to determine the next step
noneThe check helper found no request for this key

For an existing request, the result includes status, requestId, decision, and inputs. A rejection with a required reason looks like this:

{
  "status": "resolved",
  "requestId": "<request UUID>",
  "decision": "reject",
  "inputs": { "Reason": "This item is outside the exchange window." }
}

The keys in inputs are the input labels you configured, such as Reason.

Testing and operational behavior

  • Test with a conversation. Without context["conversation"], the request helper returns pending with a null requestId and creates no card; the check helper returns none. A pending response alone is not proof that a request was saved.
  • Check both outcomes. Confirm that the card appears, required text is enforced, and both approval and rejection trigger a follow-up that reads the result.
  • Keep the check action available. The continuation tells the bot to check the outcome; your workflow must expose an action that can read the matching key.
  • A decision does not undo a handoff. If someone hands the conversation off while a request is pending, resolving the card does not return it to the normal bot workflow.
  • Plan how the team monitors requests. Creating a card is not a substitute for an agent reviewing it. Decide who owns the review queue and when an unanswered request needs a full handoff.

On this page