Skip to content

Connect Diligent to AI Agents: Sync Evidence and Results Analytics

Sidharth Verma Sidharth Verma 9 min read AI & Agents
TrutoFor teams building AI agents

Give your AI agent Diligent tools.

A comprehensive engineering guide to building autonomous AI agents on top of Diligent. Bypass JSON:API complexity and ephemeral attachment URLs to automate GRC workflows, evidence syncing, and issue creation.

In this guide

  1. 01Fetch Diligent tools
  2. 02Bind tools to your LLM framework
  3. 03Implement agentic backoff logic
  4. 04Orchestrate multi-step compliance workflows

The guide

Learn how to connect Diligent to AI agents using Truto's /tools API. Automate evidence collection, control audits, and risk management with LLMs.

You want to connect Diligent to an AI agent so your system can autonomously sync audit evidence, trigger robot analytics tasks, flag compliance issues, and retrieve control details. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom GRC integration from scratch.

Governance, Risk, and Compliance (GRC) data is highly structured and unforgiving. When you give a Large Language Model (LLM) read and write access to your Diligent One Platform, it cannot afford to hallucinate payload structures or misunderstand complex relationship models. If your team uses standard conversational AI interfaces, check out our guide on connecting Diligent to ChatGPT, or if you are building on Anthropic's models, read our guide to connecting Diligent to Claude. For developers building custom autonomous workflows, you need a programmatic way to fetch these tools and bind them to your agent framework.

This guide breaks down exactly how to fetch AI-ready tools for Diligent, bind them natively to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex compliance operations. For a broader look at this design pattern across multiple SaaS verticals, read our guide on Architecting AI Agents: LangGraph, LangChain, and the SaaS Integration Bottleneck.

The Engineering Reality of the Diligent API

Giving an LLM access to external GRC data sounds straightforward in a whiteboard session. You write a Node.js function that makes a fetch request and wrap it in a tool decorator. In production against Diligent HighBond, this approach collapses under the weight of the vendor's specific architectural patterns.

Diligent's API introduces several specific integration challenges. If you hardcode these interactions directly into your agent tools, you will spend your engineering cycles writing defensive integration code instead of improving your model's reasoning capabilities.

The JSON:API Specification Trap

Diligent strictly adheres to the JSON:API specification. Standard LLMs are trained to expect and emit flat, intuitive JSON objects. When an agent wants to create a new compliance issue, it naturally attempts to send a payload like {"title": "Missing SOC 2 Report", "project_id": "12345"}.

Diligent will reject this immediately. The API requires a heavily nested structure defining the data type, ID, attributes, and explicit relationship objects. You must send:

{
  "data": {
    "type": "issues",
    "attributes": {
      "title": "Missing SOC 2 Report"
    },
    "relationships": {
      "project": {
        "data": { "type": "projects", "id": "12345" }
      }
    }
  }
}

Forcing an LLM to consistently generate this nested boilerplate across dozens of distinct endpoints leads to high hallucination rates. Truto's Proxy APIs absorb this complexity. The LLM sees a clean, flat tool schema, and Truto maps the outgoing request into the strict JSON:API envelope Diligent requires.

Ephemeral S3 Redirects for Evidence Files

Retrieving evidence from Diligent is not a simple REST call that returns a binary blob or a permanent URL. When you request to download an attachment (e.g., via the get_single_diligent_attachment_download_by_id tool), the API does not return a JSON object. Instead, if the file is stored remotely, Diligent returns a 302 Redirect to a pre-signed AWS S3 URL.

This pre-signed URL is strictly temporary - often expiring in exactly two minutes. If your agent logic attempts to fetch the URL, pass it to an asynchronous human-in-the-loop review queue, and then download it later, the request will fail. Your tool abstraction must immediately resolve the redirect and buffer the bytes into your own durable storage or directly into the agent's context window.

Strict Rate Limits with Zero Forgiveness

Diligent enforces strict rate limiting to protect platform stability. Truto's architectural stance on rate limits is explicit: Truto does not retry, throttle, or apply backoff on rate limit errors.

When Diligent returns an HTTP 429 Too Many Requests, Truto passes that error directly to the caller. We normalize the upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) conforming to the IETF specification. This means your agent runtime is fully responsible for intercepting the 429, reading the reset header, and instructing the LLM to pause or queue the task.

Diligent Hero Tools for AI Agents

Instead of building individual API wrappers for every Diligent endpoint, Truto exposes Methods defined on Resources as LLM-ready tools. The agent selects from a deterministic list of functions with guaranteed schemas.

Here are six high-leverage tools available for Diligent integration.

Create an Evidence Record

Tool: create_a_diligent_org_evidence

This tool allows the agent to create a new evidence record in the Diligent Evidence Hub. This is critical for agents acting as automated compliance collectors, taking screenshots or logs from other systems (like AWS or GitHub) and pushing them directly into the GRC platform.

