@riotprompt/riotprompt 0.0.21 → 1.0.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/CHANGELOG.md +74 -0
- package/MIGRATION.md +235 -0
- package/README.md +2 -0
- package/SECURITY.md +132 -0
- package/dist/builder.js +6 -0
- package/dist/builder.js.map +1 -1
- package/dist/cli.js +481 -22
- package/dist/context-manager.js +1 -1
- package/dist/conversation-logger.d.ts +17 -1
- package/dist/conversation-logger.js +21 -17
- package/dist/conversation-logger.js.map +1 -1
- package/dist/conversation.js +1 -1
- package/dist/error-handling.d.ts +52 -0
- package/dist/error-handling.js +132 -0
- package/dist/error-handling.js.map +1 -0
- package/dist/formatter.js +1 -1
- package/dist/iteration-strategy.js +1 -1
- package/dist/loader.js +60 -12
- package/dist/loader.js.map +1 -1
- package/dist/logger.d.ts +52 -0
- package/dist/logger.js +114 -14
- package/dist/logger.js.map +1 -1
- package/dist/logging-config.d.ts +84 -0
- package/dist/logging-config.js +116 -0
- package/dist/logging-config.js.map +1 -0
- package/dist/message-builder.js +1 -1
- package/dist/model-config.js +1 -1
- package/dist/override.js +10 -4
- package/dist/override.js.map +1 -1
- package/dist/recipes.js +6 -0
- package/dist/recipes.js.map +1 -1
- package/dist/reflection.js +1 -1
- package/dist/riotprompt.d.ts +9 -0
- package/dist/riotprompt.js +8 -0
- package/dist/riotprompt.js.map +1 -1
- package/dist/security/audit-logger.d.ts +61 -0
- package/dist/security/audit-logger.js +281 -0
- package/dist/security/audit-logger.js.map +1 -0
- package/dist/security/cli-security.d.ts +143 -0
- package/dist/security/cli-security.js +302 -0
- package/dist/security/cli-security.js.map +1 -0
- package/dist/security/defaults.d.ts +31 -0
- package/dist/security/defaults.js +72 -0
- package/dist/security/defaults.js.map +1 -0
- package/dist/security/events.d.ts +8 -0
- package/dist/security/index.d.ts +27 -0
- package/dist/security/index.js +22 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/path-guard.d.ts +161 -0
- package/dist/security/path-guard.js +327 -0
- package/dist/security/path-guard.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +117 -0
- package/dist/security/rate-limiter.js +165 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/serialization-schemas.d.ts +183 -0
- package/dist/security/serialization-schemas.js +174 -0
- package/dist/security/serialization-schemas.js.map +1 -0
- package/dist/security/timeout-guard.d.ts +123 -0
- package/dist/security/timeout-guard.js +223 -0
- package/dist/security/timeout-guard.js.map +1 -0
- package/dist/security/types.d.ts +86 -0
- package/dist/security/types.js +80 -0
- package/dist/security/types.js.map +1 -0
- package/dist/token-budget.js +1 -1
- package/dist/tools.js +1 -1
- package/guide/index.md +2 -0
- package/guide/integration.md +1109 -0
- package/guide/security.md +237 -0
- package/package.json +17 -11
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter Interfaces
|
|
3
|
+
*
|
|
4
|
+
* Provides interfaces and basic implementations for rate limiting.
|
|
5
|
+
* Production applications should use dedicated rate limiting libraries
|
|
6
|
+
* (e.g., rate-limiter-flexible, express-rate-limit) for distributed systems.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Rate limiter interface
|
|
12
|
+
* Implementation is left to users (use your preferred library)
|
|
13
|
+
*/
|
|
14
|
+
export interface RateLimiter {
|
|
15
|
+
/**
|
|
16
|
+
* Check if request is allowed
|
|
17
|
+
* @param key - Unique identifier for the rate limit bucket (e.g., user ID, IP)
|
|
18
|
+
* @returns true if allowed, false if rate limited
|
|
19
|
+
*/
|
|
20
|
+
check(key: string): Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* Get remaining requests in the current window
|
|
23
|
+
* @param key - Unique identifier for the rate limit bucket
|
|
24
|
+
* @returns Number of remaining requests
|
|
25
|
+
*/
|
|
26
|
+
remaining(key: string): Promise<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Reset rate limit for a key
|
|
29
|
+
* @param key - Unique identifier for the rate limit bucket
|
|
30
|
+
*/
|
|
31
|
+
reset(key: string): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Rate limiter configuration
|
|
35
|
+
*/
|
|
36
|
+
export interface RateLimiterConfig {
|
|
37
|
+
/** Time window in milliseconds */
|
|
38
|
+
windowMs: number;
|
|
39
|
+
/** Maximum requests allowed in the window */
|
|
40
|
+
maxRequests: number;
|
|
41
|
+
/** Optional function to generate keys from context */
|
|
42
|
+
keyGenerator?: (context: unknown) => string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* No-op rate limiter that always allows requests
|
|
46
|
+
* Use this as a default when rate limiting is not needed
|
|
47
|
+
*/
|
|
48
|
+
export declare class NoOpRateLimiter implements RateLimiter {
|
|
49
|
+
check(_key: string): Promise<boolean>;
|
|
50
|
+
remaining(_key: string): Promise<number>;
|
|
51
|
+
reset(_key: string): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Simple in-memory rate limiter
|
|
55
|
+
*
|
|
56
|
+
* **Warning**: This implementation is NOT suitable for production use in
|
|
57
|
+
* distributed systems. Use a Redis-backed solution for production.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const limiter = new MemoryRateLimiter({
|
|
62
|
+
* windowMs: 60000, // 1 minute
|
|
63
|
+
* maxRequests: 100, // 100 requests per minute
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* if (await limiter.check('user-123')) {
|
|
67
|
+
* // Process request
|
|
68
|
+
* } else {
|
|
69
|
+
* // Rate limited
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare class MemoryRateLimiter implements RateLimiter {
|
|
74
|
+
private requests;
|
|
75
|
+
private config;
|
|
76
|
+
private cleanupInterval;
|
|
77
|
+
constructor(config: RateLimiterConfig);
|
|
78
|
+
check(key: string): Promise<boolean>;
|
|
79
|
+
remaining(key: string): Promise<number>;
|
|
80
|
+
reset(key: string): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Clean up expired entries to prevent memory leaks
|
|
83
|
+
*/
|
|
84
|
+
private cleanup;
|
|
85
|
+
/**
|
|
86
|
+
* Stop the cleanup interval (call when done with the limiter)
|
|
87
|
+
*/
|
|
88
|
+
destroy(): void;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Create a rate limiter with the given configuration
|
|
92
|
+
*
|
|
93
|
+
* @param config - Rate limiter configuration
|
|
94
|
+
* @returns Rate limiter instance
|
|
95
|
+
*/
|
|
96
|
+
export declare function createRateLimiter(config: RateLimiterConfig): RateLimiter;
|
|
97
|
+
/**
|
|
98
|
+
* Create a no-op rate limiter that always allows requests
|
|
99
|
+
*
|
|
100
|
+
* @returns No-op rate limiter instance
|
|
101
|
+
*/
|
|
102
|
+
export declare function createNoOpRateLimiter(): RateLimiter;
|
|
103
|
+
/**
|
|
104
|
+
* Get the global rate limiter instance
|
|
105
|
+
* Returns a no-op limiter if not configured
|
|
106
|
+
*/
|
|
107
|
+
export declare function getRateLimiter(): RateLimiter;
|
|
108
|
+
/**
|
|
109
|
+
* Configure the global rate limiter
|
|
110
|
+
*
|
|
111
|
+
* @param config - Rate limiter configuration
|
|
112
|
+
*/
|
|
113
|
+
export declare function configureRateLimiter(config: RateLimiterConfig): void;
|
|
114
|
+
/**
|
|
115
|
+
* Reset the global rate limiter to the default no-op implementation
|
|
116
|
+
*/
|
|
117
|
+
export declare function resetRateLimiter(): void;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter Interfaces
|
|
3
|
+
*
|
|
4
|
+
* Provides interfaces and basic implementations for rate limiting.
|
|
5
|
+
* Production applications should use dedicated rate limiting libraries
|
|
6
|
+
* (e.g., rate-limiter-flexible, express-rate-limit) for distributed systems.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/ /**
|
|
10
|
+
* Rate limiter interface
|
|
11
|
+
* Implementation is left to users (use your preferred library)
|
|
12
|
+
*/ function _define_property(obj, key, value) {
|
|
13
|
+
if (key in obj) {
|
|
14
|
+
Object.defineProperty(obj, key, {
|
|
15
|
+
value: value,
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
obj[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* No-op rate limiter that always allows requests
|
|
27
|
+
* Use this as a default when rate limiting is not needed
|
|
28
|
+
*/ class NoOpRateLimiter {
|
|
29
|
+
async check(_key) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
async remaining(_key) {
|
|
33
|
+
return Number.MAX_SAFE_INTEGER;
|
|
34
|
+
}
|
|
35
|
+
async reset(_key) {
|
|
36
|
+
// No-op
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Simple in-memory rate limiter
|
|
41
|
+
*
|
|
42
|
+
* **Warning**: This implementation is NOT suitable for production use in
|
|
43
|
+
* distributed systems. Use a Redis-backed solution for production.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const limiter = new MemoryRateLimiter({
|
|
48
|
+
* windowMs: 60000, // 1 minute
|
|
49
|
+
* maxRequests: 100, // 100 requests per minute
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* if (await limiter.check('user-123')) {
|
|
53
|
+
* // Process request
|
|
54
|
+
* } else {
|
|
55
|
+
* // Rate limited
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/ class MemoryRateLimiter {
|
|
59
|
+
async check(key) {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
const record = this.requests.get(key);
|
|
62
|
+
// No record or expired - create new window
|
|
63
|
+
if (!record || record.resetAt < now) {
|
|
64
|
+
this.requests.set(key, {
|
|
65
|
+
count: 1,
|
|
66
|
+
resetAt: now + this.config.windowMs
|
|
67
|
+
});
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
// Check if limit exceeded
|
|
71
|
+
if (record.count >= this.config.maxRequests) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// Increment count
|
|
75
|
+
record.count++;
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
async remaining(key) {
|
|
79
|
+
const record = this.requests.get(key);
|
|
80
|
+
if (!record || record.resetAt < Date.now()) {
|
|
81
|
+
return this.config.maxRequests;
|
|
82
|
+
}
|
|
83
|
+
return Math.max(0, this.config.maxRequests - record.count);
|
|
84
|
+
}
|
|
85
|
+
async reset(key) {
|
|
86
|
+
this.requests.delete(key);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Clean up expired entries to prevent memory leaks
|
|
90
|
+
*/ cleanup() {
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
for (const [key, record] of this.requests.entries()){
|
|
93
|
+
if (record.resetAt < now) {
|
|
94
|
+
this.requests.delete(key);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Stop the cleanup interval (call when done with the limiter)
|
|
100
|
+
*/ destroy() {
|
|
101
|
+
if (this.cleanupInterval) {
|
|
102
|
+
clearInterval(this.cleanupInterval);
|
|
103
|
+
this.cleanupInterval = null;
|
|
104
|
+
}
|
|
105
|
+
this.requests.clear();
|
|
106
|
+
}
|
|
107
|
+
constructor(config){
|
|
108
|
+
_define_property(this, "requests", new Map());
|
|
109
|
+
_define_property(this, "config", void 0);
|
|
110
|
+
_define_property(this, "cleanupInterval", null);
|
|
111
|
+
this.config = config;
|
|
112
|
+
// Periodically clean up expired entries
|
|
113
|
+
this.cleanupInterval = setInterval(()=>{
|
|
114
|
+
this.cleanup();
|
|
115
|
+
}, config.windowMs);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create a rate limiter with the given configuration
|
|
120
|
+
*
|
|
121
|
+
* @param config - Rate limiter configuration
|
|
122
|
+
* @returns Rate limiter instance
|
|
123
|
+
*/ function createRateLimiter(config) {
|
|
124
|
+
return new MemoryRateLimiter(config);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Create a no-op rate limiter that always allows requests
|
|
128
|
+
*
|
|
129
|
+
* @returns No-op rate limiter instance
|
|
130
|
+
*/ function createNoOpRateLimiter() {
|
|
131
|
+
return new NoOpRateLimiter();
|
|
132
|
+
}
|
|
133
|
+
// Global rate limiter instance
|
|
134
|
+
let globalRateLimiter = null;
|
|
135
|
+
/**
|
|
136
|
+
* Get the global rate limiter instance
|
|
137
|
+
* Returns a no-op limiter if not configured
|
|
138
|
+
*/ function getRateLimiter() {
|
|
139
|
+
if (!globalRateLimiter) {
|
|
140
|
+
globalRateLimiter = new NoOpRateLimiter();
|
|
141
|
+
}
|
|
142
|
+
return globalRateLimiter;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Configure the global rate limiter
|
|
146
|
+
*
|
|
147
|
+
* @param config - Rate limiter configuration
|
|
148
|
+
*/ function configureRateLimiter(config) {
|
|
149
|
+
// Clean up existing limiter if it's a MemoryRateLimiter
|
|
150
|
+
if (globalRateLimiter instanceof MemoryRateLimiter) {
|
|
151
|
+
globalRateLimiter.destroy();
|
|
152
|
+
}
|
|
153
|
+
globalRateLimiter = new MemoryRateLimiter(config);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Reset the global rate limiter to the default no-op implementation
|
|
157
|
+
*/ function resetRateLimiter() {
|
|
158
|
+
if (globalRateLimiter instanceof MemoryRateLimiter) {
|
|
159
|
+
globalRateLimiter.destroy();
|
|
160
|
+
}
|
|
161
|
+
globalRateLimiter = null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { MemoryRateLimiter, NoOpRateLimiter, configureRateLimiter, createNoOpRateLimiter, createRateLimiter, getRateLimiter, resetRateLimiter };
|
|
165
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sources":["../../src/security/rate-limiter.ts"],"sourcesContent":["/**\n * Rate Limiter Interfaces\n * \n * Provides interfaces and basic implementations for rate limiting.\n * Production applications should use dedicated rate limiting libraries\n * (e.g., rate-limiter-flexible, express-rate-limit) for distributed systems.\n * \n * @packageDocumentation\n */\n\n/**\n * Rate limiter interface\n * Implementation is left to users (use your preferred library)\n */\nexport interface RateLimiter {\n /**\n * Check if request is allowed\n * @param key - Unique identifier for the rate limit bucket (e.g., user ID, IP)\n * @returns true if allowed, false if rate limited\n */\n check(key: string): Promise<boolean>;\n\n /**\n * Get remaining requests in the current window\n * @param key - Unique identifier for the rate limit bucket\n * @returns Number of remaining requests\n */\n remaining(key: string): Promise<number>;\n\n /**\n * Reset rate limit for a key\n * @param key - Unique identifier for the rate limit bucket\n */\n reset(key: string): Promise<void>;\n}\n\n/**\n * Rate limiter configuration\n */\nexport interface RateLimiterConfig {\n /** Time window in milliseconds */\n windowMs: number;\n /** Maximum requests allowed in the window */\n maxRequests: number;\n /** Optional function to generate keys from context */\n keyGenerator?: (context: unknown) => string;\n}\n\n/**\n * No-op rate limiter that always allows requests\n * Use this as a default when rate limiting is not needed\n */\nexport class NoOpRateLimiter implements RateLimiter {\n async check(_key: string): Promise<boolean> {\n return true;\n }\n\n async remaining(_key: string): Promise<number> {\n return Number.MAX_SAFE_INTEGER;\n }\n\n async reset(_key: string): Promise<void> {\n // No-op\n }\n}\n\ninterface RateLimitRecord {\n count: number;\n resetAt: number;\n}\n\n/**\n * Simple in-memory rate limiter\n * \n * **Warning**: This implementation is NOT suitable for production use in\n * distributed systems. Use a Redis-backed solution for production.\n * \n * @example\n * ```typescript\n * const limiter = new MemoryRateLimiter({\n * windowMs: 60000, // 1 minute\n * maxRequests: 100, // 100 requests per minute\n * });\n * \n * if (await limiter.check('user-123')) {\n * // Process request\n * } else {\n * // Rate limited\n * }\n * ```\n */\nexport class MemoryRateLimiter implements RateLimiter {\n private requests: Map<string, RateLimitRecord> = new Map();\n private config: RateLimiterConfig;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(config: RateLimiterConfig) {\n this.config = config;\n \n // Periodically clean up expired entries\n this.cleanupInterval = setInterval(() => {\n this.cleanup();\n }, config.windowMs);\n }\n\n async check(key: string): Promise<boolean> {\n const now = Date.now();\n const record = this.requests.get(key);\n\n // No record or expired - create new window\n if (!record || record.resetAt < now) {\n this.requests.set(key, { count: 1, resetAt: now + this.config.windowMs });\n return true;\n }\n\n // Check if limit exceeded\n if (record.count >= this.config.maxRequests) {\n return false;\n }\n\n // Increment count\n record.count++;\n return true;\n }\n\n async remaining(key: string): Promise<number> {\n const record = this.requests.get(key);\n if (!record || record.resetAt < Date.now()) {\n return this.config.maxRequests;\n }\n return Math.max(0, this.config.maxRequests - record.count);\n }\n\n async reset(key: string): Promise<void> {\n this.requests.delete(key);\n }\n\n /**\n * Clean up expired entries to prevent memory leaks\n */\n private cleanup(): void {\n const now = Date.now();\n for (const [key, record] of this.requests.entries()) {\n if (record.resetAt < now) {\n this.requests.delete(key);\n }\n }\n }\n\n /**\n * Stop the cleanup interval (call when done with the limiter)\n */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n this.requests.clear();\n }\n}\n\n/**\n * Create a rate limiter with the given configuration\n * \n * @param config - Rate limiter configuration\n * @returns Rate limiter instance\n */\nexport function createRateLimiter(config: RateLimiterConfig): RateLimiter {\n return new MemoryRateLimiter(config);\n}\n\n/**\n * Create a no-op rate limiter that always allows requests\n * \n * @returns No-op rate limiter instance\n */\nexport function createNoOpRateLimiter(): RateLimiter {\n return new NoOpRateLimiter();\n}\n\n// Global rate limiter instance\nlet globalRateLimiter: RateLimiter | null = null;\n\n/**\n * Get the global rate limiter instance\n * Returns a no-op limiter if not configured\n */\nexport function getRateLimiter(): RateLimiter {\n if (!globalRateLimiter) {\n globalRateLimiter = new NoOpRateLimiter();\n }\n return globalRateLimiter;\n}\n\n/**\n * Configure the global rate limiter\n * \n * @param config - Rate limiter configuration\n */\nexport function configureRateLimiter(config: RateLimiterConfig): void {\n // Clean up existing limiter if it's a MemoryRateLimiter\n if (globalRateLimiter instanceof MemoryRateLimiter) {\n globalRateLimiter.destroy();\n }\n globalRateLimiter = new MemoryRateLimiter(config);\n}\n\n/**\n * Reset the global rate limiter to the default no-op implementation\n */\nexport function resetRateLimiter(): void {\n if (globalRateLimiter instanceof MemoryRateLimiter) {\n globalRateLimiter.destroy();\n }\n globalRateLimiter = null;\n}\n\n"],"names":["NoOpRateLimiter","check","_key","remaining","Number","MAX_SAFE_INTEGER","reset","MemoryRateLimiter","key","now","Date","record","requests","get","resetAt","set","count","config","windowMs","maxRequests","Math","max","delete","cleanup","entries","destroy","cleanupInterval","clearInterval","clear","Map","setInterval","createRateLimiter","createNoOpRateLimiter","globalRateLimiter","getRateLimiter","configureRateLimiter","resetRateLimiter"],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Schema version for forward compatibility
|
|
4
|
+
*/
|
|
5
|
+
export declare const SCHEMA_VERSION = "1.0.0";
|
|
6
|
+
/**
|
|
7
|
+
* Maximum sizes for serialized data
|
|
8
|
+
*/
|
|
9
|
+
export declare const SERIALIZATION_LIMITS: {
|
|
10
|
+
maxContentLength: number;
|
|
11
|
+
maxArgumentsLength: number;
|
|
12
|
+
maxMessages: number;
|
|
13
|
+
maxContextItems: number;
|
|
14
|
+
maxStringLength: number;
|
|
15
|
+
maxToolCalls: number;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Tool call schema
|
|
19
|
+
*/
|
|
20
|
+
export declare const ToolCallSchema: z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
type: z.ZodLiteral<"function">;
|
|
23
|
+
function: z.ZodObject<{
|
|
24
|
+
name: z.ZodString;
|
|
25
|
+
arguments: z.ZodString;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
export type ToolCall = z.infer<typeof ToolCallSchema>;
|
|
29
|
+
/**
|
|
30
|
+
* Conversation message schema
|
|
31
|
+
*/
|
|
32
|
+
export declare const ConversationMessageSchema: z.ZodObject<{
|
|
33
|
+
role: z.ZodEnum<{
|
|
34
|
+
system: "system";
|
|
35
|
+
user: "user";
|
|
36
|
+
assistant: "assistant";
|
|
37
|
+
tool: "tool";
|
|
38
|
+
}>;
|
|
39
|
+
content: z.ZodNullable<z.ZodString>;
|
|
40
|
+
name: z.ZodOptional<z.ZodString>;
|
|
41
|
+
tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
42
|
+
id: z.ZodString;
|
|
43
|
+
type: z.ZodLiteral<"function">;
|
|
44
|
+
function: z.ZodObject<{
|
|
45
|
+
name: z.ZodString;
|
|
46
|
+
arguments: z.ZodString;
|
|
47
|
+
}, z.core.$strip>;
|
|
48
|
+
}, z.core.$strip>>>;
|
|
49
|
+
tool_call_id: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
export type ConversationMessage = z.infer<typeof ConversationMessageSchema>;
|
|
52
|
+
/**
|
|
53
|
+
* Conversation metadata schema
|
|
54
|
+
*/
|
|
55
|
+
export declare const ConversationMetadataSchema: z.ZodObject<{
|
|
56
|
+
model: z.ZodString;
|
|
57
|
+
created: z.ZodString;
|
|
58
|
+
lastModified: z.ZodString;
|
|
59
|
+
messageCount: z.ZodNumber;
|
|
60
|
+
toolCallCount: z.ZodNumber;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
export type ConversationMetadata = z.infer<typeof ConversationMetadataSchema>;
|
|
63
|
+
/**
|
|
64
|
+
* Serialized conversation schema
|
|
65
|
+
*/
|
|
66
|
+
export declare const SerializedConversationSchema: z.ZodObject<{
|
|
67
|
+
version: z.ZodOptional<z.ZodString>;
|
|
68
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
69
|
+
role: z.ZodEnum<{
|
|
70
|
+
system: "system";
|
|
71
|
+
user: "user";
|
|
72
|
+
assistant: "assistant";
|
|
73
|
+
tool: "tool";
|
|
74
|
+
}>;
|
|
75
|
+
content: z.ZodNullable<z.ZodString>;
|
|
76
|
+
name: z.ZodOptional<z.ZodString>;
|
|
77
|
+
tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
78
|
+
id: z.ZodString;
|
|
79
|
+
type: z.ZodLiteral<"function">;
|
|
80
|
+
function: z.ZodObject<{
|
|
81
|
+
name: z.ZodString;
|
|
82
|
+
arguments: z.ZodString;
|
|
83
|
+
}, z.core.$strip>;
|
|
84
|
+
}, z.core.$strip>>>;
|
|
85
|
+
tool_call_id: z.ZodOptional<z.ZodString>;
|
|
86
|
+
}, z.core.$strip>>;
|
|
87
|
+
metadata: z.ZodObject<{
|
|
88
|
+
model: z.ZodString;
|
|
89
|
+
created: z.ZodString;
|
|
90
|
+
lastModified: z.ZodString;
|
|
91
|
+
messageCount: z.ZodNumber;
|
|
92
|
+
toolCallCount: z.ZodNumber;
|
|
93
|
+
}, z.core.$strip>;
|
|
94
|
+
contextProvided: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
export type SerializedConversation = z.infer<typeof SerializedConversationSchema>;
|
|
97
|
+
/**
|
|
98
|
+
* Prompt serialization schema (flexible for various prompt structures)
|
|
99
|
+
*/
|
|
100
|
+
export declare const SerializedPromptSchema: z.ZodObject<{
|
|
101
|
+
version: z.ZodOptional<z.ZodString>;
|
|
102
|
+
persona: z.ZodOptional<z.ZodAny>;
|
|
103
|
+
instructions: z.ZodOptional<z.ZodAny>;
|
|
104
|
+
contexts: z.ZodOptional<z.ZodAny>;
|
|
105
|
+
content: z.ZodOptional<z.ZodAny>;
|
|
106
|
+
}, z.core.$strip>;
|
|
107
|
+
export type SerializedPrompt = z.infer<typeof SerializedPromptSchema>;
|
|
108
|
+
/**
|
|
109
|
+
* Logged conversation schema (for conversation-logger)
|
|
110
|
+
*/
|
|
111
|
+
export declare const LoggedConversationSchema: z.ZodObject<{
|
|
112
|
+
id: z.ZodString;
|
|
113
|
+
metadata: z.ZodObject<{
|
|
114
|
+
startTime: z.ZodUnion<readonly [z.ZodString, z.ZodDate]>;
|
|
115
|
+
endTime: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDate]>>;
|
|
116
|
+
duration: z.ZodOptional<z.ZodNumber>;
|
|
117
|
+
model: z.ZodString;
|
|
118
|
+
template: z.ZodOptional<z.ZodString>;
|
|
119
|
+
userContext: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
120
|
+
}, z.core.$strip>;
|
|
121
|
+
prompt: z.ZodOptional<z.ZodObject<{
|
|
122
|
+
persona: z.ZodOptional<z.ZodString>;
|
|
123
|
+
instructions: z.ZodOptional<z.ZodString>;
|
|
124
|
+
content: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
125
|
+
context: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
126
|
+
}, z.core.$strip>>;
|
|
127
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
128
|
+
index: z.ZodNumber;
|
|
129
|
+
timestamp: z.ZodString;
|
|
130
|
+
role: z.ZodString;
|
|
131
|
+
content: z.ZodNullable<z.ZodString>;
|
|
132
|
+
tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
133
|
+
id: z.ZodString;
|
|
134
|
+
type: z.ZodLiteral<"function">;
|
|
135
|
+
function: z.ZodObject<{
|
|
136
|
+
name: z.ZodString;
|
|
137
|
+
arguments: z.ZodString;
|
|
138
|
+
}, z.core.$strip>;
|
|
139
|
+
}, z.core.$strip>>>;
|
|
140
|
+
tool_call_id: z.ZodOptional<z.ZodString>;
|
|
141
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
142
|
+
}, z.core.$strip>>;
|
|
143
|
+
summary: z.ZodObject<{
|
|
144
|
+
totalMessages: z.ZodNumber;
|
|
145
|
+
totalTokens: z.ZodOptional<z.ZodNumber>;
|
|
146
|
+
toolCallsExecuted: z.ZodNumber;
|
|
147
|
+
iterations: z.ZodNumber;
|
|
148
|
+
finalOutput: z.ZodOptional<z.ZodString>;
|
|
149
|
+
success: z.ZodBoolean;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
export type LoggedConversation = z.infer<typeof LoggedConversationSchema>;
|
|
153
|
+
/**
|
|
154
|
+
* Validate serialized conversation data
|
|
155
|
+
*
|
|
156
|
+
* @param data - The data to validate
|
|
157
|
+
* @returns Validation result
|
|
158
|
+
*/
|
|
159
|
+
export declare function validateConversation(data: unknown): {
|
|
160
|
+
success: boolean;
|
|
161
|
+
data?: SerializedConversation;
|
|
162
|
+
error?: string;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Validate logged conversation data
|
|
166
|
+
*
|
|
167
|
+
* @param data - The data to validate
|
|
168
|
+
* @returns Validation result
|
|
169
|
+
*/
|
|
170
|
+
export declare function validateLoggedConversation(data: unknown): {
|
|
171
|
+
success: boolean;
|
|
172
|
+
data?: LoggedConversation;
|
|
173
|
+
error?: string;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Safe JSON parse with schema validation
|
|
177
|
+
*
|
|
178
|
+
* @param json - JSON string to parse
|
|
179
|
+
* @param schema - Zod schema to validate against
|
|
180
|
+
* @returns Parsed and validated data
|
|
181
|
+
* @throws Error if parsing or validation fails
|
|
182
|
+
*/
|
|
183
|
+
export declare function safeJsonParse<T>(json: string, schema: z.ZodSchema<T>): T;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Schema version for forward compatibility
|
|
5
|
+
*/ const SCHEMA_VERSION = '1.0.0';
|
|
6
|
+
/**
|
|
7
|
+
* Maximum sizes for serialized data
|
|
8
|
+
*/ const SERIALIZATION_LIMITS = {
|
|
9
|
+
maxContentLength: 1000000,
|
|
10
|
+
maxArgumentsLength: 100000,
|
|
11
|
+
maxMessages: 10000,
|
|
12
|
+
maxContextItems: 1000,
|
|
13
|
+
maxStringLength: 100,
|
|
14
|
+
maxToolCalls: 100
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Tool call schema
|
|
18
|
+
*/ const ToolCallSchema = z.object({
|
|
19
|
+
id: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
|
|
20
|
+
type: z.literal('function'),
|
|
21
|
+
function: z.object({
|
|
22
|
+
name: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
|
|
23
|
+
arguments: z.string().max(SERIALIZATION_LIMITS.maxArgumentsLength)
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Conversation message schema
|
|
28
|
+
*/ const ConversationMessageSchema = z.object({
|
|
29
|
+
role: z.enum([
|
|
30
|
+
'system',
|
|
31
|
+
'user',
|
|
32
|
+
'assistant',
|
|
33
|
+
'tool'
|
|
34
|
+
]),
|
|
35
|
+
content: z.string().nullable().refine((val)=>val === null || val.length <= SERIALIZATION_LIMITS.maxContentLength, {
|
|
36
|
+
message: `Content exceeds maximum length of ${SERIALIZATION_LIMITS.maxContentLength}`
|
|
37
|
+
}),
|
|
38
|
+
name: z.string().max(SERIALIZATION_LIMITS.maxStringLength).optional(),
|
|
39
|
+
tool_calls: z.array(ToolCallSchema).max(SERIALIZATION_LIMITS.maxToolCalls).optional(),
|
|
40
|
+
tool_call_id: z.string().max(SERIALIZATION_LIMITS.maxStringLength).optional()
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Conversation metadata schema
|
|
44
|
+
*/ const ConversationMetadataSchema = z.object({
|
|
45
|
+
model: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
|
|
46
|
+
created: z.string().datetime(),
|
|
47
|
+
lastModified: z.string().datetime(),
|
|
48
|
+
messageCount: z.number().int().nonnegative(),
|
|
49
|
+
toolCallCount: z.number().int().nonnegative()
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* Serialized conversation schema
|
|
53
|
+
*/ const SerializedConversationSchema = z.object({
|
|
54
|
+
// Optional version for forward compatibility
|
|
55
|
+
version: z.string().optional(),
|
|
56
|
+
messages: z.array(ConversationMessageSchema).max(SERIALIZATION_LIMITS.maxMessages),
|
|
57
|
+
metadata: ConversationMetadataSchema,
|
|
58
|
+
contextProvided: z.array(z.string().max(1000)).max(SERIALIZATION_LIMITS.maxContextItems).optional()
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* Prompt serialization schema (flexible for various prompt structures)
|
|
62
|
+
*/ const SerializedPromptSchema = z.object({
|
|
63
|
+
version: z.string().optional(),
|
|
64
|
+
persona: z.any().optional(),
|
|
65
|
+
instructions: z.any().optional(),
|
|
66
|
+
contexts: z.any().optional(),
|
|
67
|
+
content: z.any().optional()
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Logged conversation schema (for conversation-logger)
|
|
71
|
+
*/ const LoggedConversationSchema = z.object({
|
|
72
|
+
id: z.string().max(200),
|
|
73
|
+
metadata: z.object({
|
|
74
|
+
startTime: z.union([
|
|
75
|
+
z.string().datetime(),
|
|
76
|
+
z.date()
|
|
77
|
+
]),
|
|
78
|
+
endTime: z.union([
|
|
79
|
+
z.string().datetime(),
|
|
80
|
+
z.date()
|
|
81
|
+
]).optional(),
|
|
82
|
+
duration: z.number().nonnegative().optional(),
|
|
83
|
+
model: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
|
|
84
|
+
template: z.string().max(SERIALIZATION_LIMITS.maxStringLength).optional(),
|
|
85
|
+
userContext: z.record(z.string(), z.any()).optional()
|
|
86
|
+
}),
|
|
87
|
+
prompt: z.object({
|
|
88
|
+
persona: z.string().optional(),
|
|
89
|
+
instructions: z.string().optional(),
|
|
90
|
+
content: z.array(z.string()).optional(),
|
|
91
|
+
context: z.array(z.string()).optional()
|
|
92
|
+
}).optional(),
|
|
93
|
+
messages: z.array(z.object({
|
|
94
|
+
index: z.number().int().nonnegative(),
|
|
95
|
+
timestamp: z.string(),
|
|
96
|
+
role: z.string(),
|
|
97
|
+
content: z.string().nullable(),
|
|
98
|
+
tool_calls: z.array(ToolCallSchema).optional(),
|
|
99
|
+
tool_call_id: z.string().optional(),
|
|
100
|
+
metadata: z.record(z.string(), z.any()).optional()
|
|
101
|
+
})).max(SERIALIZATION_LIMITS.maxMessages),
|
|
102
|
+
summary: z.object({
|
|
103
|
+
totalMessages: z.number().int().nonnegative(),
|
|
104
|
+
totalTokens: z.number().int().nonnegative().optional(),
|
|
105
|
+
toolCallsExecuted: z.number().int().nonnegative(),
|
|
106
|
+
iterations: z.number().int().nonnegative(),
|
|
107
|
+
finalOutput: z.string().optional(),
|
|
108
|
+
success: z.boolean()
|
|
109
|
+
})
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* Validate serialized conversation data
|
|
113
|
+
*
|
|
114
|
+
* @param data - The data to validate
|
|
115
|
+
* @returns Validation result
|
|
116
|
+
*/ function validateConversation(data) {
|
|
117
|
+
const result = SerializedConversationSchema.safeParse(data);
|
|
118
|
+
if (result.success) {
|
|
119
|
+
return {
|
|
120
|
+
success: true,
|
|
121
|
+
data: result.data
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Create safe error message (don't leak full schema details)
|
|
125
|
+
const issues = result.error.issues.slice(0, 3) // Limit to first 3 issues
|
|
126
|
+
.map((i)=>`${i.path.join('.')}: ${i.message}`).join('; ');
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
error: issues
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Validate logged conversation data
|
|
134
|
+
*
|
|
135
|
+
* @param data - The data to validate
|
|
136
|
+
* @returns Validation result
|
|
137
|
+
*/ function validateLoggedConversation(data) {
|
|
138
|
+
const result = LoggedConversationSchema.safeParse(data);
|
|
139
|
+
if (result.success) {
|
|
140
|
+
return {
|
|
141
|
+
success: true,
|
|
142
|
+
data: result.data
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const issues = result.error.issues.slice(0, 3).map((i)=>`${i.path.join('.')}: ${i.message}`).join('; ');
|
|
146
|
+
return {
|
|
147
|
+
success: false,
|
|
148
|
+
error: issues
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Safe JSON parse with schema validation
|
|
153
|
+
*
|
|
154
|
+
* @param json - JSON string to parse
|
|
155
|
+
* @param schema - Zod schema to validate against
|
|
156
|
+
* @returns Parsed and validated data
|
|
157
|
+
* @throws Error if parsing or validation fails
|
|
158
|
+
*/ function safeJsonParse(json, schema) {
|
|
159
|
+
let parsed;
|
|
160
|
+
try {
|
|
161
|
+
parsed = JSON.parse(json);
|
|
162
|
+
} catch {
|
|
163
|
+
throw new Error('Invalid JSON format');
|
|
164
|
+
}
|
|
165
|
+
const result = schema.safeParse(parsed);
|
|
166
|
+
if (!result.success) {
|
|
167
|
+
const issues = result.error.issues.slice(0, 3).map((i)=>`${i.path.join('.')}: ${i.message}`).join('; ');
|
|
168
|
+
throw new Error(`Validation failed: ${issues}`);
|
|
169
|
+
}
|
|
170
|
+
return result.data;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { ConversationMessageSchema, ConversationMetadataSchema, LoggedConversationSchema, SCHEMA_VERSION, SERIALIZATION_LIMITS, SerializedConversationSchema, SerializedPromptSchema, ToolCallSchema, safeJsonParse, validateConversation, validateLoggedConversation };
|
|
174
|
+
//# sourceMappingURL=serialization-schemas.js.map
|