Skip to content

9. Tool Controls and Logging

Hemant Kohli edited this page Sep 23, 2026 · 3 revisions

Tool controls and structured logging

Tool policies enforce pre-execution decisions and emit a shared, versioned decision contract.

import { defineGuardConfig } from "@intflows/genkit-guard";

const config = defineGuardConfig({
  // Keep your intent and PII settings here too.
  policyVersion: "support-v1",
  tools: {
    defaultAction: "block",
    rules: {
      lookupTicket: "allow",
      summarizeTicket: "redact",
      deleteTicket: "approval-required"
    },
    approve: async ({ toolName, input, context }) => {
      // Verify a stored approval against the exact tool, arguments and authenticated user.
      // Wire your trusted approval service here. This example denies every call.
      return false;
    }
  },
  logging: {
    enabled: true,
    level: "info",
    onDecision: async decision => {
      // Optional audit sink. The event contains no prompt, arguments or PII values.
      console.log(JSON.stringify(decision));
    }
  }
});

Pass this config to initGuard and guard as described in 8.-Shared-Model-Configuration. guardMiddleware also accepts these options. When tools is configured, guard() returns a native Genkit middleware reference so tool hooks execute. Without tools, its legacy callable return is retained. Use guardMiddleware(config) for native tool scanning even without explicit policies. Do not directly invoke the return value of guard({ tools: ... }); use it in Genkit use or call its model/tool hooks in tests.

Action Before tool execution
allow Restore vault tokens, scan input, then execute
block Throw GuardToolError without executing
redact Restore and scan input, replace detected PII in nested string values with [REDACTED], then execute
approval-required Require a trusted callback to return literal true for this call; otherwise stop

Rules use exact tool names and take precedence over defaultAction. The default is allow for backward compatibility. Use defaultAction block for an allowlist. Redaction preserves object structure but may fail a tool's input schema, for example an email-validated field; adjust the tool contract or use block. Detection quality still depends on regex and the chosen model; redaction does not guarantee all sensitive content is found.

The approval callback receives a copy of restored arguments and the Genkit application context. It is not a UI or durable approval queue. Missing approval yields TOOL_APPROVAL_REQUIRED; false yields TOOL_APPROVAL_DENIED; callback failure yields TOOL_POLICY_ERROR. GuardToolError includes the content-free decision. The application must obtain approval and explicitly retry; flags in model arguments do not authorize execution. Avoid blanket approval callbacks. A blocked call prevents that tool's execution, but does not roll back other parallel tool calls.

GuardDecision schema version 1

Every prompt injection, intent, PII, and tool policy decision includes schemaVersion, decisionId, timestamp, guard, policyVersion, action, reasonCode and latencyMs. Intent decisions also include confidence (the similarity score, not a calibrated probability). Latency measures that check, not downstream tool execution. No prompt, tool arguments, tool output, classifier spans or PII values are included. Policy versions are application-supplied identifiers; do not put sensitive data in them.

Reason codes: INJECTION_PATTERN, INJECTION_CLEAR, INTENT_ALLOWED, INTENT_REJECTED, PII_DETECTED, PII_CLEAR, TOOL_ALLOWED, TOOL_BLOCKED, TOOL_REDACTED, TOOL_APPROVAL_REQUIRED, TOOL_APPROVED, TOOL_APPROVAL_DENIED, TOOL_POLICY_ERROR, MODEL_FALLBACK_USED, MODEL_UNAVAILABLE.

Console JSON emits decisions under attributes.decision with event.name guard.decision. Existing operational events and console level filtering remain. logging.onDecision is independent of console enabled/level, is awaited, and stops execution if it rejects. This allows an application to require audit delivery; it adds sink latency. Persistent decision storage is available; see 10.-Decision-Storage-and-Model-Fallback. Automatic transport retries are not provided.

Guard-generated model metadata omits prompt copies and classifier output. Application-supplied metadata and request objects are still outside this safe audit contract. Do not export entire request objects or metadata as decision logs.

The runnable example/src/tool-controls.ts demonstrates Genkit integration. Build the parent repository, install example dependencies and set GEMINI_API_KEY and GEMINI_MODEL, then run it with tsx.

Audit store/callback failures stop execution with GuardOperationalError (AUDIT_UNAVAILABLE), without exposing the original message or cause. Approval-callback failures instead produce GuardToolError with TOOL_POLICY_ERROR. See 12.-Security-and-Operational-Errors.

Clone this wiki locally