"I just validated the IAM access logs from AWS. Create a new evidence record in Diligent named 'Q3 AWS IAM Access Review' and attach the validation summary."

List Table Records

Tool: list_all_diligent_table_records

Diligent Results relies heavily on data analytic tables. This tool allows the agent to query the raw rows of a data table. Because tables can contain up to 100,000 records, agents must use the query schema to filter by table fields to narrow results down to manageable context sizes.

"Fetch the records from the 'Failed Login Attempts' table in Diligent Results. Filter for any records where the attempt count is greater than 50 in the last 24 hours."

Create a Project Issue

Tool: create_a_diligent_project_issue

When an agent identifies a compliance failure or a control gap, it needs a way to flag it for human review. This tool creates a new issue directly inside a Diligent project. Issues can only be created under active projects.

"We are missing the SOC 2 Type II report for our new vendor, Acme Corp. Create a high-priority project issue in the 'Vendor Risk Management 2026' project flagging this missing document."

Retrieve Control Details

Tool: get_single_diligent_org_control_by_id

Agents tasked with answering GRC questionnaires or verifying configurations need to read the canonical definition of a control. This tool fetches the full JSON:API resource for a control, including its description, framework links, and testing status.

"Look up control ID 8847 in Diligent. What is the stated frequency for testing this control, and who is the executive owner?"

Run a Robot Task Immediately

Tool: create_a_diligent_robot_task_run_now

Diligent ACL Robotics automates data analysis. If an agent needs fresh analytic results before making a decision, it can trigger a robot task to run on-demand. The tool returns the job ID and status, allowing the agent to poll for completion.

"Trigger the 'Weekly Payroll Exception' robot task in Diligent right now. Let me know when the job queues, and we will wait for the analytic results."

Download an Attachment

Tool: get_single_diligent_attachment_download_by_id

Agents often need to read the contents of an uploaded policy document or CSV file. This tool triggers the download flow, handling the 302 redirect to the pre-signed S3 URL. Your agent code must be prepared to handle raw file content rather than a JSON record.

"Download the attachment with ID 109384 from Diligent. Extract the text from the policy document and check if it mentions 'Zero Trust Architecture'."

For the complete list of Diligent tools and their corresponding JSON schemas, visit the Diligent integration page.

Workflows in Action

By chaining these tools, you can build agents that handle complex GRC logic autonomously. Here are two real-world workflows.

Workflow 1: Continuous Control Monitoring

An IT Compliance Administrator uses an agent to continuously monitor infrastructure configurations and log evidence against Diligent controls.

"Check the status of the 'AWS IAM MFA' control. If the latest robot analytic shows any users without MFA, create a project issue for them and upload the raw log as a new evidence record."

Execution Steps:

  1. The agent calls get_single_diligent_org_control_by_id to verify the control exists and belongs to the correct active project.
  2. The agent calls list_all_diligent_table_records targeting the Results table that the Diligent robot populates with MFA exceptions.
  3. Finding 3 users without MFA, the agent calls create_a_diligent_project_issue under the active project, noting the violation.
  4. The agent formats the log data and calls create_a_diligent_org_evidence to permanently seal the finding in the Evidence Hub.

Workflow 2: Automated Audit Remediation

An Internal Auditor uses an agent to chase down missing documentation and verify robot task execution.

"Run the 'Stale User Deactivation' robot task in Diligent now. If the job completes successfully, download the output CSV attachment and summarize the terminated users."

Execution Steps:

  1. The agent calls create_a_diligent_robot_task_run_now passing the specific task ID.
  2. The agent observes the queued_at status and enters a wait loop, polling until the job shows completed_at.
  3. Once complete, the agent extracts the generated attachment ID and calls get_single_diligent_attachment_download_by_id.
  4. The agent intercepts the 302 redirect, downloads the file content before the 2-minute expiration, and reads the CSV to summarize the findings to the auditor.

Building Multi-Step Workflows

Integrating Diligent tools into your agent framework requires fetching the schemas from Truto and binding them to the model. Because Truto standardizes rate limits into IETF headers but does not absorb them, your agent loop must implement backoff logic natively.

Here is how you architect this using TypeScript, LangChain's .bindTools(), and the Truto /tools endpoint. This exact pattern applies equally to Vercel AI SDK or CrewAI.

import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "truto-langchainjs-toolset";
import { HumanMessage } from "@langchain/core/messages";
 
// 1. Initialize the LLM
const model = new ChatOpenAI({
  modelName: "gpt-4o",
  temperature: 0,
});
 
// 2. Fetch Diligent tools from Truto for this specific integrated account
const trutoManager = new TrutoToolManager({
  apiKey: process.env.TRUTO_API_KEY,
  integratedAccountId: "diligent-account-id-123",
});
 
const diligentTools = await trutoManager.getTools();
 
// 3. Bind the Truto tools directly to the LLM
const agentWithTools = model.bindTools(diligentTools);
 
