Skip to content

feat(ENG-12325): add defender config option to StackOneToolSet#328

Open
hiskudin wants to merge 11 commits intomainfrom
feat/defender-config
Open

feat(ENG-12325): add defender config option to StackOneToolSet#328
hiskudin wants to merge 11 commits intomainfrom
feat/defender-config

Conversation

@hiskudin
Copy link
Copy Markdown

@hiskudin hiskudin commented Mar 19, 2026

Summary

Adds a defender option to StackOneToolSet for explicit control over prompt injection detection behavior on every tool call.

  • Fixes a silent bug where defender_enabled was dropped by Zod validation before reaching the RPC call
  • Extends the RPC schema to forward block_high_risk, use_tier1_classification, use_tier2_classification per-request (backend changes tracked separately)
  • Field names match canonical DefenderSettings from @stackone/core

Behavior

Usage Effect
defender omitted SDK defaults: enabled, tier 1 + tier 2 on, never blocks
defender: null Explicitly disabled — no scanning
defender: { useProjectSettings: true } Defers to project dashboard settings
defender: { enabled, blockHighRisk, ... } Explicit SDK-level config, overrides project settings

Default behavior (omit defender)

const toolset = new StackOneToolSet({ apiKey: '...' });
// → defender on, not blocking, tier 1 + tier 2 enabled

Disable entirely

const toolset = new StackOneToolSet({ apiKey: '...', defender: null });

Defer to project dashboard settings

const toolset = new StackOneToolSet({
  apiKey: '...',
  defender: { useProjectSettings: true },
});
// Combining with other fields throws ToolSetConfigError at construction

Explicit SDK-level config

const toolset = new StackOneToolSet({
  apiKey: '...',
  defender: {
    enabled: true,
    blockHighRisk: true,          // block HIGH/CRITICAL instead of just annotating
    useTier1Classification: true, // pattern-based detection
    useTier2Classification: true, // ML-based detection (requires onnxruntime-node)
  },
});

Parameters

Param Type Default Description
enabled boolean true Master switch. false disables all scanning.
blockHighRisk boolean false Block tool calls with HIGH/CRITICAL risk. When false, risky content is annotated but still returned.
useTier1Classification boolean true Fast pattern-based detection (regex rules for role markers, instruction overrides, etc.).
useTier2Classification boolean true ML-based detection (ONNX model). Catches novel attacks patterns miss. Requires onnxruntime-node at runtime.

Changes

  • src/types.tsDefenderConfig is now a discriminated union; adds DEFAULT_DEFENDER_CONFIG constant
  • src/schema.ts — adds block_high_risk, use_tier1_classification, use_tier2_classification to rpcActionRequestSchema
  • src/rpc-client.ts — forwards all new defender fields in request body
  • src/toolsets.ts — resolves defender config at construction, validates useProjectSettings exclusivity, applies three-way logic in createRpcBackedTool
  • src/index.ts — exports DEFAULT_DEFENDER_CONFIG

Notes

blockHighRisk, useTier1Classification, and useTier2Classification are forwarded in the RPC payload but require a backend change to ActionsRpcRequestDto to take effect. That work is tracked separately.

🤖 Generated with Claude Code

Adds a `defender` option to the `StackOneToolSet` constructor that allows
controlling prompt injection detection behavior at the toolset level.

- Add `DefenderConfig` interface with `enabled`, `blockHighRisk`,
  `useTier1Classification`, and `useTier2Classification` fields —
  matching canonical `DefenderSettings` names from `@stackone/core`
- Add `defender_enabled` to `rpcActionRequestSchema` so it is no longer
  silently dropped by Zod validation
- Forward `defender_enabled` through `RpcClient.rpcAction()` request body
- Thread `defenderConfig.enabled` → `defender_enabled` in every RPC call
  made by `createRpcBackedTool`
- Export `DefenderConfig` from the package index

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@hiskudin hiskudin requested a review from a team as a code owner March 19, 2026 11:16
Copilot AI review requested due to automatic review settings March 19, 2026 11:16
@hiskudin hiskudin changed the title feat: add defender config option to StackOneToolSet feat (ENG-12325): add defender config option to StackOneToolSet Mar 19, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 19, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@stackone/ai@328

commit: d35d4a9

@hiskudin hiskudin changed the title feat (ENG-12325): add defender config option to StackOneToolSet feat(ENG-12325): add defender config option to StackOneToolSet Mar 19, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/toolsets.ts">

<violation number="1" location="src/toolsets.ts:979">
P2: `dryRun` request serialization is now inconsistent with real RPC calls because `defender_enabled` is forwarded only in the live path.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a toolset-level defender configuration to StackOneToolSet so consumers can control prompt-injection detection behavior (currently via per-request defender_enabled), and fixes a silent validation issue where defender_enabled was previously dropped before reaching the RPC call.

