All integrations

OpenAI Assistants

Intercept OpenAI Assistants tool calls that require_action and route them through Cheqpoint for human review.

Install

npm install @cheqpoint/sdk openai
npm install @cheqpoint/sdk openai

Handle requires_action with Cheqpoint

TypeScript
import OpenAI from "openai";
import { CheqpointClient } from "@cheqpoint/sdk";

const openai = new OpenAI();
const cheqpoint = new CheqpointClient({ apiKey: process.env.CHEQPOINT_API_KEY! });

async function handleRequiresAction(
  threadId: string,
  runId: string,
  toolCalls: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall[]
) {
  const toolOutputs = await Promise.all(
    toolCalls.map(async (call) => {
      const args = JSON.parse(call.function.arguments);

      // Gate sensitive functions through Cheqpoint
      if (["process_refund", "transfer_funds", "delete_user"].includes(call.function.name)) {
        const result = await cheqpoint.checkpoint({
          action: call.function.name,
          summary: `Assistant wants to call ${call.function.name}`,
          details: args,
          riskLevel: "high",
        });

        if (result.status !== "APPROVED") {
          return { tool_call_id: call.id, output: `Rejected: ${result.decisionNote}` };
        }
      }

      // Execute the actual function
      const output = await executeFunction(call.function.name, args);
      return { tool_call_id: call.id, output: JSON.stringify(output) };
    })
  );

  return openai.beta.threads.runs.submitToolOutputs(threadId, runId, { tool_outputs: toolOutputs });
}
import OpenAI from "openai";
import { CheqpointClient } from "@cheqpoint/sdk";

const openai = new OpenAI();
const cheqpoint = new CheqpointClient({ apiKey: process.env.CHEQPOINT_API_KEY! });

async function handleRequiresAction(
  threadId: string,
  runId: string,
  toolCalls: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall[]
) {
  const toolOutputs = await Promise.all(
    toolCalls.map(async (call) => {
      const args = JSON.parse(call.function.arguments);

      // Gate sensitive functions through Cheqpoint
      if (["process_refund", "transfer_funds", "delete_user"].includes(call.function.name)) {
        const result = await cheqpoint.checkpoint({
          action: call.function.name,
          summary: `Assistant wants to call ${call.function.name}`,
          details: args,
          riskLevel: "high",
        });

        if (result.status !== "APPROVED") {
          return { tool_call_id: call.id, output: `Rejected: ${result.decisionNote}` };
        }
      }

      // Execute the actual function
      const output = await executeFunction(call.function.name, args);
      return { tool_call_id: call.id, output: JSON.stringify(output) };
    })
  );

  return openai.beta.threads.runs.submitToolOutputs(threadId, runId, { tool_outputs: toolOutputs });
}

Poll your run with approval handling

TypeScript
async function runWithApprovals(threadId: string, assistantId: string) {
  let run = await openai.beta.threads.runs.create(threadId, { assistant_id: assistantId });

  while (run.status !== "completed") {
    await new Promise(r => setTimeout(r, 1000));
    run = await openai.beta.threads.runs.retrieve(threadId, run.id);

    if (run.status === "requires_action") {
      const calls = run.required_action!.submit_tool_outputs.tool_calls;
      run = await handleRequiresAction(threadId, run.id, calls);
    }
  }

  const messages = await openai.beta.threads.messages.list(threadId);
  return messages.data[0].content[0];
}
async function runWithApprovals(threadId: string, assistantId: string) {
  let run = await openai.beta.threads.runs.create(threadId, { assistant_id: assistantId });

  while (run.status !== "completed") {
    await new Promise(r => setTimeout(r, 1000));
    run = await openai.beta.threads.runs.retrieve(threadId, run.id);

    if (run.status === "requires_action") {
      const calls = run.required_action!.submit_tool_outputs.tool_calls;
      run = await handleRequiresAction(threadId, run.id, calls);
    }
  }

  const messages = await openai.beta.threads.messages.list(threadId);
  return messages.data[0].content[0];
}