// 4. Implement a resilient execution loop to handle 429 Rate Limits
async function executeAgentWorkflow(prompt: string) {
  let messages = [new HumanMessage(prompt)];
  let isComplete = false;
 
  while (!isComplete) {
    try {
      const response = await agentWithTools.invoke(messages);
      messages.push(response);
 
      if (response.tool_calls && response.tool_calls.length > 0) {
        // The LLM decided to call a Diligent tool
        for (const toolCall of response.tool_calls) {
          console.log(`Executing: ${toolCall.name}`);
          
          // Execute the tool via the Truto manager
          const toolResult = await trutoManager.executeTool(
            toolCall.name,
            toolCall.args
          );
          
          messages.push({
            role: "tool",
            tool_call_id: toolCall.id,
            content: JSON.stringify(toolResult),
          });
        }
      } else {
        // No more tools to call, workflow complete
        isComplete = true;
        return response.content;
      }
    } catch (error) {
      // 5. Handle HTTP 429 Too Many Requests explicitly
      if (error.response && error.response.status === 429) {
        const resetInSeconds = error.response.headers['ratelimit-reset'] || 60;
        console.warn(`Rate limit hit. Agent sleeping for ${resetInSeconds} seconds...`);
        
        // Sleep the agent runtime, then loop will retry the invoke
        await new Promise(resolve => setTimeout(resolve, resetInSeconds * 1000));
      } else {
        throw error;
      }
    }
  }
}
 
// Trigger the agent
const result = await executeAgentWorkflow(
  "Find control ID 8847. If the test frequency is weekly, trigger the matching robot task now."
);
console.log(result);

The architectural flow for this multi-step execution looks like this:

sequenceDiagram
    participant LLM as Agent LLM
    participant Runtime as Agent Runtime
    participant Truto as Truto Proxy API
    participant Diligent as Diligent HighBond

    Runtime->>Truto: GET /integrated-account/{id}/tools
    Truto-->>Runtime: Return JSON schemas for Diligent
    Runtime->>LLM: Bind schemas via .bindTools()
    
    LLM->>Runtime: Emits tool_call (get_single_diligent_org_control_by_id)
    Runtime->>Truto: GET /proxy/controls/8847
    Truto->>Diligent: GET /v1/orgs/{org_id}/controls/8847
    Diligent-->>Truto: Return JSON:API Control Object
    Truto-->>Runtime: Flattened Control JSON
    Runtime->>LLM: Provide tool result
    
    LLM->>Runtime: Emits tool_call (create_a_diligent_robot_task_run_now)
    Runtime->>Truto: POST /proxy/robot_tasks/run
    Truto->>Diligent: POST /v1/orgs/{org_id}/robot_tasks/run
    Diligent-->>Truto: HTTP 429 Too Many Requests
    Truto-->>Runtime: 429 (ratelimit-reset: 60)
    
    Note over Runtime: Runtime intercepts 429<br>Initiates 60s backoff sleep
    Runtime->>Truto: POST /proxy/robot_tasks/run (Retry)
    Truto->>Diligent: POST /v1/orgs/{org_id}/robot_tasks/run
    Diligent-->>Truto: 200 OK (Job ID: 123)
    Truto-->>Runtime: Job ID: 123
    Runtime->>LLM: Provide tool result

Building an agent that successfully manages state, reasoning, and context window limits is a hard engineering problem. You should not compound that difficulty by forcing your developers to manually write JSON:API transformation layers, track ephemeral S3 redirect lifecycles, and maintain API specifications for GRC platforms.

By leveraging Truto's /tools endpoint, you provide your agents with clean, deterministic functions, allowing your team to focus on workflow orchestration instead of integration maintenance.

Two ways to put Diligent to work

Truto

For product teams

Give your agent Diligent tools

Your customers connect their own Diligent accounts. Your product gets one API and MCP tools for Diligent, through Truto.

FAQ

Does Truto automatically handle Diligent's API rate limits?
No. Truto does not retry, throttle, or apply backoff on rate limit errors. When Diligent returns an HTTP 429, Truto passes that error to the caller and normalizes the rate limit information into standard headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF spec. Your agent framework is responsible for handling the backoff.
How does Truto handle Diligent's JSON:API spec requirements?
Truto abstracts the strict JSON:API wrapping payload requirements. The proxy tools exposed to the LLM via the /tools endpoint accept flat, intuitive JSON arguments, and Truto formats the outgoing payload to match Diligent's strict data, type, and attributes hierarchy before transmission.
Can I use Truto's Diligent tools with LangGraph or CrewAI?
Yes. Truto's tools are framework-agnostic. The /tools endpoint returns standard JSON schemas that can be bound directly to any LLM using framework-native methods like .bindTools() in LangChain, or registered as custom actions in CrewAI and the Vercel AI SDK.
Diligent DiligentAI agent tools Get a sandbox

More from our Blog