Changes:

  • Introduces DefenderConfig and exports it from the public entrypoint.
  • Extends the RPC request Zod schema to accept defender_enabled and forwards it in the RPC client request payload.
  • Adds defender to StackOneToolSet config and threads defender.enabled → defender_enabled into RPC calls.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/types.ts Adds DefenderConfig interface describing toolset-level defender settings.
src/toolsets.ts Accepts/stores defender config on the toolset and injects defender_enabled into RPC calls.
src/schema.ts Updates rpcActionRequestSchema to validate defender_enabled so it isn’t stripped.
src/rpc-client.ts Includes validated defender_enabled in the JSON payload sent to /actions/rpc.
src/index.ts Re-exports DefenderConfig for SDK consumers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

hiskudin and others added 2 commits March 19, 2026 11:49
- Include defender_enabled in dryRun payload to match live RPC path
- Clarify JSDoc that only enabled is currently applied per-request
- Add tests for defender_enabled forwarding in rpc-client and toolsets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nd SDK defaults

- Replace `DefenderConfig` interface with a discriminated union:
  - `{ useProjectSettings: true }` → defer to project dashboard settings
  - `{ enabled?, blockHighRisk?, useTier1Classification?, useTier2Classification? }` → SDK-level config
- Add `DEFAULT_DEFENDER_CONFIG`: enabled=true, blockHighRisk=false, tier1+tier2 on
- Omitting `defender` now applies SDK defaults (enabled, not blocking) rather than
  deferring to project settings — this makes SDK behavior explicit and predictable
- `defender: null` explicitly disables defender for all tool calls
- Constructor throws `ToolSetConfigError` if `useProjectSettings: true` is combined
  with other fields
- Extend `rpcActionRequestSchema` and `RpcClient` to forward `block_high_risk`,
  `use_tier1_classification`, `use_tier2_classification` per-request (backend support
  for these is tracked separately)
- Export `DEFAULT_DEFENDER_CONFIG` from package index

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/toolsets.ts">

<violation number="1" location="src/toolsets.ts:995">
P2: `dryRun` no longer matches the real RPC payload for defender settings.</violation>
</file>

<file name="src/rpc-client.ts">

<violation number="1" location="src/rpc-client.ts:56">
P1: Don't forward the unsupported defender tuning fields yet. Only `defender_enabled` is wired through the RPC API today, so sending the other three keys can break RPC calls until the backend DTO is updated.</violation>
</file>

<file name="src/types.ts">

<violation number="1" location="src/types.ts:271">
P1: Defaulting omitted `defender` to an explicit config overrides existing project settings for every RPC call.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

* Defender is enabled but outputs are never blocked — scans run and results are annotated only.
*/
export const DEFAULT_DEFENDER_CONFIG = {
enabled: true,
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Defaulting omitted defender to an explicit config overrides existing project settings for every RPC call.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/types.ts, line 271:

<comment>Defaulting omitted `defender` to an explicit config overrides existing project settings for every RPC call.</comment>

<file context>
@@ -239,28 +239,37 @@ export interface ClaudeAgentSdkOptions {
+ * Defender is enabled but outputs are never blocked — scans run and results are annotated only.
+ */
+export const DEFAULT_DEFENDER_CONFIG = {
+	enabled: true,
+	blockHighRisk: false,
+	useTier1Classification: true,
</file context>
Fix with Cubic

hiskudin and others added 2 commits March 19, 2026 16:48
…ults

- Move defenderFields computation before dryRun block so both paths share the same logic
- Fix TypeScript error: defenderConfig.enabled was accessed on the useProjectSettings union variant
- Update tests to reflect new behavior: omitting defender now applies SDK defaults instead of undefined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ternary expression used mixed tabs+spaces alignment which oxfmt rejects.
Replaced with an if-else block that uses consistent tab indentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@hiskudin hiskudin marked this pull request as draft March 19, 2026 17:22
@hiskudin hiskudin marked this pull request as draft March 19, 2026 17:22
hiskudin and others added 3 commits March 20, 2026 10:47
SDK defaults will override project-level defender settings when no
explicit defender config is passed. A console.warn nudges users to
either pass an explicit config or opt into useProjectSettings: true.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@hiskudin hiskudin marked this pull request as ready for review March 20, 2026 11:12
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 8 files

hiskudin and others added 3 commits March 23, 2026 12:03
Replace flat defender_enabled/block_high_risk/use_tier*_classification fields
with a nested defender_config object. Keep defender_enabled for backward compat.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
knip flagged defenderConfigRequestSchema as an unused export since it
is only used internally within schema.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@glebedel
Copy link
Copy Markdown
Contributor

@hiskudin you now have merge conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants