@lleverage-ai/agent-sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2321 -0
- package/dist/agent.d.ts +52 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +2122 -0
- package/dist/agent.js.map +1 -0
- package/dist/backend.d.ts +378 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +71 -0
- package/dist/backend.js.map +1 -0
- package/dist/backends/composite.d.ts +258 -0
- package/dist/backends/composite.d.ts.map +1 -0
- package/dist/backends/composite.js +437 -0
- package/dist/backends/composite.js.map +1 -0
- package/dist/backends/filesystem.d.ts +268 -0
- package/dist/backends/filesystem.d.ts.map +1 -0
- package/dist/backends/filesystem.js +623 -0
- package/dist/backends/filesystem.js.map +1 -0
- package/dist/backends/index.d.ts +14 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +14 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/persistent.d.ts +312 -0
- package/dist/backends/persistent.d.ts.map +1 -0
- package/dist/backends/persistent.js +519 -0
- package/dist/backends/persistent.js.map +1 -0
- package/dist/backends/sandbox.d.ts +315 -0
- package/dist/backends/sandbox.d.ts.map +1 -0
- package/dist/backends/sandbox.js +490 -0
- package/dist/backends/sandbox.js.map +1 -0
- package/dist/backends/state.d.ts +225 -0
- package/dist/backends/state.d.ts.map +1 -0
- package/dist/backends/state.js +396 -0
- package/dist/backends/state.js.map +1 -0
- package/dist/checkpointer/file-saver.d.ts +182 -0
- package/dist/checkpointer/file-saver.d.ts.map +1 -0
- package/dist/checkpointer/file-saver.js +298 -0
- package/dist/checkpointer/file-saver.js.map +1 -0
- package/dist/checkpointer/index.d.ts +40 -0
- package/dist/checkpointer/index.d.ts.map +1 -0
- package/dist/checkpointer/index.js +40 -0
- package/dist/checkpointer/index.js.map +1 -0
- package/dist/checkpointer/kv-saver.d.ts +142 -0
- package/dist/checkpointer/kv-saver.d.ts.map +1 -0
- package/dist/checkpointer/kv-saver.js +176 -0
- package/dist/checkpointer/kv-saver.js.map +1 -0
- package/dist/checkpointer/memory-saver.d.ts +158 -0
- package/dist/checkpointer/memory-saver.d.ts.map +1 -0
- package/dist/checkpointer/memory-saver.js +222 -0
- package/dist/checkpointer/memory-saver.js.map +1 -0
- package/dist/checkpointer/types.d.ts +353 -0
- package/dist/checkpointer/types.d.ts.map +1 -0
- package/dist/checkpointer/types.js +159 -0
- package/dist/checkpointer/types.js.map +1 -0
- package/dist/context-manager.d.ts +627 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +1039 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/context.d.ts +57 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +76 -0
- package/dist/context.js.map +1 -0
- package/dist/errors/index.d.ts +611 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +1023 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/generation-helpers.d.ts +126 -0
- package/dist/generation-helpers.d.ts.map +1 -0
- package/dist/generation-helpers.js +181 -0
- package/dist/generation-helpers.js.map +1 -0
- package/dist/hooks/audit.d.ts +210 -0
- package/dist/hooks/audit.d.ts.map +1 -0
- package/dist/hooks/audit.js +305 -0
- package/dist/hooks/audit.js.map +1 -0
- package/dist/hooks/cache.d.ts +180 -0
- package/dist/hooks/cache.d.ts.map +1 -0
- package/dist/hooks/cache.js +273 -0
- package/dist/hooks/cache.js.map +1 -0
- package/dist/hooks/guardrails.d.ts +145 -0
- package/dist/hooks/guardrails.d.ts.map +1 -0
- package/dist/hooks/guardrails.js +326 -0
- package/dist/hooks/guardrails.js.map +1 -0
- package/dist/hooks/index.d.ts +18 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +32 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/logging.d.ts +193 -0
- package/dist/hooks/logging.d.ts.map +1 -0
- package/dist/hooks/logging.js +345 -0
- package/dist/hooks/logging.js.map +1 -0
- package/dist/hooks/parallel-guardrails.d.ts +268 -0
- package/dist/hooks/parallel-guardrails.d.ts.map +1 -0
- package/dist/hooks/parallel-guardrails.js +416 -0
- package/dist/hooks/parallel-guardrails.js.map +1 -0
- package/dist/hooks/rate-limit.d.ts +305 -0
- package/dist/hooks/rate-limit.d.ts.map +1 -0
- package/dist/hooks/rate-limit.js +372 -0
- package/dist/hooks/rate-limit.js.map +1 -0
- package/dist/hooks/retry.d.ts +144 -0
- package/dist/hooks/retry.d.ts.map +1 -0
- package/dist/hooks/retry.js +210 -0
- package/dist/hooks/retry.js.map +1 -0
- package/dist/hooks/secrets.d.ts +174 -0
- package/dist/hooks/secrets.d.ts.map +1 -0
- package/dist/hooks/secrets.js +306 -0
- package/dist/hooks/secrets.js.map +1 -0
- package/dist/hooks.d.ts +229 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +352 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/env.d.ts +25 -0
- package/dist/mcp/env.d.ts.map +1 -0
- package/dist/mcp/env.js +18 -0
- package/dist/mcp/env.js.map +1 -0
- package/dist/mcp/index.d.ts +16 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +17 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +184 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +446 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/mcp/types.d.ts +58 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +7 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/mcp/validation.d.ts +119 -0
- package/dist/mcp/validation.d.ts.map +1 -0
- package/dist/mcp/validation.js +407 -0
- package/dist/mcp/validation.js.map +1 -0
- package/dist/mcp/virtual-server.d.ts +78 -0
- package/dist/mcp/virtual-server.d.ts.map +1 -0
- package/dist/mcp/virtual-server.js +137 -0
- package/dist/mcp/virtual-server.js.map +1 -0
- package/dist/memory/filesystem-store.d.ts +217 -0
- package/dist/memory/filesystem-store.d.ts.map +1 -0
- package/dist/memory/filesystem-store.js +343 -0
- package/dist/memory/filesystem-store.js.map +1 -0
- package/dist/memory/index.d.ts +46 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +46 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/loader.d.ts +396 -0
- package/dist/memory/loader.d.ts.map +1 -0
- package/dist/memory/loader.js +419 -0
- package/dist/memory/loader.js.map +1 -0
- package/dist/memory/permissions.d.ts +282 -0
- package/dist/memory/permissions.d.ts.map +1 -0
- package/dist/memory/permissions.js +297 -0
- package/dist/memory/permissions.js.map +1 -0
- package/dist/memory/rules.d.ts +249 -0
- package/dist/memory/rules.d.ts.map +1 -0
- package/dist/memory/rules.js +362 -0
- package/dist/memory/rules.js.map +1 -0
- package/dist/memory/store.d.ts +286 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +263 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/middleware/apply.d.ts +73 -0
- package/dist/middleware/apply.d.ts.map +1 -0
- package/dist/middleware/apply.js +219 -0
- package/dist/middleware/apply.js.map +1 -0
- package/dist/middleware/context.d.ts +33 -0
- package/dist/middleware/context.d.ts.map +1 -0
- package/dist/middleware/context.js +176 -0
- package/dist/middleware/context.js.map +1 -0
- package/dist/middleware/index.d.ts +31 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +32 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/logging.d.ts +137 -0
- package/dist/middleware/logging.d.ts.map +1 -0
- package/dist/middleware/logging.js +374 -0
- package/dist/middleware/logging.js.map +1 -0
- package/dist/middleware/types.d.ts +183 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware/types.js +11 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/observability/events.d.ts +183 -0
- package/dist/observability/events.d.ts.map +1 -0
- package/dist/observability/events.js +305 -0
- package/dist/observability/events.js.map +1 -0
- package/dist/observability/index.d.ts +55 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +87 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/logger.d.ts +318 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +436 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +341 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +490 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/preset.d.ts +161 -0
- package/dist/observability/preset.d.ts.map +1 -0
- package/dist/observability/preset.js +133 -0
- package/dist/observability/preset.js.map +1 -0
- package/dist/observability/streaming.d.ts +113 -0
- package/dist/observability/streaming.d.ts.map +1 -0
- package/dist/observability/streaming.js +114 -0
- package/dist/observability/streaming.js.map +1 -0
- package/dist/observability/tracing.d.ts +378 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +539 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/plugins.d.ts +55 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +63 -0
- package/dist/plugins.js.map +1 -0
- package/dist/presets/index.d.ts +7 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +7 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/production.d.ts +262 -0
- package/dist/presets/production.d.ts.map +1 -0
- package/dist/presets/production.js +295 -0
- package/dist/presets/production.js.map +1 -0
- package/dist/security/index.d.ts +179 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +323 -0
- package/dist/security/index.js.map +1 -0
- package/dist/subagents/advanced.d.ts +413 -0
- package/dist/subagents/advanced.d.ts.map +1 -0
- package/dist/subagents/advanced.js +396 -0
- package/dist/subagents/advanced.js.map +1 -0
- package/dist/subagents/index.d.ts +14 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +15 -0
- package/dist/subagents/index.js.map +1 -0
- package/dist/subagents.d.ts +73 -0
- package/dist/subagents.d.ts.map +1 -0
- package/dist/subagents.js +213 -0
- package/dist/subagents.js.map +1 -0
- package/dist/task-store/file-store.d.ts +76 -0
- package/dist/task-store/file-store.d.ts.map +1 -0
- package/dist/task-store/file-store.js +190 -0
- package/dist/task-store/file-store.js.map +1 -0
- package/dist/task-store/index.d.ts +11 -0
- package/dist/task-store/index.d.ts.map +1 -0
- package/dist/task-store/index.js +10 -0
- package/dist/task-store/index.js.map +1 -0
- package/dist/task-store/kv-store.d.ts +140 -0
- package/dist/task-store/kv-store.d.ts.map +1 -0
- package/dist/task-store/kv-store.js +169 -0
- package/dist/task-store/kv-store.js.map +1 -0
- package/dist/task-store/memory-store.d.ts +66 -0
- package/dist/task-store/memory-store.d.ts.map +1 -0
- package/dist/task-store/memory-store.js +125 -0
- package/dist/task-store/memory-store.js.map +1 -0
- package/dist/task-store/types.d.ts +235 -0
- package/dist/task-store/types.d.ts.map +1 -0
- package/dist/task-store/types.js +110 -0
- package/dist/task-store/types.js.map +1 -0
- package/dist/testing/assertions.d.ts +401 -0
- package/dist/testing/assertions.d.ts.map +1 -0
- package/dist/testing/assertions.js +630 -0
- package/dist/testing/assertions.js.map +1 -0
- package/dist/testing/index.d.ts +343 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +360 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-agent.d.ts +214 -0
- package/dist/testing/mock-agent.d.ts.map +1 -0
- package/dist/testing/mock-agent.js +448 -0
- package/dist/testing/mock-agent.js.map +1 -0
- package/dist/testing/recorder.d.ts +288 -0
- package/dist/testing/recorder.d.ts.map +1 -0
- package/dist/testing/recorder.js +499 -0
- package/dist/testing/recorder.js.map +1 -0
- package/dist/tools/execute.d.ts +104 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +191 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/factory.d.ts +260 -0
- package/dist/tools/factory.d.ts.map +1 -0
- package/dist/tools/factory.js +241 -0
- package/dist/tools/factory.js.map +1 -0
- package/dist/tools/filesystem.d.ts +215 -0
- package/dist/tools/filesystem.d.ts.map +1 -0
- package/dist/tools/filesystem.js +311 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/index.d.ts +33 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +33 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search.d.ts +59 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +94 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/skills.d.ts +354 -0
- package/dist/tools/skills.d.ts.map +1 -0
- package/dist/tools/skills.js +413 -0
- package/dist/tools/skills.js.map +1 -0
- package/dist/tools/task.d.ts +272 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +521 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/tools/todos.d.ts +131 -0
- package/dist/tools/todos.d.ts.map +1 -0
- package/dist/tools/todos.js +120 -0
- package/dist/tools/todos.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +424 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +607 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/user-interaction.d.ts +116 -0
- package/dist/tools/user-interaction.d.ts.map +1 -0
- package/dist/tools/user-interaction.js +147 -0
- package/dist/tools/user-interaction.js.map +1 -0
- package/dist/tools/utils.d.ts +124 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +189 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools.d.ts +74 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +73 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +2421 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +55 -0
- package/dist/types.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate limiting hook utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides rate limiting hooks that track token usage and enforce limits
|
|
5
|
+
* using the unified hook system.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { HookCallback, PostGenerateInput } from "../types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Server-provided rate limit information from response headers.
|
|
12
|
+
*
|
|
13
|
+
* @category Hooks
|
|
14
|
+
*/
|
|
15
|
+
export interface ServerRateLimitInfo {
|
|
16
|
+
/**
|
|
17
|
+
* Maximum requests allowed in the current window.
|
|
18
|
+
* Typically from `x-ratelimit-limit` or `ratelimit-limit` header.
|
|
19
|
+
*/
|
|
20
|
+
limit?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Number of requests remaining in the current window.
|
|
23
|
+
* Typically from `x-ratelimit-remaining` or `ratelimit-remaining` header.
|
|
24
|
+
*/
|
|
25
|
+
remaining?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Timestamp when the rate limit window resets (Unix seconds).
|
|
28
|
+
* Typically from `x-ratelimit-reset` or `ratelimit-reset` header.
|
|
29
|
+
*/
|
|
30
|
+
reset?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Number of seconds until the rate limit window resets.
|
|
33
|
+
* Typically from `retry-after` header when rate limited.
|
|
34
|
+
*/
|
|
35
|
+
retryAfter?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Options for creating rate limit hooks.
|
|
39
|
+
*
|
|
40
|
+
* @category Hooks
|
|
41
|
+
*/
|
|
42
|
+
export interface RateLimitHooksOptions {
|
|
43
|
+
/**
|
|
44
|
+
* Maximum tokens per time window.
|
|
45
|
+
* @defaultValue 100000
|
|
46
|
+
*/
|
|
47
|
+
maxTokensPerWindow?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Time window in milliseconds for token counting.
|
|
50
|
+
* @defaultValue 60000 (1 minute)
|
|
51
|
+
*/
|
|
52
|
+
windowMs?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Message to show when rate limit is exceeded.
|
|
55
|
+
* @defaultValue "Rate limit exceeded. Please try again later."
|
|
56
|
+
*/
|
|
57
|
+
limitMessage?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Custom function to determine if a request should be rate limited.
|
|
60
|
+
* Return true to allow, false to deny.
|
|
61
|
+
* @defaultValue Check token count against limit
|
|
62
|
+
*/
|
|
63
|
+
shouldAllow?: (tokensUsed: number, maxTokens: number) => boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Enable server rate limit integration.
|
|
66
|
+
* When enabled, hooks will attempt to extract rate limit information
|
|
67
|
+
* from model response headers (e.g., x-ratelimit-* headers) and use
|
|
68
|
+
* server-provided limits in addition to client-side tracking.
|
|
69
|
+
*
|
|
70
|
+
* @defaultValue false
|
|
71
|
+
*/
|
|
72
|
+
enableServerLimits?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Custom function to extract server rate limit info from response metadata.
|
|
75
|
+
* Use this if your provider uses non-standard header names or formats.
|
|
76
|
+
*
|
|
77
|
+
* @param result - The generation result which may contain response metadata
|
|
78
|
+
* @returns Server rate limit information, or undefined if not available
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* extractServerLimits: (result) => {
|
|
83
|
+
* const headers = result.rawResponse?.headers;
|
|
84
|
+
* if (!headers) return undefined;
|
|
85
|
+
* return {
|
|
86
|
+
* limit: parseInt(headers['x-custom-limit'] || '0'),
|
|
87
|
+
* remaining: parseInt(headers['x-custom-remaining'] || '0'),
|
|
88
|
+
* reset: parseInt(headers['x-custom-reset'] || '0'),
|
|
89
|
+
* };
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
extractServerLimits?: (result: PostGenerateInput) => ServerRateLimitInfo | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Enable per-tool quota tracking.
|
|
96
|
+
* When enabled, tracks token usage separately for each tool,
|
|
97
|
+
* allowing different tools to have independent rate limits.
|
|
98
|
+
*
|
|
99
|
+
* **Note**: This feature is designed for future tool-based rate limiting hooks
|
|
100
|
+
* (PreToolUse/PostToolUse). The current generation-based hooks (PreGenerate/PostGenerate)
|
|
101
|
+
* track overall token usage, not per-tool usage.
|
|
102
|
+
*
|
|
103
|
+
* @defaultValue false
|
|
104
|
+
* @experimental
|
|
105
|
+
*/
|
|
106
|
+
perToolQuota?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Per-tool token limits when perToolQuota is enabled.
|
|
109
|
+
* Maps tool names to their maximum tokens per window.
|
|
110
|
+
*
|
|
111
|
+
* **Note**: This feature is designed for future tool-based rate limiting hooks.
|
|
112
|
+
* Current generation-based hooks do not use this configuration.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* {
|
|
117
|
+
* 'Write': 10000, // Write tool limited to 10k tokens per window
|
|
118
|
+
* 'Bash': 5000, // Bash tool limited to 5k tokens per window
|
|
119
|
+
* 'Read': 20000, // Read tool limited to 20k tokens per window
|
|
120
|
+
* }
|
|
121
|
+
* ```
|
|
122
|
+
* @experimental
|
|
123
|
+
*/
|
|
124
|
+
toolLimits?: Record<string, number>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Token bucket rate limiter implementation.
|
|
128
|
+
*
|
|
129
|
+
* Tracks token usage in a sliding window with automatic cleanup of old entries.
|
|
130
|
+
* Supports per-tool quota tracking and server-provided rate limit integration.
|
|
131
|
+
*
|
|
132
|
+
* @category Hooks
|
|
133
|
+
*/
|
|
134
|
+
export declare class TokenBucketRateLimiter {
|
|
135
|
+
private usage;
|
|
136
|
+
private maxTokens;
|
|
137
|
+
private windowMs;
|
|
138
|
+
private serverLimitInfo?;
|
|
139
|
+
private perToolQuota;
|
|
140
|
+
private toolLimits;
|
|
141
|
+
constructor(maxTokensPerWindow: number, windowMs: number, perToolQuota?: boolean, toolLimits?: Record<string, number>);
|
|
142
|
+
/**
|
|
143
|
+
* Try to acquire tokens. Returns true if allowed, false if would exceed limit.
|
|
144
|
+
* If tool is provided and per-tool quotas are enabled, checks against tool-specific limit.
|
|
145
|
+
*/
|
|
146
|
+
tryAcquire(tool?: string): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Record token usage for a tool.
|
|
149
|
+
*/
|
|
150
|
+
recordUsage(tokens: number, tool?: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Get current token usage in the window.
|
|
153
|
+
* If tool is provided and per-tool quotas are enabled, returns usage for that tool only.
|
|
154
|
+
*/
|
|
155
|
+
getCurrentUsage(tool?: string): number;
|
|
156
|
+
/**
|
|
157
|
+
* Get remaining tokens in current window.
|
|
158
|
+
* Uses server limits if available, otherwise falls back to client-side tracking.
|
|
159
|
+
*/
|
|
160
|
+
getRemainingTokens(tool?: string): number;
|
|
161
|
+
/**
|
|
162
|
+
* Update with server-provided rate limit information.
|
|
163
|
+
* This information takes precedence over client-side tracking.
|
|
164
|
+
*/
|
|
165
|
+
updateServerLimits(info: ServerRateLimitInfo): void;
|
|
166
|
+
/**
|
|
167
|
+
* Get current server limit information if available.
|
|
168
|
+
*/
|
|
169
|
+
getServerLimits(): ServerRateLimitInfo | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Get the effective limit for a tool (tool-specific or global).
|
|
172
|
+
*/
|
|
173
|
+
private getEffectiveLimit;
|
|
174
|
+
/**
|
|
175
|
+
* Remove entries outside the current window.
|
|
176
|
+
*/
|
|
177
|
+
private cleanup;
|
|
178
|
+
/**
|
|
179
|
+
* Reset all usage data and server limit info.
|
|
180
|
+
*/
|
|
181
|
+
reset(): void;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Default server rate limit extractor.
|
|
185
|
+
*
|
|
186
|
+
* Attempts to extract rate limit information from common response header patterns:
|
|
187
|
+
* - `x-ratelimit-*` (OpenAI, Anthropic, etc.)
|
|
188
|
+
* - `ratelimit-*` (standard format)
|
|
189
|
+
* - `retry-after` (when rate limited)
|
|
190
|
+
*
|
|
191
|
+
* @param result - PostGenerate hook input containing the generation result
|
|
192
|
+
* @returns Server rate limit info if headers are present, undefined otherwise
|
|
193
|
+
*
|
|
194
|
+
* @category Hooks
|
|
195
|
+
*/
|
|
196
|
+
export declare function extractStandardRateLimitHeaders(result: PostGenerateInput): ServerRateLimitInfo | undefined;
|
|
197
|
+
/**
|
|
198
|
+
* Creates rate limiting hooks for PreGenerate and PostGenerate events.
|
|
199
|
+
*
|
|
200
|
+
* The PreGenerate hook checks if the rate limit would be exceeded and denies
|
|
201
|
+
* the request if so. The PostGenerate hook records actual token usage.
|
|
202
|
+
*
|
|
203
|
+
* This replaces rate limiting middleware with hook-based rate limiting that
|
|
204
|
+
* works correctly with the unified hook system.
|
|
205
|
+
*
|
|
206
|
+
* @param options - Configuration options
|
|
207
|
+
* @returns Array of two hooks: [PreGenerate rate check, PostGenerate usage tracking]
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const [rateCheck, usageTracker] = createRateLimitHooks({
|
|
212
|
+
* maxTokensPerWindow: 50000, // 50k tokens
|
|
213
|
+
* windowMs: 60000, // per minute
|
|
214
|
+
* });
|
|
215
|
+
*
|
|
216
|
+
* const agent = createAgent({
|
|
217
|
+
* model,
|
|
218
|
+
* hooks: {
|
|
219
|
+
* PreGenerate: [{ hooks: [rateCheck] }],
|
|
220
|
+
* PostGenerate: [{ hooks: [usageTracker] }],
|
|
221
|
+
* },
|
|
222
|
+
* });
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```typescript
|
|
227
|
+
* // Custom rate limit logic
|
|
228
|
+
* const hooks = createRateLimitHooks({
|
|
229
|
+
* shouldAllow: (tokensUsed, maxTokens) => {
|
|
230
|
+
* // Allow if under 80% of limit
|
|
231
|
+
* return tokensUsed < maxTokens * 0.8;
|
|
232
|
+
* },
|
|
233
|
+
* });
|
|
234
|
+
* ```
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* // With server rate limit integration
|
|
239
|
+
* const hooks = createRateLimitHooks({
|
|
240
|
+
* maxTokensPerWindow: 100000,
|
|
241
|
+
* enableServerLimits: true, // Parse x-ratelimit-* headers
|
|
242
|
+
* });
|
|
243
|
+
* ```
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* // Custom server limit extraction for non-standard headers
|
|
248
|
+
* const hooks = createRateLimitHooks({
|
|
249
|
+
* enableServerLimits: true,
|
|
250
|
+
* extractServerLimits: (result) => {
|
|
251
|
+
* const headers = result.response?.headers;
|
|
252
|
+
* return {
|
|
253
|
+
* remaining: parseInt(headers?.['x-custom-remaining'] || '0'),
|
|
254
|
+
* reset: parseInt(headers?.['x-custom-reset'] || '0'),
|
|
255
|
+
* };
|
|
256
|
+
* },
|
|
257
|
+
* });
|
|
258
|
+
* ```
|
|
259
|
+
*
|
|
260
|
+
* @category Hooks
|
|
261
|
+
*/
|
|
262
|
+
export declare function createRateLimitHooks(options?: RateLimitHooksOptions): [HookCallback, HookCallback];
|
|
263
|
+
/**
|
|
264
|
+
* Creates managed rate limit hooks with programmatic control.
|
|
265
|
+
*
|
|
266
|
+
* Returns hooks along with functions to get current usage, reset limits,
|
|
267
|
+
* and check remaining capacity.
|
|
268
|
+
*
|
|
269
|
+
* @param options - Configuration options
|
|
270
|
+
* @returns Object with hooks and rate limit control functions
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```typescript
|
|
274
|
+
* const { hooks, getCurrentUsage, getRemainingTokens, reset } = createManagedRateLimitHooks({
|
|
275
|
+
* maxTokensPerWindow: 100000,
|
|
276
|
+
* windowMs: 60000,
|
|
277
|
+
* });
|
|
278
|
+
*
|
|
279
|
+
* const agent = createAgent({
|
|
280
|
+
* model,
|
|
281
|
+
* hooks: {
|
|
282
|
+
* PreGenerate: [{ hooks: [hooks[0]] }],
|
|
283
|
+
* PostGenerate: [{ hooks: [hooks[1]] }],
|
|
284
|
+
* },
|
|
285
|
+
* });
|
|
286
|
+
*
|
|
287
|
+
* // Check current usage
|
|
288
|
+
* const used = getCurrentUsage();
|
|
289
|
+
* const remaining = getRemainingTokens();
|
|
290
|
+
* console.log(`Token usage: ${used} / ${maxTokensPerWindow} (${remaining} remaining)`);
|
|
291
|
+
*
|
|
292
|
+
* // Reset limits (e.g., for testing or manual override)
|
|
293
|
+
* reset();
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* @category Hooks
|
|
297
|
+
*/
|
|
298
|
+
export declare function createManagedRateLimitHooks(options?: RateLimitHooksOptions): {
|
|
299
|
+
hooks: [HookCallback, HookCallback];
|
|
300
|
+
getCurrentUsage: () => number;
|
|
301
|
+
getRemainingTokens: () => number;
|
|
302
|
+
getServerLimits: () => ServerRateLimitInfo | undefined;
|
|
303
|
+
reset: () => void;
|
|
304
|
+
};
|
|
305
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/hooks/rate-limit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate limiting hook utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides rate limiting hooks that track token usage and enforce limits
|
|
5
|
+
* using the unified hook system.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Token bucket rate limiter implementation.
|
|
11
|
+
*
|
|
12
|
+
* Tracks token usage in a sliding window with automatic cleanup of old entries.
|
|
13
|
+
* Supports per-tool quota tracking and server-provided rate limit integration.
|
|
14
|
+
*
|
|
15
|
+
* @category Hooks
|
|
16
|
+
*/
|
|
17
|
+
export class TokenBucketRateLimiter {
|
|
18
|
+
usage = [];
|
|
19
|
+
maxTokens;
|
|
20
|
+
windowMs;
|
|
21
|
+
serverLimitInfo;
|
|
22
|
+
perToolQuota;
|
|
23
|
+
toolLimits;
|
|
24
|
+
constructor(maxTokensPerWindow, windowMs, perToolQuota = false, toolLimits = {}) {
|
|
25
|
+
this.maxTokens = maxTokensPerWindow;
|
|
26
|
+
this.windowMs = windowMs;
|
|
27
|
+
this.perToolQuota = perToolQuota;
|
|
28
|
+
this.toolLimits = toolLimits;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Try to acquire tokens. Returns true if allowed, false if would exceed limit.
|
|
32
|
+
* If tool is provided and per-tool quotas are enabled, checks against tool-specific limit.
|
|
33
|
+
*/
|
|
34
|
+
tryAcquire(tool) {
|
|
35
|
+
this.cleanup();
|
|
36
|
+
// Check server limits first if available
|
|
37
|
+
if (this.serverLimitInfo?.remaining !== undefined) {
|
|
38
|
+
if (this.serverLimitInfo.remaining <= 0) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Check client-side limits
|
|
43
|
+
const currentUsage = this.getCurrentUsage(tool);
|
|
44
|
+
const limit = this.getEffectiveLimit(tool);
|
|
45
|
+
return currentUsage < limit;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Record token usage for a tool.
|
|
49
|
+
*/
|
|
50
|
+
recordUsage(tokens, tool) {
|
|
51
|
+
this.cleanup();
|
|
52
|
+
this.usage.push({
|
|
53
|
+
timestamp: Date.now(),
|
|
54
|
+
tokens,
|
|
55
|
+
tool,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get current token usage in the window.
|
|
60
|
+
* If tool is provided and per-tool quotas are enabled, returns usage for that tool only.
|
|
61
|
+
*/
|
|
62
|
+
getCurrentUsage(tool) {
|
|
63
|
+
this.cleanup();
|
|
64
|
+
if (this.perToolQuota && tool) {
|
|
65
|
+
return this.usage
|
|
66
|
+
.filter((entry) => entry.tool === tool)
|
|
67
|
+
.reduce((sum, entry) => sum + entry.tokens, 0);
|
|
68
|
+
}
|
|
69
|
+
return this.usage.reduce((sum, entry) => sum + entry.tokens, 0);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get remaining tokens in current window.
|
|
73
|
+
* Uses server limits if available, otherwise falls back to client-side tracking.
|
|
74
|
+
*/
|
|
75
|
+
getRemainingTokens(tool) {
|
|
76
|
+
// Prefer server-provided remaining count if available
|
|
77
|
+
if (this.serverLimitInfo?.remaining !== undefined) {
|
|
78
|
+
return Math.max(0, this.serverLimitInfo.remaining);
|
|
79
|
+
}
|
|
80
|
+
const current = this.getCurrentUsage(tool);
|
|
81
|
+
const limit = this.getEffectiveLimit(tool);
|
|
82
|
+
return Math.max(0, limit - current);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Update with server-provided rate limit information.
|
|
86
|
+
* This information takes precedence over client-side tracking.
|
|
87
|
+
*/
|
|
88
|
+
updateServerLimits(info) {
|
|
89
|
+
this.serverLimitInfo = info;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get current server limit information if available.
|
|
93
|
+
*/
|
|
94
|
+
getServerLimits() {
|
|
95
|
+
return this.serverLimitInfo;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the effective limit for a tool (tool-specific or global).
|
|
99
|
+
*/
|
|
100
|
+
getEffectiveLimit(tool) {
|
|
101
|
+
if (this.perToolQuota && tool && this.toolLimits[tool]) {
|
|
102
|
+
return this.toolLimits[tool];
|
|
103
|
+
}
|
|
104
|
+
return this.maxTokens;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Remove entries outside the current window.
|
|
108
|
+
*/
|
|
109
|
+
cleanup() {
|
|
110
|
+
const cutoff = Date.now() - this.windowMs;
|
|
111
|
+
this.usage = this.usage.filter((entry) => entry.timestamp > cutoff);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Reset all usage data and server limit info.
|
|
115
|
+
*/
|
|
116
|
+
reset() {
|
|
117
|
+
this.usage = [];
|
|
118
|
+
this.serverLimitInfo = undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Default server rate limit extractor.
|
|
123
|
+
*
|
|
124
|
+
* Attempts to extract rate limit information from common response header patterns:
|
|
125
|
+
* - `x-ratelimit-*` (OpenAI, Anthropic, etc.)
|
|
126
|
+
* - `ratelimit-*` (standard format)
|
|
127
|
+
* - `retry-after` (when rate limited)
|
|
128
|
+
*
|
|
129
|
+
* @param result - PostGenerate hook input containing the generation result
|
|
130
|
+
* @returns Server rate limit info if headers are present, undefined otherwise
|
|
131
|
+
*
|
|
132
|
+
* @category Hooks
|
|
133
|
+
*/
|
|
134
|
+
export function extractStandardRateLimitHeaders(result) {
|
|
135
|
+
// AI SDK v6 may expose response metadata via result.response or result.rawResponse
|
|
136
|
+
// This is a best-effort extraction that handles common patterns
|
|
137
|
+
// biome-ignore lint/suspicious/noExplicitAny: AI SDK internal structure varies by version
|
|
138
|
+
const headers = result.response?.headers || result.rawResponse?.headers;
|
|
139
|
+
if (!headers)
|
|
140
|
+
return undefined;
|
|
141
|
+
// Normalize headers to lowercase for case-insensitive matching
|
|
142
|
+
const normalizedHeaders = {};
|
|
143
|
+
if (typeof headers === "object") {
|
|
144
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
145
|
+
if (typeof value === "string") {
|
|
146
|
+
normalizedHeaders[key.toLowerCase()] = value;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Try common header patterns
|
|
151
|
+
const limitStr = normalizedHeaders["x-ratelimit-limit"] || normalizedHeaders["ratelimit-limit"];
|
|
152
|
+
const remainingStr = normalizedHeaders["x-ratelimit-remaining"] || normalizedHeaders["ratelimit-remaining"];
|
|
153
|
+
const resetStr = normalizedHeaders["x-ratelimit-reset"] || normalizedHeaders["ratelimit-reset"];
|
|
154
|
+
const retryAfterStr = normalizedHeaders["retry-after"];
|
|
155
|
+
// Parse values
|
|
156
|
+
const limit = limitStr ? Number.parseInt(limitStr, 10) : undefined;
|
|
157
|
+
const remaining = remainingStr ? Number.parseInt(remainingStr, 10) : undefined;
|
|
158
|
+
const reset = resetStr ? Number.parseInt(resetStr, 10) : undefined;
|
|
159
|
+
const retryAfter = retryAfterStr ? Number.parseInt(retryAfterStr, 10) : undefined;
|
|
160
|
+
// Return undefined if no rate limit headers found
|
|
161
|
+
if (limit === undefined &&
|
|
162
|
+
remaining === undefined &&
|
|
163
|
+
reset === undefined &&
|
|
164
|
+
retryAfter === undefined) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
limit: !Number.isNaN(limit) ? limit : undefined,
|
|
169
|
+
remaining: !Number.isNaN(remaining) ? remaining : undefined,
|
|
170
|
+
reset: !Number.isNaN(reset) ? reset : undefined,
|
|
171
|
+
retryAfter: !Number.isNaN(retryAfter) ? retryAfter : undefined,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Creates rate limiting hooks for PreGenerate and PostGenerate events.
|
|
176
|
+
*
|
|
177
|
+
* The PreGenerate hook checks if the rate limit would be exceeded and denies
|
|
178
|
+
* the request if so. The PostGenerate hook records actual token usage.
|
|
179
|
+
*
|
|
180
|
+
* This replaces rate limiting middleware with hook-based rate limiting that
|
|
181
|
+
* works correctly with the unified hook system.
|
|
182
|
+
*
|
|
183
|
+
* @param options - Configuration options
|
|
184
|
+
* @returns Array of two hooks: [PreGenerate rate check, PostGenerate usage tracking]
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* const [rateCheck, usageTracker] = createRateLimitHooks({
|
|
189
|
+
* maxTokensPerWindow: 50000, // 50k tokens
|
|
190
|
+
* windowMs: 60000, // per minute
|
|
191
|
+
* });
|
|
192
|
+
*
|
|
193
|
+
* const agent = createAgent({
|
|
194
|
+
* model,
|
|
195
|
+
* hooks: {
|
|
196
|
+
* PreGenerate: [{ hooks: [rateCheck] }],
|
|
197
|
+
* PostGenerate: [{ hooks: [usageTracker] }],
|
|
198
|
+
* },
|
|
199
|
+
* });
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* // Custom rate limit logic
|
|
205
|
+
* const hooks = createRateLimitHooks({
|
|
206
|
+
* shouldAllow: (tokensUsed, maxTokens) => {
|
|
207
|
+
* // Allow if under 80% of limit
|
|
208
|
+
* return tokensUsed < maxTokens * 0.8;
|
|
209
|
+
* },
|
|
210
|
+
* });
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* // With server rate limit integration
|
|
216
|
+
* const hooks = createRateLimitHooks({
|
|
217
|
+
* maxTokensPerWindow: 100000,
|
|
218
|
+
* enableServerLimits: true, // Parse x-ratelimit-* headers
|
|
219
|
+
* });
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* // Custom server limit extraction for non-standard headers
|
|
225
|
+
* const hooks = createRateLimitHooks({
|
|
226
|
+
* enableServerLimits: true,
|
|
227
|
+
* extractServerLimits: (result) => {
|
|
228
|
+
* const headers = result.response?.headers;
|
|
229
|
+
* return {
|
|
230
|
+
* remaining: parseInt(headers?.['x-custom-remaining'] || '0'),
|
|
231
|
+
* reset: parseInt(headers?.['x-custom-reset'] || '0'),
|
|
232
|
+
* };
|
|
233
|
+
* },
|
|
234
|
+
* });
|
|
235
|
+
* ```
|
|
236
|
+
*
|
|
237
|
+
* @category Hooks
|
|
238
|
+
*/
|
|
239
|
+
export function createRateLimitHooks(options = {}) {
|
|
240
|
+
const { maxTokensPerWindow = 100000, windowMs = 60000, // 1 minute
|
|
241
|
+
limitMessage = "Rate limit exceeded. Please try again later.", shouldAllow = (tokensUsed, maxTokens) => tokensUsed < maxTokens, enableServerLimits = false, extractServerLimits = extractStandardRateLimitHeaders, perToolQuota = false, toolLimits = {}, } = options;
|
|
242
|
+
const rateLimiter = new TokenBucketRateLimiter(maxTokensPerWindow, windowMs, perToolQuota, toolLimits);
|
|
243
|
+
// PreGenerate: Check rate limit
|
|
244
|
+
const rateCheck = async (input) => {
|
|
245
|
+
if (input.hook_event_name !== "PreGenerate")
|
|
246
|
+
return {};
|
|
247
|
+
const currentUsage = rateLimiter.getCurrentUsage();
|
|
248
|
+
if (!shouldAllow(currentUsage, maxTokensPerWindow)) {
|
|
249
|
+
// Check if we have server reset time for better error message
|
|
250
|
+
const serverLimits = rateLimiter.getServerLimits();
|
|
251
|
+
let reason = limitMessage;
|
|
252
|
+
if (serverLimits?.reset) {
|
|
253
|
+
const resetDate = new Date(serverLimits.reset * 1000);
|
|
254
|
+
reason = `${limitMessage} Rate limit resets at ${resetDate.toISOString()}.`;
|
|
255
|
+
}
|
|
256
|
+
else if (serverLimits?.retryAfter) {
|
|
257
|
+
reason = `${limitMessage} Retry after ${serverLimits.retryAfter} seconds.`;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
hookSpecificOutput: {
|
|
261
|
+
hookEventName: "PreGenerate",
|
|
262
|
+
permissionDecision: "deny",
|
|
263
|
+
permissionDecisionReason: reason,
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return {};
|
|
268
|
+
};
|
|
269
|
+
// PostGenerate: Record usage and update server limits
|
|
270
|
+
const usageTracker = async (input) => {
|
|
271
|
+
if (input.hook_event_name !== "PostGenerate")
|
|
272
|
+
return {};
|
|
273
|
+
const postGenInput = input;
|
|
274
|
+
const tokens = postGenInput.result.usage?.totalTokens ?? 0;
|
|
275
|
+
// Record client-side usage
|
|
276
|
+
rateLimiter.recordUsage(tokens);
|
|
277
|
+
// Update with server-provided limits if enabled
|
|
278
|
+
if (enableServerLimits) {
|
|
279
|
+
const serverLimits = extractServerLimits(postGenInput);
|
|
280
|
+
if (serverLimits) {
|
|
281
|
+
rateLimiter.updateServerLimits(serverLimits);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return {};
|
|
285
|
+
};
|
|
286
|
+
return [rateCheck, usageTracker];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Creates managed rate limit hooks with programmatic control.
|
|
290
|
+
*
|
|
291
|
+
* Returns hooks along with functions to get current usage, reset limits,
|
|
292
|
+
* and check remaining capacity.
|
|
293
|
+
*
|
|
294
|
+
* @param options - Configuration options
|
|
295
|
+
* @returns Object with hooks and rate limit control functions
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```typescript
|
|
299
|
+
* const { hooks, getCurrentUsage, getRemainingTokens, reset } = createManagedRateLimitHooks({
|
|
300
|
+
* maxTokensPerWindow: 100000,
|
|
301
|
+
* windowMs: 60000,
|
|
302
|
+
* });
|
|
303
|
+
*
|
|
304
|
+
* const agent = createAgent({
|
|
305
|
+
* model,
|
|
306
|
+
* hooks: {
|
|
307
|
+
* PreGenerate: [{ hooks: [hooks[0]] }],
|
|
308
|
+
* PostGenerate: [{ hooks: [hooks[1]] }],
|
|
309
|
+
* },
|
|
310
|
+
* });
|
|
311
|
+
*
|
|
312
|
+
* // Check current usage
|
|
313
|
+
* const used = getCurrentUsage();
|
|
314
|
+
* const remaining = getRemainingTokens();
|
|
315
|
+
* console.log(`Token usage: ${used} / ${maxTokensPerWindow} (${remaining} remaining)`);
|
|
316
|
+
*
|
|
317
|
+
* // Reset limits (e.g., for testing or manual override)
|
|
318
|
+
* reset();
|
|
319
|
+
* ```
|
|
320
|
+
*
|
|
321
|
+
* @category Hooks
|
|
322
|
+
*/
|
|
323
|
+
export function createManagedRateLimitHooks(options = {}) {
|
|
324
|
+
const { maxTokensPerWindow = 100000, windowMs = 60000, limitMessage = "Rate limit exceeded. Please try again later.", shouldAllow = (tokensUsed, maxTokens) => tokensUsed < maxTokens, enableServerLimits = false, extractServerLimits = extractStandardRateLimitHeaders, perToolQuota = false, toolLimits = {}, } = options;
|
|
325
|
+
const rateLimiter = new TokenBucketRateLimiter(maxTokensPerWindow, windowMs, perToolQuota, toolLimits);
|
|
326
|
+
const rateCheck = async (input) => {
|
|
327
|
+
if (input.hook_event_name !== "PreGenerate")
|
|
328
|
+
return {};
|
|
329
|
+
const currentUsage = rateLimiter.getCurrentUsage();
|
|
330
|
+
if (!shouldAllow(currentUsage, maxTokensPerWindow)) {
|
|
331
|
+
const serverLimits = rateLimiter.getServerLimits();
|
|
332
|
+
let reason = limitMessage;
|
|
333
|
+
if (serverLimits?.reset) {
|
|
334
|
+
const resetDate = new Date(serverLimits.reset * 1000);
|
|
335
|
+
reason = `${limitMessage} Rate limit resets at ${resetDate.toISOString()}.`;
|
|
336
|
+
}
|
|
337
|
+
else if (serverLimits?.retryAfter) {
|
|
338
|
+
reason = `${limitMessage} Retry after ${serverLimits.retryAfter} seconds.`;
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
hookSpecificOutput: {
|
|
342
|
+
hookEventName: "PreGenerate",
|
|
343
|
+
permissionDecision: "deny",
|
|
344
|
+
permissionDecisionReason: reason,
|
|
345
|
+
},
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
return {};
|
|
349
|
+
};
|
|
350
|
+
const usageTracker = async (input) => {
|
|
351
|
+
if (input.hook_event_name !== "PostGenerate")
|
|
352
|
+
return {};
|
|
353
|
+
const postGenInput = input;
|
|
354
|
+
const tokens = postGenInput.result.usage?.totalTokens ?? 0;
|
|
355
|
+
rateLimiter.recordUsage(tokens);
|
|
356
|
+
if (enableServerLimits) {
|
|
357
|
+
const serverLimits = extractServerLimits(postGenInput);
|
|
358
|
+
if (serverLimits) {
|
|
359
|
+
rateLimiter.updateServerLimits(serverLimits);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return {};
|
|
363
|
+
};
|
|
364
|
+
return {
|
|
365
|
+
hooks: [rateCheck, usageTracker],
|
|
366
|
+
getCurrentUsage: () => rateLimiter.getCurrentUsage(),
|
|
367
|
+
getRemainingTokens: () => rateLimiter.getRemainingTokens(),
|
|
368
|
+
getServerLimits: () => rateLimiter.getServerLimits(),
|
|
369
|
+
reset: () => rateLimiter.reset(),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/hooks/rate-limit.ts"],"names":[],"mappings":"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"}
|