crewly 1.8.8 → 1.8.9
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/dist/backend/backend/src/constants.d.ts +12 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +12 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/browser/browser.controller.js +17 -0
- package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +8 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +15 -7
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-bridge.service.js +15 -29
- package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +97 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js +174 -15
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.d.ts +12 -4
- package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.js +17 -5
- package/dist/backend/backend/src/services/browser/browser-relay-adapter.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +75 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +164 -12
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +12 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +12 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/cli/src/index.js +0 -0
- package/package.json +1 -1
- package/config/constants.d.ts.map +0 -1
- package/config/index.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +0 -169
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +0 -1779
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +0 -513
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +0 -1568
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts +0 -86
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js +0 -147
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/api-client.d.ts +0 -68
- package/dist/backend/backend/src/services/agent/crewly-agent/api-client.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/api-client.js +0 -131
- package/dist/backend/backend/src/services/agent/crewly-agent/api-client.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.d.ts +0 -130
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.js +0 -263
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-log.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts +0 -74
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js +0 -140
- package/dist/backend/backend/src/services/agent/crewly-agent/audit-trail.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts +0 -29
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js +0 -279
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +0 -340
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +0 -1176
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts +0 -79
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js +0 -145
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.d.ts +0 -79
- package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.js +0 -218
- package/dist/backend/backend/src/services/agent/crewly-agent/env-isolation.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts +0 -16
- package/dist/backend/backend/src/services/agent/crewly-agent/index.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/index.js +0 -16
- package/dist/backend/backend/src/services/agent/crewly-agent/index.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts +0 -135
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js +0 -185
- package/dist/backend/backend/src/services/agent/crewly-agent/mcp-tool-bridge.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +0 -141
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +0 -310
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.d.ts +0 -91
- package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.js +0 -143
- package/dist/backend/backend/src/services/agent/crewly-agent/output-filter.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.d.ts +0 -103
- package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.js +0 -256
- package/dist/backend/backend/src/services/agent/crewly-agent/prompt-guard.service.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +0 -143
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +0 -264
- package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.d.ts +0 -13
- package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js +0 -91
- package/dist/backend/backend/src/services/agent/crewly-agent/smoke-test.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts +0 -135
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js +0 -1937
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js.map +0 -1
- package/dist/backend/backend/src/services/autonomous/auto-assign.service.d.ts +0 -429
- package/dist/backend/backend/src/services/autonomous/auto-assign.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/autonomous/auto-assign.service.js +0 -852
- package/dist/backend/backend/src/services/autonomous/auto-assign.service.js.map +0 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +0 -171
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js +0 -725
- package/dist/backend/backend/src/services/project/task-tracking.service.js.map +0 -1
- package/dist/backend/backend/src/services/v3/project-task-watcher.service.d.ts +0 -118
- package/dist/backend/backend/src/services/v3/project-task-watcher.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/v3/project-task-watcher.service.js +0 -326
- package/dist/backend/backend/src/services/v3/project-task-watcher.service.js.map +0 -1
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +0 -74
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +0 -154
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +0 -1
- package/dist/backend/backend/src/types/auto-assign.types.d.ts +0 -271
- package/dist/backend/backend/src/types/auto-assign.types.d.ts.map +0 -1
- package/dist/backend/backend/src/types/auto-assign.types.js +0 -136
- package/dist/backend/backend/src/types/auto-assign.types.js.map +0 -1
- package/dist/backend/backend/src/utils/esm-require.utils.d.ts +0 -111
- package/dist/backend/backend/src/utils/esm-require.utils.d.ts.map +0 -1
- package/dist/backend/backend/src/utils/esm-require.utils.js +0 -124
- package/dist/backend/backend/src/utils/esm-require.utils.js.map +0 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +0 -220
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +0 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js +0 -37
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +0 -1
- package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.d.ts +0 -56
- package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.d.ts.map +0 -1
- package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.js +0 -91
- package/dist/cli/backend/src/services/knowledge/fts5-search-strategy.js.map +0 -1
- package/dist/cli/backend/src/services/knowledge/learnings-index.service.d.ts +0 -159
- package/dist/cli/backend/src/services/knowledge/learnings-index.service.d.ts.map +0 -1
- package/dist/cli/backend/src/services/knowledge/learnings-index.service.js +0 -304
- package/dist/cli/backend/src/services/knowledge/learnings-index.service.js.map +0 -1
- package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.d.ts +0 -115
- package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.d.ts.map +0 -1
- package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.js +0 -215
- package/dist/cli/backend/src/services/knowledge/wiki-compiler.service.js.map +0 -1
- package/dist/cli/backend/src/services/memory/embedding-provider.d.ts +0 -78
- package/dist/cli/backend/src/services/memory/embedding-provider.d.ts.map +0 -1
- package/dist/cli/backend/src/services/memory/embedding-provider.js +0 -179
- package/dist/cli/backend/src/services/memory/embedding-provider.js.map +0 -1
- package/dist/cli/backend/src/services/memory/vector-store.service.d.ts +0 -331
- package/dist/cli/backend/src/services/memory/vector-store.service.d.ts.map +0 -1
- package/dist/cli/backend/src/services/memory/vector-store.service.js +0 -814
- package/dist/cli/backend/src/services/memory/vector-store.service.js.map +0 -1
- package/dist/cli/backend/src/services/project/task-tracking.service.d.ts +0 -171
- package/dist/cli/backend/src/services/project/task-tracking.service.d.ts.map +0 -1
- package/dist/cli/backend/src/services/project/task-tracking.service.js +0 -725
- package/dist/cli/backend/src/services/project/task-tracking.service.js.map +0 -1
- package/dist/cli/backend/src/types/auto-assign.types.d.ts +0 -271
- package/dist/cli/backend/src/types/auto-assign.types.d.ts.map +0 -1
- package/dist/cli/backend/src/types/auto-assign.types.js +0 -136
- package/dist/cli/backend/src/types/auto-assign.types.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-guard.service.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/prompt-guard.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,QAAQ,EAAE,gBAAgB,GAAG,UAAU,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;CACpF;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;IACpC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,YAAY,EA2FjD,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,YAAY,EAqBnD,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,EAQnD,CAAC;AAEF;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAC1D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0B;IAEzD;;;;;OAKG;gBAED,yBAAyB,CAAC,EAAE,YAAY,EAAE,EAC1C,wBAAwB,CAAC,EAAE,YAAY,EAAE;IAU3C;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB;IAmB/C;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB;IAmB7C;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAMrC;;;;;;;;OAQG;IACH,gBAAgB,CACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,gBAAgB,GAC5B,UAAU;CAiBd"}
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Guard Service — Prompt Injection Protection
|
|
3
|
-
*
|
|
4
|
-
* Detects and blocks prompt injection attempts that try to extract API keys,
|
|
5
|
-
* secrets, or sensitive environment variables through agent commands.
|
|
6
|
-
*
|
|
7
|
-
* Integrates with the tool registry to block dangerous bash commands and
|
|
8
|
-
* logs blocked attempts to the audit trail.
|
|
9
|
-
*
|
|
10
|
-
* @module services/agent/crewly-agent/prompt-guard.service
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* const guard = new PromptGuardService();
|
|
15
|
-
* const result = guard.checkCommand('echo $ANTHROPIC_API_KEY');
|
|
16
|
-
* // { blocked: true, reason: 'Key extraction attempt: echo env var', pattern: '...' }
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
/**
|
|
20
|
-
* Patterns that detect attempts to extract API keys or secrets via bash commands.
|
|
21
|
-
*/
|
|
22
|
-
export const KEY_EXTRACTION_PATTERNS = [
|
|
23
|
-
// Direct env var echo/print
|
|
24
|
-
{
|
|
25
|
-
pattern: /\becho\s+\$[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH)/i,
|
|
26
|
-
reason: 'Attempt to echo sensitive environment variable',
|
|
27
|
-
category: 'env_extraction',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
pattern: /\bprintf\s+.*\$[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|AUTH)/i,
|
|
31
|
-
reason: 'Attempt to printf sensitive environment variable',
|
|
32
|
-
category: 'env_extraction',
|
|
33
|
-
},
|
|
34
|
-
// env/printenv with grep for secrets
|
|
35
|
-
{
|
|
36
|
-
pattern: /\benv\b.*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API|AUTH)/i,
|
|
37
|
-
reason: 'Attempt to grep env for secrets',
|
|
38
|
-
category: 'env_extraction',
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
pattern: /\bprintenv\b.*(?:KEY|SECRET|TOKEN|PASSWORD|API|AUTH)/i,
|
|
42
|
-
reason: 'Attempt to printenv sensitive variable',
|
|
43
|
-
category: 'env_extraction',
|
|
44
|
-
},
|
|
45
|
-
// set | grep (bash set command dumps all vars)
|
|
46
|
-
{
|
|
47
|
-
pattern: /\bset\b\s*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API|AUTH)/i,
|
|
48
|
-
reason: 'Attempt to dump shell variables and grep for secrets',
|
|
49
|
-
category: 'env_extraction',
|
|
50
|
-
},
|
|
51
|
-
// Reading sensitive config files (must come before bare env/printenv to avoid early match on "cat .env")
|
|
52
|
-
{
|
|
53
|
-
pattern: /\bcat\s+.*\.env\b/i,
|
|
54
|
-
reason: 'Attempt to read .env file',
|
|
55
|
-
category: 'file_exfiltration',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
pattern: /\bcat\s+.*(?:credentials|secrets|\.aws\/credentials|\.npmrc|\.netrc|\.pgpass)/i,
|
|
59
|
-
reason: 'Attempt to read credentials file',
|
|
60
|
-
category: 'file_exfiltration',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
pattern: /\bcat\s+.*\/etc\/shadow\b/i,
|
|
64
|
-
reason: 'Attempt to read system password file',
|
|
65
|
-
category: 'file_exfiltration',
|
|
66
|
-
},
|
|
67
|
-
// Direct env dump
|
|
68
|
-
{
|
|
69
|
-
pattern: /\benv\s*$/i,
|
|
70
|
-
reason: 'Attempt to dump all environment variables',
|
|
71
|
-
category: 'key_dump',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
pattern: /\bprintenv\s*$/i,
|
|
75
|
-
reason: 'Attempt to dump all environment variables',
|
|
76
|
-
category: 'key_dump',
|
|
77
|
-
},
|
|
78
|
-
// compgen dumps shell vars/functions
|
|
79
|
-
{
|
|
80
|
-
pattern: /\bcompgen\s+-[ev]/i,
|
|
81
|
-
reason: 'Attempt to dump shell variables via compgen',
|
|
82
|
-
category: 'key_dump',
|
|
83
|
-
},
|
|
84
|
-
// base64 encoding secrets for exfiltration
|
|
85
|
-
{
|
|
86
|
-
pattern: /\bbase64\b.*\$[A-Z_]*(?:KEY|SECRET|TOKEN)/i,
|
|
87
|
-
reason: 'Attempt to base64 encode secret for exfiltration',
|
|
88
|
-
category: 'file_exfiltration',
|
|
89
|
-
},
|
|
90
|
-
// curl/wget exfiltration of env vars
|
|
91
|
-
{
|
|
92
|
-
pattern: /\b(?:curl|wget)\b.*\$[A-Z_]*(?:KEY|SECRET|TOKEN)/i,
|
|
93
|
-
reason: 'Attempt to exfiltrate secret via HTTP request',
|
|
94
|
-
category: 'file_exfiltration',
|
|
95
|
-
},
|
|
96
|
-
// Python/Node one-liners to access env
|
|
97
|
-
{
|
|
98
|
-
pattern: /\bpython[23]?\s+-c\s+.*os\.environ/i,
|
|
99
|
-
reason: 'Attempt to access env via Python subprocess',
|
|
100
|
-
category: 'env_extraction',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
pattern: /\bnode\s+-e\s+.*process\.env/i,
|
|
104
|
-
reason: 'Attempt to access env via Node subprocess',
|
|
105
|
-
category: 'env_extraction',
|
|
106
|
-
},
|
|
107
|
-
// Specific key variable names in $() or backtick subshells
|
|
108
|
-
{
|
|
109
|
-
pattern: /\$\(.*(?:ANTHROPIC_API_KEY|OPENAI_API_KEY|GOOGLE_API_KEY|AWS_SECRET|STRIPE_SECRET)/i,
|
|
110
|
-
reason: 'Attempt to expand sensitive env var in subshell',
|
|
111
|
-
category: 'env_extraction',
|
|
112
|
-
},
|
|
113
|
-
];
|
|
114
|
-
/**
|
|
115
|
-
* Prompt-level injection patterns (detected in natural language prompts, not just commands).
|
|
116
|
-
*/
|
|
117
|
-
export const PROMPT_INJECTION_PATTERNS = [
|
|
118
|
-
{
|
|
119
|
-
pattern: /(?:print|show|reveal|tell\s+me|display|output|give\s+me|share)\s+(?:(?:your|the|my|me\s+the)\s+)?(?:api[_ ]?key|secret|token|password|credentials)/i,
|
|
120
|
-
reason: 'Prompt injection: request to reveal API key/secret',
|
|
121
|
-
category: 'prompt_injection',
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
pattern: /(?:what\s+is|what's)\s+(?:your|the|my)\s+(?:api[_ ]?key|secret[_ ]?key|auth[_ ]?token|password)/i,
|
|
125
|
-
reason: 'Prompt injection: question about API key/secret',
|
|
126
|
-
category: 'prompt_injection',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
pattern: /ignore\s+(?:previous|all|your)\s+(?:instructions|rules|safety)/i,
|
|
130
|
-
reason: 'Prompt injection: instruction override attempt',
|
|
131
|
-
category: 'prompt_injection',
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
pattern: /(?:override|bypass|disable|turn\s+off)\s+(?:security|safety|filter|guardrail|redaction)/i,
|
|
135
|
-
reason: 'Prompt injection: attempt to disable security filters',
|
|
136
|
-
category: 'prompt_injection',
|
|
137
|
-
},
|
|
138
|
-
];
|
|
139
|
-
/**
|
|
140
|
-
* Additional blocked command patterns for tool-registry.ts integration.
|
|
141
|
-
* These extend the existing BLOCKED_COMMAND_PATTERNS with key extraction blocks.
|
|
142
|
-
*/
|
|
143
|
-
export const KEY_EXTRACTION_BLOCKED_COMMANDS = [
|
|
144
|
-
/\benv\s*$/i,
|
|
145
|
-
/\bprintenv\s*$/i,
|
|
146
|
-
/\benv\b.*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API)/i,
|
|
147
|
-
/\bset\b\s*\|\s*grep\s+.*(?:KEY|SECRET|TOKEN|PASSWORD|API)/i,
|
|
148
|
-
/\bcompgen\s+-[ev]/i,
|
|
149
|
-
/\bcat\s+.*\.env\b/i,
|
|
150
|
-
/\bcat\s+.*(?:credentials|secrets|\.aws\/credentials|\.npmrc|\.netrc|\.pgpass)/i,
|
|
151
|
-
];
|
|
152
|
-
/**
|
|
153
|
-
* Service that detects and blocks prompt injection and key extraction attempts.
|
|
154
|
-
*/
|
|
155
|
-
export class PromptGuardService {
|
|
156
|
-
commandPatterns;
|
|
157
|
-
promptPatterns;
|
|
158
|
-
/**
|
|
159
|
-
* Creates a new PromptGuardService.
|
|
160
|
-
*
|
|
161
|
-
* @param additionalCommandPatterns - Extra command-level patterns
|
|
162
|
-
* @param additionalPromptPatterns - Extra prompt-level patterns
|
|
163
|
-
*/
|
|
164
|
-
constructor(additionalCommandPatterns, additionalPromptPatterns) {
|
|
165
|
-
this.commandPatterns = additionalCommandPatterns
|
|
166
|
-
? [...KEY_EXTRACTION_PATTERNS, ...additionalCommandPatterns]
|
|
167
|
-
: KEY_EXTRACTION_PATTERNS;
|
|
168
|
-
this.promptPatterns = additionalPromptPatterns
|
|
169
|
-
? [...PROMPT_INJECTION_PATTERNS, ...additionalPromptPatterns]
|
|
170
|
-
: PROMPT_INJECTION_PATTERNS;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Checks a bash command for key extraction attempts.
|
|
174
|
-
*
|
|
175
|
-
* @param command - Raw bash command string
|
|
176
|
-
* @returns Guard check result
|
|
177
|
-
*/
|
|
178
|
-
checkCommand(command) {
|
|
179
|
-
if (!command) {
|
|
180
|
-
return { blocked: false, reason: '' };
|
|
181
|
-
}
|
|
182
|
-
for (const guard of this.commandPatterns) {
|
|
183
|
-
if (guard.pattern.test(command)) {
|
|
184
|
-
return {
|
|
185
|
-
blocked: true,
|
|
186
|
-
reason: guard.reason,
|
|
187
|
-
category: guard.category,
|
|
188
|
-
matchedPattern: guard.pattern.source,
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return { blocked: false, reason: '' };
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Checks a user/agent prompt for injection attempts targeting secrets.
|
|
196
|
-
*
|
|
197
|
-
* @param prompt - The text prompt or message
|
|
198
|
-
* @returns Guard check result
|
|
199
|
-
*/
|
|
200
|
-
checkPrompt(prompt) {
|
|
201
|
-
if (!prompt) {
|
|
202
|
-
return { blocked: false, reason: '' };
|
|
203
|
-
}
|
|
204
|
-
for (const guard of this.promptPatterns) {
|
|
205
|
-
if (guard.pattern.test(prompt)) {
|
|
206
|
-
return {
|
|
207
|
-
blocked: true,
|
|
208
|
-
reason: guard.reason,
|
|
209
|
-
category: guard.category,
|
|
210
|
-
matchedPattern: guard.pattern.source,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return { blocked: false, reason: '' };
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Checks both command and prompt patterns.
|
|
218
|
-
* Use this for comprehensive scanning of any agent input.
|
|
219
|
-
*
|
|
220
|
-
* @param text - Text to check (command or prompt)
|
|
221
|
-
* @returns Guard check result
|
|
222
|
-
*/
|
|
223
|
-
check(text) {
|
|
224
|
-
const cmdResult = this.checkCommand(text);
|
|
225
|
-
if (cmdResult.blocked)
|
|
226
|
-
return cmdResult;
|
|
227
|
-
return this.checkPrompt(text);
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Creates an audit entry for a blocked attempt.
|
|
231
|
-
*
|
|
232
|
-
* @param sessionName - Agent session that triggered the block
|
|
233
|
-
* @param toolName - Tool that was used (e.g. 'bash_exec')
|
|
234
|
-
* @param command - The blocked command
|
|
235
|
-
* @param guardResult - The guard check result
|
|
236
|
-
* @returns AuditEntry suitable for the audit log
|
|
237
|
-
*/
|
|
238
|
-
createAuditEntry(sessionName, toolName, command, guardResult) {
|
|
239
|
-
return {
|
|
240
|
-
timestamp: new Date().toISOString(),
|
|
241
|
-
sessionName,
|
|
242
|
-
toolName,
|
|
243
|
-
sensitivity: 'destructive',
|
|
244
|
-
args: {
|
|
245
|
-
command,
|
|
246
|
-
blockedReason: guardResult.reason,
|
|
247
|
-
category: guardResult.category || 'unknown',
|
|
248
|
-
matchedPattern: guardResult.matchedPattern || '',
|
|
249
|
-
},
|
|
250
|
-
success: false,
|
|
251
|
-
error: `Blocked by prompt guard: ${guardResult.reason}`,
|
|
252
|
-
durationMs: 0,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
//# sourceMappingURL=prompt-guard.service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-guard.service.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/prompt-guard.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rate Limiter for Crewly Agent API Calls
|
|
3
|
-
*
|
|
4
|
-
* Provides token-bucket rate limiting, message coalescing, and 429 retry
|
|
5
|
-
* logic to prevent Gemini API quota exhaustion when multiple agents are
|
|
6
|
-
* actively generating messages.
|
|
7
|
-
*
|
|
8
|
-
* @module services/agent/crewly-agent/rate-limiter
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Configuration for the rate limiter.
|
|
12
|
-
*/
|
|
13
|
-
export interface RateLimiterConfig {
|
|
14
|
-
/** Maximum requests allowed per window */
|
|
15
|
-
maxRequestsPerWindow: number;
|
|
16
|
-
/** Time window in milliseconds */
|
|
17
|
-
windowMs: number;
|
|
18
|
-
/** Maximum retry attempts for 429 errors */
|
|
19
|
-
maxRetries: number;
|
|
20
|
-
/** Initial backoff delay in milliseconds for 429 retries */
|
|
21
|
-
initialBackoffMs: number;
|
|
22
|
-
/** Backoff multiplier for exponential retry */
|
|
23
|
-
backoffMultiplier: number;
|
|
24
|
-
/** Maximum backoff delay in milliseconds */
|
|
25
|
-
maxBackoffMs: number;
|
|
26
|
-
/** Coalescing window — how long to wait for additional messages before processing (ms) */
|
|
27
|
-
coalesceWindowMs: number;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Default rate limiter configuration.
|
|
31
|
-
*/
|
|
32
|
-
export declare const RATE_LIMITER_DEFAULTS: RateLimiterConfig;
|
|
33
|
-
/**
|
|
34
|
-
* Token-bucket rate limiter with message coalescing and 429 retry.
|
|
35
|
-
*
|
|
36
|
-
* Features:
|
|
37
|
-
* - **Rate limiting**: Enforces max requests per time window using a sliding window.
|
|
38
|
-
* - **Message coalescing**: Groups messages arriving within a short window into one.
|
|
39
|
-
* - **429 retry**: Wraps API calls with exponential backoff on quota errors.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```typescript
|
|
43
|
-
* const limiter = new RateLimiter<AgentRunResult>();
|
|
44
|
-
* const result = await limiter.enqueue('Check status', undefined, async (msg) => {
|
|
45
|
-
* return agentRunner.run(msg);
|
|
46
|
-
* });
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
export declare class RateLimiter<T> {
|
|
50
|
-
private config;
|
|
51
|
-
private requestTimestamps;
|
|
52
|
-
private queue;
|
|
53
|
-
private processing;
|
|
54
|
-
private coalesceTimer;
|
|
55
|
-
/**
|
|
56
|
-
* Create a new RateLimiter instance.
|
|
57
|
-
*
|
|
58
|
-
* @param config - Optional partial config overrides
|
|
59
|
-
*/
|
|
60
|
-
constructor(config?: Partial<RateLimiterConfig>);
|
|
61
|
-
/**
|
|
62
|
-
* Enqueue a message for rate-limited processing.
|
|
63
|
-
*
|
|
64
|
-
* If multiple messages arrive within the coalescing window, they are
|
|
65
|
-
* merged into a single request to reduce API call count.
|
|
66
|
-
*
|
|
67
|
-
* @param message - Message to process
|
|
68
|
-
* @param metadata - Optional metadata
|
|
69
|
-
* @param handler - Async function that performs the actual API call
|
|
70
|
-
* @returns Result from the handler
|
|
71
|
-
*/
|
|
72
|
-
enqueue(message: string, metadata: Record<string, string> | undefined, handler: (message: string, metadata?: Record<string, string>) => Promise<T>): Promise<T>;
|
|
73
|
-
/**
|
|
74
|
-
* Get the current number of messages in the queue.
|
|
75
|
-
*
|
|
76
|
-
* @returns Queue length
|
|
77
|
-
*/
|
|
78
|
-
getQueueLength(): number;
|
|
79
|
-
/**
|
|
80
|
-
* Check if the rate limiter is currently processing.
|
|
81
|
-
*
|
|
82
|
-
* @returns True if processing
|
|
83
|
-
*/
|
|
84
|
-
isProcessing(): boolean;
|
|
85
|
-
/**
|
|
86
|
-
* Get the number of requests made in the current window.
|
|
87
|
-
*
|
|
88
|
-
* @returns Request count in current window
|
|
89
|
-
*/
|
|
90
|
-
getRequestCountInWindow(): number;
|
|
91
|
-
/**
|
|
92
|
-
* Get the current configuration.
|
|
93
|
-
*
|
|
94
|
-
* @returns Rate limiter configuration
|
|
95
|
-
*/
|
|
96
|
-
getConfig(): RateLimiterConfig;
|
|
97
|
-
/**
|
|
98
|
-
* Reset internal state (for testing).
|
|
99
|
-
*/
|
|
100
|
-
reset(): void;
|
|
101
|
-
/**
|
|
102
|
-
* Process the queue: coalesce messages, enforce rate limit, execute with retry.
|
|
103
|
-
*
|
|
104
|
-
* @param handler - The actual API call handler
|
|
105
|
-
*/
|
|
106
|
-
private processQueue;
|
|
107
|
-
/**
|
|
108
|
-
* Wait until we have capacity in the rate limit window.
|
|
109
|
-
*/
|
|
110
|
-
private waitForCapacity;
|
|
111
|
-
/**
|
|
112
|
-
* Remove timestamps older than the current window.
|
|
113
|
-
*/
|
|
114
|
-
private pruneOldTimestamps;
|
|
115
|
-
/**
|
|
116
|
-
* Coalesce multiple queued messages into a single message.
|
|
117
|
-
*
|
|
118
|
-
* If there's only one message, it passes through unchanged.
|
|
119
|
-
* Multiple messages are joined with a separator and a header.
|
|
120
|
-
*
|
|
121
|
-
* @param batch - Array of queued messages to coalesce
|
|
122
|
-
* @returns Single coalesced message and metadata from the most recent item
|
|
123
|
-
*/
|
|
124
|
-
private coalesceMessages;
|
|
125
|
-
/**
|
|
126
|
-
* Execute the handler with exponential backoff retry on 429/quota errors.
|
|
127
|
-
*
|
|
128
|
-
* @param message - Message to send
|
|
129
|
-
* @param metadata - Optional metadata
|
|
130
|
-
* @param handler - The API call handler
|
|
131
|
-
* @returns Handler result
|
|
132
|
-
* @throws Error after max retries exhausted
|
|
133
|
-
*/
|
|
134
|
-
private executeWithRetry;
|
|
135
|
-
/**
|
|
136
|
-
* Check if an error is retryable (429 or quota-related).
|
|
137
|
-
*
|
|
138
|
-
* @param error - The error to check
|
|
139
|
-
* @returns True if the error should be retried
|
|
140
|
-
*/
|
|
141
|
-
private isRetryableError;
|
|
142
|
-
}
|
|
143
|
-
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAQnC,CAAC;AAkBF;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,WAAW,CAAC,CAAC;IACxB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAA8C;IAEnE;;;;OAIG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAI/C;;;;;;;;;;OAUG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC5C,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC1E,OAAO,CAAC,CAAC,CAAC;IA0Bb;;;;OAIG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;OAIG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,uBAAuB,IAAI,MAAM;IAKjC;;;;OAIG;IACH,SAAS,IAAI,iBAAiB;IAI9B;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;;;OAIG;YACW,YAAY;IAiD1B;;OAEG;YACW,eAAe;IAgB7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;;;;;;;OAQG;YACW,gBAAgB;IAqC9B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;CAUzB"}
|
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rate Limiter for Crewly Agent API Calls
|
|
3
|
-
*
|
|
4
|
-
* Provides token-bucket rate limiting, message coalescing, and 429 retry
|
|
5
|
-
* logic to prevent Gemini API quota exhaustion when multiple agents are
|
|
6
|
-
* actively generating messages.
|
|
7
|
-
*
|
|
8
|
-
* @module services/agent/crewly-agent/rate-limiter
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Default rate limiter configuration.
|
|
12
|
-
*/
|
|
13
|
-
export const RATE_LIMITER_DEFAULTS = {
|
|
14
|
-
maxRequestsPerWindow: 10,
|
|
15
|
-
windowMs: 60_000,
|
|
16
|
-
maxRetries: 3,
|
|
17
|
-
initialBackoffMs: 5_000,
|
|
18
|
-
backoffMultiplier: 2,
|
|
19
|
-
maxBackoffMs: 60_000,
|
|
20
|
-
coalesceWindowMs: 2_000,
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Token-bucket rate limiter with message coalescing and 429 retry.
|
|
24
|
-
*
|
|
25
|
-
* Features:
|
|
26
|
-
* - **Rate limiting**: Enforces max requests per time window using a sliding window.
|
|
27
|
-
* - **Message coalescing**: Groups messages arriving within a short window into one.
|
|
28
|
-
* - **429 retry**: Wraps API calls with exponential backoff on quota errors.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* const limiter = new RateLimiter<AgentRunResult>();
|
|
33
|
-
* const result = await limiter.enqueue('Check status', undefined, async (msg) => {
|
|
34
|
-
* return agentRunner.run(msg);
|
|
35
|
-
* });
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export class RateLimiter {
|
|
39
|
-
config;
|
|
40
|
-
requestTimestamps = [];
|
|
41
|
-
queue = [];
|
|
42
|
-
processing = false;
|
|
43
|
-
coalesceTimer = null;
|
|
44
|
-
/**
|
|
45
|
-
* Create a new RateLimiter instance.
|
|
46
|
-
*
|
|
47
|
-
* @param config - Optional partial config overrides
|
|
48
|
-
*/
|
|
49
|
-
constructor(config) {
|
|
50
|
-
this.config = { ...RATE_LIMITER_DEFAULTS, ...config };
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Enqueue a message for rate-limited processing.
|
|
54
|
-
*
|
|
55
|
-
* If multiple messages arrive within the coalescing window, they are
|
|
56
|
-
* merged into a single request to reduce API call count.
|
|
57
|
-
*
|
|
58
|
-
* @param message - Message to process
|
|
59
|
-
* @param metadata - Optional metadata
|
|
60
|
-
* @param handler - Async function that performs the actual API call
|
|
61
|
-
* @returns Result from the handler
|
|
62
|
-
*/
|
|
63
|
-
enqueue(message, metadata, handler) {
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
this.queue.push({
|
|
66
|
-
message,
|
|
67
|
-
metadata,
|
|
68
|
-
resolve,
|
|
69
|
-
reject,
|
|
70
|
-
enqueuedAt: Date.now(),
|
|
71
|
-
});
|
|
72
|
-
// Reset coalesce timer — wait for more messages before processing
|
|
73
|
-
if (this.coalesceTimer) {
|
|
74
|
-
clearTimeout(this.coalesceTimer);
|
|
75
|
-
}
|
|
76
|
-
this.coalesceTimer = setTimeout(() => {
|
|
77
|
-
this.coalesceTimer = null;
|
|
78
|
-
if (!this.processing) {
|
|
79
|
-
this.processQueue(handler).catch(() => {
|
|
80
|
-
// Errors are already routed to individual promise reject callbacks
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}, this.config.coalesceWindowMs);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Get the current number of messages in the queue.
|
|
88
|
-
*
|
|
89
|
-
* @returns Queue length
|
|
90
|
-
*/
|
|
91
|
-
getQueueLength() {
|
|
92
|
-
return this.queue.length;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Check if the rate limiter is currently processing.
|
|
96
|
-
*
|
|
97
|
-
* @returns True if processing
|
|
98
|
-
*/
|
|
99
|
-
isProcessing() {
|
|
100
|
-
return this.processing;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Get the number of requests made in the current window.
|
|
104
|
-
*
|
|
105
|
-
* @returns Request count in current window
|
|
106
|
-
*/
|
|
107
|
-
getRequestCountInWindow() {
|
|
108
|
-
this.pruneOldTimestamps();
|
|
109
|
-
return this.requestTimestamps.length;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Get the current configuration.
|
|
113
|
-
*
|
|
114
|
-
* @returns Rate limiter configuration
|
|
115
|
-
*/
|
|
116
|
-
getConfig() {
|
|
117
|
-
return { ...this.config };
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Reset internal state (for testing).
|
|
121
|
-
*/
|
|
122
|
-
reset() {
|
|
123
|
-
this.requestTimestamps = [];
|
|
124
|
-
this.queue = [];
|
|
125
|
-
this.processing = false;
|
|
126
|
-
if (this.coalesceTimer) {
|
|
127
|
-
clearTimeout(this.coalesceTimer);
|
|
128
|
-
this.coalesceTimer = null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Process the queue: coalesce messages, enforce rate limit, execute with retry.
|
|
133
|
-
*
|
|
134
|
-
* @param handler - The actual API call handler
|
|
135
|
-
*/
|
|
136
|
-
async processQueue(handler) {
|
|
137
|
-
this.processing = true;
|
|
138
|
-
try {
|
|
139
|
-
while (this.queue.length > 0) {
|
|
140
|
-
// Wait for rate limit window if needed
|
|
141
|
-
await this.waitForCapacity();
|
|
142
|
-
// Coalesce all pending messages into one
|
|
143
|
-
const batch = this.queue.splice(0, this.queue.length);
|
|
144
|
-
const coalesced = this.coalesceMessages(batch);
|
|
145
|
-
// Record this request timestamp
|
|
146
|
-
this.requestTimestamps.push(Date.now());
|
|
147
|
-
// Execute with 429 retry
|
|
148
|
-
try {
|
|
149
|
-
const result = await this.executeWithRetry(coalesced.message, coalesced.metadata, handler);
|
|
150
|
-
// Resolve all promises in the batch with the same result
|
|
151
|
-
for (const item of batch) {
|
|
152
|
-
item.resolve(result);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
// Reject all promises in the batch
|
|
157
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
158
|
-
for (const item of batch) {
|
|
159
|
-
item.reject(err);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
finally {
|
|
165
|
-
this.processing = false;
|
|
166
|
-
// Check if more messages arrived while processing
|
|
167
|
-
if (this.queue.length > 0) {
|
|
168
|
-
this.processQueue(handler).catch(() => {
|
|
169
|
-
// Errors are already routed to individual promise reject callbacks
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Wait until we have capacity in the rate limit window.
|
|
176
|
-
*/
|
|
177
|
-
async waitForCapacity() {
|
|
178
|
-
this.pruneOldTimestamps();
|
|
179
|
-
while (this.requestTimestamps.length >= this.config.maxRequestsPerWindow) {
|
|
180
|
-
// Calculate how long to wait until the oldest request falls out of the window
|
|
181
|
-
const oldestTimestamp = this.requestTimestamps[0];
|
|
182
|
-
const waitMs = (oldestTimestamp + this.config.windowMs) - Date.now() + 100; // +100ms buffer
|
|
183
|
-
if (waitMs > 0) {
|
|
184
|
-
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
185
|
-
}
|
|
186
|
-
this.pruneOldTimestamps();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Remove timestamps older than the current window.
|
|
191
|
-
*/
|
|
192
|
-
pruneOldTimestamps() {
|
|
193
|
-
const cutoff = Date.now() - this.config.windowMs;
|
|
194
|
-
this.requestTimestamps = this.requestTimestamps.filter((ts) => ts > cutoff);
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Coalesce multiple queued messages into a single message.
|
|
198
|
-
*
|
|
199
|
-
* If there's only one message, it passes through unchanged.
|
|
200
|
-
* Multiple messages are joined with a separator and a header.
|
|
201
|
-
*
|
|
202
|
-
* @param batch - Array of queued messages to coalesce
|
|
203
|
-
* @returns Single coalesced message and metadata from the most recent item
|
|
204
|
-
*/
|
|
205
|
-
coalesceMessages(batch) {
|
|
206
|
-
if (batch.length === 1) {
|
|
207
|
-
return { message: batch[0].message, metadata: batch[0].metadata };
|
|
208
|
-
}
|
|
209
|
-
// Use metadata from the most recent message
|
|
210
|
-
const latestMetadata = batch[batch.length - 1].metadata;
|
|
211
|
-
// Coalesce messages with a numbered separator
|
|
212
|
-
const parts = batch.map((item, index) => {
|
|
213
|
-
return `[Message ${index + 1}/${batch.length}]\n${item.message}`;
|
|
214
|
-
});
|
|
215
|
-
const coalesced = `${batch.length} messages received while rate-limited. Process them together:\n\n${parts.join('\n\n---\n\n')}`;
|
|
216
|
-
return { message: coalesced, metadata: latestMetadata };
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Execute the handler with exponential backoff retry on 429/quota errors.
|
|
220
|
-
*
|
|
221
|
-
* @param message - Message to send
|
|
222
|
-
* @param metadata - Optional metadata
|
|
223
|
-
* @param handler - The API call handler
|
|
224
|
-
* @returns Handler result
|
|
225
|
-
* @throws Error after max retries exhausted
|
|
226
|
-
*/
|
|
227
|
-
async executeWithRetry(message, metadata, handler) {
|
|
228
|
-
let lastError = null;
|
|
229
|
-
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
230
|
-
try {
|
|
231
|
-
return await handler(message, metadata);
|
|
232
|
-
}
|
|
233
|
-
catch (error) {
|
|
234
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
235
|
-
// Only retry on 429 / quota errors
|
|
236
|
-
if (!this.isRetryableError(lastError)) {
|
|
237
|
-
throw lastError;
|
|
238
|
-
}
|
|
239
|
-
if (attempt >= this.config.maxRetries) {
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
// Exponential backoff
|
|
243
|
-
const backoffMs = Math.min(this.config.initialBackoffMs * Math.pow(this.config.backoffMultiplier, attempt), this.config.maxBackoffMs);
|
|
244
|
-
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
throw new Error(`Rate limit retries exhausted (${this.config.maxRetries} attempts). Last error: ${lastError?.message}`);
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Check if an error is retryable (429 or quota-related).
|
|
251
|
-
*
|
|
252
|
-
* @param error - The error to check
|
|
253
|
-
* @returns True if the error should be retried
|
|
254
|
-
*/
|
|
255
|
-
isRetryableError(error) {
|
|
256
|
-
const message = error.message.toLowerCase();
|
|
257
|
-
return (message.includes('429') ||
|
|
258
|
-
message.includes('quota') ||
|
|
259
|
-
message.includes('rate limit') ||
|
|
260
|
-
message.includes('resource_exhausted') ||
|
|
261
|
-
message.includes('too many requests'));
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
//# sourceMappingURL=rate-limiter.js.map
|