Skip to content

feat: add composable guardrails for TACTool (rate limiting) - #86

Open
yatharth-1504 wants to merge 2 commits into
twilio:mainfrom
yatharth-1504:feat/tool-guardrails
Open

feat: add composable guardrails for TACTool (rate limiting)#86
yatharth-1504 wants to merge 2 commits into
twilio:mainfrom
yatharth-1504:feat/tool-guardrails

Conversation

@yatharth-1504

Copy link
Copy Markdown

Summary

Adds a composable guardrail system to packages/tools that lets developers wrap any TACTool with rate limiting before the tool's implementation runs. This is the foundation for a broader guardrail system (content filtering + withGuardrails() wrapper coming in a follow-up PR).

New files:

  • packages/tools/src/lib/errors.tsGuardrailError with a type field ('rate_limit' | 'content_filter')
  • packages/tools/src/lib/rate-limiter.tsSlidingWindowRateLimiter (sliding window, in-memory, per-key)

Modified:

  • packages/tools/src/index.ts — exports GuardrailError publicly

Usage preview (once withGuardrails() lands in the follow-up):

import { createSendMessageTool, withGuardrails } from 'twilio-agent-connect';

const safeSendMessage = withGuardrails(
  createSendMessageTool(channel, conversationId),
  {
    rateLimit: {
      maxCalls: 5,
      windowMs: 60_000,
      keyFn: () => conversationId, // per-conversation limit
    },
  }
);

When the limit is exceeded, GuardrailError is thrown — LLM SDKs surface this as a tool-result message so the model can respond gracefully ("I've sent too many messages, please wait a moment").

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring

Checklist

  • Tests added/updated
  • Documentation updated
  • Tested E2E

SDK Parity

  • Change is TypeScript-specific (no Python update needed)

Copilot AI lite review requested due to automatic review settings August 27, 2026 11:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an initial “guardrails” foundation to the packages/tools package by introducing a typed GuardrailError and an in-memory sliding-window rate limiter intended to run before a TACTool implementation executes.

Changes:

  • Introduces GuardrailError with a discriminating type (rate_limit / content_filter) for guardrail failures.
  • Adds SlidingWindowRateLimiter (per-key, in-memory) to enforce call limits within a time window.
  • Adds Vitest coverage for the new error type and rate-limiter behavior, and exports GuardrailError from the tools package entrypoint.

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
tests/rate-limiter.test.ts Adds unit tests for sliding-window rate limiting behavior (limits, reset, per-key isolation).
tests/guardrails.test.ts Adds unit tests for GuardrailError shape (name, message, type).
packages/tools/src/lib/rate-limiter.ts Introduces SlidingWindowRateLimiter implementation for rate limiting guardrails.
packages/tools/src/lib/errors.ts Adds GuardrailError used to signal guardrail blocks.
packages/tools/src/index.ts Exports GuardrailError from the tools package public API.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +9 to +13
export class SlidingWindowRateLimiter<TParams> {
private readonly timestamps: Map<string, number[]> = new Map();

constructor(private readonly config: RateLimitConfig<TParams>) {}

}

export class SlidingWindowRateLimiter<TParams> {
private readonly timestamps: Map<string, number[]> = new Map();
@@ -0,0 +1,30 @@
import { GuardrailError } from './errors.js';
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.

2 participants