ai.matey.middleware 0.2.0
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/dist/cjs/caching.js +226 -0
- package/dist/cjs/caching.js.map +1 -0
- package/dist/cjs/conversation-history.js +213 -0
- package/dist/cjs/conversation-history.js.map +1 -0
- package/dist/cjs/cost-tracking.js +355 -0
- package/dist/cjs/cost-tracking.js.map +1 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/logging.js +174 -0
- package/dist/cjs/logging.js.map +1 -0
- package/dist/cjs/opentelemetry.js +499 -0
- package/dist/cjs/opentelemetry.js.map +1 -0
- package/dist/cjs/retry.js +205 -0
- package/dist/cjs/retry.js.map +1 -0
- package/dist/cjs/security.js +175 -0
- package/dist/cjs/security.js.map +1 -0
- package/dist/cjs/telemetry.js +216 -0
- package/dist/cjs/telemetry.js.map +1 -0
- package/dist/cjs/transform.js +284 -0
- package/dist/cjs/transform.js.map +1 -0
- package/dist/cjs/validation.js +506 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/caching.js +221 -0
- package/dist/esm/caching.js.map +1 -0
- package/dist/esm/conversation-history.js +207 -0
- package/dist/esm/conversation-history.js.map +1 -0
- package/dist/esm/cost-tracking.js +347 -0
- package/dist/esm/cost-tracking.js.map +1 -0
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/logging.js +171 -0
- package/dist/esm/logging.js.map +1 -0
- package/dist/esm/opentelemetry.js +458 -0
- package/dist/esm/opentelemetry.js.map +1 -0
- package/dist/esm/retry.js +198 -0
- package/dist/esm/retry.js.map +1 -0
- package/dist/esm/security.js +169 -0
- package/dist/esm/security.js.map +1 -0
- package/dist/esm/telemetry.js +210 -0
- package/dist/esm/telemetry.js.map +1 -0
- package/dist/esm/transform.js +272 -0
- package/dist/esm/transform.js.map +1 -0
- package/dist/esm/validation.js +494 -0
- package/dist/esm/validation.js.map +1 -0
- package/dist/types/caching.d.ts +98 -0
- package/dist/types/caching.d.ts.map +1 -0
- package/dist/types/conversation-history.d.ts +188 -0
- package/dist/types/conversation-history.d.ts.map +1 -0
- package/dist/types/cost-tracking.d.ts +262 -0
- package/dist/types/cost-tracking.d.ts.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/logging.d.ts +82 -0
- package/dist/types/logging.d.ts.map +1 -0
- package/dist/types/opentelemetry.d.ts +219 -0
- package/dist/types/opentelemetry.d.ts.map +1 -0
- package/dist/types/retry.d.ts +86 -0
- package/dist/types/retry.d.ts.map +1 -0
- package/dist/types/security.d.ts +120 -0
- package/dist/types/security.d.ts.map +1 -0
- package/dist/types/telemetry.d.ts +120 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/dist/types/transform.d.ts +184 -0
- package/dist/types/transform.d.ts.map +1 -0
- package/dist/types/validation.d.ts +356 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/package.json +203 -0
- package/readme.md +103 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Middleware
|
|
3
|
+
*
|
|
4
|
+
* Adds security headers and implements security best practices for HTTP responses.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Default security configuration
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_SECURITY_CONFIG = {
|
|
12
|
+
contentSecurityPolicy: "default-src 'self'",
|
|
13
|
+
contentTypeOptions: 'nosniff',
|
|
14
|
+
frameOptions: 'DENY',
|
|
15
|
+
xssProtection: '1; mode=block',
|
|
16
|
+
hsts: 'max-age=31536000; includeSubDomains',
|
|
17
|
+
referrerPolicy: 'strict-origin-when-cross-origin',
|
|
18
|
+
permissionsPolicy: 'geolocation=(), microphone=(), camera=()',
|
|
19
|
+
poweredBy: false,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Create security headers middleware
|
|
23
|
+
*
|
|
24
|
+
* Adds security headers to responses to protect against common vulnerabilities.
|
|
25
|
+
*
|
|
26
|
+
* @param config - Security configuration
|
|
27
|
+
* @returns Middleware function
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { createSecurityMiddleware } from 'ai.matey';
|
|
32
|
+
*
|
|
33
|
+
* const security = createSecurityMiddleware({
|
|
34
|
+
* contentSecurityPolicy: "default-src 'self'",
|
|
35
|
+
* hsts: 'max-age=31536000',
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* bridge.use(security);
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example Production Configuration
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const productionSecurity = createSecurityMiddleware({
|
|
44
|
+
* contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
|
|
45
|
+
* frameOptions: 'DENY',
|
|
46
|
+
* hsts: 'max-age=31536000; includeSubDomains; preload',
|
|
47
|
+
* referrerPolicy: 'strict-origin-when-cross-origin',
|
|
48
|
+
* permissionsPolicy: 'geolocation=(), microphone=(), camera=(), payment=()',
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function createSecurityMiddleware(config = {}) {
|
|
53
|
+
const mergedConfig = {
|
|
54
|
+
...DEFAULT_SECURITY_CONFIG,
|
|
55
|
+
...config,
|
|
56
|
+
};
|
|
57
|
+
return async (context, next) => {
|
|
58
|
+
// Add security headers to request metadata (will be passed through to response)
|
|
59
|
+
// Note: In ai.matey, security headers should ideally be added at the HTTP layer
|
|
60
|
+
// This middleware just marks that security headers should be added
|
|
61
|
+
const custom = context.request.metadata?.custom || {};
|
|
62
|
+
const securityHeaders = {};
|
|
63
|
+
const headers = securityHeaders;
|
|
64
|
+
// Content Security Policy
|
|
65
|
+
if (mergedConfig.contentSecurityPolicy !== false) {
|
|
66
|
+
headers['Content-Security-Policy'] = mergedConfig.contentSecurityPolicy;
|
|
67
|
+
}
|
|
68
|
+
// X-Content-Type-Options
|
|
69
|
+
if (mergedConfig.contentTypeOptions !== false) {
|
|
70
|
+
headers['X-Content-Type-Options'] = mergedConfig.contentTypeOptions;
|
|
71
|
+
}
|
|
72
|
+
// X-Frame-Options
|
|
73
|
+
if (mergedConfig.frameOptions !== false) {
|
|
74
|
+
headers['X-Frame-Options'] = mergedConfig.frameOptions;
|
|
75
|
+
}
|
|
76
|
+
// X-XSS-Protection
|
|
77
|
+
if (mergedConfig.xssProtection !== false) {
|
|
78
|
+
headers['X-XSS-Protection'] = mergedConfig.xssProtection;
|
|
79
|
+
}
|
|
80
|
+
// Strict-Transport-Security
|
|
81
|
+
if (mergedConfig.hsts !== false) {
|
|
82
|
+
headers['Strict-Transport-Security'] = mergedConfig.hsts;
|
|
83
|
+
}
|
|
84
|
+
// Referrer-Policy
|
|
85
|
+
if (mergedConfig.referrerPolicy !== false) {
|
|
86
|
+
headers['Referrer-Policy'] = mergedConfig.referrerPolicy;
|
|
87
|
+
}
|
|
88
|
+
// Permissions-Policy
|
|
89
|
+
if (mergedConfig.permissionsPolicy !== false) {
|
|
90
|
+
headers['Permissions-Policy'] = mergedConfig.permissionsPolicy;
|
|
91
|
+
}
|
|
92
|
+
// Remove X-Powered-By (or set custom value)
|
|
93
|
+
if (mergedConfig.poweredBy === false) {
|
|
94
|
+
// Mark for removal
|
|
95
|
+
headers['X-Powered-By'] = '';
|
|
96
|
+
}
|
|
97
|
+
else if (mergedConfig.poweredBy) {
|
|
98
|
+
headers['X-Powered-By'] = mergedConfig.poweredBy;
|
|
99
|
+
}
|
|
100
|
+
// Add custom headers
|
|
101
|
+
if (config.customHeaders) {
|
|
102
|
+
Object.assign(headers, config.customHeaders);
|
|
103
|
+
}
|
|
104
|
+
// Store headers in custom metadata (HTTP layer should apply these)
|
|
105
|
+
const newCustom = {
|
|
106
|
+
...custom,
|
|
107
|
+
securityHeaders,
|
|
108
|
+
};
|
|
109
|
+
// Update request with security headers metadata
|
|
110
|
+
context.request = {
|
|
111
|
+
...context.request,
|
|
112
|
+
metadata: {
|
|
113
|
+
...context.request.metadata,
|
|
114
|
+
custom: newCustom,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
// Execute next middleware/backend
|
|
118
|
+
return await next();
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Create production-ready security middleware with strict settings
|
|
123
|
+
*
|
|
124
|
+
* @returns Middleware with production security settings
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* import { createProductionSecurityMiddleware } from 'ai.matey';
|
|
129
|
+
*
|
|
130
|
+
* bridge.use(createProductionSecurityMiddleware());
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function createProductionSecurityMiddleware() {
|
|
134
|
+
return createSecurityMiddleware({
|
|
135
|
+
contentSecurityPolicy: "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",
|
|
136
|
+
frameOptions: 'DENY',
|
|
137
|
+
hsts: 'max-age=31536000; includeSubDomains; preload',
|
|
138
|
+
xssProtection: '1; mode=block',
|
|
139
|
+
contentTypeOptions: 'nosniff',
|
|
140
|
+
referrerPolicy: 'strict-origin-when-cross-origin',
|
|
141
|
+
permissionsPolicy: 'geolocation=(), microphone=(), camera=(), payment=(), usb=()',
|
|
142
|
+
poweredBy: false,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create development-friendly security middleware with relaxed settings
|
|
147
|
+
*
|
|
148
|
+
* @returns Middleware with development security settings
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* import { createDevelopmentSecurityMiddleware } from 'ai.matey';
|
|
153
|
+
*
|
|
154
|
+
* bridge.use(createDevelopmentSecurityMiddleware());
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export function createDevelopmentSecurityMiddleware() {
|
|
158
|
+
return createSecurityMiddleware({
|
|
159
|
+
contentSecurityPolicy: false, // Disable for easier development
|
|
160
|
+
frameOptions: 'SAMEORIGIN',
|
|
161
|
+
hsts: false, // Don't enforce HTTPS in development
|
|
162
|
+
xssProtection: '1; mode=block',
|
|
163
|
+
contentTypeOptions: 'nosniff',
|
|
164
|
+
referrerPolicy: 'strict-origin-when-cross-origin',
|
|
165
|
+
permissionsPolicy: false,
|
|
166
|
+
poweredBy: false,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/security.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry Middleware
|
|
3
|
+
*
|
|
4
|
+
* Tracks metrics, events, and performance data for requests and responses.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Metric names.
|
|
10
|
+
*/
|
|
11
|
+
export const MetricNames = {
|
|
12
|
+
REQUEST_COUNT: 'ai.adapter.request.count',
|
|
13
|
+
REQUEST_DURATION: 'ai.adapter.request.duration',
|
|
14
|
+
REQUEST_ERROR: 'ai.adapter.request.error',
|
|
15
|
+
TOKEN_PROMPT: 'ai.adapter.tokens.prompt',
|
|
16
|
+
TOKEN_COMPLETION: 'ai.adapter.tokens.completion',
|
|
17
|
+
TOKEN_TOTAL: 'ai.adapter.tokens.total',
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Event names.
|
|
21
|
+
*/
|
|
22
|
+
export const EventNames = {
|
|
23
|
+
REQUEST_START: 'ai.adapter.request.start',
|
|
24
|
+
REQUEST_COMPLETE: 'ai.adapter.request.complete',
|
|
25
|
+
REQUEST_ERROR: 'ai.adapter.request.error',
|
|
26
|
+
};
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Sampling
|
|
29
|
+
// ============================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Determine if this request should be sampled.
|
|
32
|
+
*/
|
|
33
|
+
function shouldSample(sampleRate) {
|
|
34
|
+
return Math.random() < sampleRate;
|
|
35
|
+
}
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Middleware Factory
|
|
38
|
+
// ============================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Create telemetry middleware.
|
|
41
|
+
*
|
|
42
|
+
* Tracks metrics and events for monitoring and observability.
|
|
43
|
+
*
|
|
44
|
+
* @param config Telemetry configuration
|
|
45
|
+
* @returns Telemetry middleware
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const telemetry = createTelemetryMiddleware({
|
|
50
|
+
* sink: {
|
|
51
|
+
* recordMetric: (name, value, tags) => {
|
|
52
|
+
* console.log(`Metric: ${name} = ${value}`, tags);
|
|
53
|
+
* },
|
|
54
|
+
* recordEvent: (name, data) => {
|
|
55
|
+
* console.log(`Event: ${name}`, data);
|
|
56
|
+
* }
|
|
57
|
+
* },
|
|
58
|
+
* trackCounts: true,
|
|
59
|
+
* trackLatencies: true,
|
|
60
|
+
* trackTokens: true
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* bridge.use(telemetry);
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export function createTelemetryMiddleware(config) {
|
|
67
|
+
const { sink, trackCounts = true, trackLatencies = true, trackErrors = true, trackTokens = true, tags = {}, sampleRate = 1.0, } = config;
|
|
68
|
+
return async (context, next) => {
|
|
69
|
+
// Check if we should sample this request
|
|
70
|
+
const sampled = shouldSample(sampleRate);
|
|
71
|
+
const startTime = Date.now();
|
|
72
|
+
const requestId = context.request.metadata.requestId;
|
|
73
|
+
// Build base tags
|
|
74
|
+
const baseTags = {
|
|
75
|
+
...tags,
|
|
76
|
+
request_id: requestId,
|
|
77
|
+
model: context.request.parameters?.model ?? 'unknown',
|
|
78
|
+
stream: String(context.request.stream ?? false),
|
|
79
|
+
frontend: context.request.metadata.provenance?.frontend ?? 'unknown',
|
|
80
|
+
};
|
|
81
|
+
// Record request start event
|
|
82
|
+
if (sampled) {
|
|
83
|
+
sink.recordEvent(EventNames.REQUEST_START, {
|
|
84
|
+
requestId,
|
|
85
|
+
model: context.request.parameters?.model,
|
|
86
|
+
messageCount: context.request.messages.length,
|
|
87
|
+
stream: context.request.stream,
|
|
88
|
+
timestamp: startTime,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
// Call next middleware/handler
|
|
93
|
+
const response = await next();
|
|
94
|
+
const duration = Date.now() - startTime;
|
|
95
|
+
// Add backend to tags
|
|
96
|
+
const responseTags = {
|
|
97
|
+
...baseTags,
|
|
98
|
+
backend: response.metadata.provenance?.backend ?? 'unknown',
|
|
99
|
+
finish_reason: response.finishReason,
|
|
100
|
+
};
|
|
101
|
+
// Record metrics
|
|
102
|
+
if (sampled) {
|
|
103
|
+
// Track request count
|
|
104
|
+
if (trackCounts) {
|
|
105
|
+
sink.recordMetric(MetricNames.REQUEST_COUNT, 1, {
|
|
106
|
+
...responseTags,
|
|
107
|
+
status: 'success',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
// Track latency
|
|
111
|
+
if (trackLatencies) {
|
|
112
|
+
sink.recordMetric(MetricNames.REQUEST_DURATION, duration, responseTags);
|
|
113
|
+
}
|
|
114
|
+
// Track token usage
|
|
115
|
+
if (trackTokens && response.usage) {
|
|
116
|
+
if (response.usage.promptTokens) {
|
|
117
|
+
sink.recordMetric(MetricNames.TOKEN_PROMPT, response.usage.promptTokens, responseTags);
|
|
118
|
+
}
|
|
119
|
+
if (response.usage.completionTokens) {
|
|
120
|
+
sink.recordMetric(MetricNames.TOKEN_COMPLETION, response.usage.completionTokens, responseTags);
|
|
121
|
+
}
|
|
122
|
+
if (response.usage.totalTokens) {
|
|
123
|
+
sink.recordMetric(MetricNames.TOKEN_TOTAL, response.usage.totalTokens, responseTags);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Record completion event
|
|
127
|
+
sink.recordEvent(EventNames.REQUEST_COMPLETE, {
|
|
128
|
+
requestId,
|
|
129
|
+
duration,
|
|
130
|
+
backend: response.metadata.provenance?.backend,
|
|
131
|
+
finishReason: response.finishReason,
|
|
132
|
+
usage: response.usage,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return response;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const duration = Date.now() - startTime;
|
|
140
|
+
// Add error info to tags
|
|
141
|
+
const errorTags = {
|
|
142
|
+
...baseTags,
|
|
143
|
+
error_type: error instanceof Error ? error.name : 'unknown',
|
|
144
|
+
};
|
|
145
|
+
// Record error metrics
|
|
146
|
+
if (sampled) {
|
|
147
|
+
if (trackCounts) {
|
|
148
|
+
sink.recordMetric(MetricNames.REQUEST_COUNT, 1, {
|
|
149
|
+
...errorTags,
|
|
150
|
+
status: 'error',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (trackLatencies) {
|
|
154
|
+
sink.recordMetric(MetricNames.REQUEST_DURATION, duration, errorTags);
|
|
155
|
+
}
|
|
156
|
+
if (trackErrors) {
|
|
157
|
+
sink.recordMetric(MetricNames.REQUEST_ERROR, 1, errorTags);
|
|
158
|
+
}
|
|
159
|
+
// Record error event
|
|
160
|
+
sink.recordEvent(EventNames.REQUEST_ERROR, {
|
|
161
|
+
requestId,
|
|
162
|
+
duration,
|
|
163
|
+
error: error instanceof Error ? error.message : String(error),
|
|
164
|
+
errorType: error instanceof Error ? error.name : 'unknown',
|
|
165
|
+
timestamp: Date.now(),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// Re-throw error
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Built-in Sinks
|
|
175
|
+
// ============================================================================
|
|
176
|
+
/**
|
|
177
|
+
* Console telemetry sink for development/debugging.
|
|
178
|
+
*/
|
|
179
|
+
export class ConsoleTelemetrySink {
|
|
180
|
+
recordMetric(name, value, tags) {
|
|
181
|
+
console.warn('[Telemetry Metric]', { name, value, tags });
|
|
182
|
+
}
|
|
183
|
+
recordEvent(name, data) {
|
|
184
|
+
console.warn('[Telemetry Event]', { name, data });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* In-memory telemetry sink for testing.
|
|
189
|
+
*/
|
|
190
|
+
export class InMemoryTelemetrySink {
|
|
191
|
+
metrics = [];
|
|
192
|
+
events = [];
|
|
193
|
+
recordMetric(name, value, tags) {
|
|
194
|
+
this.metrics.push({ name, value, tags });
|
|
195
|
+
}
|
|
196
|
+
recordEvent(name, data) {
|
|
197
|
+
this.events.push({ name, data });
|
|
198
|
+
}
|
|
199
|
+
getMetrics() {
|
|
200
|
+
return [...this.metrics];
|
|
201
|
+
}
|
|
202
|
+
getEvents() {
|
|
203
|
+
return [...this.events];
|
|
204
|
+
}
|
|
205
|
+
clear() {
|
|
206
|
+
this.metrics = [];
|
|
207
|
+
this.events = [];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/telemetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform Middleware
|
|
3
|
+
*
|
|
4
|
+
* Transforms requests and responses with custom functions.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Middleware Factory
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Create transform middleware.
|
|
13
|
+
*
|
|
14
|
+
* Applies custom transformations to requests and responses.
|
|
15
|
+
*
|
|
16
|
+
* @param config Transform configuration
|
|
17
|
+
* @returns Transform middleware
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Add system message prefix
|
|
22
|
+
* const transform = createTransformMiddleware({
|
|
23
|
+
* transformRequest: (request) => ({
|
|
24
|
+
* ...request,
|
|
25
|
+
* messages: [
|
|
26
|
+
* { role: 'system', content: 'You are helpful.' },
|
|
27
|
+
* ...request.messages
|
|
28
|
+
* ]
|
|
29
|
+
* })
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* bridge.use(transform);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function createTransformMiddleware(config = {}) {
|
|
36
|
+
const { transformRequest, transformResponse, transformMessages } = config;
|
|
37
|
+
return async (context, next) => {
|
|
38
|
+
let request = context.request;
|
|
39
|
+
// Apply message transformations
|
|
40
|
+
if (transformMessages) {
|
|
41
|
+
const transformedMessages = await Promise.all(request.messages.map((msg) => Promise.resolve(transformMessages(msg))));
|
|
42
|
+
request = {
|
|
43
|
+
...request,
|
|
44
|
+
messages: transformedMessages,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Apply request transformation
|
|
48
|
+
if (transformRequest) {
|
|
49
|
+
request = await transformRequest(request);
|
|
50
|
+
}
|
|
51
|
+
// Update context with transformed request
|
|
52
|
+
context.request = request;
|
|
53
|
+
// Call next middleware/handler
|
|
54
|
+
let response = await next();
|
|
55
|
+
// Apply response transformation
|
|
56
|
+
if (transformResponse) {
|
|
57
|
+
response = await transformResponse(response);
|
|
58
|
+
}
|
|
59
|
+
return response;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Built-in Transformers
|
|
64
|
+
// ============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Create a prompt rewriting transformer.
|
|
67
|
+
*
|
|
68
|
+
* @param rewriter Function to rewrite prompt text
|
|
69
|
+
* @returns Message transformer
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const transformer = createPromptRewriter((text) => {
|
|
74
|
+
* return text.replace(/foo/g, 'bar');
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export function createPromptRewriter(rewriter) {
|
|
79
|
+
return async (message) => {
|
|
80
|
+
// Only transform text content
|
|
81
|
+
if (typeof message.content === 'string') {
|
|
82
|
+
return {
|
|
83
|
+
...message,
|
|
84
|
+
content: await rewriter(message.content),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Transform text in content blocks
|
|
88
|
+
if (Array.isArray(message.content)) {
|
|
89
|
+
const transformedContent = await Promise.all(message.content.map(async (block) => {
|
|
90
|
+
if (block.type === 'text') {
|
|
91
|
+
return {
|
|
92
|
+
...block,
|
|
93
|
+
text: await rewriter(block.text),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return block;
|
|
97
|
+
}));
|
|
98
|
+
return {
|
|
99
|
+
...message,
|
|
100
|
+
content: transformedContent,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return message;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create a parameter modifier transformer.
|
|
108
|
+
*
|
|
109
|
+
* @param modifier Function to modify parameters
|
|
110
|
+
* @returns Request transformer
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const transformer = createParameterModifier((params) => ({
|
|
115
|
+
* ...params,
|
|
116
|
+
* temperature: Math.min(params.temperature ?? 0.7, 0.9)
|
|
117
|
+
* }));
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export function createParameterModifier(modifier) {
|
|
121
|
+
return async (request) => {
|
|
122
|
+
return {
|
|
123
|
+
...request,
|
|
124
|
+
parameters: await modifier(request.parameters),
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create a response filter transformer.
|
|
130
|
+
*
|
|
131
|
+
* @param filter Function to filter/modify response
|
|
132
|
+
* @returns Response transformer
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* const transformer = createResponseFilter((response) => {
|
|
137
|
+
* // Remove custom metadata
|
|
138
|
+
* const { custom, ...metadata } = response.metadata;
|
|
139
|
+
* return { ...response, metadata };
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export function createResponseFilter(filter) {
|
|
144
|
+
return filter;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Create a system message injector.
|
|
148
|
+
*
|
|
149
|
+
* @param systemMessage System message to inject
|
|
150
|
+
* @param position Where to inject ('start' or 'end')
|
|
151
|
+
* @returns Request transformer
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const transformer = createSystemMessageInjector(
|
|
156
|
+
* 'You are a helpful assistant.',
|
|
157
|
+
* 'start'
|
|
158
|
+
* );
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export function createSystemMessageInjector(systemMessage, position = 'start') {
|
|
162
|
+
return (request) => {
|
|
163
|
+
const systemMsg = {
|
|
164
|
+
role: 'system',
|
|
165
|
+
content: systemMessage,
|
|
166
|
+
};
|
|
167
|
+
const messages = position === 'start' ? [systemMsg, ...request.messages] : [...request.messages, systemMsg];
|
|
168
|
+
return {
|
|
169
|
+
...request,
|
|
170
|
+
messages,
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a message filter transformer.
|
|
176
|
+
*
|
|
177
|
+
* @param predicate Function to determine if message should be kept
|
|
178
|
+
* @returns Request transformer
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* // Remove all system messages
|
|
183
|
+
* const transformer = createMessageFilter(
|
|
184
|
+
* (msg) => msg.role !== 'system'
|
|
185
|
+
* );
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export function createMessageFilter(predicate) {
|
|
189
|
+
return async (request) => {
|
|
190
|
+
const filteredMessages = [];
|
|
191
|
+
for (const message of request.messages) {
|
|
192
|
+
if (await predicate(message)) {
|
|
193
|
+
filteredMessages.push(message);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
...request,
|
|
198
|
+
messages: filteredMessages,
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Create a content sanitizer transformer.
|
|
204
|
+
*
|
|
205
|
+
* @param sanitizer Function to sanitize message content
|
|
206
|
+
* @returns Message transformer
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* // Remove sensitive data
|
|
211
|
+
* const transformer = createContentSanitizer((text) => {
|
|
212
|
+
* return text.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]');
|
|
213
|
+
* });
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export function createContentSanitizer(sanitizer) {
|
|
217
|
+
return createPromptRewriter(sanitizer);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Compose multiple request transformers.
|
|
221
|
+
*
|
|
222
|
+
* @param transformers Request transformers to compose
|
|
223
|
+
* @returns Composed request transformer
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```typescript
|
|
227
|
+
* const composed = composeRequestTransformers(
|
|
228
|
+
* createSystemMessageInjector('Be helpful'),
|
|
229
|
+
* createParameterModifier(params => ({ ...params, temperature: 0.7 }))
|
|
230
|
+
* );
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export function composeRequestTransformers(...transformers) {
|
|
234
|
+
return async (request) => {
|
|
235
|
+
let result = request;
|
|
236
|
+
for (const transformer of transformers) {
|
|
237
|
+
result = await transformer(result);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Compose multiple response transformers.
|
|
244
|
+
*
|
|
245
|
+
* @param transformers Response transformers to compose
|
|
246
|
+
* @returns Composed response transformer
|
|
247
|
+
*/
|
|
248
|
+
export function composeResponseTransformers(...transformers) {
|
|
249
|
+
return async (response) => {
|
|
250
|
+
let result = response;
|
|
251
|
+
for (const transformer of transformers) {
|
|
252
|
+
result = await transformer(result);
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Compose multiple message transformers.
|
|
259
|
+
*
|
|
260
|
+
* @param transformers Message transformers to compose
|
|
261
|
+
* @returns Composed message transformer
|
|
262
|
+
*/
|
|
263
|
+
export function composeMessageTransformers(...transformers) {
|
|
264
|
+
return async (message) => {
|
|
265
|
+
let result = message;
|
|
266
|
+
for (const transformer of transformers) {
|
|
267
|
+
result = await transformer(result);
|
|
268
|
+
}
|
|
269
|
+
return result;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/transform.ts"],"names":[],"mappings":"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"}
|