Skip to main content

Using Mandaitor with OpenAI Agents

Module 04 · Agentic systemsInteroperability

Using Mandaitor with OpenAI Agents

Intermediate12–16 min2 prerequisites
Before you start
  • Understand Mandaitor's mandate, tool and execution model.
  • Basic familiarity with OpenAI function/tool calling.
After this lesson you can
  • explain where Mandaitor sits in an OpenAI tool-calling loop
  • have a tool call carried out by Mandaitor instead of by your own code
  • map OpenAI agent concepts onto Mandaitor's execution model

OpenAI's function calling, the Responses API and the Agents SDK share one shape: the model decides to call a tool you defined, and your code runs it. Mandaitor changes what "runs it" means for a business operation. Your tool handler holds no credential for the target system and performs no write. It asks Mandaitor, which reads the real record, decides against the agent's mandates, asks a person where a mandate says so, performs the write, and returns the outcome with a signed receipt. You keep OpenAI; the write moves to Mandaitor.

Where Mandaitor sits in the loop​

The model can propose anything. Your handler passes the proposal on as a request that names the operation and the record, never the record's facts. Mandaitor decides on what it reads from the target system, so neither the model nor your handler can talk an amount down, and neither ever sees a credential that could write without asking.

Model proposes

The tool call is a request, not a right

OpenAI decides a tool should run and supplies arguments. Nothing has happened yet: it is a proposal.

Mandaitor decides and acts

On the record, not the arguments

Your handler names the tool and the record. Mandaitor reads the record, decides against the agent's mandates, and writes with a credential neither the model nor your code holds.

The model learns the outcome

A result it can reason about

Written, with a receipt; waiting for a person's approval; or refused, with the reason. The model can report it, wait, or stop.

The pattern in code​

Define the function as usual. Its handler asks Mandaitor with the agent's own identity, through the SDK's executions client (@mandaitor/sdk 5.1.0 or later), and returns what became of the request:

import { MandaitorExecutionsClient } from "@mandaitor/sdk";

// The agent's identity: its DID and the key it registered. No SAP credential anywhere.
const executions = new MandaitorExecutionsClient({
agent: {
did: process.env.AGENT_DID!,
keyId: process.env.AGENT_KEY_ID!,
privateKey: process.env.AGENT_PRIVATE_KEY_PEM!,
},
});

// The function you expose to the model.
export const releaseRequisitionTool = {
type: "function",
name: "release_purchase_requisition",
description: "Release a purchase requisition in SAP, so that purchasing can order it.",
parameters: {
type: "object",
properties: {
purchase_requisition: { type: "string", description: "The requisition's number" },
purpose: { type: "string", description: "Why, in one sentence, for the approver" },
},
required: ["purchase_requisition"],
additionalProperties: false,
},
};

// OpenAI calls this with the arguments it chose. It asks Mandaitor, and never writes itself.
export async function releaseRequisition(
args: { purchase_requisition: string; purpose?: string },
callId: string, // the model's tool call id
) {
const { execution: requested } = await executions.requestExecution({
tool: "sap.purchase_requisition.release",
arguments: { purchase_requisition: args.purchase_requisition },
// A retry of the same tool call reuses its key, so it is never written twice.
idempotency_key: callId,
purpose: args.purpose,
});
const execution = await executions.waitForExecution(requested.execution_id);
// What the model sees: the outcome and why. Never a credential.
return { state: execution.state, reason: execution.state_reason, result: execution.result };
}

The model receives the state as an ordinary tool result. SUCCEEDED comes with the released requisition. AWAITING_APPROVAL means a person decides, and the model can say so. DENIED comes with a reason it can explain, such as AMOUNT_ABOVE_LIMIT. The signed receipt stays in the execution, for your records.

If your agent framework can connect to remote MCP servers, it can connect to Mandaitor's MCP server instead. Each tool call then becomes an execution with no handler code at all.

Try a mandate live​

The mandate the agent acts under is written once, by a person. The demo below runs the real @mandaitor/react creator against an in-browser mock; edit the code to change the actions or resources.

Live Editor
<DocuWrapper>
  <MandateCreator
    availableActions={[
      { id: "procurement.requisition.release", label: "Release requisition", description: "Release a purchase requisition for ordering" },
    ]}
    defaultResources={["procurement:plant:1000/requisition:*"]}
  />
</DocuWrapper>
Result
Loading...
OpenAI conceptMandaitor concept
Tool / function callA tool request: one tool and one record
Assistant / agent identityA registered agent, named by its DID, with a key only it holds
Function argumentsThe record's identifier and an optional purpose, never its facts
Tool result returned to the modelThe execution's state and its reason, and in SUCCEEDED the result
Nothing built-inThe signed receipt, and the Proof-of-Mandate on the audit trail
Check your understanding

With Mandaitor in an OpenAI tool-calling loop, who performs the write?

  • Mandaitor, with its own credential, after deciding on the record. Your handler only asks.
  • Your handler, once Mandaitor answers ALLOW.
  • The model, once its system prompt says it may.
Reveal answer

The model proposes, your handler asks, and Mandaitor decides on the record as the target system holds it, then performs the write itself. Neither the model nor your code holds a credential that could write without asking, so the mandate is the only way in.

From concept to implementation​

This lesson is the mental model. When you are ready to build, the guides cover the concrete calls end to end.

Progress

Save your learning progress

Mark this lesson as complete to update the Academy overview without requiring an account.