Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.stackone.com/llms.txt

Use this file to discover all available pages before exploring further.

New to tool defense? Start with Tool Defense 101 for an overview of why, how, and when to use it.

Configuration Modes

The defender option on StackOneToolSet accepts four shapes. Each maps to a distinct behavior for the RPC calls that toolset makes.

Default (defer to project dashboard)

Omitting defender leaves the project’s dashboard setting in charge. The SDK adds no defender_config field to the RPC payload, so whatever you configured in the StackOne dashboard takes effect.
import { StackOneToolSet } from '@stackone/ai';

const toolset = new StackOneToolSet();
// defenderMode === 'project'
The explicit form is equivalent:
const toolset = new StackOneToolSet({
  defender: { useProjectSettings: true },
});
// defenderMode === 'project'
Use the explicit form when you want the call site to document that deferring is intentional rather than an oversight. useProjectSettings: true cannot be combined with other defender fields; passing both throws a ToolSetConfigError at construction time.

Explicit SDK-level config

Pass an object to override your project’s dashboard setting with explicit per-toolset values. Missing fields fall back to DEFAULT_DEFENDER_CONFIG, which has all scanning on and blocking off.
import { DEFAULT_DEFENDER_CONFIG, StackOneToolSet } from '@stackone/ai';

// Opt in with safe defaults, but block on HIGH or CRITICAL risk
const toolset = new StackOneToolSet({
  defender: { ...DEFAULT_DEFENDER_CONFIG, blockHighRisk: true },
});
// defenderMode === 'explicit'

// Fully specified
const fullyExplicit = new StackOneToolSet({
  defender: {
    enabled: true,
    blockHighRisk: false,
    useTier1Classification: true,
    useTier2Classification: false, // skip ML scoring on this toolset
  },
});
FieldTypeFallbackDescription
enabledbooleantrueMaster switch for this toolset
blockHighRiskbooleanfalseThrow on HIGH or CRITICAL risk instead of annotating
useTier1ClassificationbooleantruePattern-based detection (regex, role markers)
useTier2ClassificationbooleantrueML-based detection (local ONNX model)

Force disabled

Pass null to forcibly disable defender for this toolset. The SDK sends defender_config with every field set to false, overriding whatever the dashboard says.
const toolset = new StackOneToolSet({ defender: null });
// defenderMode === 'disabled'
Use this for trusted internal flows where you’ve already vetted the data source and want to avoid scanning latency.

Inspecting the Resolved Mode

Every toolset exposes a defenderMode getter that returns one of three strings:
const toolset = new StackOneToolSet({
  defender: { ...DEFAULT_DEFENDER_CONFIG, blockHighRisk: true },
});

toolset.defenderMode; // 'project' | 'disabled' | 'explicit'
ValueMeaning
'project'SDK adds no defender_config; the project dashboard setting controls behavior
'disabled'SDK forces defender off, overriding the dashboard
'explicit'SDK sends an explicit defender_config, overriding the dashboard
The getter is useful in tests, custom observability, and conditional logging without poking at private internals.

Override warning

When the SDK overrides the project dashboard (modes disabled or explicit), it emits a console.warn once per process per distinct override shape. Repeat constructions with the same configuration stay quiet, so wrapping the SDK in a per-request factory will not flood your logs.
Defender forcibly disabled via SDK config; project dashboard setting will be ignored.
Defender configured via SDK (enabled=true, blockHighRisk=true, useTier1Classification=true, useTier2Classification=true); project dashboard setting will be ignored.

Reading the Response

When defender runs (modes explicit or, on the backend side, when project mode resolves to enabled), the RPC response includes a defenderMetadata sibling next to data:
const tools = await toolset.fetchTools();
const tool = tools.toArray().find((t) => t.name === 'gmail_list_messages');

const result = await tool.execute({ body: { max_results: 5 } });

const metadata = (result as { defenderMetadata?: DefenderMetadata }).defenderMetadata;

interface DefenderMetadata {
  applied: boolean;
  result: {
    allowed: boolean;
    riskLevel: 'low' | 'medium' | 'high' | 'critical';
    fieldsSanitized: string[];
    patternsByField: Record<string, string[]>;
    detections: unknown[];
    tier2SkipReason?: string;
    latencyMs: number;
  };
}
FieldDescription
appliedfalse when defender was configured but skipped (e.g. all classification disabled), true when it ran
result.allowedfalse only when blockHighRisk was on and content classified as HIGH or CRITICAL caused the call to be blocked
result.riskLevelFinal risk classification for the response
result.fieldsSanitizedJSON paths to fields whose content was annotated or stripped
result.patternsByFieldPer-field map of detection pattern IDs that fired
result.detectionsRaw detection records from Tier 1 / Tier 2
result.tier2SkipReasonPresent only when Tier 2 was skipped (e.g. "No strings extracted from tool result")
result.latencyMsTime defender spent classifying this response
A typed accessor is not yet exposed on the SDK response surface, so casting through the response object is the current ergonomic.

Runtime Validation

The constructor validates useProjectSettings: true is not combined with other defender fields. JavaScript callers that bypass TypeScript get a runtime error:
new StackOneToolSet({
  defender: { useProjectSettings: true, enabled: true },
});
// throws ToolSetConfigError:
// "Cannot combine useProjectSettings: true with explicit defender options. Use one or the other."
TypeScript catches this at compile time via the discriminated union; the runtime guard exists for JS consumers and runtime-built configs.

Next Steps