@agentforge/core 0.1.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/dist/index.js ADDED
@@ -0,0 +1,3905 @@
1
+ // src/tools/types.ts
2
+ var ToolCategory = /* @__PURE__ */ ((ToolCategory2) => {
3
+ ToolCategory2["FILE_SYSTEM"] = "file-system";
4
+ ToolCategory2["WEB"] = "web";
5
+ ToolCategory2["CODE"] = "code";
6
+ ToolCategory2["DATABASE"] = "database";
7
+ ToolCategory2["API"] = "api";
8
+ ToolCategory2["UTILITY"] = "utility";
9
+ ToolCategory2["CUSTOM"] = "custom";
10
+ return ToolCategory2;
11
+ })(ToolCategory || {});
12
+
13
+ // src/tools/schemas.ts
14
+ import { z } from "zod";
15
+ var ToolCategorySchema = z.nativeEnum(ToolCategory, {
16
+ errorMap: () => ({
17
+ message: `Must be a valid ToolCategory: ${Object.values(ToolCategory).join(", ")}`
18
+ })
19
+ });
20
+ var ToolExampleSchema = z.object({
21
+ /**
22
+ * Description must be a non-empty string
23
+ */
24
+ description: z.string().min(1, "Example description cannot be empty"),
25
+ /**
26
+ * Input must be an object (can have any properties)
27
+ */
28
+ input: z.record(z.unknown()),
29
+ /**
30
+ * Output is optional and can be anything
31
+ */
32
+ output: z.unknown().optional(),
33
+ /**
34
+ * Explanation is optional but must be non-empty if provided
35
+ */
36
+ explanation: z.string().min(1).optional()
37
+ });
38
+ var ToolNameSchema = z.string().min(2, "Tool name must be at least 2 characters").max(50, "Tool name must be at most 50 characters").regex(
39
+ /^[a-z][a-z0-9-]*[a-z0-9]$/,
40
+ "Tool name must be kebab-case (lowercase letters, numbers, hyphens only, must start with a letter)"
41
+ );
42
+ var ToolMetadataSchema = z.object({
43
+ // ===== REQUIRED FIELDS =====
44
+ /**
45
+ * Tool name - must be valid kebab-case
46
+ */
47
+ name: ToolNameSchema,
48
+ /**
49
+ * Description - must be meaningful (at least 10 characters)
50
+ */
51
+ description: z.string().min(10, "Tool description must be at least 10 characters").max(500, "Tool description must be at most 500 characters"),
52
+ /**
53
+ * Category - must be a valid ToolCategory
54
+ */
55
+ category: ToolCategorySchema,
56
+ // ===== OPTIONAL FIELDS =====
57
+ /**
58
+ * Display name - if provided, must be non-empty
59
+ */
60
+ displayName: z.string().min(1).optional(),
61
+ /**
62
+ * Tags - array of non-empty strings
63
+ */
64
+ tags: z.array(z.string().min(1)).optional(),
65
+ /**
66
+ * Examples - array of valid ToolExample objects
67
+ */
68
+ examples: z.array(ToolExampleSchema).optional(),
69
+ /**
70
+ * Usage notes - if provided, must be meaningful
71
+ */
72
+ usageNotes: z.string().min(10).optional(),
73
+ /**
74
+ * Limitations - array of non-empty strings
75
+ */
76
+ limitations: z.array(z.string().min(1)).optional(),
77
+ /**
78
+ * Version - if provided, should follow semver format
79
+ * Examples: '1.0.0', '2.1.3', '0.1.0-beta', '1.0.0-alpha.1'
80
+ */
81
+ version: z.string().regex(
82
+ /^\d+\.\d+\.\d+(-[a-z0-9.-]+)?$/i,
83
+ "Version should follow semantic versioning (e.g., 1.0.0)"
84
+ ).optional(),
85
+ /**
86
+ * Author - if provided, must be non-empty
87
+ */
88
+ author: z.string().min(1).optional(),
89
+ /**
90
+ * Deprecated flag
91
+ */
92
+ deprecated: z.boolean().optional(),
93
+ /**
94
+ * Replacement tool name - if provided, must be valid tool name
95
+ */
96
+ replacedBy: ToolNameSchema.optional()
97
+ });
98
+ function validateToolMetadata(metadata) {
99
+ return ToolMetadataSchema.safeParse(metadata);
100
+ }
101
+ function validateToolName(name) {
102
+ return ToolNameSchema.safeParse(name).success;
103
+ }
104
+
105
+ // src/tools/validation.ts
106
+ import { z as z2 } from "zod";
107
+ var MissingDescriptionError = class extends Error {
108
+ constructor(fieldPath, fieldType) {
109
+ super(
110
+ `Schema field "${fieldPath.join(".")}" (${fieldType}) is missing a description. All fields must have descriptions for LLM understanding. Use .describe("...") on this field.`
111
+ );
112
+ this.fieldPath = fieldPath;
113
+ this.fieldType = fieldType;
114
+ this.name = "MissingDescriptionError";
115
+ }
116
+ };
117
+ function validateSchemaDescriptions(schema, fieldPath = []) {
118
+ const def = schema._def;
119
+ const typeName = def.typeName;
120
+ if (schema instanceof z2.ZodObject) {
121
+ const shape = schema.shape;
122
+ Object.entries(shape).forEach(([key, fieldSchema]) => {
123
+ validateSchemaDescriptions(fieldSchema, [...fieldPath, key]);
124
+ });
125
+ return;
126
+ }
127
+ if (schema instanceof z2.ZodArray) {
128
+ validateSchemaDescriptions(def.type, [...fieldPath, "[]"]);
129
+ return;
130
+ }
131
+ if (schema instanceof z2.ZodOptional) {
132
+ const wrapperDescription = def.description;
133
+ const innerDescription = def.innerType._def.description;
134
+ if (fieldPath.length > 0 && !wrapperDescription && !innerDescription) {
135
+ throw new MissingDescriptionError(fieldPath, typeName);
136
+ }
137
+ if (!wrapperDescription) {
138
+ validateSchemaDescriptions(def.innerType, fieldPath);
139
+ }
140
+ return;
141
+ }
142
+ if (schema instanceof z2.ZodNullable) {
143
+ const wrapperDescription = def.description;
144
+ const innerDescription = def.innerType._def.description;
145
+ if (fieldPath.length > 0 && !wrapperDescription && !innerDescription) {
146
+ throw new MissingDescriptionError(fieldPath, typeName);
147
+ }
148
+ if (!wrapperDescription) {
149
+ validateSchemaDescriptions(def.innerType, fieldPath);
150
+ }
151
+ return;
152
+ }
153
+ if (schema instanceof z2.ZodDefault) {
154
+ const wrapperDescription = def.description;
155
+ const innerDescription = def.innerType._def.description;
156
+ if (fieldPath.length > 0 && !wrapperDescription && !innerDescription) {
157
+ throw new MissingDescriptionError(fieldPath, typeName);
158
+ }
159
+ if (!wrapperDescription) {
160
+ validateSchemaDescriptions(def.innerType, fieldPath);
161
+ }
162
+ return;
163
+ }
164
+ if (schema instanceof z2.ZodUnion) {
165
+ def.options.forEach((option, index) => {
166
+ validateSchemaDescriptions(option, [...fieldPath, `option${index}`]);
167
+ });
168
+ return;
169
+ }
170
+ if (schema instanceof z2.ZodIntersection) {
171
+ validateSchemaDescriptions(def.left, fieldPath);
172
+ validateSchemaDescriptions(def.right, fieldPath);
173
+ return;
174
+ }
175
+ if (schema instanceof z2.ZodRecord) {
176
+ validateSchemaDescriptions(def.valueType, [...fieldPath, "[key]"]);
177
+ return;
178
+ }
179
+ if (schema instanceof z2.ZodTuple) {
180
+ def.items.forEach((item, index) => {
181
+ validateSchemaDescriptions(item, [...fieldPath, `[${index}]`]);
182
+ });
183
+ return;
184
+ }
185
+ if (fieldPath.length > 0) {
186
+ const description = def.description;
187
+ if (!description || description.trim() === "") {
188
+ throw new MissingDescriptionError(fieldPath, typeName);
189
+ }
190
+ }
191
+ }
192
+ function safeValidateSchemaDescriptions(schema) {
193
+ try {
194
+ validateSchemaDescriptions(schema);
195
+ return { success: true };
196
+ } catch (error) {
197
+ if (error instanceof MissingDescriptionError) {
198
+ return { success: false, error };
199
+ }
200
+ throw error;
201
+ }
202
+ }
203
+ function getMissingDescriptions(schema) {
204
+ const missing = [];
205
+ function check(s, path = []) {
206
+ const def = s._def;
207
+ const typeName = def.typeName;
208
+ if (s instanceof z2.ZodObject) {
209
+ const shape = s.shape;
210
+ Object.entries(shape).forEach(([key, fieldSchema]) => {
211
+ check(fieldSchema, [...path, key]);
212
+ });
213
+ return;
214
+ }
215
+ if (s instanceof z2.ZodOptional || s instanceof z2.ZodNullable || s instanceof z2.ZodDefault) {
216
+ const wrapperDescription = def.description;
217
+ const innerDescription = def.innerType._def.description;
218
+ if (path.length > 0 && !wrapperDescription && !innerDescription) {
219
+ missing.push(path.join("."));
220
+ }
221
+ if (!wrapperDescription) {
222
+ check(def.innerType, path);
223
+ }
224
+ return;
225
+ }
226
+ if (s instanceof z2.ZodArray) {
227
+ check(def.type, [...path, "[]"]);
228
+ return;
229
+ }
230
+ if (path.length > 0) {
231
+ const description = def.description;
232
+ if (!description || description.trim() === "") {
233
+ missing.push(path.join("."));
234
+ }
235
+ }
236
+ }
237
+ check(schema);
238
+ return missing;
239
+ }
240
+
241
+ // src/tools/helpers.ts
242
+ function createTool(metadata, schema, execute) {
243
+ const metadataResult = validateToolMetadata(metadata);
244
+ if (!metadataResult.success) {
245
+ const errors = metadataResult.error.errors.map((err) => ` - ${err.path.join(".")}: ${err.message}`).join("\n");
246
+ throw new Error(`Invalid tool metadata:
247
+ ${errors}`);
248
+ }
249
+ validateSchemaDescriptions(schema);
250
+ return {
251
+ metadata: metadataResult.data,
252
+ schema,
253
+ execute
254
+ };
255
+ }
256
+ function createToolUnsafe(metadata, schema, execute) {
257
+ const metadataResult = validateToolMetadata(metadata);
258
+ if (!metadataResult.success) {
259
+ const errors = metadataResult.error.errors.map((err) => ` - ${err.path.join(".")}: ${err.message}`).join("\n");
260
+ throw new Error(`Invalid tool metadata:
261
+ ${errors}`);
262
+ }
263
+ return {
264
+ metadata: metadataResult.data,
265
+ schema,
266
+ execute
267
+ };
268
+ }
269
+ function validateTool(tool) {
270
+ const errors = [];
271
+ const metadataResult = validateToolMetadata(tool.metadata);
272
+ if (!metadataResult.success) {
273
+ metadataResult.error.errors.forEach((err) => {
274
+ errors.push(`Metadata: ${err.path.join(".")}: ${err.message}`);
275
+ });
276
+ }
277
+ try {
278
+ validateSchemaDescriptions(tool.schema);
279
+ } catch (error) {
280
+ if (error instanceof Error) {
281
+ errors.push(`Schema: ${error.message}`);
282
+ }
283
+ }
284
+ return {
285
+ success: errors.length === 0,
286
+ errors
287
+ };
288
+ }
289
+
290
+ // src/tools/builder.ts
291
+ var ToolBuilder = class {
292
+ metadata = {};
293
+ _schema;
294
+ _execute;
295
+ /**
296
+ * Set the tool name (required)
297
+ *
298
+ * @param name - Tool name in kebab-case (e.g., 'read-file')
299
+ */
300
+ name(name) {
301
+ this.metadata.name = name;
302
+ return this;
303
+ }
304
+ /**
305
+ * Set the tool description (required)
306
+ *
307
+ * @param description - Clear description of what the tool does
308
+ */
309
+ description(description) {
310
+ this.metadata.description = description;
311
+ return this;
312
+ }
313
+ /**
314
+ * Set the tool category (required)
315
+ *
316
+ * @param category - Tool category for organization
317
+ */
318
+ category(category) {
319
+ this.metadata.category = category;
320
+ return this;
321
+ }
322
+ /**
323
+ * Set the display name (optional)
324
+ *
325
+ * @param displayName - Human-friendly name for UI display
326
+ */
327
+ displayName(displayName) {
328
+ this.metadata.displayName = displayName;
329
+ return this;
330
+ }
331
+ /**
332
+ * Set tags for searchability (optional)
333
+ *
334
+ * @param tags - Array of tags for categorization and search
335
+ */
336
+ tags(tags) {
337
+ this.metadata.tags = tags;
338
+ return this;
339
+ }
340
+ /**
341
+ * Add a single tag (optional)
342
+ *
343
+ * @param tag - Tag to add
344
+ */
345
+ tag(tag) {
346
+ if (!this.metadata.tags) {
347
+ this.metadata.tags = [];
348
+ }
349
+ this.metadata.tags.push(tag);
350
+ return this;
351
+ }
352
+ /**
353
+ * Add an example (optional)
354
+ *
355
+ * @param example - Usage example for the tool
356
+ */
357
+ example(example) {
358
+ if (!this.metadata.examples) {
359
+ this.metadata.examples = [];
360
+ }
361
+ this.metadata.examples.push(example);
362
+ return this;
363
+ }
364
+ /**
365
+ * Set usage notes (optional)
366
+ *
367
+ * @param notes - Important usage information
368
+ */
369
+ usageNotes(notes) {
370
+ this.metadata.usageNotes = notes;
371
+ return this;
372
+ }
373
+ /**
374
+ * Set limitations (optional)
375
+ *
376
+ * @param limitations - Array of known limitations
377
+ */
378
+ limitations(limitations) {
379
+ this.metadata.limitations = limitations;
380
+ return this;
381
+ }
382
+ /**
383
+ * Add a single limitation (optional)
384
+ *
385
+ * @param limitation - Limitation to add
386
+ */
387
+ limitation(limitation) {
388
+ if (!this.metadata.limitations) {
389
+ this.metadata.limitations = [];
390
+ }
391
+ this.metadata.limitations.push(limitation);
392
+ return this;
393
+ }
394
+ /**
395
+ * Set version (optional)
396
+ *
397
+ * @param version - Semantic version string
398
+ */
399
+ version(version) {
400
+ this.metadata.version = version;
401
+ return this;
402
+ }
403
+ /**
404
+ * Set author (optional)
405
+ *
406
+ * @param author - Tool author name
407
+ */
408
+ author(author) {
409
+ this.metadata.author = author;
410
+ return this;
411
+ }
412
+ /**
413
+ * Set the input schema (required)
414
+ *
415
+ * All fields MUST have .describe() for LLM understanding!
416
+ *
417
+ * @param schema - Zod schema for input validation
418
+ */
419
+ schema(schema) {
420
+ this._schema = schema;
421
+ return this;
422
+ }
423
+ /**
424
+ * Set the implementation function (required)
425
+ *
426
+ * @param execute - Async function that implements the tool
427
+ */
428
+ implement(execute) {
429
+ this._execute = execute;
430
+ return this;
431
+ }
432
+ /**
433
+ * Build the tool with validation
434
+ *
435
+ * Validates:
436
+ * - All required fields are present
437
+ * - Metadata is valid
438
+ * - Schema has descriptions on all fields
439
+ *
440
+ * @returns The validated tool
441
+ * @throws {Error} If validation fails
442
+ */
443
+ build() {
444
+ if (!this.metadata.name) {
445
+ throw new Error("Tool name is required. Use .name() to set it.");
446
+ }
447
+ if (!this.metadata.description) {
448
+ throw new Error("Tool description is required. Use .description() to set it.");
449
+ }
450
+ if (!this.metadata.category) {
451
+ throw new Error("Tool category is required. Use .category() to set it.");
452
+ }
453
+ if (!this._schema) {
454
+ throw new Error("Tool schema is required. Use .schema() to set it.");
455
+ }
456
+ if (!this._execute) {
457
+ throw new Error("Tool implementation is required. Use .implement() to set it.");
458
+ }
459
+ return createTool(
460
+ this.metadata,
461
+ this._schema,
462
+ this._execute
463
+ );
464
+ }
465
+ };
466
+ function toolBuilder() {
467
+ return new ToolBuilder();
468
+ }
469
+
470
+ // src/langchain/converter.ts
471
+ import { DynamicStructuredTool } from "@langchain/core/tools";
472
+ import { zodToJsonSchema } from "zod-to-json-schema";
473
+ function toLangChainTool(tool) {
474
+ return new DynamicStructuredTool({
475
+ name: tool.metadata.name,
476
+ description: tool.metadata.description,
477
+ schema: tool.schema,
478
+ func: async (input) => {
479
+ const result = await tool.execute(input);
480
+ if (typeof result === "string") {
481
+ return result;
482
+ }
483
+ if (typeof result === "object" && result !== null) {
484
+ return JSON.stringify(result, null, 2);
485
+ }
486
+ return String(result);
487
+ }
488
+ });
489
+ }
490
+ function toLangChainTools(tools) {
491
+ return tools.map(toLangChainTool);
492
+ }
493
+ function getToolJsonSchema(tool) {
494
+ const jsonSchema = zodToJsonSchema(tool.schema, {
495
+ name: tool.metadata.name,
496
+ $refStrategy: "none"
497
+ // Don't use $ref for nested schemas
498
+ });
499
+ if (jsonSchema.$ref && jsonSchema.definitions) {
500
+ const refName = jsonSchema.$ref.replace("#/definitions/", "");
501
+ return jsonSchema.definitions[refName] || jsonSchema;
502
+ }
503
+ return jsonSchema;
504
+ }
505
+ function getToolDescription(tool) {
506
+ const { metadata } = tool;
507
+ const parts = [];
508
+ parts.push(`${metadata.name}: ${metadata.description}`);
509
+ if (metadata.displayName) {
510
+ parts.push(`Display Name: ${metadata.displayName}`);
511
+ }
512
+ parts.push(`Category: ${metadata.category}`);
513
+ if (metadata.tags && metadata.tags.length > 0) {
514
+ parts.push(`Tags: ${metadata.tags.join(", ")}`);
515
+ }
516
+ if (metadata.usageNotes) {
517
+ parts.push(`
518
+ Usage Notes: ${metadata.usageNotes}`);
519
+ }
520
+ if (metadata.limitations && metadata.limitations.length > 0) {
521
+ parts.push(`
522
+ Limitations:`);
523
+ metadata.limitations.forEach((limit) => {
524
+ parts.push(` - ${limit}`);
525
+ });
526
+ }
527
+ if (metadata.examples && metadata.examples.length > 0) {
528
+ parts.push(`
529
+ Examples:`);
530
+ metadata.examples.forEach((example, i) => {
531
+ parts.push(` ${i + 1}. ${example.description}`);
532
+ if (example.explanation) {
533
+ parts.push(` ${example.explanation}`);
534
+ }
535
+ });
536
+ }
537
+ return parts.join("\n");
538
+ }
539
+
540
+ // src/tools/registry.ts
541
+ var RegistryEvent = /* @__PURE__ */ ((RegistryEvent2) => {
542
+ RegistryEvent2["TOOL_REGISTERED"] = "tool:registered";
543
+ RegistryEvent2["TOOL_REMOVED"] = "tool:removed";
544
+ RegistryEvent2["TOOL_UPDATED"] = "tool:updated";
545
+ RegistryEvent2["REGISTRY_CLEARED"] = "registry:cleared";
546
+ return RegistryEvent2;
547
+ })(RegistryEvent || {});
548
+ var ToolRegistry = class {
549
+ tools = /* @__PURE__ */ new Map();
550
+ eventHandlers = /* @__PURE__ */ new Map();
551
+ /**
552
+ * Register a tool in the registry
553
+ *
554
+ * @param tool - The tool to register
555
+ * @throws Error if a tool with the same name already exists
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * registry.register(readFileTool);
560
+ * ```
561
+ */
562
+ register(tool) {
563
+ const name = tool.metadata.name;
564
+ if (this.tools.has(name)) {
565
+ throw new Error(
566
+ `Tool with name "${name}" is already registered. Use update() to modify it.`
567
+ );
568
+ }
569
+ this.tools.set(name, tool);
570
+ this.emit("tool:registered" /* TOOL_REGISTERED */, tool);
571
+ }
572
+ /**
573
+ * Get a tool by name
574
+ *
575
+ * @param name - The tool name
576
+ * @returns The tool, or undefined if not found
577
+ *
578
+ * @example
579
+ * ```ts
580
+ * const tool = registry.get('read-file');
581
+ * if (tool) {
582
+ * const result = await tool.execute({ path: './file.txt' });
583
+ * }
584
+ * ```
585
+ */
586
+ get(name) {
587
+ return this.tools.get(name);
588
+ }
589
+ /**
590
+ * Check if a tool exists in the registry
591
+ *
592
+ * @param name - The tool name
593
+ * @returns True if the tool exists
594
+ *
595
+ * @example
596
+ * ```ts
597
+ * if (registry.has('read-file')) {
598
+ * console.log('Tool exists!');
599
+ * }
600
+ * ```
601
+ */
602
+ has(name) {
603
+ return this.tools.has(name);
604
+ }
605
+ /**
606
+ * Remove a tool from the registry
607
+ *
608
+ * @param name - The tool name
609
+ * @returns True if the tool was removed, false if it didn't exist
610
+ *
611
+ * @example
612
+ * ```ts
613
+ * const removed = registry.remove('read-file');
614
+ * console.log(removed ? 'Removed' : 'Not found');
615
+ * ```
616
+ */
617
+ remove(name) {
618
+ const tool = this.tools.get(name);
619
+ if (!tool) {
620
+ return false;
621
+ }
622
+ this.tools.delete(name);
623
+ this.emit("tool:removed" /* TOOL_REMOVED */, tool);
624
+ return true;
625
+ }
626
+ /**
627
+ * Update an existing tool
628
+ *
629
+ * @param name - The tool name
630
+ * @param tool - The new tool definition
631
+ * @returns True if updated, false if the tool didn't exist
632
+ *
633
+ * @example
634
+ * ```ts
635
+ * const updated = registry.update('read-file', newReadFileTool);
636
+ * ```
637
+ */
638
+ update(name, tool) {
639
+ if (!this.tools.has(name)) {
640
+ return false;
641
+ }
642
+ this.tools.set(name, tool);
643
+ this.emit("tool:updated" /* TOOL_UPDATED */, { name, tool });
644
+ return true;
645
+ }
646
+ /**
647
+ * Get all registered tools
648
+ *
649
+ * @returns Array of all tools
650
+ *
651
+ * @example
652
+ * ```ts
653
+ * const allTools = registry.getAll();
654
+ * console.log(`Total tools: ${allTools.length}`);
655
+ * ```
656
+ */
657
+ getAll() {
658
+ return Array.from(this.tools.values());
659
+ }
660
+ /**
661
+ * Get tools by category
662
+ *
663
+ * @param category - The tool category
664
+ * @returns Array of tools in the category
665
+ *
666
+ * @example
667
+ * ```ts
668
+ * const fileTools = registry.getByCategory(ToolCategory.FILE_SYSTEM);
669
+ * ```
670
+ */
671
+ getByCategory(category) {
672
+ return this.getAll().filter((tool) => tool.metadata.category === category);
673
+ }
674
+ /**
675
+ * Get tools by tag
676
+ *
677
+ * @param tag - The tag to search for
678
+ * @returns Array of tools with the tag
679
+ *
680
+ * @example
681
+ * ```ts
682
+ * const fileTools = registry.getByTag('file');
683
+ * ```
684
+ */
685
+ getByTag(tag) {
686
+ return this.getAll().filter(
687
+ (tool) => tool.metadata.tags?.includes(tag)
688
+ );
689
+ }
690
+ /**
691
+ * Search tools by name or description
692
+ *
693
+ * Case-insensitive search across tool names, display names, and descriptions.
694
+ *
695
+ * @param query - The search query
696
+ * @returns Array of matching tools
697
+ *
698
+ * @example
699
+ * ```ts
700
+ * const results = registry.search('file');
701
+ * // Returns tools with 'file' in name or description
702
+ * ```
703
+ */
704
+ search(query) {
705
+ const lowerQuery = query.toLowerCase();
706
+ return this.getAll().filter((tool) => {
707
+ const name = tool.metadata.name.toLowerCase();
708
+ const displayName = tool.metadata.displayName?.toLowerCase() || "";
709
+ const description = tool.metadata.description.toLowerCase();
710
+ return name.includes(lowerQuery) || displayName.includes(lowerQuery) || description.includes(lowerQuery);
711
+ });
712
+ }
713
+ /**
714
+ * Register multiple tools at once
715
+ *
716
+ * @param tools - Array of tools to register
717
+ * @throws Error if any tool name conflicts with existing tools
718
+ *
719
+ * @example
720
+ * ```ts
721
+ * registry.registerMany([tool1, tool2, tool3]);
722
+ * ```
723
+ */
724
+ registerMany(tools) {
725
+ const conflicts = [];
726
+ for (const tool of tools) {
727
+ if (this.tools.has(tool.metadata.name)) {
728
+ conflicts.push(tool.metadata.name);
729
+ }
730
+ }
731
+ if (conflicts.length > 0) {
732
+ throw new Error(
733
+ `Cannot register tools: the following names already exist: ${conflicts.join(", ")}`
734
+ );
735
+ }
736
+ for (const tool of tools) {
737
+ this.register(tool);
738
+ }
739
+ }
740
+ /**
741
+ * Clear all tools from the registry
742
+ *
743
+ * @example
744
+ * ```ts
745
+ * registry.clear();
746
+ * console.log(registry.size()); // 0
747
+ * ```
748
+ */
749
+ clear() {
750
+ this.tools.clear();
751
+ this.emit("registry:cleared" /* REGISTRY_CLEARED */, null);
752
+ }
753
+ /**
754
+ * Get the number of registered tools
755
+ *
756
+ * @returns Number of tools in the registry
757
+ *
758
+ * @example
759
+ * ```ts
760
+ * console.log(`Registry has ${registry.size()} tools`);
761
+ * ```
762
+ */
763
+ size() {
764
+ return this.tools.size;
765
+ }
766
+ /**
767
+ * Get all tool names
768
+ *
769
+ * @returns Array of tool names
770
+ *
771
+ * @example
772
+ * ```ts
773
+ * const names = registry.getNames();
774
+ * console.log('Available tools:', names.join(', '));
775
+ * ```
776
+ */
777
+ getNames() {
778
+ return Array.from(this.tools.keys());
779
+ }
780
+ /**
781
+ * Register an event handler
782
+ *
783
+ * @param event - The event to listen for
784
+ * @param handler - The handler function
785
+ *
786
+ * @example
787
+ * ```ts
788
+ * registry.on(RegistryEvent.TOOL_REGISTERED, (tool) => {
789
+ * console.log('New tool:', tool.metadata.name);
790
+ * });
791
+ * ```
792
+ */
793
+ on(event, handler) {
794
+ if (!this.eventHandlers.has(event)) {
795
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
796
+ }
797
+ this.eventHandlers.get(event).add(handler);
798
+ }
799
+ /**
800
+ * Unregister an event handler
801
+ *
802
+ * @param event - The event to stop listening for
803
+ * @param handler - The handler function to remove
804
+ *
805
+ * @example
806
+ * ```ts
807
+ * const handler = (tool) => console.log(tool);
808
+ * registry.on(RegistryEvent.TOOL_REGISTERED, handler);
809
+ * registry.off(RegistryEvent.TOOL_REGISTERED, handler);
810
+ * ```
811
+ */
812
+ off(event, handler) {
813
+ const handlers = this.eventHandlers.get(event);
814
+ if (handlers) {
815
+ handlers.delete(handler);
816
+ }
817
+ }
818
+ /**
819
+ * Emit an event to all registered handlers
820
+ *
821
+ * @param event - The event to emit
822
+ * @param data - The event data
823
+ * @private
824
+ */
825
+ emit(event, data) {
826
+ const handlers = this.eventHandlers.get(event);
827
+ if (handlers) {
828
+ handlers.forEach((handler) => {
829
+ try {
830
+ handler(data);
831
+ } catch (error) {
832
+ console.error(`Error in event handler for ${event}:`, error);
833
+ }
834
+ });
835
+ }
836
+ }
837
+ /**
838
+ * Convert all registered tools to LangChain format
839
+ *
840
+ * This allows the entire registry to be used with LangChain agents.
841
+ *
842
+ * @returns Array of LangChain DynamicStructuredTools
843
+ *
844
+ * @example
845
+ * ```ts
846
+ * const registry = new ToolRegistry();
847
+ * registry.registerMany([tool1, tool2, tool3]);
848
+ *
849
+ * const langchainTools = registry.toLangChainTools();
850
+ *
851
+ * const agent = createAgent({
852
+ * model: new ChatOpenAI(),
853
+ * tools: langchainTools,
854
+ * });
855
+ * ```
856
+ */
857
+ toLangChainTools() {
858
+ return toLangChainTools(this.getAll());
859
+ }
860
+ /**
861
+ * Generate a formatted prompt describing all tools
862
+ *
863
+ * Creates a human-readable description of all tools in the registry,
864
+ * suitable for inclusion in LLM prompts.
865
+ *
866
+ * @param options - Options for customizing the prompt
867
+ * @returns Formatted prompt string
868
+ *
869
+ * @example
870
+ * ```ts
871
+ * const prompt = registry.generatePrompt({
872
+ * includeExamples: true,
873
+ * groupByCategory: true,
874
+ * maxExamplesPerTool: 2,
875
+ * });
876
+ *
877
+ * console.log(prompt);
878
+ * // Available Tools:
879
+ * //
880
+ * // FILE SYSTEM TOOLS:
881
+ * // - read-file: Read a file from the file system
882
+ * // Parameters: path (string)
883
+ * // Example: Read a text file
884
+ * // Input: { "path": "./README.md" }
885
+ * // ...
886
+ * ```
887
+ */
888
+ generatePrompt(options = {}) {
889
+ const {
890
+ includeExamples = false,
891
+ includeNotes = false,
892
+ includeLimitations = false,
893
+ groupByCategory = false,
894
+ categories,
895
+ maxExamplesPerTool
896
+ } = options;
897
+ let tools = this.getAll();
898
+ if (categories && categories.length > 0) {
899
+ tools = tools.filter((tool) => categories.includes(tool.metadata.category));
900
+ }
901
+ if (tools.length === 0) {
902
+ return "No tools available.";
903
+ }
904
+ const lines = ["Available Tools:", ""];
905
+ if (groupByCategory) {
906
+ const toolsByCategory = /* @__PURE__ */ new Map();
907
+ for (const tool of tools) {
908
+ const category = tool.metadata.category;
909
+ if (!toolsByCategory.has(category)) {
910
+ toolsByCategory.set(category, []);
911
+ }
912
+ toolsByCategory.get(category).push(tool);
913
+ }
914
+ for (const [category, categoryTools] of toolsByCategory) {
915
+ lines.push(`${category.toUpperCase().replace(/-/g, " ")} TOOLS:`);
916
+ for (const tool of categoryTools) {
917
+ lines.push(...this.formatToolForPrompt(tool, {
918
+ includeExamples,
919
+ includeNotes,
920
+ includeLimitations,
921
+ maxExamplesPerTool
922
+ }));
923
+ }
924
+ lines.push("");
925
+ }
926
+ } else {
927
+ for (const tool of tools) {
928
+ lines.push(...this.formatToolForPrompt(tool, {
929
+ includeExamples,
930
+ includeNotes,
931
+ includeLimitations,
932
+ maxExamplesPerTool
933
+ }));
934
+ lines.push("");
935
+ }
936
+ }
937
+ return lines.join("\n").trim();
938
+ }
939
+ /**
940
+ * Format a single tool for inclusion in a prompt
941
+ *
942
+ * @param tool - The tool to format
943
+ * @param options - Formatting options
944
+ * @returns Array of formatted lines
945
+ * @private
946
+ */
947
+ formatToolForPrompt(tool, options) {
948
+ const { metadata } = tool;
949
+ const lines = [];
950
+ lines.push(`- ${metadata.name}: ${metadata.description}`);
951
+ const schemaShape = tool.schema._def?.shape?.();
952
+ if (schemaShape) {
953
+ const params = Object.keys(schemaShape);
954
+ if (params.length > 0) {
955
+ const paramDescriptions = params.map((param) => {
956
+ const field = schemaShape[param];
957
+ const type = field._def?.typeName?.replace("Zod", "").toLowerCase() || "any";
958
+ return `${param} (${type})`;
959
+ });
960
+ lines.push(` Parameters: ${paramDescriptions.join(", ")}`);
961
+ }
962
+ }
963
+ if (options.includeNotes && metadata.usageNotes) {
964
+ lines.push(` Notes: ${metadata.usageNotes}`);
965
+ }
966
+ if (options.includeExamples && metadata.examples && metadata.examples.length > 0) {
967
+ const maxExamples = options.maxExamplesPerTool || metadata.examples.length;
968
+ const examples = metadata.examples.slice(0, maxExamples);
969
+ for (const example of examples) {
970
+ lines.push(` Example: ${example.description}`);
971
+ lines.push(` Input: ${JSON.stringify(example.input)}`);
972
+ if (example.explanation) {
973
+ lines.push(` ${example.explanation}`);
974
+ }
975
+ }
976
+ }
977
+ if (options.includeLimitations && metadata.limitations && metadata.limitations.length > 0) {
978
+ lines.push(` Limitations:`);
979
+ for (const limitation of metadata.limitations) {
980
+ lines.push(` - ${limitation}`);
981
+ }
982
+ }
983
+ return lines;
984
+ }
985
+ };
986
+
987
+ // src/tools/executor.ts
988
+ var PRIORITY_ORDER = {
989
+ critical: 0,
990
+ high: 1,
991
+ normal: 2,
992
+ low: 3
993
+ };
994
+ function createToolExecutor(config = {}) {
995
+ const {
996
+ maxConcurrent = 5,
997
+ timeout: timeout2 = 3e4,
998
+ retryPolicy,
999
+ priorityFn = () => "normal",
1000
+ onExecutionStart,
1001
+ onExecutionComplete,
1002
+ onExecutionError
1003
+ } = config;
1004
+ let activeExecutions = 0;
1005
+ const queue = [];
1006
+ const metrics = {
1007
+ totalExecutions: 0,
1008
+ successfulExecutions: 0,
1009
+ failedExecutions: 0,
1010
+ totalDuration: 0,
1011
+ averageDuration: 0,
1012
+ byPriority: { low: 0, normal: 0, high: 0, critical: 0 }
1013
+ };
1014
+ function calculateBackoff(attempt, policy) {
1015
+ const initialDelay = policy.initialDelay || 1e3;
1016
+ const maxDelay = policy.maxDelay || 3e4;
1017
+ let delay;
1018
+ switch (policy.backoff) {
1019
+ case "linear":
1020
+ delay = initialDelay * attempt;
1021
+ break;
1022
+ case "exponential":
1023
+ delay = initialDelay * Math.pow(2, attempt - 1);
1024
+ break;
1025
+ case "fixed":
1026
+ default:
1027
+ delay = initialDelay;
1028
+ }
1029
+ return Math.min(delay, maxDelay);
1030
+ }
1031
+ async function executeWithRetry(tool, input, policy) {
1032
+ if (!policy) {
1033
+ return await tool.invoke(input);
1034
+ }
1035
+ let lastError;
1036
+ for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
1037
+ try {
1038
+ return await tool.invoke(input);
1039
+ } catch (error) {
1040
+ lastError = error;
1041
+ if (policy.retryableErrors && policy.retryableErrors.length > 0) {
1042
+ const isRetryable = policy.retryableErrors.some(
1043
+ (msg) => lastError.message.includes(msg)
1044
+ );
1045
+ if (!isRetryable) {
1046
+ throw lastError;
1047
+ }
1048
+ }
1049
+ if (attempt < policy.maxAttempts) {
1050
+ const delay = calculateBackoff(attempt, policy);
1051
+ await new Promise((resolve) => setTimeout(resolve, delay));
1052
+ }
1053
+ }
1054
+ }
1055
+ throw lastError;
1056
+ }
1057
+ async function executeSingle(tool, input, priority) {
1058
+ const startTime = Date.now();
1059
+ try {
1060
+ onExecutionStart?.(tool, input);
1061
+ const result = await Promise.race([
1062
+ executeWithRetry(tool, input, retryPolicy),
1063
+ new Promise(
1064
+ (_, reject) => setTimeout(() => reject(new Error("Tool execution timeout")), timeout2)
1065
+ )
1066
+ ]);
1067
+ const duration = Date.now() - startTime;
1068
+ metrics.totalExecutions++;
1069
+ metrics.successfulExecutions++;
1070
+ metrics.totalDuration += duration;
1071
+ metrics.averageDuration = metrics.totalDuration / metrics.totalExecutions;
1072
+ metrics.byPriority[priority]++;
1073
+ onExecutionComplete?.(tool, input, result, duration);
1074
+ return result;
1075
+ } catch (error) {
1076
+ const duration = Date.now() - startTime;
1077
+ metrics.totalExecutions++;
1078
+ metrics.failedExecutions++;
1079
+ metrics.totalDuration += duration;
1080
+ metrics.averageDuration = metrics.totalDuration / metrics.totalExecutions;
1081
+ onExecutionError?.(tool, input, error, duration);
1082
+ throw error;
1083
+ }
1084
+ }
1085
+ async function processQueue() {
1086
+ while (queue.length > 0 && activeExecutions < maxConcurrent) {
1087
+ queue.sort((a, b) => {
1088
+ const priorityDiff = PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority];
1089
+ if (priorityDiff !== 0) return priorityDiff;
1090
+ return a.timestamp - b.timestamp;
1091
+ });
1092
+ const execution = queue.shift();
1093
+ if (!execution) break;
1094
+ activeExecutions++;
1095
+ executeSingle(execution.tool, execution.input, execution.priority).then((result) => {
1096
+ execution.resolve(result);
1097
+ }).catch((error) => {
1098
+ execution.reject(error);
1099
+ }).finally(() => {
1100
+ activeExecutions--;
1101
+ processQueue();
1102
+ });
1103
+ }
1104
+ }
1105
+ async function execute(tool, input, options = {}) {
1106
+ const priority = options.priority || priorityFn(tool);
1107
+ return new Promise((resolve, reject) => {
1108
+ queue.push({
1109
+ tool,
1110
+ input,
1111
+ priority,
1112
+ resolve,
1113
+ reject,
1114
+ timestamp: Date.now()
1115
+ });
1116
+ processQueue();
1117
+ });
1118
+ }
1119
+ async function executeParallel(executions) {
1120
+ return Promise.all(
1121
+ executions.map(
1122
+ (exec) => execute(exec.tool, exec.input, { priority: exec.priority })
1123
+ )
1124
+ );
1125
+ }
1126
+ function getMetrics() {
1127
+ return { ...metrics };
1128
+ }
1129
+ function resetMetrics() {
1130
+ metrics.totalExecutions = 0;
1131
+ metrics.successfulExecutions = 0;
1132
+ metrics.failedExecutions = 0;
1133
+ metrics.totalDuration = 0;
1134
+ metrics.averageDuration = 0;
1135
+ metrics.byPriority = { low: 0, normal: 0, high: 0, critical: 0 };
1136
+ }
1137
+ function getQueueStatus() {
1138
+ return {
1139
+ queueLength: queue.length,
1140
+ activeExecutions,
1141
+ maxConcurrent
1142
+ };
1143
+ }
1144
+ return {
1145
+ execute,
1146
+ executeParallel,
1147
+ getMetrics,
1148
+ resetMetrics,
1149
+ getQueueStatus
1150
+ };
1151
+ }
1152
+
1153
+ // src/tools/lifecycle.ts
1154
+ var ManagedTool = class {
1155
+ name;
1156
+ description;
1157
+ initializeFn;
1158
+ executeFn;
1159
+ cleanupFn;
1160
+ healthCheckFn;
1161
+ autoCleanup;
1162
+ healthCheckInterval;
1163
+ _initialized = false;
1164
+ _context;
1165
+ _stats = {
1166
+ initialized: false,
1167
+ totalExecutions: 0,
1168
+ successfulExecutions: 0,
1169
+ failedExecutions: 0
1170
+ };
1171
+ _healthCheckTimer;
1172
+ constructor(config) {
1173
+ this.name = config.name;
1174
+ this.description = config.description;
1175
+ this.initializeFn = config.initialize?.bind(this);
1176
+ this.executeFn = config.execute.bind(this);
1177
+ this.cleanupFn = config.cleanup?.bind(this);
1178
+ this.healthCheckFn = config.healthCheck?.bind(this);
1179
+ this.autoCleanup = config.autoCleanup ?? true;
1180
+ this.healthCheckInterval = config.healthCheckInterval;
1181
+ this._context = config.context;
1182
+ if (this.autoCleanup) {
1183
+ process.on("beforeExit", () => {
1184
+ this.cleanup().catch(console.error);
1185
+ });
1186
+ }
1187
+ }
1188
+ /**
1189
+ * Get the tool context (e.g., connection pool, API client)
1190
+ */
1191
+ get context() {
1192
+ return this._context;
1193
+ }
1194
+ /**
1195
+ * Set the tool context
1196
+ */
1197
+ set context(value) {
1198
+ this._context = value;
1199
+ }
1200
+ /**
1201
+ * Check if tool is initialized
1202
+ */
1203
+ get initialized() {
1204
+ return this._initialized;
1205
+ }
1206
+ /**
1207
+ * Initialize the tool
1208
+ */
1209
+ async initialize() {
1210
+ if (this._initialized) {
1211
+ return;
1212
+ }
1213
+ if (this.initializeFn) {
1214
+ await this.initializeFn();
1215
+ }
1216
+ this._initialized = true;
1217
+ this._stats.initialized = true;
1218
+ if (this.healthCheckInterval && this.healthCheckFn) {
1219
+ this._healthCheckTimer = setInterval(async () => {
1220
+ try {
1221
+ const result = await this.healthCheckFn();
1222
+ this._stats.lastHealthCheck = result;
1223
+ this._stats.lastHealthCheckTime = Date.now();
1224
+ } catch (error) {
1225
+ this._stats.lastHealthCheck = {
1226
+ healthy: false,
1227
+ error: error.message
1228
+ };
1229
+ this._stats.lastHealthCheckTime = Date.now();
1230
+ }
1231
+ }, this.healthCheckInterval);
1232
+ }
1233
+ }
1234
+ /**
1235
+ * Execute the tool
1236
+ */
1237
+ async execute(input) {
1238
+ if (!this._initialized) {
1239
+ throw new Error(`Tool ${this.name} is not initialized. Call initialize() first.`);
1240
+ }
1241
+ const startTime = Date.now();
1242
+ this._stats.totalExecutions++;
1243
+ try {
1244
+ const result = await this.executeFn(input);
1245
+ this._stats.successfulExecutions++;
1246
+ this._stats.lastExecutionTime = Date.now() - startTime;
1247
+ return result;
1248
+ } catch (error) {
1249
+ this._stats.failedExecutions++;
1250
+ this._stats.lastExecutionTime = Date.now() - startTime;
1251
+ throw error;
1252
+ }
1253
+ }
1254
+ /**
1255
+ * Cleanup the tool
1256
+ */
1257
+ async cleanup() {
1258
+ if (!this._initialized) {
1259
+ return;
1260
+ }
1261
+ if (this._healthCheckTimer) {
1262
+ clearInterval(this._healthCheckTimer);
1263
+ this._healthCheckTimer = void 0;
1264
+ }
1265
+ if (this.cleanupFn) {
1266
+ await this.cleanupFn();
1267
+ }
1268
+ this._initialized = false;
1269
+ this._stats.initialized = false;
1270
+ }
1271
+ /**
1272
+ * Run health check
1273
+ */
1274
+ async healthCheck() {
1275
+ if (!this._initialized) {
1276
+ return {
1277
+ healthy: false,
1278
+ error: "Tool is not initialized"
1279
+ };
1280
+ }
1281
+ if (!this.healthCheckFn) {
1282
+ return {
1283
+ healthy: true,
1284
+ metadata: { message: "No health check configured" }
1285
+ };
1286
+ }
1287
+ try {
1288
+ const result = await this.healthCheckFn();
1289
+ this._stats.lastHealthCheck = result;
1290
+ this._stats.lastHealthCheckTime = Date.now();
1291
+ return result;
1292
+ } catch (error) {
1293
+ const result = {
1294
+ healthy: false,
1295
+ error: error.message
1296
+ };
1297
+ this._stats.lastHealthCheck = result;
1298
+ this._stats.lastHealthCheckTime = Date.now();
1299
+ return result;
1300
+ }
1301
+ }
1302
+ /**
1303
+ * Get tool statistics
1304
+ */
1305
+ getStats() {
1306
+ return { ...this._stats };
1307
+ }
1308
+ /**
1309
+ * Reset statistics
1310
+ */
1311
+ resetStats() {
1312
+ this._stats.totalExecutions = 0;
1313
+ this._stats.successfulExecutions = 0;
1314
+ this._stats.failedExecutions = 0;
1315
+ this._stats.lastExecutionTime = void 0;
1316
+ }
1317
+ /**
1318
+ * Convert to LangChain tool format
1319
+ */
1320
+ toLangChainTool() {
1321
+ return {
1322
+ name: this.name,
1323
+ description: this.description,
1324
+ invoke: async (input) => {
1325
+ return await this.execute(input);
1326
+ }
1327
+ };
1328
+ }
1329
+ };
1330
+ function createManagedTool(config) {
1331
+ return new ManagedTool(config);
1332
+ }
1333
+
1334
+ // src/tools/composition.ts
1335
+ function sequential(tools) {
1336
+ return {
1337
+ name: `sequential(${tools.map((t) => t.name).join(" -> ")})`,
1338
+ description: `Execute tools sequentially: ${tools.map((t) => t.name).join(" -> ")}`,
1339
+ invoke: async (input) => {
1340
+ let result = input;
1341
+ for (const tool of tools) {
1342
+ result = await tool.invoke(result);
1343
+ }
1344
+ return result;
1345
+ }
1346
+ };
1347
+ }
1348
+ function parallel(tools) {
1349
+ return {
1350
+ name: `parallel(${tools.map((t) => t.name).join(", ")})`,
1351
+ description: `Execute tools in parallel: ${tools.map((t) => t.name).join(", ")}`,
1352
+ invoke: async (input) => {
1353
+ const results = await Promise.all(tools.map((tool) => tool.invoke(input)));
1354
+ return results;
1355
+ }
1356
+ };
1357
+ }
1358
+ function conditional(config) {
1359
+ return {
1360
+ name: `conditional(${config.onTrue.name} | ${config.onFalse.name})`,
1361
+ description: `Conditionally execute ${config.onTrue.name} or ${config.onFalse.name}`,
1362
+ invoke: async (input) => {
1363
+ const shouldExecuteTrue = await config.condition(input);
1364
+ const tool = shouldExecuteTrue ? config.onTrue : config.onFalse;
1365
+ return await tool.invoke(input);
1366
+ }
1367
+ };
1368
+ }
1369
+ function composeTool(config) {
1370
+ return {
1371
+ name: config.name,
1372
+ description: config.description || `Composed tool: ${config.name}`,
1373
+ invoke: async (input) => {
1374
+ let result = input;
1375
+ for (const step of config.steps) {
1376
+ if (Array.isArray(step)) {
1377
+ result = await parallel(step).invoke(result);
1378
+ } else if ("condition" in step) {
1379
+ result = await conditional(step).invoke(result);
1380
+ } else {
1381
+ result = await step.invoke(result);
1382
+ }
1383
+ }
1384
+ if (config.transformResult) {
1385
+ result = config.transformResult(result);
1386
+ }
1387
+ return result;
1388
+ }
1389
+ };
1390
+ }
1391
+ function retry(tool, options = {}) {
1392
+ const { maxAttempts = 3, delay = 1e3, backoff = "exponential" } = options;
1393
+ return {
1394
+ name: `retry(${tool.name})`,
1395
+ description: `${tool.description} (with retry)`,
1396
+ invoke: async (input) => {
1397
+ let lastError;
1398
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1399
+ try {
1400
+ return await tool.invoke(input);
1401
+ } catch (error) {
1402
+ lastError = error;
1403
+ if (attempt < maxAttempts) {
1404
+ const waitTime = backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1405
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
1406
+ }
1407
+ }
1408
+ }
1409
+ throw lastError;
1410
+ }
1411
+ };
1412
+ }
1413
+ function timeout(tool, ms) {
1414
+ return {
1415
+ name: `timeout(${tool.name})`,
1416
+ description: `${tool.description} (with ${ms}ms timeout)`,
1417
+ invoke: async (input) => {
1418
+ return Promise.race([
1419
+ tool.invoke(input),
1420
+ new Promise(
1421
+ (_, reject) => setTimeout(() => reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`)), ms)
1422
+ )
1423
+ ]);
1424
+ }
1425
+ };
1426
+ }
1427
+ function cache(tool, ttl) {
1428
+ const cacheMap = /* @__PURE__ */ new Map();
1429
+ return {
1430
+ name: `cache(${tool.name})`,
1431
+ description: `${tool.description} (with caching)`,
1432
+ invoke: async (input) => {
1433
+ const key = JSON.stringify(input);
1434
+ const cached = cacheMap.get(key);
1435
+ if (cached) {
1436
+ if (!ttl || Date.now() - cached.timestamp < ttl) {
1437
+ return cached.result;
1438
+ }
1439
+ cacheMap.delete(key);
1440
+ }
1441
+ const result = await tool.invoke(input);
1442
+ cacheMap.set(key, { result, timestamp: Date.now() });
1443
+ return result;
1444
+ }
1445
+ };
1446
+ }
1447
+
1448
+ // src/tools/testing.ts
1449
+ function createMockTool(config) {
1450
+ const {
1451
+ name,
1452
+ description = `Mock tool: ${name}`,
1453
+ responses = [],
1454
+ defaultResponse,
1455
+ latency,
1456
+ errorRate = 0
1457
+ } = config;
1458
+ const invocations = [];
1459
+ return {
1460
+ name,
1461
+ description,
1462
+ invoke: async (input) => {
1463
+ const startTime = Date.now();
1464
+ if (latency) {
1465
+ const delay = typeof latency === "number" ? latency : Math.random() * (latency.max - latency.min) + latency.min;
1466
+ await new Promise((resolve) => setTimeout(resolve, delay));
1467
+ }
1468
+ if (errorRate > 0 && Math.random() < errorRate) {
1469
+ const error2 = new Error(`Random error from ${name}`);
1470
+ invocations.push({
1471
+ input,
1472
+ error: error2,
1473
+ timestamp: startTime,
1474
+ duration: Date.now() - startTime
1475
+ });
1476
+ throw error2;
1477
+ }
1478
+ const matchingResponse = responses.find((r) => {
1479
+ if (typeof r.input === "function") {
1480
+ return r.input(input);
1481
+ }
1482
+ return JSON.stringify(r.input) === JSON.stringify(input);
1483
+ });
1484
+ if (matchingResponse) {
1485
+ if (matchingResponse.error) {
1486
+ invocations.push({
1487
+ input,
1488
+ error: matchingResponse.error,
1489
+ timestamp: startTime,
1490
+ duration: Date.now() - startTime
1491
+ });
1492
+ throw matchingResponse.error;
1493
+ }
1494
+ invocations.push({
1495
+ input,
1496
+ output: matchingResponse.output,
1497
+ timestamp: startTime,
1498
+ duration: Date.now() - startTime
1499
+ });
1500
+ return matchingResponse.output;
1501
+ }
1502
+ if (defaultResponse !== void 0) {
1503
+ invocations.push({
1504
+ input,
1505
+ output: defaultResponse,
1506
+ timestamp: startTime,
1507
+ duration: Date.now() - startTime
1508
+ });
1509
+ return defaultResponse;
1510
+ }
1511
+ const error = new Error(`No mock response configured for input: ${JSON.stringify(input)}`);
1512
+ invocations.push({
1513
+ input,
1514
+ error,
1515
+ timestamp: startTime,
1516
+ duration: Date.now() - startTime
1517
+ });
1518
+ throw error;
1519
+ },
1520
+ getInvocations: () => [...invocations],
1521
+ clearInvocations: () => {
1522
+ invocations.length = 0;
1523
+ }
1524
+ };
1525
+ }
1526
+ function createToolSimulator(config) {
1527
+ const { tools, errorRate = 0, latency, recordInvocations = true } = config;
1528
+ const toolMap = new Map(tools.map((t) => [t.name, t]));
1529
+ const invocations = /* @__PURE__ */ new Map();
1530
+ if (recordInvocations) {
1531
+ tools.forEach((t) => invocations.set(t.name, []));
1532
+ }
1533
+ function generateLatency() {
1534
+ if (!latency) return 0;
1535
+ const u1 = Math.random();
1536
+ const u2 = Math.random();
1537
+ const z3 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
1538
+ return Math.max(0, latency.mean + z3 * latency.stddev);
1539
+ }
1540
+ return {
1541
+ execute: async (toolName, input) => {
1542
+ const tool = toolMap.get(toolName);
1543
+ if (!tool) {
1544
+ throw new Error(`Tool ${toolName} not found in simulator`);
1545
+ }
1546
+ const startTime = Date.now();
1547
+ if (latency) {
1548
+ const delay = generateLatency();
1549
+ await new Promise((resolve) => setTimeout(resolve, delay));
1550
+ }
1551
+ if (errorRate > 0 && Math.random() < errorRate) {
1552
+ const error = new Error(`Simulated error from ${toolName}`);
1553
+ if (recordInvocations) {
1554
+ invocations.get(toolName).push({
1555
+ input,
1556
+ error,
1557
+ timestamp: startTime,
1558
+ duration: Date.now() - startTime
1559
+ });
1560
+ }
1561
+ throw error;
1562
+ }
1563
+ try {
1564
+ const result = await tool.invoke(input);
1565
+ if (recordInvocations) {
1566
+ invocations.get(toolName).push({
1567
+ input,
1568
+ output: result,
1569
+ timestamp: startTime,
1570
+ duration: Date.now() - startTime
1571
+ });
1572
+ }
1573
+ return result;
1574
+ } catch (error) {
1575
+ if (recordInvocations) {
1576
+ invocations.get(toolName).push({
1577
+ input,
1578
+ error,
1579
+ timestamp: startTime,
1580
+ duration: Date.now() - startTime
1581
+ });
1582
+ }
1583
+ throw error;
1584
+ }
1585
+ },
1586
+ getInvocations: (toolName) => {
1587
+ return invocations.get(toolName) ? [...invocations.get(toolName)] : [];
1588
+ },
1589
+ getAllInvocations: () => {
1590
+ const all = {};
1591
+ invocations.forEach((invs, name) => {
1592
+ all[name] = [...invs];
1593
+ });
1594
+ return all;
1595
+ },
1596
+ clearInvocations: (toolName) => {
1597
+ if (toolName) {
1598
+ invocations.get(toolName)?.splice(0);
1599
+ } else {
1600
+ invocations.forEach((invs) => invs.splice(0));
1601
+ }
1602
+ }
1603
+ };
1604
+ }
1605
+
1606
+ // src/langgraph/state.ts
1607
+ import { Annotation } from "@langchain/langgraph";
1608
+ function createStateAnnotation(config) {
1609
+ const stateDefinition = {};
1610
+ for (const [key, channelConfig] of Object.entries(config)) {
1611
+ if (channelConfig.reducer) {
1612
+ stateDefinition[key] = Annotation({
1613
+ reducer: channelConfig.reducer,
1614
+ default: channelConfig.default
1615
+ });
1616
+ } else {
1617
+ stateDefinition[key] = Annotation();
1618
+ }
1619
+ }
1620
+ return Annotation.Root(stateDefinition);
1621
+ }
1622
+ function validateState(state, config) {
1623
+ const validated = {};
1624
+ for (const [key, channelConfig] of Object.entries(config)) {
1625
+ if (channelConfig.schema && key in state) {
1626
+ validated[key] = channelConfig.schema.parse(state[key]);
1627
+ } else if (key in state) {
1628
+ validated[key] = state[key];
1629
+ } else if (channelConfig.default) {
1630
+ validated[key] = channelConfig.default();
1631
+ }
1632
+ }
1633
+ return validated;
1634
+ }
1635
+ function mergeState(currentState, update, config) {
1636
+ const merged = { ...currentState };
1637
+ for (const [key, value] of Object.entries(update)) {
1638
+ const channelConfig = config[key];
1639
+ if (channelConfig?.reducer && key in merged) {
1640
+ merged[key] = channelConfig.reducer(merged[key], value);
1641
+ } else {
1642
+ merged[key] = value;
1643
+ }
1644
+ }
1645
+ return merged;
1646
+ }
1647
+
1648
+ // src/langgraph/builders/sequential.ts
1649
+ import { StateGraph, END, START } from "@langchain/langgraph";
1650
+ function createSequentialWorkflow(stateSchema, nodes, options = {}) {
1651
+ const { autoStartEnd = true, name } = options;
1652
+ if (nodes.length === 0) {
1653
+ throw new Error("Sequential workflow must have at least one node");
1654
+ }
1655
+ const nodeNames = /* @__PURE__ */ new Set();
1656
+ for (const node of nodes) {
1657
+ if (nodeNames.has(node.name)) {
1658
+ throw new Error(`Duplicate node name: ${node.name}`);
1659
+ }
1660
+ nodeNames.add(node.name);
1661
+ }
1662
+ const graph = new StateGraph(stateSchema);
1663
+ for (const { name: nodeName, node } of nodes) {
1664
+ graph.addNode(nodeName, node);
1665
+ }
1666
+ if (autoStartEnd) {
1667
+ graph.addEdge(START, nodes[0].name);
1668
+ }
1669
+ for (let i = 0; i < nodes.length - 1; i++) {
1670
+ graph.addEdge(nodes[i].name, nodes[i + 1].name);
1671
+ }
1672
+ if (autoStartEnd) {
1673
+ graph.addEdge(nodes[nodes.length - 1].name, END);
1674
+ }
1675
+ return graph;
1676
+ }
1677
+ function sequentialBuilder(stateSchema) {
1678
+ const nodes = [];
1679
+ let options = {};
1680
+ return {
1681
+ /**
1682
+ * Add a node to the sequential workflow
1683
+ */
1684
+ addNode(name, node, description) {
1685
+ nodes.push({ name, node, description });
1686
+ return this;
1687
+ },
1688
+ /**
1689
+ * Set options for the workflow
1690
+ */
1691
+ options(opts) {
1692
+ options = { ...options, ...opts };
1693
+ return this;
1694
+ },
1695
+ /**
1696
+ * Build the StateGraph
1697
+ */
1698
+ build() {
1699
+ return createSequentialWorkflow(stateSchema, nodes, options);
1700
+ }
1701
+ };
1702
+ }
1703
+
1704
+ // src/langgraph/builders/parallel.ts
1705
+ import { StateGraph as StateGraph2, END as END2, START as START2 } from "@langchain/langgraph";
1706
+ function createParallelWorkflow(stateSchema, config, options = {}) {
1707
+ const { parallel: parallel2, aggregate } = config;
1708
+ const { autoStartEnd = true, name } = options;
1709
+ if (parallel2.length === 0) {
1710
+ throw new Error("Parallel workflow must have at least one parallel node");
1711
+ }
1712
+ const nodeNames = /* @__PURE__ */ new Set();
1713
+ for (const node of parallel2) {
1714
+ if (nodeNames.has(node.name)) {
1715
+ throw new Error(`Duplicate node name: ${node.name}`);
1716
+ }
1717
+ nodeNames.add(node.name);
1718
+ }
1719
+ if (aggregate && nodeNames.has(aggregate.name)) {
1720
+ throw new Error(`Duplicate node name: ${aggregate.name}`);
1721
+ }
1722
+ const graph = new StateGraph2(stateSchema);
1723
+ for (const { name: nodeName, node } of parallel2) {
1724
+ graph.addNode(nodeName, node);
1725
+ }
1726
+ if (aggregate) {
1727
+ graph.addNode(aggregate.name, aggregate.node);
1728
+ }
1729
+ if (autoStartEnd) {
1730
+ for (const { name: nodeName } of parallel2) {
1731
+ graph.addEdge(START2, nodeName);
1732
+ }
1733
+ }
1734
+ if (aggregate) {
1735
+ for (const { name: nodeName } of parallel2) {
1736
+ graph.addEdge(nodeName, aggregate.name);
1737
+ }
1738
+ if (autoStartEnd) {
1739
+ graph.addEdge(aggregate.name, END2);
1740
+ }
1741
+ } else if (autoStartEnd) {
1742
+ for (const { name: nodeName } of parallel2) {
1743
+ graph.addEdge(nodeName, END2);
1744
+ }
1745
+ }
1746
+ return graph;
1747
+ }
1748
+
1749
+ // src/langgraph/builders/conditional.ts
1750
+ function createConditionalRouter(config) {
1751
+ const { routes, condition, description } = config;
1752
+ if (Object.keys(routes).length === 0) {
1753
+ throw new Error("Conditional router must have at least one route");
1754
+ }
1755
+ if (typeof condition !== "function") {
1756
+ throw new Error("Conditional router must have a condition function");
1757
+ }
1758
+ return {
1759
+ routes,
1760
+ condition,
1761
+ description
1762
+ };
1763
+ }
1764
+ function createBinaryRouter(config) {
1765
+ const { condition, ifTrue, ifFalse, description } = config;
1766
+ return {
1767
+ routes: {
1768
+ true: ifTrue,
1769
+ false: ifFalse
1770
+ },
1771
+ condition: (state) => condition(state) ? "true" : "false",
1772
+ description
1773
+ };
1774
+ }
1775
+ function createMultiRouter(config) {
1776
+ const { discriminator, routes, default: defaultRoute, description } = config;
1777
+ return {
1778
+ routes,
1779
+ condition: (state) => {
1780
+ const key = discriminator(state);
1781
+ if (key in routes) {
1782
+ return key;
1783
+ }
1784
+ if (defaultRoute !== void 0) {
1785
+ return defaultRoute;
1786
+ }
1787
+ throw new Error(`No route found for discriminator value: ${key}`);
1788
+ },
1789
+ description
1790
+ };
1791
+ }
1792
+
1793
+ // src/langgraph/builders/subgraph.ts
1794
+ import { StateGraph as StateGraph3 } from "@langchain/langgraph";
1795
+ function createSubgraph(stateSchema, builder) {
1796
+ const graph = new StateGraph3(stateSchema);
1797
+ const configured = builder(graph);
1798
+ return configured.compile();
1799
+ }
1800
+ function composeGraphs(parentGraph, subgraph, options) {
1801
+ const { name } = options;
1802
+ parentGraph.addNode(name, subgraph);
1803
+ return parentGraph;
1804
+ }
1805
+
1806
+ // src/langgraph/patterns/retry.ts
1807
+ function calculateDelay(attempt, strategy, initialDelay, maxDelay) {
1808
+ let delay;
1809
+ switch (strategy) {
1810
+ case "constant":
1811
+ delay = initialDelay;
1812
+ break;
1813
+ case "linear":
1814
+ delay = initialDelay * attempt;
1815
+ break;
1816
+ case "exponential":
1817
+ delay = initialDelay * Math.pow(2, attempt - 1);
1818
+ break;
1819
+ }
1820
+ return Math.min(delay, maxDelay);
1821
+ }
1822
+ function sleep(ms) {
1823
+ return new Promise((resolve) => setTimeout(resolve, ms));
1824
+ }
1825
+ function withRetry(node, options = {}) {
1826
+ const {
1827
+ maxAttempts = 3,
1828
+ backoff = "exponential",
1829
+ initialDelay = 1e3,
1830
+ maxDelay = 3e4,
1831
+ onRetry,
1832
+ shouldRetry = () => true
1833
+ } = options;
1834
+ return async (state) => {
1835
+ let lastError;
1836
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1837
+ try {
1838
+ return await Promise.resolve(node(state));
1839
+ } catch (error) {
1840
+ lastError = error instanceof Error ? error : new Error(String(error));
1841
+ if (!shouldRetry(lastError)) {
1842
+ throw lastError;
1843
+ }
1844
+ if (attempt === maxAttempts) {
1845
+ throw lastError;
1846
+ }
1847
+ if (onRetry) {
1848
+ onRetry(lastError, attempt);
1849
+ }
1850
+ const delay = calculateDelay(attempt, backoff, initialDelay, maxDelay);
1851
+ await sleep(delay);
1852
+ }
1853
+ }
1854
+ throw lastError || new Error("Retry failed");
1855
+ };
1856
+ }
1857
+
1858
+ // src/langgraph/patterns/error-handler.ts
1859
+ function withErrorHandler(node, options) {
1860
+ const { onError, logError, rethrow = false } = options;
1861
+ return async (state) => {
1862
+ try {
1863
+ return await Promise.resolve(node(state));
1864
+ } catch (error) {
1865
+ const err = error instanceof Error ? error : new Error(String(error));
1866
+ if (logError) {
1867
+ logError(err, state);
1868
+ }
1869
+ const result = await Promise.resolve(onError(err, state));
1870
+ if (rethrow) {
1871
+ throw err;
1872
+ }
1873
+ return result;
1874
+ }
1875
+ };
1876
+ }
1877
+
1878
+ // src/langgraph/patterns/timeout.ts
1879
+ var TimeoutError = class extends Error {
1880
+ constructor(timeout2) {
1881
+ super(`Node execution timed out after ${timeout2}ms`);
1882
+ this.name = "TimeoutError";
1883
+ }
1884
+ };
1885
+ function withTimeout(node, options) {
1886
+ const { timeout: timeout2, onTimeout, logTimeout, throwOnTimeout = false } = options;
1887
+ return async (state) => {
1888
+ const timeoutPromise = new Promise((_, reject) => {
1889
+ setTimeout(() => {
1890
+ reject(new TimeoutError(timeout2));
1891
+ }, timeout2);
1892
+ });
1893
+ try {
1894
+ return await Promise.race([Promise.resolve(node(state)), timeoutPromise]);
1895
+ } catch (error) {
1896
+ if (error instanceof TimeoutError) {
1897
+ if (logTimeout) {
1898
+ logTimeout(state);
1899
+ }
1900
+ if (throwOnTimeout) {
1901
+ throw error;
1902
+ }
1903
+ return await Promise.resolve(onTimeout(state));
1904
+ }
1905
+ throw error;
1906
+ }
1907
+ };
1908
+ }
1909
+
1910
+ // src/langgraph/persistence/checkpointer.ts
1911
+ import { MemorySaver } from "@langchain/langgraph";
1912
+ function createMemoryCheckpointer(options) {
1913
+ return new MemorySaver();
1914
+ }
1915
+ async function createSqliteCheckpointer(options = {}) {
1916
+ const { path = ":memory:", autoMigrate = true } = options;
1917
+ try {
1918
+ const { SqliteSaver } = await import("@langchain/langgraph-checkpoint-sqlite");
1919
+ const checkpointer = SqliteSaver.fromConnString(path);
1920
+ if (autoMigrate) {
1921
+ await checkpointer.setup();
1922
+ }
1923
+ return checkpointer;
1924
+ } catch (error) {
1925
+ if (error instanceof Error && error.message.includes("Cannot find module")) {
1926
+ throw new Error(
1927
+ "SQLite checkpointer requires @langchain/langgraph-checkpoint-sqlite to be installed. Install it with: npm install @langchain/langgraph-checkpoint-sqlite"
1928
+ );
1929
+ }
1930
+ throw error;
1931
+ }
1932
+ }
1933
+ function isMemoryCheckpointer(checkpointer) {
1934
+ return checkpointer instanceof MemorySaver;
1935
+ }
1936
+
1937
+ // src/langgraph/persistence/thread.ts
1938
+ import { randomUUID } from "crypto";
1939
+ function generateThreadId(seed) {
1940
+ if (seed && seed.length > 0) {
1941
+ const hash = Buffer.from(seed).toString("base64").replace(/[^a-zA-Z0-9]/g, "");
1942
+ return `thread-${hash}`;
1943
+ }
1944
+ return randomUUID();
1945
+ }
1946
+ function createThreadConfig(config = {}) {
1947
+ const { threadId = generateThreadId(), checkpointId, checkpointNamespace, metadata } = config;
1948
+ const runnableConfig = {
1949
+ configurable: {
1950
+ thread_id: threadId
1951
+ }
1952
+ };
1953
+ if (checkpointId) {
1954
+ runnableConfig.configurable.checkpoint_id = checkpointId;
1955
+ }
1956
+ if (checkpointNamespace) {
1957
+ runnableConfig.configurable.checkpoint_ns = checkpointNamespace;
1958
+ }
1959
+ if (metadata) {
1960
+ runnableConfig.metadata = metadata;
1961
+ }
1962
+ return runnableConfig;
1963
+ }
1964
+ function createConversationConfig(config) {
1965
+ const { userId, sessionId, metadata = {} } = config;
1966
+ const threadId = sessionId ? generateThreadId(`${userId}-${sessionId}`) : generateThreadId(userId);
1967
+ return createThreadConfig({
1968
+ threadId,
1969
+ metadata: {
1970
+ ...metadata,
1971
+ userId,
1972
+ sessionId
1973
+ }
1974
+ });
1975
+ }
1976
+
1977
+ // src/langgraph/persistence/utils.ts
1978
+ async function getCheckpointHistory(checkpointer, options) {
1979
+ const { threadId, limit = 10, before } = options;
1980
+ const config = {
1981
+ configurable: {
1982
+ thread_id: threadId
1983
+ }
1984
+ };
1985
+ if (before) {
1986
+ config.configurable.checkpoint_id = before;
1987
+ }
1988
+ const checkpoints = [];
1989
+ for await (const checkpoint of checkpointer.list(config, { limit })) {
1990
+ checkpoints.push(checkpoint);
1991
+ }
1992
+ return checkpoints;
1993
+ }
1994
+ async function getLatestCheckpoint(checkpointer, options) {
1995
+ const { threadId } = options;
1996
+ const config = {
1997
+ configurable: {
1998
+ thread_id: threadId
1999
+ }
2000
+ };
2001
+ const tuple = await checkpointer.getTuple(config);
2002
+ return tuple || null;
2003
+ }
2004
+ async function clearThread(checkpointer, options) {
2005
+ const { threadId } = options;
2006
+ const checkpoints = await getCheckpointHistory(checkpointer, {
2007
+ threadId,
2008
+ limit: 1e3
2009
+ // Get all checkpoints
2010
+ });
2011
+ if (checkpoints.length > 0) {
2012
+ throw new Error(
2013
+ "Clearing threads is not supported by the current checkpointer implementation. Consider using a new thread ID instead."
2014
+ );
2015
+ }
2016
+ }
2017
+
2018
+ // src/langgraph/observability/langsmith.ts
2019
+ var globalConfig = null;
2020
+ function configureLangSmith(config) {
2021
+ globalConfig = config;
2022
+ if (config.apiKey) {
2023
+ process.env.LANGSMITH_API_KEY = config.apiKey;
2024
+ }
2025
+ if (config.projectName) {
2026
+ process.env.LANGSMITH_PROJECT = config.projectName;
2027
+ }
2028
+ if (config.tracingEnabled !== void 0) {
2029
+ process.env.LANGSMITH_TRACING = config.tracingEnabled ? "true" : "false";
2030
+ } else if (config.apiKey) {
2031
+ process.env.LANGSMITH_TRACING = "true";
2032
+ }
2033
+ if (config.endpoint) {
2034
+ process.env.LANGSMITH_ENDPOINT = config.endpoint;
2035
+ }
2036
+ }
2037
+ function getLangSmithConfig() {
2038
+ return globalConfig;
2039
+ }
2040
+ function isTracingEnabled() {
2041
+ return process.env.LANGSMITH_TRACING === "true";
2042
+ }
2043
+ function withTracing(node, options) {
2044
+ const { name, metadata, tags, runName } = options;
2045
+ return async (state) => {
2046
+ if (isTracingEnabled()) {
2047
+ const result = await Promise.resolve(node(state));
2048
+ return result;
2049
+ }
2050
+ return await Promise.resolve(node(state));
2051
+ };
2052
+ }
2053
+
2054
+ // src/langgraph/observability/logger.ts
2055
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
2056
+ LogLevel2["DEBUG"] = "debug";
2057
+ LogLevel2["INFO"] = "info";
2058
+ LogLevel2["WARN"] = "warn";
2059
+ LogLevel2["ERROR"] = "error";
2060
+ return LogLevel2;
2061
+ })(LogLevel || {});
2062
+ var LOG_LEVEL_PRIORITY = {
2063
+ ["debug" /* DEBUG */]: 0,
2064
+ ["info" /* INFO */]: 1,
2065
+ ["warn" /* WARN */]: 2,
2066
+ ["error" /* ERROR */]: 3
2067
+ };
2068
+ var LoggerImpl = class _LoggerImpl {
2069
+ name;
2070
+ options;
2071
+ context;
2072
+ constructor(name, options = {}, context = {}) {
2073
+ this.name = name;
2074
+ this.context = context;
2075
+ this.options = {
2076
+ level: options.level ?? "info" /* INFO */,
2077
+ format: options.format ?? "pretty",
2078
+ destination: options.destination ?? process.stdout,
2079
+ includeTimestamp: options.includeTimestamp ?? true,
2080
+ includeContext: options.includeContext ?? true
2081
+ };
2082
+ }
2083
+ debug(message, data) {
2084
+ this.log("debug" /* DEBUG */, message, data);
2085
+ }
2086
+ info(message, data) {
2087
+ this.log("info" /* INFO */, message, data);
2088
+ }
2089
+ warn(message, data) {
2090
+ this.log("warn" /* WARN */, message, data);
2091
+ }
2092
+ error(message, data) {
2093
+ this.log("error" /* ERROR */, message, data);
2094
+ }
2095
+ withContext(context) {
2096
+ return new _LoggerImpl(this.name, this.options, { ...this.context, ...context });
2097
+ }
2098
+ log(level, message, data) {
2099
+ if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.options.level]) {
2100
+ return;
2101
+ }
2102
+ const entry = {
2103
+ level,
2104
+ name: this.name,
2105
+ message
2106
+ };
2107
+ if (this.options.includeTimestamp) {
2108
+ entry.timestamp = (/* @__PURE__ */ new Date()).toISOString();
2109
+ }
2110
+ if (this.options.includeContext && Object.keys(this.context).length > 0) {
2111
+ entry.context = this.context;
2112
+ }
2113
+ if (data) {
2114
+ entry.data = data;
2115
+ }
2116
+ const output = this.format(entry);
2117
+ this.options.destination.write(output + "\n");
2118
+ }
2119
+ format(entry) {
2120
+ if (this.options.format === "json") {
2121
+ return JSON.stringify(entry);
2122
+ }
2123
+ const parts = [];
2124
+ if (entry.timestamp) {
2125
+ parts.push(`[${entry.timestamp}]`);
2126
+ }
2127
+ parts.push(`[${entry.level.toUpperCase()}]`);
2128
+ parts.push(`[${entry.name}]`);
2129
+ parts.push(entry.message);
2130
+ if (entry.context) {
2131
+ parts.push(`context=${JSON.stringify(entry.context)}`);
2132
+ }
2133
+ if (entry.data) {
2134
+ parts.push(`data=${JSON.stringify(entry.data)}`);
2135
+ }
2136
+ return parts.join(" ");
2137
+ }
2138
+ };
2139
+ function createLogger(name, options) {
2140
+ return new LoggerImpl(name, options);
2141
+ }
2142
+
2143
+ // src/langgraph/observability/metrics.ts
2144
+ var MetricType = /* @__PURE__ */ ((MetricType2) => {
2145
+ MetricType2["COUNTER"] = "counter";
2146
+ MetricType2["GAUGE"] = "gauge";
2147
+ MetricType2["HISTOGRAM"] = "histogram";
2148
+ return MetricType2;
2149
+ })(MetricType || {});
2150
+ var MetricsImpl = class {
2151
+ name;
2152
+ metrics = [];
2153
+ counters = /* @__PURE__ */ new Map();
2154
+ constructor(name) {
2155
+ this.name = name;
2156
+ }
2157
+ increment(name, value = 1, labels) {
2158
+ const key = this.getKey(name, labels);
2159
+ const current = this.counters.get(key) ?? 0;
2160
+ this.counters.set(key, current + value);
2161
+ this.record({
2162
+ type: "counter" /* COUNTER */,
2163
+ name: this.prefixName(name),
2164
+ value: current + value,
2165
+ timestamp: Date.now(),
2166
+ labels
2167
+ });
2168
+ }
2169
+ decrement(name, value = 1, labels) {
2170
+ this.increment(name, -value, labels);
2171
+ }
2172
+ gauge(name, value, labels) {
2173
+ this.record({
2174
+ type: "gauge" /* GAUGE */,
2175
+ name: this.prefixName(name),
2176
+ value,
2177
+ timestamp: Date.now(),
2178
+ labels
2179
+ });
2180
+ }
2181
+ histogram(name, value, labels) {
2182
+ this.record({
2183
+ type: "histogram" /* HISTOGRAM */,
2184
+ name: this.prefixName(name),
2185
+ value,
2186
+ timestamp: Date.now(),
2187
+ labels
2188
+ });
2189
+ }
2190
+ startTimer(name, labels) {
2191
+ const startTime = Date.now();
2192
+ return {
2193
+ end: () => {
2194
+ const duration = Date.now() - startTime;
2195
+ this.histogram(name, duration, labels);
2196
+ return duration;
2197
+ }
2198
+ };
2199
+ }
2200
+ getMetrics() {
2201
+ return [...this.metrics];
2202
+ }
2203
+ clear() {
2204
+ this.metrics = [];
2205
+ this.counters.clear();
2206
+ }
2207
+ record(entry) {
2208
+ this.metrics.push(entry);
2209
+ }
2210
+ prefixName(name) {
2211
+ return `${this.name}.${name}`;
2212
+ }
2213
+ getKey(name, labels) {
2214
+ const labelStr = labels ? JSON.stringify(labels) : "";
2215
+ return `${name}:${labelStr}`;
2216
+ }
2217
+ };
2218
+ function createMetrics(name) {
2219
+ return new MetricsImpl(name);
2220
+ }
2221
+ function withMetrics(node, options) {
2222
+ const {
2223
+ name,
2224
+ trackDuration = true,
2225
+ trackErrors = true,
2226
+ trackInvocations = true,
2227
+ metrics = createMetrics(name)
2228
+ } = options;
2229
+ return async (state) => {
2230
+ if (trackInvocations) {
2231
+ metrics.increment(`${name}.invocations`);
2232
+ }
2233
+ const timer = trackDuration ? metrics.startTimer(`${name}.duration`) : null;
2234
+ try {
2235
+ const result = await Promise.resolve(node(state));
2236
+ metrics.increment(`${name}.success`);
2237
+ return result;
2238
+ } catch (error) {
2239
+ if (trackErrors) {
2240
+ metrics.increment(`${name}.errors`);
2241
+ }
2242
+ throw error;
2243
+ } finally {
2244
+ if (timer) {
2245
+ timer.end();
2246
+ }
2247
+ }
2248
+ };
2249
+ }
2250
+
2251
+ // src/langgraph/observability/errors.ts
2252
+ var AgentError = class _AgentError extends Error {
2253
+ code;
2254
+ node;
2255
+ state;
2256
+ metadata;
2257
+ cause;
2258
+ timestamp;
2259
+ constructor(message, context = {}) {
2260
+ super(message);
2261
+ this.name = "AgentError";
2262
+ this.code = context.code;
2263
+ this.node = context.node;
2264
+ this.state = context.state;
2265
+ this.metadata = context.metadata;
2266
+ this.cause = context.cause;
2267
+ this.timestamp = Date.now();
2268
+ if (Error.captureStackTrace) {
2269
+ Error.captureStackTrace(this, _AgentError);
2270
+ }
2271
+ }
2272
+ /**
2273
+ * Convert error to JSON for logging/reporting
2274
+ */
2275
+ toJSON() {
2276
+ return {
2277
+ name: this.name,
2278
+ message: this.message,
2279
+ code: this.code,
2280
+ node: this.node,
2281
+ state: this.state,
2282
+ metadata: this.metadata,
2283
+ timestamp: this.timestamp,
2284
+ stack: this.stack,
2285
+ cause: this.cause ? {
2286
+ name: this.cause.name,
2287
+ message: this.cause.message,
2288
+ stack: this.cause.stack
2289
+ } : void 0
2290
+ };
2291
+ }
2292
+ /**
2293
+ * Get a human-readable string representation
2294
+ */
2295
+ toString() {
2296
+ const parts = [`${this.name}: ${this.message}`];
2297
+ if (this.code) {
2298
+ parts.push(`Code: ${this.code}`);
2299
+ }
2300
+ if (this.node) {
2301
+ parts.push(`Node: ${this.node}`);
2302
+ }
2303
+ if (this.cause) {
2304
+ parts.push(`Caused by: ${this.cause.message}`);
2305
+ }
2306
+ return parts.join("\n");
2307
+ }
2308
+ };
2309
+ var ErrorReporterImpl = class {
2310
+ options;
2311
+ constructor(options) {
2312
+ this.options = {
2313
+ onError: options.onError,
2314
+ includeStackTrace: options.includeStackTrace ?? true,
2315
+ includeState: options.includeState ?? false,
2316
+ rethrow: options.rethrow ?? true
2317
+ };
2318
+ }
2319
+ wrap(node, nodeName) {
2320
+ return async (state) => {
2321
+ try {
2322
+ return await Promise.resolve(node(state));
2323
+ } catch (error) {
2324
+ const agentError = this.toAgentError(error, {
2325
+ node: nodeName,
2326
+ state: this.options.includeState ? state : void 0
2327
+ });
2328
+ await this.report(agentError);
2329
+ if (this.options.rethrow) {
2330
+ throw agentError;
2331
+ }
2332
+ return state;
2333
+ }
2334
+ };
2335
+ }
2336
+ async report(error, context) {
2337
+ const agentError = this.toAgentError(error, context);
2338
+ try {
2339
+ await Promise.resolve(this.options.onError(agentError));
2340
+ } catch (reportError) {
2341
+ console.error("Error reporting failed:", reportError);
2342
+ }
2343
+ }
2344
+ toAgentError(error, context) {
2345
+ if (error instanceof AgentError) {
2346
+ return error;
2347
+ }
2348
+ return new AgentError(error.message, {
2349
+ ...context,
2350
+ cause: error
2351
+ });
2352
+ }
2353
+ };
2354
+ function createErrorReporter(options) {
2355
+ return new ErrorReporterImpl(options);
2356
+ }
2357
+
2358
+ // src/langgraph/middleware/compose.ts
2359
+ function compose(...middleware) {
2360
+ return (node) => {
2361
+ return middleware.reduceRight(
2362
+ (wrappedNode, mw) => mw(wrappedNode),
2363
+ node
2364
+ );
2365
+ };
2366
+ }
2367
+ function composeWithOptions(options, ...middleware) {
2368
+ const { reverse = false, name, catchErrors = true } = options;
2369
+ return (node) => {
2370
+ const orderedMiddleware = reverse ? [...middleware].reverse() : middleware;
2371
+ let wrappedNode = orderedMiddleware.reduceRight(
2372
+ (wrappedNode2, mw) => mw(wrappedNode2),
2373
+ node
2374
+ );
2375
+ if (catchErrors) {
2376
+ const originalNode = wrappedNode;
2377
+ wrappedNode = async (state) => {
2378
+ try {
2379
+ return await Promise.resolve(originalNode(state));
2380
+ } catch (error) {
2381
+ const enhancedError = error instanceof Error ? error : new Error(String(error));
2382
+ if (name) {
2383
+ enhancedError.message = `[${name}] ${enhancedError.message}`;
2384
+ }
2385
+ throw enhancedError;
2386
+ }
2387
+ };
2388
+ }
2389
+ return wrappedNode;
2390
+ };
2391
+ }
2392
+ var MiddlewareChain = class {
2393
+ middleware = [];
2394
+ options = {};
2395
+ /**
2396
+ * Add middleware to the chain.
2397
+ */
2398
+ use(middleware) {
2399
+ this.middleware.push(middleware);
2400
+ return this;
2401
+ }
2402
+ /**
2403
+ * Set composition options.
2404
+ */
2405
+ withOptions(options) {
2406
+ this.options = { ...this.options, ...options };
2407
+ return this;
2408
+ }
2409
+ /**
2410
+ * Build the middleware chain and apply it to a node.
2411
+ */
2412
+ build(node) {
2413
+ if (this.middleware.length === 0) {
2414
+ return node;
2415
+ }
2416
+ return composeWithOptions(this.options, ...this.middleware)(node);
2417
+ }
2418
+ /**
2419
+ * Get the number of middleware in the chain.
2420
+ */
2421
+ get length() {
2422
+ return this.middleware.length;
2423
+ }
2424
+ };
2425
+ function chain() {
2426
+ return new MiddlewareChain();
2427
+ }
2428
+ function createMiddlewareContext() {
2429
+ return {
2430
+ executionId: `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2431
+ startTime: Date.now(),
2432
+ data: {},
2433
+ middlewareStack: []
2434
+ };
2435
+ }
2436
+
2437
+ // src/langgraph/middleware/logging.ts
2438
+ var withLogging = (options) => {
2439
+ const {
2440
+ logger: providedLogger,
2441
+ name = "node",
2442
+ level = "info",
2443
+ logInput = true,
2444
+ logOutput = true,
2445
+ logDuration = true,
2446
+ logErrors = true,
2447
+ extractData,
2448
+ onStart,
2449
+ onComplete,
2450
+ onError
2451
+ } = options;
2452
+ const logger = providedLogger || createLogger(name, { level });
2453
+ return (node) => {
2454
+ return async (state) => {
2455
+ const startTime = Date.now();
2456
+ try {
2457
+ if (logInput) {
2458
+ const data = extractData ? extractData(state) : { state };
2459
+ logger.info("Node execution started", data);
2460
+ }
2461
+ if (onStart) {
2462
+ onStart(state);
2463
+ }
2464
+ const result = await Promise.resolve(node(state));
2465
+ const duration = Date.now() - startTime;
2466
+ if (logOutput) {
2467
+ const data = extractData ? extractData(result) : { result };
2468
+ if (logDuration) {
2469
+ logger.info(`Node execution completed (${duration}ms)`, data);
2470
+ } else {
2471
+ logger.info("Node execution completed", data);
2472
+ }
2473
+ }
2474
+ if (onComplete) {
2475
+ onComplete(state, result, duration);
2476
+ }
2477
+ return result;
2478
+ } catch (error) {
2479
+ const duration = Date.now() - startTime;
2480
+ const err = error instanceof Error ? error : new Error(String(error));
2481
+ if (logErrors) {
2482
+ logger.error(`Node execution failed (${duration}ms)`, {
2483
+ error: err.message,
2484
+ stack: err.stack
2485
+ });
2486
+ }
2487
+ if (onError) {
2488
+ onError(err, duration);
2489
+ }
2490
+ throw error;
2491
+ }
2492
+ };
2493
+ };
2494
+ };
2495
+
2496
+ // src/langgraph/middleware/presets.ts
2497
+ function withRetry2(options) {
2498
+ return (node) => withRetry(node, options);
2499
+ }
2500
+ function withErrorHandler2(options) {
2501
+ return (node) => withErrorHandler(node, options);
2502
+ }
2503
+ function withTimeout2(options) {
2504
+ return (node) => withTimeout(node, options);
2505
+ }
2506
+ function withMetrics2(options) {
2507
+ return (node) => withMetrics(node, options);
2508
+ }
2509
+ function withTracing2(options) {
2510
+ return (node) => withTracing(node, options);
2511
+ }
2512
+ function withLogging2(options) {
2513
+ return (node) => withLogging(options)(node);
2514
+ }
2515
+ function production(node, options) {
2516
+ const {
2517
+ nodeName,
2518
+ logger,
2519
+ enableMetrics = true,
2520
+ enableTracing = true,
2521
+ enableRetry = true,
2522
+ timeout: timeout2 = 3e4,
2523
+ retryOptions = {},
2524
+ errorOptions = {}
2525
+ } = options;
2526
+ const actualLogger = logger || createLogger(nodeName, { level: "info" /* INFO */ });
2527
+ const middleware = [];
2528
+ middleware.push(
2529
+ withLogging2({
2530
+ logger: actualLogger,
2531
+ name: nodeName,
2532
+ logInput: false,
2533
+ // Don't log input in production by default
2534
+ logOutput: false,
2535
+ // Don't log output in production by default
2536
+ logDuration: true,
2537
+ logErrors: true
2538
+ })
2539
+ );
2540
+ middleware.push(
2541
+ withErrorHandler2({
2542
+ onError: (error, state) => {
2543
+ return state;
2544
+ },
2545
+ ...errorOptions
2546
+ })
2547
+ );
2548
+ if (enableRetry) {
2549
+ middleware.push(
2550
+ withRetry2({
2551
+ maxAttempts: 3,
2552
+ backoff: "exponential",
2553
+ initialDelay: 1e3,
2554
+ ...retryOptions
2555
+ })
2556
+ );
2557
+ }
2558
+ middleware.push(
2559
+ withTimeout2({
2560
+ timeout: timeout2,
2561
+ onTimeout: (state) => {
2562
+ return state;
2563
+ }
2564
+ })
2565
+ );
2566
+ if (enableMetrics) {
2567
+ middleware.push(
2568
+ withMetrics2({
2569
+ name: nodeName,
2570
+ trackDuration: true,
2571
+ trackErrors: true,
2572
+ trackInvocations: true
2573
+ })
2574
+ );
2575
+ }
2576
+ if (enableTracing) {
2577
+ middleware.push(
2578
+ withTracing2({
2579
+ name: nodeName,
2580
+ metadata: { preset: "production" }
2581
+ })
2582
+ );
2583
+ }
2584
+ return compose(...middleware)(node);
2585
+ }
2586
+ function development(node, options) {
2587
+ const {
2588
+ nodeName,
2589
+ verbose = true,
2590
+ logger
2591
+ } = options;
2592
+ const actualLogger = logger || createLogger(nodeName, { level: "debug" /* DEBUG */ });
2593
+ return withLogging2({
2594
+ logger: actualLogger,
2595
+ name: nodeName,
2596
+ logInput: verbose,
2597
+ logOutput: verbose,
2598
+ logDuration: true,
2599
+ logErrors: true
2600
+ })(node);
2601
+ }
2602
+ function testing(node, options) {
2603
+ const {
2604
+ nodeName,
2605
+ mockResponse,
2606
+ simulateError,
2607
+ delay = 0,
2608
+ trackInvocations = false
2609
+ } = options;
2610
+ const invocations = [];
2611
+ const wrappedNode = async (state) => {
2612
+ if (trackInvocations) {
2613
+ invocations.push(state);
2614
+ }
2615
+ if (delay > 0) {
2616
+ await new Promise((resolve) => setTimeout(resolve, delay));
2617
+ }
2618
+ if (simulateError) {
2619
+ throw simulateError;
2620
+ }
2621
+ if (mockResponse) {
2622
+ return { ...state, ...mockResponse };
2623
+ }
2624
+ return await Promise.resolve(node(state));
2625
+ };
2626
+ wrappedNode.invocations = invocations;
2627
+ return wrappedNode;
2628
+ }
2629
+ var presets = {
2630
+ production,
2631
+ development,
2632
+ testing
2633
+ };
2634
+
2635
+ // src/streaming/transformers.ts
2636
+ async function* chunk(stream, options) {
2637
+ const { size } = options;
2638
+ if (size <= 0) {
2639
+ throw new Error("Chunk size must be greater than 0");
2640
+ }
2641
+ let buffer = [];
2642
+ for await (const item of stream) {
2643
+ buffer.push(item);
2644
+ if (buffer.length >= size) {
2645
+ yield buffer;
2646
+ buffer = [];
2647
+ }
2648
+ }
2649
+ if (buffer.length > 0) {
2650
+ yield buffer;
2651
+ }
2652
+ }
2653
+ async function* batch(stream, options) {
2654
+ const { maxSize, maxWait } = options;
2655
+ if (maxSize <= 0) {
2656
+ throw new Error("Batch maxSize must be greater than 0");
2657
+ }
2658
+ if (maxWait <= 0) {
2659
+ throw new Error("Batch maxWait must be greater than 0");
2660
+ }
2661
+ let buffer = [];
2662
+ let timeoutId = null;
2663
+ const flushBuffer = () => {
2664
+ if (timeoutId) {
2665
+ clearTimeout(timeoutId);
2666
+ timeoutId = null;
2667
+ }
2668
+ if (buffer.length === 0) {
2669
+ return null;
2670
+ }
2671
+ const result = buffer;
2672
+ buffer = [];
2673
+ return result;
2674
+ };
2675
+ try {
2676
+ for await (const item of stream) {
2677
+ buffer.push(item);
2678
+ if (buffer.length >= maxSize) {
2679
+ const result = flushBuffer();
2680
+ if (result) {
2681
+ yield result;
2682
+ }
2683
+ } else if (!timeoutId) {
2684
+ timeoutId = setTimeout(() => {
2685
+ }, maxWait);
2686
+ }
2687
+ }
2688
+ const remaining = flushBuffer();
2689
+ if (remaining) {
2690
+ yield remaining;
2691
+ }
2692
+ } finally {
2693
+ if (timeoutId) {
2694
+ clearTimeout(timeoutId);
2695
+ }
2696
+ }
2697
+ }
2698
+ async function* throttle(stream, options) {
2699
+ const { rate, per } = options;
2700
+ if (rate <= 0) {
2701
+ throw new Error("Throttle rate must be greater than 0");
2702
+ }
2703
+ if (per <= 0) {
2704
+ throw new Error("Throttle per must be greater than 0");
2705
+ }
2706
+ const interval = per / rate;
2707
+ let lastEmit = 0;
2708
+ for await (const item of stream) {
2709
+ const now = Date.now();
2710
+ const timeSinceLastEmit = now - lastEmit;
2711
+ if (timeSinceLastEmit < interval) {
2712
+ await new Promise((resolve) => setTimeout(resolve, interval - timeSinceLastEmit));
2713
+ }
2714
+ lastEmit = Date.now();
2715
+ yield item;
2716
+ }
2717
+ }
2718
+
2719
+ // src/streaming/aggregators.ts
2720
+ async function collect(stream) {
2721
+ const items = [];
2722
+ for await (const item of stream) {
2723
+ items.push(item);
2724
+ }
2725
+ return items;
2726
+ }
2727
+ async function reduce(stream, reducer, initialValue) {
2728
+ let accumulator = initialValue;
2729
+ for await (const item of stream) {
2730
+ accumulator = reducer(accumulator, item);
2731
+ }
2732
+ return accumulator;
2733
+ }
2734
+ async function* merge(streams) {
2735
+ if (streams.length === 0) {
2736
+ return;
2737
+ }
2738
+ const iterators = streams.map((stream) => stream[Symbol.asyncIterator]());
2739
+ const active = new Set(iterators);
2740
+ const promises = /* @__PURE__ */ new Map();
2741
+ const createPromise = (iterator) => {
2742
+ return iterator.next().then((result) => ({ iterator, result }));
2743
+ };
2744
+ for (const iterator of iterators) {
2745
+ promises.set(iterator, createPromise(iterator));
2746
+ }
2747
+ while (active.size > 0) {
2748
+ const { iterator, result } = await Promise.race(promises.values());
2749
+ if (result.done) {
2750
+ active.delete(iterator);
2751
+ promises.delete(iterator);
2752
+ } else {
2753
+ yield result.value;
2754
+ promises.set(iterator, createPromise(iterator));
2755
+ }
2756
+ }
2757
+ }
2758
+ async function* filter(stream, predicate) {
2759
+ for await (const item of stream) {
2760
+ if (await predicate(item)) {
2761
+ yield item;
2762
+ }
2763
+ }
2764
+ }
2765
+ async function* map(stream, mapper) {
2766
+ for await (const item of stream) {
2767
+ yield await mapper(item);
2768
+ }
2769
+ }
2770
+ async function* take(stream, count) {
2771
+ if (count <= 0) {
2772
+ return;
2773
+ }
2774
+ let taken = 0;
2775
+ for await (const item of stream) {
2776
+ yield item;
2777
+ taken++;
2778
+ if (taken >= count) {
2779
+ break;
2780
+ }
2781
+ }
2782
+ }
2783
+
2784
+ // src/streaming/progress.ts
2785
+ function createProgressTracker(options) {
2786
+ const { total, onProgress, onComplete, onCancel } = options;
2787
+ if (total <= 0) {
2788
+ throw new Error("Total must be greater than 0");
2789
+ }
2790
+ let current = 0;
2791
+ let startTime = 0;
2792
+ let cancelled = false;
2793
+ const calculateProgress = () => {
2794
+ const elapsed = Date.now() - startTime;
2795
+ const percentage = Math.min(100, current / total * 100);
2796
+ let eta = 0;
2797
+ if (current > 0 && current < total) {
2798
+ const timePerItem = elapsed / current;
2799
+ const remaining = total - current;
2800
+ eta = Math.round(timePerItem * remaining / 1e3);
2801
+ }
2802
+ return {
2803
+ current,
2804
+ total,
2805
+ percentage: Math.round(percentage * 100) / 100,
2806
+ // Round to 2 decimal places
2807
+ eta,
2808
+ startTime,
2809
+ elapsed
2810
+ };
2811
+ };
2812
+ return {
2813
+ start() {
2814
+ if (startTime > 0) {
2815
+ throw new Error("Progress tracker already started");
2816
+ }
2817
+ startTime = Date.now();
2818
+ current = 0;
2819
+ cancelled = false;
2820
+ },
2821
+ update(newCurrent) {
2822
+ if (startTime === 0) {
2823
+ throw new Error("Progress tracker not started");
2824
+ }
2825
+ if (cancelled) {
2826
+ throw new Error("Progress tracker cancelled");
2827
+ }
2828
+ if (newCurrent < 0) {
2829
+ throw new Error("Current progress cannot be negative");
2830
+ }
2831
+ if (newCurrent > total) {
2832
+ newCurrent = total;
2833
+ }
2834
+ current = newCurrent;
2835
+ if (onProgress) {
2836
+ onProgress(calculateProgress());
2837
+ }
2838
+ },
2839
+ complete() {
2840
+ if (startTime === 0) {
2841
+ throw new Error("Progress tracker not started");
2842
+ }
2843
+ if (cancelled) {
2844
+ throw new Error("Progress tracker cancelled");
2845
+ }
2846
+ current = total;
2847
+ const progress = calculateProgress();
2848
+ if (onProgress) {
2849
+ onProgress(progress);
2850
+ }
2851
+ if (onComplete) {
2852
+ onComplete(progress);
2853
+ }
2854
+ },
2855
+ cancel() {
2856
+ if (startTime === 0) {
2857
+ throw new Error("Progress tracker not started");
2858
+ }
2859
+ if (cancelled) {
2860
+ return;
2861
+ }
2862
+ cancelled = true;
2863
+ if (onCancel) {
2864
+ onCancel();
2865
+ }
2866
+ },
2867
+ getProgress() {
2868
+ if (startTime === 0) {
2869
+ throw new Error("Progress tracker not started");
2870
+ }
2871
+ return calculateProgress();
2872
+ },
2873
+ isCancelled() {
2874
+ return cancelled;
2875
+ }
2876
+ };
2877
+ }
2878
+
2879
+ // src/streaming/sse.ts
2880
+ function formatSSEEvent(event) {
2881
+ const lines = [];
2882
+ if (event.id) {
2883
+ lines.push(`id: ${event.id}`);
2884
+ }
2885
+ if (event.event) {
2886
+ lines.push(`event: ${event.event}`);
2887
+ }
2888
+ if (event.retry !== void 0) {
2889
+ lines.push(`retry: ${event.retry}`);
2890
+ }
2891
+ const dataLines = event.data.split("\n");
2892
+ for (const line of dataLines) {
2893
+ lines.push(`data: ${line}`);
2894
+ }
2895
+ return lines.join("\n") + "\n\n";
2896
+ }
2897
+ function createSSEFormatter(options = {}) {
2898
+ const { eventTypes = {}, heartbeat = 0, retry: retry2 } = options;
2899
+ return {
2900
+ async *format(stream) {
2901
+ let heartbeatInterval = null;
2902
+ let lastEventId = 0;
2903
+ try {
2904
+ if (heartbeat > 0) {
2905
+ heartbeatInterval = setInterval(() => {
2906
+ }, heartbeat);
2907
+ }
2908
+ if (retry2 !== void 0) {
2909
+ yield formatSSEEvent({ data: "", retry: retry2 });
2910
+ }
2911
+ for await (const item of stream) {
2912
+ let event;
2913
+ let matched = false;
2914
+ for (const [type, mapper] of Object.entries(eventTypes)) {
2915
+ try {
2916
+ const mapped = mapper(item);
2917
+ if (mapped) {
2918
+ event = {
2919
+ ...mapped,
2920
+ id: String(++lastEventId)
2921
+ };
2922
+ matched = true;
2923
+ break;
2924
+ }
2925
+ } catch {
2926
+ }
2927
+ }
2928
+ if (!matched) {
2929
+ event = {
2930
+ data: JSON.stringify(item),
2931
+ id: String(++lastEventId)
2932
+ };
2933
+ }
2934
+ yield formatSSEEvent(event);
2935
+ if (heartbeatInterval) {
2936
+ clearInterval(heartbeatInterval);
2937
+ heartbeatInterval = setInterval(() => {
2938
+ }, heartbeat);
2939
+ }
2940
+ }
2941
+ } finally {
2942
+ if (heartbeatInterval) {
2943
+ clearInterval(heartbeatInterval);
2944
+ }
2945
+ }
2946
+ }
2947
+ };
2948
+ }
2949
+ function createHeartbeat() {
2950
+ return ": heartbeat\n\n";
2951
+ }
2952
+ function parseSSEEvent(eventString) {
2953
+ const lines = eventString.trim().split("\n");
2954
+ const event = { data: "" };
2955
+ for (const line of lines) {
2956
+ if (line.startsWith("id:")) {
2957
+ event.id = line.slice(3).trim();
2958
+ } else if (line.startsWith("event:")) {
2959
+ event.event = line.slice(6).trim();
2960
+ } else if (line.startsWith("retry:")) {
2961
+ event.retry = parseInt(line.slice(6).trim(), 10);
2962
+ } else if (line.startsWith("data:")) {
2963
+ const data = line.slice(5).trim();
2964
+ event.data = event.data ? `${event.data}
2965
+ ${data}` : data;
2966
+ }
2967
+ }
2968
+ return event.data !== void 0 ? event : null;
2969
+ }
2970
+
2971
+ // src/streaming/websocket.ts
2972
+ function createWebSocketHandler(options) {
2973
+ const { onConnect, onMessage, onError, onClose, heartbeat = 0 } = options;
2974
+ return function handler(ws, req) {
2975
+ let heartbeatInterval = null;
2976
+ let isAlive = true;
2977
+ if (heartbeat > 0) {
2978
+ heartbeatInterval = setInterval(() => {
2979
+ if (!isAlive) {
2980
+ if (heartbeatInterval) {
2981
+ clearInterval(heartbeatInterval);
2982
+ }
2983
+ ws.terminate();
2984
+ return;
2985
+ }
2986
+ isAlive = false;
2987
+ ws.ping();
2988
+ }, heartbeat);
2989
+ ws.on("pong", () => {
2990
+ isAlive = true;
2991
+ });
2992
+ }
2993
+ if (onConnect) {
2994
+ try {
2995
+ onConnect(ws, req);
2996
+ } catch (error) {
2997
+ if (onError) {
2998
+ onError(ws, error);
2999
+ }
3000
+ }
3001
+ }
3002
+ ws.on("message", async (data) => {
3003
+ try {
3004
+ let message;
3005
+ if (typeof data === "string") {
3006
+ try {
3007
+ message = JSON.parse(data);
3008
+ } catch {
3009
+ message = data;
3010
+ }
3011
+ } else {
3012
+ message = data;
3013
+ }
3014
+ if (onMessage) {
3015
+ await onMessage(ws, message);
3016
+ }
3017
+ } catch (error) {
3018
+ if (onError) {
3019
+ onError(ws, error);
3020
+ }
3021
+ }
3022
+ });
3023
+ ws.on("error", (error) => {
3024
+ if (onError) {
3025
+ onError(ws, error);
3026
+ }
3027
+ });
3028
+ ws.on("close", (code, reason) => {
3029
+ if (heartbeatInterval) {
3030
+ clearInterval(heartbeatInterval);
3031
+ }
3032
+ if (onClose) {
3033
+ onClose(ws, code, reason);
3034
+ }
3035
+ });
3036
+ };
3037
+ }
3038
+ function sendMessage(ws, message) {
3039
+ if (ws.readyState === 1) {
3040
+ ws.send(JSON.stringify(message));
3041
+ }
3042
+ }
3043
+ function broadcast(clients, message) {
3044
+ const data = JSON.stringify(message);
3045
+ for (const client of clients) {
3046
+ if (client.readyState === 1) {
3047
+ client.send(data);
3048
+ }
3049
+ }
3050
+ }
3051
+ function createMessage(type, data, error) {
3052
+ return { type, data, error };
3053
+ }
3054
+
3055
+ // src/resources/pool.ts
3056
+ var ConnectionPool = class {
3057
+ constructor(options) {
3058
+ this.options = options;
3059
+ const poolConfig = options.pool || {};
3060
+ const min = poolConfig.min || 0;
3061
+ if (min > 0) {
3062
+ this.initialize(min).catch((error) => {
3063
+ console.error("Failed to initialize pool:", error);
3064
+ });
3065
+ }
3066
+ const evictionInterval = poolConfig.evictionInterval || 6e4;
3067
+ this.evictionTimer = setInterval(() => {
3068
+ this.evictIdleConnections().catch((error) => {
3069
+ console.error("Failed to evict idle connections:", error);
3070
+ });
3071
+ }, evictionInterval);
3072
+ const healthCheck = options.healthCheck || {};
3073
+ if (healthCheck.enabled) {
3074
+ const interval = healthCheck.interval || 3e4;
3075
+ this.healthCheckTimer = setInterval(() => {
3076
+ this.performHealthChecks().catch((error) => {
3077
+ console.error("Health check failed:", error);
3078
+ options.onHealthCheckFail?.(error);
3079
+ });
3080
+ }, interval);
3081
+ }
3082
+ }
3083
+ connections = [];
3084
+ pending = [];
3085
+ stats = {
3086
+ size: 0,
3087
+ available: 0,
3088
+ pending: 0,
3089
+ acquired: 0,
3090
+ created: 0,
3091
+ destroyed: 0,
3092
+ healthChecksPassed: 0,
3093
+ healthChecksFailed: 0
3094
+ };
3095
+ evictionTimer;
3096
+ healthCheckTimer;
3097
+ draining = false;
3098
+ async initialize(count) {
3099
+ const promises = Array.from({ length: count }, () => this.createConnection());
3100
+ await Promise.all(promises);
3101
+ }
3102
+ async createConnection() {
3103
+ const connection = await this.options.factory();
3104
+ this.connections.push({
3105
+ connection,
3106
+ createdAt: Date.now(),
3107
+ lastUsedAt: Date.now(),
3108
+ inUse: false
3109
+ });
3110
+ this.stats.created++;
3111
+ this.stats.size++;
3112
+ this.stats.available++;
3113
+ return connection;
3114
+ }
3115
+ async destroyConnection(pooled) {
3116
+ const index = this.connections.indexOf(pooled);
3117
+ if (index !== -1) {
3118
+ this.connections.splice(index, 1);
3119
+ }
3120
+ if (this.options.destroyer) {
3121
+ await this.options.destroyer(pooled.connection);
3122
+ }
3123
+ this.options.onDestroy?.(pooled.connection);
3124
+ this.stats.destroyed++;
3125
+ this.stats.size--;
3126
+ if (!pooled.inUse) {
3127
+ this.stats.available--;
3128
+ }
3129
+ }
3130
+ async acquire() {
3131
+ if (this.draining) {
3132
+ throw new Error("Pool is draining");
3133
+ }
3134
+ const available = this.connections.find((c) => !c.inUse);
3135
+ if (available) {
3136
+ available.inUse = true;
3137
+ available.lastUsedAt = Date.now();
3138
+ this.stats.available--;
3139
+ this.stats.acquired++;
3140
+ this.options.onAcquire?.(available.connection);
3141
+ return available.connection;
3142
+ }
3143
+ const poolConfig = this.options.pool || {};
3144
+ const max = poolConfig.max || 10;
3145
+ if (this.connections.length < max) {
3146
+ const connection = await this.createConnection();
3147
+ const pooled = this.connections.find((c) => c.connection === connection);
3148
+ pooled.inUse = true;
3149
+ this.stats.available--;
3150
+ this.stats.acquired++;
3151
+ this.options.onAcquire?.(connection);
3152
+ return connection;
3153
+ }
3154
+ return new Promise((resolve, reject) => {
3155
+ const timeout2 = poolConfig.acquireTimeout || 3e4;
3156
+ const timer = setTimeout(() => {
3157
+ const index = this.pending.findIndex((p) => p.resolve === resolve);
3158
+ if (index !== -1) {
3159
+ this.pending.splice(index, 1);
3160
+ this.stats.pending--;
3161
+ }
3162
+ reject(new Error("Acquire timeout"));
3163
+ }, timeout2);
3164
+ this.pending.push({ resolve, reject, timeout: timer });
3165
+ this.stats.pending++;
3166
+ });
3167
+ }
3168
+ async release(connection) {
3169
+ const pooled = this.connections.find((c) => c.connection === connection);
3170
+ if (!pooled) {
3171
+ throw new Error("Connection not found in pool");
3172
+ }
3173
+ if (!pooled.inUse) {
3174
+ throw new Error("Connection is not in use");
3175
+ }
3176
+ pooled.inUse = false;
3177
+ pooled.lastUsedAt = Date.now();
3178
+ this.stats.available++;
3179
+ this.stats.acquired--;
3180
+ this.options.onRelease?.(connection);
3181
+ const pending = this.pending.shift();
3182
+ if (pending) {
3183
+ clearTimeout(pending.timeout);
3184
+ this.stats.pending--;
3185
+ pooled.inUse = true;
3186
+ this.stats.available--;
3187
+ this.stats.acquired++;
3188
+ this.options.onAcquire?.(connection);
3189
+ pending.resolve(connection);
3190
+ }
3191
+ }
3192
+ async evictIdleConnections() {
3193
+ const poolConfig = this.options.pool || {};
3194
+ const idleTimeout = poolConfig.idleTimeout || 6e4;
3195
+ const min = poolConfig.min || 0;
3196
+ const now = Date.now();
3197
+ const toEvict = this.connections.filter(
3198
+ (c) => !c.inUse && now - c.lastUsedAt > idleTimeout && this.connections.length > min
3199
+ );
3200
+ for (const pooled of toEvict) {
3201
+ await this.destroyConnection(pooled);
3202
+ }
3203
+ }
3204
+ async performHealthChecks() {
3205
+ if (!this.options.validator) {
3206
+ return;
3207
+ }
3208
+ const healthCheck = this.options.healthCheck || {};
3209
+ const timeout2 = healthCheck.timeout || 5e3;
3210
+ const retries = healthCheck.retries || 1;
3211
+ for (const pooled of this.connections) {
3212
+ if (pooled.inUse) {
3213
+ continue;
3214
+ }
3215
+ let healthy = false;
3216
+ for (let i = 0; i < retries; i++) {
3217
+ try {
3218
+ const result = await Promise.race([
3219
+ this.options.validator(pooled.connection),
3220
+ new Promise(
3221
+ (_, reject) => setTimeout(() => reject(new Error("Health check timeout")), timeout2)
3222
+ )
3223
+ ]);
3224
+ if (result) {
3225
+ healthy = true;
3226
+ break;
3227
+ }
3228
+ } catch (error) {
3229
+ }
3230
+ }
3231
+ if (healthy) {
3232
+ this.stats.healthChecksPassed++;
3233
+ } else {
3234
+ this.stats.healthChecksFailed++;
3235
+ await this.destroyConnection(pooled);
3236
+ }
3237
+ }
3238
+ }
3239
+ async drain() {
3240
+ this.draining = true;
3241
+ for (const pending of this.pending) {
3242
+ clearTimeout(pending.timeout);
3243
+ pending.reject(new Error("Pool is draining"));
3244
+ }
3245
+ this.pending = [];
3246
+ this.stats.pending = 0;
3247
+ while (this.connections.some((c) => c.inUse)) {
3248
+ await new Promise((resolve) => setTimeout(resolve, 100));
3249
+ }
3250
+ }
3251
+ async clear() {
3252
+ if (this.evictionTimer) {
3253
+ clearInterval(this.evictionTimer);
3254
+ this.evictionTimer = void 0;
3255
+ }
3256
+ if (this.healthCheckTimer) {
3257
+ clearInterval(this.healthCheckTimer);
3258
+ this.healthCheckTimer = void 0;
3259
+ }
3260
+ const connections = [...this.connections];
3261
+ for (const pooled of connections) {
3262
+ await this.destroyConnection(pooled);
3263
+ }
3264
+ }
3265
+ getStats() {
3266
+ return { ...this.stats };
3267
+ }
3268
+ };
3269
+ function createConnectionPool(options) {
3270
+ return new ConnectionPool(options);
3271
+ }
3272
+
3273
+ // src/resources/database-pool.ts
3274
+ var MockDatabaseConnection = class {
3275
+ constructor(config) {
3276
+ this.config = config;
3277
+ }
3278
+ closed = false;
3279
+ async query(sql, params) {
3280
+ if (this.closed) {
3281
+ throw new Error("Connection is closed");
3282
+ }
3283
+ return [];
3284
+ }
3285
+ async execute(sql, params) {
3286
+ if (this.closed) {
3287
+ throw new Error("Connection is closed");
3288
+ }
3289
+ }
3290
+ async close() {
3291
+ this.closed = true;
3292
+ }
3293
+ };
3294
+ var DatabasePool = class {
3295
+ constructor(options) {
3296
+ this.options = options;
3297
+ const healthCheckQuery = options.healthCheck?.query || "SELECT 1";
3298
+ this.pool = createConnectionPool({
3299
+ factory: async () => {
3300
+ const connection = new MockDatabaseConnection(options.config);
3301
+ options.onConnect?.(connection);
3302
+ return connection;
3303
+ },
3304
+ destroyer: async (connection) => {
3305
+ await connection.close();
3306
+ options.onDisconnect?.(connection);
3307
+ },
3308
+ validator: async (connection) => {
3309
+ try {
3310
+ await connection.query(healthCheckQuery);
3311
+ return true;
3312
+ } catch {
3313
+ return false;
3314
+ }
3315
+ },
3316
+ pool: options.pool,
3317
+ healthCheck: options.healthCheck
3318
+ });
3319
+ }
3320
+ pool;
3321
+ async acquire() {
3322
+ return this.pool.acquire();
3323
+ }
3324
+ async release(connection) {
3325
+ return this.pool.release(connection);
3326
+ }
3327
+ async query(sql, params) {
3328
+ const connection = await this.acquire();
3329
+ try {
3330
+ return await connection.query(sql, params);
3331
+ } finally {
3332
+ await this.release(connection);
3333
+ }
3334
+ }
3335
+ async execute(sql, params) {
3336
+ const connection = await this.acquire();
3337
+ try {
3338
+ await connection.execute(sql, params);
3339
+ } finally {
3340
+ await this.release(connection);
3341
+ }
3342
+ }
3343
+ async drain() {
3344
+ return this.pool.drain();
3345
+ }
3346
+ async clear() {
3347
+ return this.pool.clear();
3348
+ }
3349
+ getStats() {
3350
+ return this.pool.getStats();
3351
+ }
3352
+ };
3353
+ function createDatabasePool(options) {
3354
+ return new DatabasePool(options);
3355
+ }
3356
+
3357
+ // src/resources/http-pool.ts
3358
+ var MockHttpClient = class {
3359
+ constructor(config) {
3360
+ this.config = config;
3361
+ }
3362
+ closed = false;
3363
+ async get(url, config) {
3364
+ return this.request({ ...config, url, method: "GET" });
3365
+ }
3366
+ async post(url, data, config) {
3367
+ return this.request({ ...config, url, method: "POST", data });
3368
+ }
3369
+ async put(url, data, config) {
3370
+ return this.request({ ...config, url, method: "PUT", data });
3371
+ }
3372
+ async delete(url, config) {
3373
+ return this.request({ ...config, url, method: "DELETE" });
3374
+ }
3375
+ async request(config) {
3376
+ if (this.closed) {
3377
+ throw new Error("Client is closed");
3378
+ }
3379
+ return {
3380
+ data: {},
3381
+ status: 200,
3382
+ statusText: "OK",
3383
+ headers: {}
3384
+ };
3385
+ }
3386
+ async close() {
3387
+ this.closed = true;
3388
+ }
3389
+ };
3390
+ var HttpPool = class {
3391
+ constructor(options) {
3392
+ this.options = options;
3393
+ const healthCheckEndpoint = options.healthCheck?.endpoint || "/health";
3394
+ const healthCheckMethod = options.healthCheck?.method || "GET";
3395
+ this.pool = createConnectionPool({
3396
+ factory: async () => {
3397
+ const client = new MockHttpClient(options.config);
3398
+ options.onConnect?.(client);
3399
+ return client;
3400
+ },
3401
+ destroyer: async (client) => {
3402
+ await client.close();
3403
+ options.onDisconnect?.(client);
3404
+ },
3405
+ validator: async (client) => {
3406
+ try {
3407
+ const response = await client.request({
3408
+ url: healthCheckEndpoint,
3409
+ method: healthCheckMethod
3410
+ });
3411
+ return response.status >= 200 && response.status < 300;
3412
+ } catch {
3413
+ return false;
3414
+ }
3415
+ },
3416
+ pool: options.pool,
3417
+ healthCheck: options.healthCheck
3418
+ });
3419
+ }
3420
+ pool;
3421
+ async acquire() {
3422
+ return this.pool.acquire();
3423
+ }
3424
+ async release(client) {
3425
+ return this.pool.release(client);
3426
+ }
3427
+ async request(config) {
3428
+ const client = await this.acquire();
3429
+ try {
3430
+ return await client.request(config);
3431
+ } finally {
3432
+ await this.release(client);
3433
+ }
3434
+ }
3435
+ async drain() {
3436
+ return this.pool.drain();
3437
+ }
3438
+ async clear() {
3439
+ return this.pool.clear();
3440
+ }
3441
+ getStats() {
3442
+ return this.pool.getStats();
3443
+ }
3444
+ };
3445
+ function createHttpPool(options) {
3446
+ return new HttpPool(options);
3447
+ }
3448
+
3449
+ // src/resources/memory.ts
3450
+ var MemoryManager = class {
3451
+ constructor(options) {
3452
+ this.options = options;
3453
+ }
3454
+ cleanupHandlers = /* @__PURE__ */ new Map();
3455
+ checkTimer;
3456
+ leakDetectionTimer;
3457
+ previousMemory;
3458
+ running = false;
3459
+ start() {
3460
+ if (this.running) {
3461
+ return;
3462
+ }
3463
+ this.running = true;
3464
+ const interval = this.options.checkInterval || 1e4;
3465
+ this.checkTimer = setInterval(() => {
3466
+ this.checkMemory();
3467
+ }, interval);
3468
+ const leakDetection = this.options.leakDetection || {};
3469
+ if (leakDetection.enabled) {
3470
+ const sampleInterval = leakDetection.sampleInterval || 6e4;
3471
+ this.leakDetectionTimer = setInterval(() => {
3472
+ this.detectLeaks();
3473
+ }, sampleInterval);
3474
+ }
3475
+ }
3476
+ stop() {
3477
+ if (!this.running) {
3478
+ return;
3479
+ }
3480
+ this.running = false;
3481
+ if (this.checkTimer) {
3482
+ clearInterval(this.checkTimer);
3483
+ this.checkTimer = void 0;
3484
+ }
3485
+ if (this.leakDetectionTimer) {
3486
+ clearInterval(this.leakDetectionTimer);
3487
+ this.leakDetectionTimer = void 0;
3488
+ }
3489
+ }
3490
+ registerCleanup(name, handler) {
3491
+ this.cleanupHandlers.set(name, handler);
3492
+ }
3493
+ unregisterCleanup(name) {
3494
+ this.cleanupHandlers.delete(name);
3495
+ }
3496
+ async cleanup(name) {
3497
+ if (name) {
3498
+ const handler = this.cleanupHandlers.get(name);
3499
+ if (handler) {
3500
+ await handler();
3501
+ }
3502
+ } else {
3503
+ for (const handler of this.cleanupHandlers.values()) {
3504
+ await handler();
3505
+ }
3506
+ }
3507
+ }
3508
+ getStats() {
3509
+ const memUsage = process.memoryUsage();
3510
+ const total = this.options.maxMemory || memUsage.heapTotal;
3511
+ const used = memUsage.heapUsed;
3512
+ return {
3513
+ used,
3514
+ total,
3515
+ percentage: used / total * 100,
3516
+ heapUsed: memUsage.heapUsed,
3517
+ heapTotal: memUsage.heapTotal,
3518
+ external: memUsage.external,
3519
+ arrayBuffers: memUsage.arrayBuffers
3520
+ };
3521
+ }
3522
+ forceGC() {
3523
+ if (global.gc) {
3524
+ global.gc();
3525
+ } else {
3526
+ console.warn("Garbage collection is not exposed. Run with --expose-gc flag.");
3527
+ }
3528
+ }
3529
+ checkMemory() {
3530
+ const stats = this.getStats();
3531
+ const threshold = this.options.thresholdPercentage || 80;
3532
+ if (stats.percentage >= threshold) {
3533
+ this.options.onThreshold?.(stats);
3534
+ }
3535
+ if (this.options.maxMemory && stats.used >= this.options.maxMemory) {
3536
+ this.options.onLimit?.(stats).catch((error) => {
3537
+ console.error("Error in onLimit handler:", error);
3538
+ });
3539
+ }
3540
+ }
3541
+ detectLeaks() {
3542
+ const stats = this.getStats();
3543
+ if (this.previousMemory) {
3544
+ const growth = stats.used - this.previousMemory.used;
3545
+ const growthPercentage = growth / this.previousMemory.used * 100;
3546
+ const threshold = this.options.leakDetection?.growthThreshold || 10;
3547
+ if (growthPercentage > threshold) {
3548
+ this.options.onLeak?.(stats);
3549
+ }
3550
+ }
3551
+ this.previousMemory = stats;
3552
+ }
3553
+ };
3554
+ function createMemoryManager(options) {
3555
+ return new MemoryManager(options);
3556
+ }
3557
+
3558
+ // src/resources/batch.ts
3559
+ var BatchProcessor = class {
3560
+ constructor(options) {
3561
+ this.options = options;
3562
+ }
3563
+ pending = [];
3564
+ timer;
3565
+ processing = false;
3566
+ stats = {
3567
+ totalBatches: 0,
3568
+ totalItems: 0,
3569
+ averageBatchSize: 0,
3570
+ averageWaitTime: 0,
3571
+ successfulBatches: 0,
3572
+ failedBatches: 0
3573
+ };
3574
+ add(input) {
3575
+ return new Promise((resolve, reject) => {
3576
+ this.pending.push({
3577
+ input,
3578
+ resolve,
3579
+ reject,
3580
+ addedAt: Date.now()
3581
+ });
3582
+ if (!this.timer) {
3583
+ this.timer = setTimeout(() => {
3584
+ this.processBatch();
3585
+ }, this.options.maxWaitTime);
3586
+ }
3587
+ if (this.pending.length >= this.options.maxBatchSize) {
3588
+ this.processBatch();
3589
+ }
3590
+ });
3591
+ }
3592
+ async flush() {
3593
+ if (this.pending.length > 0) {
3594
+ await this.processBatch();
3595
+ }
3596
+ }
3597
+ async processBatch() {
3598
+ if (this.processing || this.pending.length === 0) {
3599
+ return;
3600
+ }
3601
+ this.processing = true;
3602
+ if (this.timer) {
3603
+ clearTimeout(this.timer);
3604
+ this.timer = void 0;
3605
+ }
3606
+ const batchSize = Math.min(this.pending.length, this.options.maxBatchSize);
3607
+ const batch2 = this.pending.splice(0, batchSize);
3608
+ const inputs = batch2.map((item) => item.input);
3609
+ const now = Date.now();
3610
+ const waitTimes = batch2.map((item) => now - item.addedAt);
3611
+ const avgWaitTime = waitTimes.reduce((sum, time) => sum + time, 0) / waitTimes.length;
3612
+ this.stats.totalBatches++;
3613
+ this.stats.totalItems += batch2.length;
3614
+ this.stats.averageBatchSize = (this.stats.averageBatchSize * (this.stats.totalBatches - 1) + batch2.length) / this.stats.totalBatches;
3615
+ this.stats.averageWaitTime = (this.stats.averageWaitTime * (this.stats.totalBatches - 1) + avgWaitTime) / this.stats.totalBatches;
3616
+ this.options.onBatchStart?.(inputs);
3617
+ try {
3618
+ const results = await this.options.processor(inputs);
3619
+ if (results.length !== batch2.length) {
3620
+ throw new Error(
3621
+ `Processor returned ${results.length} results for ${batch2.length} inputs`
3622
+ );
3623
+ }
3624
+ for (let i = 0; i < batch2.length; i++) {
3625
+ batch2[i].resolve(results[i]);
3626
+ }
3627
+ this.stats.successfulBatches++;
3628
+ this.options.onBatchComplete?.(inputs, results);
3629
+ } catch (error) {
3630
+ this.stats.failedBatches++;
3631
+ this.options.onBatchError?.(inputs, error);
3632
+ for (const item of batch2) {
3633
+ if (this.options.onItemError) {
3634
+ const fallback = this.options.onItemError(item.input, error);
3635
+ if (fallback !== void 0) {
3636
+ item.resolve(fallback);
3637
+ } else {
3638
+ item.reject(error);
3639
+ }
3640
+ } else {
3641
+ item.reject(error);
3642
+ }
3643
+ }
3644
+ } finally {
3645
+ this.processing = false;
3646
+ if (this.pending.length > 0) {
3647
+ this.timer = setTimeout(() => {
3648
+ this.processBatch();
3649
+ }, this.options.maxWaitTime);
3650
+ }
3651
+ }
3652
+ }
3653
+ getStats() {
3654
+ return { ...this.stats };
3655
+ }
3656
+ getPendingCount() {
3657
+ return this.pending.length;
3658
+ }
3659
+ };
3660
+ function createBatchProcessor(options) {
3661
+ return new BatchProcessor(options);
3662
+ }
3663
+
3664
+ // src/resources/circuit-breaker.ts
3665
+ var CircuitBreaker = class {
3666
+ constructor(options) {
3667
+ this.options = options;
3668
+ }
3669
+ state = "closed";
3670
+ failures = 0;
3671
+ successes = 0;
3672
+ totalCalls = 0;
3673
+ stateChanges = 0;
3674
+ lastFailureTime;
3675
+ lastSuccessTime;
3676
+ resetTimer;
3677
+ callHistory = [];
3678
+ halfOpenAttempts = 0;
3679
+ async execute(fn) {
3680
+ if (this.state === "open") {
3681
+ throw new Error("Circuit breaker is open");
3682
+ }
3683
+ if (this.state === "half-open") {
3684
+ const maxAttempts = this.options.halfOpenRequests || 1;
3685
+ if (this.halfOpenAttempts >= maxAttempts) {
3686
+ throw new Error("Circuit breaker is half-open and at capacity");
3687
+ }
3688
+ this.halfOpenAttempts++;
3689
+ }
3690
+ this.totalCalls++;
3691
+ try {
3692
+ const result = await fn();
3693
+ this.onSuccess();
3694
+ return result;
3695
+ } catch (error) {
3696
+ this.onFailure(error);
3697
+ throw error;
3698
+ }
3699
+ }
3700
+ wrap(fn) {
3701
+ return async (...args) => {
3702
+ return this.execute(() => fn(...args));
3703
+ };
3704
+ }
3705
+ onSuccess() {
3706
+ this.successes++;
3707
+ this.lastSuccessTime = Date.now();
3708
+ this.recordCall(true);
3709
+ this.options.onSuccess?.();
3710
+ if (this.state === "half-open") {
3711
+ this.transitionTo("closed");
3712
+ this.failures = 0;
3713
+ this.halfOpenAttempts = 0;
3714
+ }
3715
+ }
3716
+ onFailure(error) {
3717
+ this.failures++;
3718
+ this.lastFailureTime = Date.now();
3719
+ this.recordCall(false);
3720
+ this.options.onFailure?.(error);
3721
+ const shouldTrip = this.options.shouldTrip?.(error) ?? true;
3722
+ if (!shouldTrip) {
3723
+ return;
3724
+ }
3725
+ if (this.state === "half-open") {
3726
+ this.transitionTo("open");
3727
+ this.halfOpenAttempts = 0;
3728
+ this.scheduleReset();
3729
+ } else if (this.state === "closed") {
3730
+ const recentFailures = this.getRecentFailures();
3731
+ if (recentFailures >= this.options.failureThreshold) {
3732
+ this.transitionTo("open");
3733
+ this.scheduleReset();
3734
+ }
3735
+ }
3736
+ }
3737
+ recordCall(success) {
3738
+ this.callHistory.push({
3739
+ timestamp: Date.now(),
3740
+ success
3741
+ });
3742
+ const monitoringPeriod = this.options.monitoringPeriod || 6e4;
3743
+ const cutoff = Date.now() - monitoringPeriod;
3744
+ this.callHistory = this.callHistory.filter((record) => record.timestamp >= cutoff);
3745
+ }
3746
+ getRecentFailures() {
3747
+ return this.callHistory.filter((record) => !record.success).length;
3748
+ }
3749
+ scheduleReset() {
3750
+ if (this.resetTimer) {
3751
+ clearTimeout(this.resetTimer);
3752
+ }
3753
+ this.resetTimer = setTimeout(() => {
3754
+ this.transitionTo("half-open");
3755
+ this.halfOpenAttempts = 0;
3756
+ }, this.options.resetTimeout);
3757
+ }
3758
+ transitionTo(newState) {
3759
+ const previousState = this.state;
3760
+ if (previousState === newState) {
3761
+ return;
3762
+ }
3763
+ this.state = newState;
3764
+ this.stateChanges++;
3765
+ this.options.onStateChange?.(newState, previousState);
3766
+ }
3767
+ getState() {
3768
+ return this.state;
3769
+ }
3770
+ getStats() {
3771
+ return {
3772
+ state: this.state,
3773
+ failures: this.failures,
3774
+ successes: this.successes,
3775
+ totalCalls: this.totalCalls,
3776
+ failureRate: this.totalCalls > 0 ? this.failures / this.totalCalls : 0,
3777
+ lastFailureTime: this.lastFailureTime,
3778
+ lastSuccessTime: this.lastSuccessTime,
3779
+ stateChanges: this.stateChanges
3780
+ };
3781
+ }
3782
+ reset() {
3783
+ this.state = "closed";
3784
+ this.failures = 0;
3785
+ this.successes = 0;
3786
+ this.halfOpenAttempts = 0;
3787
+ this.callHistory = [];
3788
+ if (this.resetTimer) {
3789
+ clearTimeout(this.resetTimer);
3790
+ this.resetTimer = void 0;
3791
+ }
3792
+ }
3793
+ };
3794
+ function createCircuitBreaker(options) {
3795
+ return new CircuitBreaker(options);
3796
+ }
3797
+ export {
3798
+ AgentError,
3799
+ BatchProcessor,
3800
+ CircuitBreaker,
3801
+ ConnectionPool,
3802
+ DatabasePool,
3803
+ HttpPool,
3804
+ LogLevel,
3805
+ ManagedTool,
3806
+ MemoryManager,
3807
+ MetricType,
3808
+ MiddlewareChain,
3809
+ MissingDescriptionError,
3810
+ RegistryEvent,
3811
+ TimeoutError,
3812
+ ToolBuilder,
3813
+ ToolCategory,
3814
+ ToolCategorySchema,
3815
+ ToolExampleSchema,
3816
+ ToolMetadataSchema,
3817
+ ToolNameSchema,
3818
+ ToolRegistry,
3819
+ batch,
3820
+ broadcast,
3821
+ cache,
3822
+ chain,
3823
+ chunk,
3824
+ clearThread,
3825
+ collect,
3826
+ compose,
3827
+ composeGraphs,
3828
+ composeTool,
3829
+ composeWithOptions,
3830
+ conditional,
3831
+ configureLangSmith,
3832
+ createBatchProcessor,
3833
+ createBinaryRouter,
3834
+ createCircuitBreaker,
3835
+ createConditionalRouter,
3836
+ createConnectionPool,
3837
+ createConversationConfig,
3838
+ createDatabasePool,
3839
+ createErrorReporter,
3840
+ createHeartbeat,
3841
+ createHttpPool,
3842
+ createLogger,
3843
+ createManagedTool,
3844
+ createMemoryCheckpointer,
3845
+ createMemoryManager,
3846
+ createMessage,
3847
+ createMetrics,
3848
+ createMiddlewareContext,
3849
+ createMockTool,
3850
+ createMultiRouter,
3851
+ createParallelWorkflow,
3852
+ createProgressTracker,
3853
+ createSSEFormatter,
3854
+ createSequentialWorkflow,
3855
+ createSqliteCheckpointer,
3856
+ createStateAnnotation,
3857
+ createSubgraph,
3858
+ createThreadConfig,
3859
+ createTool,
3860
+ createToolExecutor,
3861
+ createToolSimulator,
3862
+ createToolUnsafe,
3863
+ createWebSocketHandler,
3864
+ development,
3865
+ filter,
3866
+ generateThreadId,
3867
+ getCheckpointHistory,
3868
+ getLangSmithConfig,
3869
+ getLatestCheckpoint,
3870
+ getMissingDescriptions,
3871
+ getToolDescription,
3872
+ getToolJsonSchema,
3873
+ isMemoryCheckpointer,
3874
+ isTracingEnabled,
3875
+ map,
3876
+ merge,
3877
+ mergeState,
3878
+ parallel,
3879
+ parseSSEEvent,
3880
+ presets,
3881
+ production,
3882
+ reduce,
3883
+ retry,
3884
+ safeValidateSchemaDescriptions,
3885
+ sendMessage,
3886
+ sequential,
3887
+ sequentialBuilder,
3888
+ take,
3889
+ testing,
3890
+ throttle,
3891
+ timeout,
3892
+ toLangChainTool,
3893
+ toLangChainTools,
3894
+ toolBuilder,
3895
+ validateSchemaDescriptions,
3896
+ validateState,
3897
+ validateTool,
3898
+ validateToolMetadata,
3899
+ validateToolName,
3900
+ withErrorHandler,
3901
+ withMetrics,
3902
+ withRetry,
3903
+ withTimeout,
3904
+ withTracing
3905
+ };