@agentforge/core 0.16.36 → 0.16.38

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.cjs CHANGED
@@ -493,7 +493,54 @@ function validateTool(tool) {
493
493
  };
494
494
  }
495
495
 
496
- // src/tools/builder.ts
496
+ // src/tools/builder-finalize.ts
497
+ function assertBuildable(metadata, schema, invoke) {
498
+ if (!metadata.name) {
499
+ throw new Error("Tool name is required. Use .name() to set it.");
500
+ }
501
+ if (!metadata.description) {
502
+ throw new Error("Tool description is required. Use .description() to set it.");
503
+ }
504
+ if (!metadata.category) {
505
+ throw new Error("Tool category is required. Use .category() to set it.");
506
+ }
507
+ if (!schema) {
508
+ throw new Error("Tool schema is required. Use .schema() to set it.");
509
+ }
510
+ if (!invoke) {
511
+ throw new Error("Tool implementation is required. Use .implement() to set it.");
512
+ }
513
+ }
514
+ function buildTool(metadata, schema, invoke) {
515
+ assertBuildable(metadata, schema, invoke);
516
+ const finalSchema = schema;
517
+ const finalInvoke = invoke;
518
+ return createTool(metadata, finalSchema, async function(input) {
519
+ return finalInvoke.call(this, input);
520
+ });
521
+ }
522
+
523
+ // src/tools/builder-implementation.ts
524
+ function wrapInvoke(invoke) {
525
+ return async function(input) {
526
+ return invoke.call(this, input);
527
+ };
528
+ }
529
+ function wrapSafeInvoke(invoke) {
530
+ return wrapInvoke(async function(input) {
531
+ try {
532
+ const data = await invoke.call(this, input);
533
+ return { success: true, data };
534
+ } catch (error) {
535
+ return {
536
+ success: false,
537
+ error: error instanceof Error ? error.message : String(error)
538
+ };
539
+ }
540
+ });
541
+ }
542
+
543
+ // src/tools/builder-metadata.ts
497
544
  function cloneRelations(relations) {
498
545
  if (!relations) {
499
546
  return void 0;
@@ -532,309 +579,115 @@ function cloneMetadata(metadata) {
532
579
  relations: cloneRelations(metadata.relations)
533
580
  };
534
581
  }
582
+ function appendMetadataList(metadata, key, value) {
583
+ if (!metadata[key]) {
584
+ metadata[key] = [];
585
+ }
586
+ metadata[key].push(value);
587
+ }
588
+ function appendExample(metadata, example) {
589
+ if (!metadata.examples) {
590
+ metadata.examples = [];
591
+ }
592
+ metadata.examples.push(example);
593
+ }
594
+ function setRelation(metadata, relation, tools) {
595
+ metadata.relations = {
596
+ ...metadata.relations ?? {},
597
+ [relation]: tools
598
+ };
599
+ }
600
+
601
+ // src/tools/builder.ts
535
602
  var ToolBuilder = class _ToolBuilder {
536
603
  constructor(metadata = {}, _schema, _invoke) {
537
604
  this.metadata = metadata;
538
605
  this._schema = _schema;
539
606
  this._invoke = _invoke;
540
607
  }
541
- /**
542
- * Set the tool name (required)
543
- *
544
- * @param name - Tool name in kebab-case (e.g., 'read-file')
545
- */
546
608
  name(name) {
547
609
  this.metadata.name = name;
548
610
  return this;
549
611
  }
550
- /**
551
- * Set the tool description (required)
552
- *
553
- * @param description - Clear description of what the tool does
554
- */
555
612
  description(description) {
556
613
  this.metadata.description = description;
557
614
  return this;
558
615
  }
559
- /**
560
- * Set the tool category (required)
561
- *
562
- * @param category - Tool category for organization
563
- */
564
616
  category(category) {
565
617
  this.metadata.category = category;
566
618
  return this;
567
619
  }
568
- /**
569
- * Set the display name (optional)
570
- *
571
- * @param displayName - Human-friendly name for UI display
572
- */
573
620
  displayName(displayName) {
574
621
  this.metadata.displayName = displayName;
575
622
  return this;
576
623
  }
577
- /**
578
- * Set tags for searchability (optional)
579
- *
580
- * @param tags - Array of tags for categorization and search
581
- */
582
624
  tags(tags) {
583
625
  this.metadata.tags = tags;
584
626
  return this;
585
627
  }
586
- /**
587
- * Add a single tag (optional)
588
- *
589
- * @param tag - Tag to add
590
- */
591
628
  tag(tag) {
592
- if (!this.metadata.tags) {
593
- this.metadata.tags = [];
594
- }
595
- this.metadata.tags.push(tag);
629
+ appendMetadataList(this.metadata, "tags", tag);
596
630
  return this;
597
631
  }
598
- /**
599
- * Add an example (optional)
600
- *
601
- * @param example - Usage example for the tool
602
- */
603
632
  example(example) {
604
- if (!this.metadata.examples) {
605
- this.metadata.examples = [];
606
- }
607
- this.metadata.examples.push(example);
633
+ appendExample(this.metadata, example);
608
634
  return this;
609
635
  }
610
- /**
611
- * Set usage notes (optional)
612
- *
613
- * @param notes - Important usage information
614
- */
615
636
  usageNotes(notes) {
616
637
  this.metadata.usageNotes = notes;
617
638
  return this;
618
639
  }
619
- /**
620
- * Set limitations (optional)
621
- *
622
- * @param limitations - Array of known limitations
623
- */
624
640
  limitations(limitations) {
625
641
  this.metadata.limitations = limitations;
626
642
  return this;
627
643
  }
628
- /**
629
- * Add a single limitation (optional)
630
- *
631
- * @param limitation - Limitation to add
632
- */
633
644
  limitation(limitation) {
634
- if (!this.metadata.limitations) {
635
- this.metadata.limitations = [];
636
- }
637
- this.metadata.limitations.push(limitation);
645
+ appendMetadataList(this.metadata, "limitations", limitation);
638
646
  return this;
639
647
  }
640
- /**
641
- * Set version (optional)
642
- *
643
- * @param version - Semantic version string
644
- */
645
648
  version(version) {
646
649
  this.metadata.version = version;
647
650
  return this;
648
651
  }
649
- /**
650
- * Set author (optional)
651
- *
652
- * @param author - Tool author name
653
- */
654
652
  author(author) {
655
653
  this.metadata.author = author;
656
654
  return this;
657
655
  }
658
- /**
659
- * Set tools that must be called before this tool (optional)
660
- *
661
- * @param tools - Array of tool names that are required
662
- * @example
663
- * ```ts
664
- * .requires(['view-file', 'search-codebase'])
665
- * ```
666
- */
667
656
  requires(tools) {
668
- if (!this.metadata.relations) {
669
- this.metadata.relations = {};
670
- }
671
- this.metadata.relations.requires = tools;
657
+ setRelation(this.metadata, "requires", tools);
672
658
  return this;
673
659
  }
674
- /**
675
- * Set tools that work well with this tool (optional)
676
- *
677
- * @param tools - Array of tool names that are suggested
678
- * @example
679
- * ```ts
680
- * .suggests(['run-tests', 'format-code'])
681
- * ```
682
- */
683
660
  suggests(tools) {
684
- if (!this.metadata.relations) {
685
- this.metadata.relations = {};
686
- }
687
- this.metadata.relations.suggests = tools;
661
+ setRelation(this.metadata, "suggests", tools);
688
662
  return this;
689
663
  }
690
- /**
691
- * Set tools that conflict with this tool (optional)
692
- *
693
- * @param tools - Array of tool names that conflict
694
- * @example
695
- * ```ts
696
- * .conflicts(['delete-file'])
697
- * ```
698
- */
699
664
  conflicts(tools) {
700
- if (!this.metadata.relations) {
701
- this.metadata.relations = {};
702
- }
703
- this.metadata.relations.conflicts = tools;
665
+ setRelation(this.metadata, "conflicts", tools);
704
666
  return this;
705
667
  }
706
- /**
707
- * Set tools this typically follows in a workflow (optional)
708
- *
709
- * @param tools - Array of tool names this follows
710
- * @example
711
- * ```ts
712
- * .follows(['search-codebase', 'view-file'])
713
- * ```
714
- */
715
668
  follows(tools) {
716
- if (!this.metadata.relations) {
717
- this.metadata.relations = {};
718
- }
719
- this.metadata.relations.follows = tools;
669
+ setRelation(this.metadata, "follows", tools);
720
670
  return this;
721
671
  }
722
- /**
723
- * Set tools this typically precedes in a workflow (optional)
724
- *
725
- * @param tools - Array of tool names this precedes
726
- * @example
727
- * ```ts
728
- * .precedes(['run-tests'])
729
- * ```
730
- */
731
672
  precedes(tools) {
732
- if (!this.metadata.relations) {
733
- this.metadata.relations = {};
734
- }
735
- this.metadata.relations.precedes = tools;
673
+ setRelation(this.metadata, "precedes", tools);
736
674
  return this;
737
675
  }
738
- /**
739
- * Set the input schema (required)
740
- *
741
- * All fields MUST have .describe() for LLM understanding!
742
- *
743
- * @param schema - Zod schema for input validation
744
- */
745
676
  schema(schema) {
746
677
  return new _ToolBuilder(cloneMetadata(this.metadata), schema, this._invoke);
747
678
  }
748
- /**
749
- * Set the implementation function (required)
750
- *
751
- * @param invoke - Async function that implements the tool
752
- */
753
679
  implement(invoke) {
754
- const wrappedInvoke = async function(input) {
755
- return invoke.call(this, input);
756
- };
757
- return new _ToolBuilder(cloneMetadata(this.metadata), this._schema, wrappedInvoke);
680
+ return new _ToolBuilder(cloneMetadata(this.metadata), this._schema, wrapInvoke(invoke));
758
681
  }
759
- /**
760
- * Set the implementation function with automatic error handling
761
- *
762
- * Wraps the implementation in a try-catch block and returns a standardized
763
- * result object with success/error information.
764
- *
765
- * @param invoke - Async function that implements the tool
766
- * @returns ToolBuilder with safe result type { success: boolean; data?: T; error?: string }
767
- *
768
- * @example
769
- * ```ts
770
- * const tool = toolBuilder()
771
- * .name('read-file')
772
- * .schema(z.object({ path: z.string() }))
773
- * .implementSafe(async ({ path }) => {
774
- * return await fs.readFile(path, 'utf-8');
775
- * })
776
- * .build();
777
- *
778
- * // Result will be: { success: true, data: "file content" }
779
- * // Or on error: { success: false, error: "ENOENT: no such file..." }
780
- * ```
781
- */
782
682
  implementSafe(invoke) {
783
- const safeInvoke = async function(input) {
784
- try {
785
- const data = await invoke.call(this, input);
786
- return { success: true, data };
787
- } catch (error) {
788
- return {
789
- success: false,
790
- error: error instanceof Error ? error.message : String(error)
791
- };
792
- }
793
- };
794
- const wrappedInvoke = async function(input) {
795
- return safeInvoke.call(this, input);
796
- };
797
683
  return new _ToolBuilder(
798
684
  cloneMetadata(this.metadata),
799
685
  this._schema,
800
- wrappedInvoke
686
+ wrapSafeInvoke(invoke)
801
687
  );
802
688
  }
803
- /**
804
- * Build the tool with validation
805
- *
806
- * Validates:
807
- * - All required fields are present
808
- * - Metadata is valid
809
- * - Schema has descriptions on all fields
810
- *
811
- * @returns The validated tool
812
- * @throws {Error} If validation fails
813
- */
814
689
  build() {
815
- if (!this.metadata.name) {
816
- throw new Error("Tool name is required. Use .name() to set it.");
817
- }
818
- if (!this.metadata.description) {
819
- throw new Error("Tool description is required. Use .description() to set it.");
820
- }
821
- if (!this.metadata.category) {
822
- throw new Error("Tool category is required. Use .category() to set it.");
823
- }
824
- if (!this._schema) {
825
- throw new Error("Tool schema is required. Use .schema() to set it.");
826
- }
827
- if (!this._invoke) {
828
- throw new Error("Tool implementation is required. Use .implement() to set it.");
829
- }
830
- const invoke = this._invoke;
831
- return createTool(
832
- this.metadata,
833
- this._schema,
834
- async function(input) {
835
- return invoke.call(this, input);
836
- }
837
- );
690
+ return buildTool(this.metadata, this._schema, this._invoke);
838
691
  }
839
692
  };
840
693
  function toolBuilder() {
package/dist/index.d.cts CHANGED
@@ -920,231 +920,40 @@ declare function validateTool(tool: Tool): {
920
920
  errors: string[];
921
921
  };
922
922
 
923
- /**
924
- * Tool Builder API
925
- *
926
- * Fluent interface for creating tools with automatic validation.
927
- *
928
- * @example
929
- * ```ts
930
- * const tool = createToolBuilder()
931
- * .name('read-file')
932
- * .description('Read a file from the file system')
933
- * .category(ToolCategory.FILE_SYSTEM)
934
- * .tags(['file', 'read', 'io'])
935
- * .schema(z.object({
936
- * path: z.string().describe('Path to the file')
937
- * }))
938
- * .implement(async ({ path }) => {
939
- * // Implementation
940
- * })
941
- * .build();
942
- * ```
943
- */
944
-
945
923
  type ToolInvoke<TOutput> = (this: unknown, input: unknown) => Promise<TOutput>;
946
- /**
947
- * Builder for creating tools with a fluent API
948
- *
949
- * This provides a more ergonomic way to create tools compared to
950
- * manually constructing the metadata object.
951
- */
924
+ type SafeToolResult<T> = {
925
+ success: boolean;
926
+ data?: T;
927
+ error?: string;
928
+ };
929
+
952
930
  declare class ToolBuilder<TInput = unknown, TOutput = unknown> {
953
931
  private metadata;
954
932
  private _schema?;
955
933
  private _invoke?;
956
934
  constructor(metadata?: Partial<ToolMetadata>, _schema?: z.ZodSchema<TInput> | undefined, _invoke?: ToolInvoke<TOutput> | undefined);
957
- /**
958
- * Set the tool name (required)
959
- *
960
- * @param name - Tool name in kebab-case (e.g., 'read-file')
961
- */
962
935
  name(name: string): this;
963
- /**
964
- * Set the tool description (required)
965
- *
966
- * @param description - Clear description of what the tool does
967
- */
968
936
  description(description: string): this;
969
- /**
970
- * Set the tool category (required)
971
- *
972
- * @param category - Tool category for organization
973
- */
974
937
  category(category: ToolCategory): this;
975
- /**
976
- * Set the display name (optional)
977
- *
978
- * @param displayName - Human-friendly name for UI display
979
- */
980
938
  displayName(displayName: string): this;
981
- /**
982
- * Set tags for searchability (optional)
983
- *
984
- * @param tags - Array of tags for categorization and search
985
- */
986
939
  tags(tags: string[]): this;
987
- /**
988
- * Add a single tag (optional)
989
- *
990
- * @param tag - Tag to add
991
- */
992
940
  tag(tag: string): this;
993
- /**
994
- * Add an example (optional)
995
- *
996
- * @param example - Usage example for the tool
997
- */
998
941
  example(example: ToolExample): this;
999
- /**
1000
- * Set usage notes (optional)
1001
- *
1002
- * @param notes - Important usage information
1003
- */
1004
942
  usageNotes(notes: string): this;
1005
- /**
1006
- * Set limitations (optional)
1007
- *
1008
- * @param limitations - Array of known limitations
1009
- */
1010
943
  limitations(limitations: string[]): this;
1011
- /**
1012
- * Add a single limitation (optional)
1013
- *
1014
- * @param limitation - Limitation to add
1015
- */
1016
944
  limitation(limitation: string): this;
1017
- /**
1018
- * Set version (optional)
1019
- *
1020
- * @param version - Semantic version string
1021
- */
1022
945
  version(version: string): this;
1023
- /**
1024
- * Set author (optional)
1025
- *
1026
- * @param author - Tool author name
1027
- */
1028
946
  author(author: string): this;
1029
- /**
1030
- * Set tools that must be called before this tool (optional)
1031
- *
1032
- * @param tools - Array of tool names that are required
1033
- * @example
1034
- * ```ts
1035
- * .requires(['view-file', 'search-codebase'])
1036
- * ```
1037
- */
1038
947
  requires(tools: string[]): this;
1039
- /**
1040
- * Set tools that work well with this tool (optional)
1041
- *
1042
- * @param tools - Array of tool names that are suggested
1043
- * @example
1044
- * ```ts
1045
- * .suggests(['run-tests', 'format-code'])
1046
- * ```
1047
- */
1048
948
  suggests(tools: string[]): this;
1049
- /**
1050
- * Set tools that conflict with this tool (optional)
1051
- *
1052
- * @param tools - Array of tool names that conflict
1053
- * @example
1054
- * ```ts
1055
- * .conflicts(['delete-file'])
1056
- * ```
1057
- */
1058
949
  conflicts(tools: string[]): this;
1059
- /**
1060
- * Set tools this typically follows in a workflow (optional)
1061
- *
1062
- * @param tools - Array of tool names this follows
1063
- * @example
1064
- * ```ts
1065
- * .follows(['search-codebase', 'view-file'])
1066
- * ```
1067
- */
1068
950
  follows(tools: string[]): this;
1069
- /**
1070
- * Set tools this typically precedes in a workflow (optional)
1071
- *
1072
- * @param tools - Array of tool names this precedes
1073
- * @example
1074
- * ```ts
1075
- * .precedes(['run-tests'])
1076
- * ```
1077
- */
1078
951
  precedes(tools: string[]): this;
1079
- /**
1080
- * Set the input schema (required)
1081
- *
1082
- * All fields MUST have .describe() for LLM understanding!
1083
- *
1084
- * @param schema - Zod schema for input validation
1085
- */
1086
952
  schema<T>(schema: z.ZodSchema<T>): ToolBuilder<T, TOutput>;
1087
- /**
1088
- * Set the implementation function (required)
1089
- *
1090
- * @param invoke - Async function that implements the tool
1091
- */
1092
953
  implement<T>(invoke: (input: TInput) => Promise<T>): ToolBuilder<TInput, T>;
1093
- /**
1094
- * Set the implementation function with automatic error handling
1095
- *
1096
- * Wraps the implementation in a try-catch block and returns a standardized
1097
- * result object with success/error information.
1098
- *
1099
- * @param invoke - Async function that implements the tool
1100
- * @returns ToolBuilder with safe result type { success: boolean; data?: T; error?: string }
1101
- *
1102
- * @example
1103
- * ```ts
1104
- * const tool = toolBuilder()
1105
- * .name('read-file')
1106
- * .schema(z.object({ path: z.string() }))
1107
- * .implementSafe(async ({ path }) => {
1108
- * return await fs.readFile(path, 'utf-8');
1109
- * })
1110
- * .build();
1111
- *
1112
- * // Result will be: { success: true, data: "file content" }
1113
- * // Or on error: { success: false, error: "ENOENT: no such file..." }
1114
- * ```
1115
- */
1116
- implementSafe<T>(invoke: (input: TInput) => Promise<T>): ToolBuilder<TInput, {
1117
- success: boolean;
1118
- data?: T;
1119
- error?: string;
1120
- }>;
1121
- /**
1122
- * Build the tool with validation
1123
- *
1124
- * Validates:
1125
- * - All required fields are present
1126
- * - Metadata is valid
1127
- * - Schema has descriptions on all fields
1128
- *
1129
- * @returns The validated tool
1130
- * @throws {Error} If validation fails
1131
- */
954
+ implementSafe<T>(invoke: (input: TInput) => Promise<T>): ToolBuilder<TInput, SafeToolResult<T>>;
1132
955
  build(): Tool<TInput, TOutput>;
1133
956
  }
1134
- /**
1135
- * Create a new tool builder
1136
- *
1137
- * @example
1138
- * ```ts
1139
- * const tool = toolBuilder()
1140
- * .name('my-tool')
1141
- * .description('Does something useful')
1142
- * .category(ToolCategory.UTILITY)
1143
- * .schema(z.object({ input: z.string().describe('Input') }))
1144
- * .implement(async ({ input }) => input)
1145
- * .build();
1146
- * ```
1147
- */
1148
957
  declare function toolBuilder(): ToolBuilder;
1149
958
 
1150
959
  type RegistryTool = Tool<unknown, unknown>;
package/dist/index.d.ts CHANGED
@@ -920,231 +920,40 @@ declare function validateTool(tool: Tool): {
920
920
  errors: string[];
921
921
  };
922
922
 
923
- /**
924
- * Tool Builder API
925
- *
926
- * Fluent interface for creating tools with automatic validation.
927
- *
928
- * @example
929
- * ```ts
930
- * const tool = createToolBuilder()
931
- * .name('read-file')
932
- * .description('Read a file from the file system')
933
- * .category(ToolCategory.FILE_SYSTEM)
934
- * .tags(['file', 'read', 'io'])
935
- * .schema(z.object({
936
- * path: z.string().describe('Path to the file')
937
- * }))
938
- * .implement(async ({ path }) => {
939
- * // Implementation
940
- * })
941
- * .build();
942
- * ```
943
- */
944
-
945
923
  type ToolInvoke<TOutput> = (this: unknown, input: unknown) => Promise<TOutput>;
946
- /**
947
- * Builder for creating tools with a fluent API
948
- *
949
- * This provides a more ergonomic way to create tools compared to
950
- * manually constructing the metadata object.
951
- */
924
+ type SafeToolResult<T> = {
925
+ success: boolean;
926
+ data?: T;
927
+ error?: string;
928
+ };
929
+
952
930
  declare class ToolBuilder<TInput = unknown, TOutput = unknown> {
953
931
  private metadata;
954
932
  private _schema?;
955
933
  private _invoke?;
956
934
  constructor(metadata?: Partial<ToolMetadata>, _schema?: z.ZodSchema<TInput> | undefined, _invoke?: ToolInvoke<TOutput> | undefined);
957
- /**
958
- * Set the tool name (required)
959
- *
960
- * @param name - Tool name in kebab-case (e.g., 'read-file')
961
- */
962
935
  name(name: string): this;
963
- /**
964
- * Set the tool description (required)
965
- *
966
- * @param description - Clear description of what the tool does
967
- */
968
936
  description(description: string): this;
969
- /**
970
- * Set the tool category (required)
971
- *
972
- * @param category - Tool category for organization
973
- */
974
937
  category(category: ToolCategory): this;
975
- /**
976
- * Set the display name (optional)
977
- *
978
- * @param displayName - Human-friendly name for UI display
979
- */
980
938
  displayName(displayName: string): this;
981
- /**
982
- * Set tags for searchability (optional)
983
- *
984
- * @param tags - Array of tags for categorization and search
985
- */
986
939
  tags(tags: string[]): this;
987
- /**
988
- * Add a single tag (optional)
989
- *
990
- * @param tag - Tag to add
991
- */
992
940
  tag(tag: string): this;
993
- /**
994
- * Add an example (optional)
995
- *
996
- * @param example - Usage example for the tool
997
- */
998
941
  example(example: ToolExample): this;
999
- /**
1000
- * Set usage notes (optional)
1001
- *
1002
- * @param notes - Important usage information
1003
- */
1004
942
  usageNotes(notes: string): this;
1005
- /**
1006
- * Set limitations (optional)
1007
- *
1008
- * @param limitations - Array of known limitations
1009
- */
1010
943
  limitations(limitations: string[]): this;
1011
- /**
1012
- * Add a single limitation (optional)
1013
- *
1014
- * @param limitation - Limitation to add
1015
- */
1016
944
  limitation(limitation: string): this;
1017
- /**
1018
- * Set version (optional)
1019
- *
1020
- * @param version - Semantic version string
1021
- */
1022
945
  version(version: string): this;
1023
- /**
1024
- * Set author (optional)
1025
- *
1026
- * @param author - Tool author name
1027
- */
1028
946
  author(author: string): this;
1029
- /**
1030
- * Set tools that must be called before this tool (optional)
1031
- *
1032
- * @param tools - Array of tool names that are required
1033
- * @example
1034
- * ```ts
1035
- * .requires(['view-file', 'search-codebase'])
1036
- * ```
1037
- */
1038
947
  requires(tools: string[]): this;
1039
- /**
1040
- * Set tools that work well with this tool (optional)
1041
- *
1042
- * @param tools - Array of tool names that are suggested
1043
- * @example
1044
- * ```ts
1045
- * .suggests(['run-tests', 'format-code'])
1046
- * ```
1047
- */
1048
948
  suggests(tools: string[]): this;
1049
- /**
1050
- * Set tools that conflict with this tool (optional)
1051
- *
1052
- * @param tools - Array of tool names that conflict
1053
- * @example
1054
- * ```ts
1055
- * .conflicts(['delete-file'])
1056
- * ```
1057
- */
1058
949
  conflicts(tools: string[]): this;
1059
- /**
1060
- * Set tools this typically follows in a workflow (optional)
1061
- *
1062
- * @param tools - Array of tool names this follows
1063
- * @example
1064
- * ```ts
1065
- * .follows(['search-codebase', 'view-file'])
1066
- * ```
1067
- */
1068
950
  follows(tools: string[]): this;
1069
- /**
1070
- * Set tools this typically precedes in a workflow (optional)
1071
- *
1072
- * @param tools - Array of tool names this precedes
1073
- * @example
1074
- * ```ts
1075
- * .precedes(['run-tests'])
1076
- * ```
1077
- */
1078
951
  precedes(tools: string[]): this;
1079
- /**
1080
- * Set the input schema (required)
1081
- *
1082
- * All fields MUST have .describe() for LLM understanding!
1083
- *
1084
- * @param schema - Zod schema for input validation
1085
- */
1086
952
  schema<T>(schema: z.ZodSchema<T>): ToolBuilder<T, TOutput>;
1087
- /**
1088
- * Set the implementation function (required)
1089
- *
1090
- * @param invoke - Async function that implements the tool
1091
- */
1092
953
  implement<T>(invoke: (input: TInput) => Promise<T>): ToolBuilder<TInput, T>;
1093
- /**
1094
- * Set the implementation function with automatic error handling
1095
- *
1096
- * Wraps the implementation in a try-catch block and returns a standardized
1097
- * result object with success/error information.
1098
- *
1099
- * @param invoke - Async function that implements the tool
1100
- * @returns ToolBuilder with safe result type { success: boolean; data?: T; error?: string }
1101
- *
1102
- * @example
1103
- * ```ts
1104
- * const tool = toolBuilder()
1105
- * .name('read-file')
1106
- * .schema(z.object({ path: z.string() }))
1107
- * .implementSafe(async ({ path }) => {
1108
- * return await fs.readFile(path, 'utf-8');
1109
- * })
1110
- * .build();
1111
- *
1112
- * // Result will be: { success: true, data: "file content" }
1113
- * // Or on error: { success: false, error: "ENOENT: no such file..." }
1114
- * ```
1115
- */
1116
- implementSafe<T>(invoke: (input: TInput) => Promise<T>): ToolBuilder<TInput, {
1117
- success: boolean;
1118
- data?: T;
1119
- error?: string;
1120
- }>;
1121
- /**
1122
- * Build the tool with validation
1123
- *
1124
- * Validates:
1125
- * - All required fields are present
1126
- * - Metadata is valid
1127
- * - Schema has descriptions on all fields
1128
- *
1129
- * @returns The validated tool
1130
- * @throws {Error} If validation fails
1131
- */
954
+ implementSafe<T>(invoke: (input: TInput) => Promise<T>): ToolBuilder<TInput, SafeToolResult<T>>;
1132
955
  build(): Tool<TInput, TOutput>;
1133
956
  }
1134
- /**
1135
- * Create a new tool builder
1136
- *
1137
- * @example
1138
- * ```ts
1139
- * const tool = toolBuilder()
1140
- * .name('my-tool')
1141
- * .description('Does something useful')
1142
- * .category(ToolCategory.UTILITY)
1143
- * .schema(z.object({ input: z.string().describe('Input') }))
1144
- * .implement(async ({ input }) => input)
1145
- * .build();
1146
- * ```
1147
- */
1148
957
  declare function toolBuilder(): ToolBuilder;
1149
958
 
1150
959
  type RegistryTool = Tool<unknown, unknown>;
package/dist/index.js CHANGED
@@ -318,7 +318,54 @@ function validateTool(tool) {
318
318
  };
319
319
  }
320
320
 
321
- // src/tools/builder.ts
321
+ // src/tools/builder-finalize.ts
322
+ function assertBuildable(metadata, schema, invoke) {
323
+ if (!metadata.name) {
324
+ throw new Error("Tool name is required. Use .name() to set it.");
325
+ }
326
+ if (!metadata.description) {
327
+ throw new Error("Tool description is required. Use .description() to set it.");
328
+ }
329
+ if (!metadata.category) {
330
+ throw new Error("Tool category is required. Use .category() to set it.");
331
+ }
332
+ if (!schema) {
333
+ throw new Error("Tool schema is required. Use .schema() to set it.");
334
+ }
335
+ if (!invoke) {
336
+ throw new Error("Tool implementation is required. Use .implement() to set it.");
337
+ }
338
+ }
339
+ function buildTool(metadata, schema, invoke) {
340
+ assertBuildable(metadata, schema, invoke);
341
+ const finalSchema = schema;
342
+ const finalInvoke = invoke;
343
+ return createTool(metadata, finalSchema, async function(input) {
344
+ return finalInvoke.call(this, input);
345
+ });
346
+ }
347
+
348
+ // src/tools/builder-implementation.ts
349
+ function wrapInvoke(invoke) {
350
+ return async function(input) {
351
+ return invoke.call(this, input);
352
+ };
353
+ }
354
+ function wrapSafeInvoke(invoke) {
355
+ return wrapInvoke(async function(input) {
356
+ try {
357
+ const data = await invoke.call(this, input);
358
+ return { success: true, data };
359
+ } catch (error) {
360
+ return {
361
+ success: false,
362
+ error: error instanceof Error ? error.message : String(error)
363
+ };
364
+ }
365
+ });
366
+ }
367
+
368
+ // src/tools/builder-metadata.ts
322
369
  function cloneRelations(relations) {
323
370
  if (!relations) {
324
371
  return void 0;
@@ -357,309 +404,115 @@ function cloneMetadata(metadata) {
357
404
  relations: cloneRelations(metadata.relations)
358
405
  };
359
406
  }
407
+ function appendMetadataList(metadata, key, value) {
408
+ if (!metadata[key]) {
409
+ metadata[key] = [];
410
+ }
411
+ metadata[key].push(value);
412
+ }
413
+ function appendExample(metadata, example) {
414
+ if (!metadata.examples) {
415
+ metadata.examples = [];
416
+ }
417
+ metadata.examples.push(example);
418
+ }
419
+ function setRelation(metadata, relation, tools) {
420
+ metadata.relations = {
421
+ ...metadata.relations ?? {},
422
+ [relation]: tools
423
+ };
424
+ }
425
+
426
+ // src/tools/builder.ts
360
427
  var ToolBuilder = class _ToolBuilder {
361
428
  constructor(metadata = {}, _schema, _invoke) {
362
429
  this.metadata = metadata;
363
430
  this._schema = _schema;
364
431
  this._invoke = _invoke;
365
432
  }
366
- /**
367
- * Set the tool name (required)
368
- *
369
- * @param name - Tool name in kebab-case (e.g., 'read-file')
370
- */
371
433
  name(name) {
372
434
  this.metadata.name = name;
373
435
  return this;
374
436
  }
375
- /**
376
- * Set the tool description (required)
377
- *
378
- * @param description - Clear description of what the tool does
379
- */
380
437
  description(description) {
381
438
  this.metadata.description = description;
382
439
  return this;
383
440
  }
384
- /**
385
- * Set the tool category (required)
386
- *
387
- * @param category - Tool category for organization
388
- */
389
441
  category(category) {
390
442
  this.metadata.category = category;
391
443
  return this;
392
444
  }
393
- /**
394
- * Set the display name (optional)
395
- *
396
- * @param displayName - Human-friendly name for UI display
397
- */
398
445
  displayName(displayName) {
399
446
  this.metadata.displayName = displayName;
400
447
  return this;
401
448
  }
402
- /**
403
- * Set tags for searchability (optional)
404
- *
405
- * @param tags - Array of tags for categorization and search
406
- */
407
449
  tags(tags) {
408
450
  this.metadata.tags = tags;
409
451
  return this;
410
452
  }
411
- /**
412
- * Add a single tag (optional)
413
- *
414
- * @param tag - Tag to add
415
- */
416
453
  tag(tag) {
417
- if (!this.metadata.tags) {
418
- this.metadata.tags = [];
419
- }
420
- this.metadata.tags.push(tag);
454
+ appendMetadataList(this.metadata, "tags", tag);
421
455
  return this;
422
456
  }
423
- /**
424
- * Add an example (optional)
425
- *
426
- * @param example - Usage example for the tool
427
- */
428
457
  example(example) {
429
- if (!this.metadata.examples) {
430
- this.metadata.examples = [];
431
- }
432
- this.metadata.examples.push(example);
458
+ appendExample(this.metadata, example);
433
459
  return this;
434
460
  }
435
- /**
436
- * Set usage notes (optional)
437
- *
438
- * @param notes - Important usage information
439
- */
440
461
  usageNotes(notes) {
441
462
  this.metadata.usageNotes = notes;
442
463
  return this;
443
464
  }
444
- /**
445
- * Set limitations (optional)
446
- *
447
- * @param limitations - Array of known limitations
448
- */
449
465
  limitations(limitations) {
450
466
  this.metadata.limitations = limitations;
451
467
  return this;
452
468
  }
453
- /**
454
- * Add a single limitation (optional)
455
- *
456
- * @param limitation - Limitation to add
457
- */
458
469
  limitation(limitation) {
459
- if (!this.metadata.limitations) {
460
- this.metadata.limitations = [];
461
- }
462
- this.metadata.limitations.push(limitation);
470
+ appendMetadataList(this.metadata, "limitations", limitation);
463
471
  return this;
464
472
  }
465
- /**
466
- * Set version (optional)
467
- *
468
- * @param version - Semantic version string
469
- */
470
473
  version(version) {
471
474
  this.metadata.version = version;
472
475
  return this;
473
476
  }
474
- /**
475
- * Set author (optional)
476
- *
477
- * @param author - Tool author name
478
- */
479
477
  author(author) {
480
478
  this.metadata.author = author;
481
479
  return this;
482
480
  }
483
- /**
484
- * Set tools that must be called before this tool (optional)
485
- *
486
- * @param tools - Array of tool names that are required
487
- * @example
488
- * ```ts
489
- * .requires(['view-file', 'search-codebase'])
490
- * ```
491
- */
492
481
  requires(tools) {
493
- if (!this.metadata.relations) {
494
- this.metadata.relations = {};
495
- }
496
- this.metadata.relations.requires = tools;
482
+ setRelation(this.metadata, "requires", tools);
497
483
  return this;
498
484
  }
499
- /**
500
- * Set tools that work well with this tool (optional)
501
- *
502
- * @param tools - Array of tool names that are suggested
503
- * @example
504
- * ```ts
505
- * .suggests(['run-tests', 'format-code'])
506
- * ```
507
- */
508
485
  suggests(tools) {
509
- if (!this.metadata.relations) {
510
- this.metadata.relations = {};
511
- }
512
- this.metadata.relations.suggests = tools;
486
+ setRelation(this.metadata, "suggests", tools);
513
487
  return this;
514
488
  }
515
- /**
516
- * Set tools that conflict with this tool (optional)
517
- *
518
- * @param tools - Array of tool names that conflict
519
- * @example
520
- * ```ts
521
- * .conflicts(['delete-file'])
522
- * ```
523
- */
524
489
  conflicts(tools) {
525
- if (!this.metadata.relations) {
526
- this.metadata.relations = {};
527
- }
528
- this.metadata.relations.conflicts = tools;
490
+ setRelation(this.metadata, "conflicts", tools);
529
491
  return this;
530
492
  }
531
- /**
532
- * Set tools this typically follows in a workflow (optional)
533
- *
534
- * @param tools - Array of tool names this follows
535
- * @example
536
- * ```ts
537
- * .follows(['search-codebase', 'view-file'])
538
- * ```
539
- */
540
493
  follows(tools) {
541
- if (!this.metadata.relations) {
542
- this.metadata.relations = {};
543
- }
544
- this.metadata.relations.follows = tools;
494
+ setRelation(this.metadata, "follows", tools);
545
495
  return this;
546
496
  }
547
- /**
548
- * Set tools this typically precedes in a workflow (optional)
549
- *
550
- * @param tools - Array of tool names this precedes
551
- * @example
552
- * ```ts
553
- * .precedes(['run-tests'])
554
- * ```
555
- */
556
497
  precedes(tools) {
557
- if (!this.metadata.relations) {
558
- this.metadata.relations = {};
559
- }
560
- this.metadata.relations.precedes = tools;
498
+ setRelation(this.metadata, "precedes", tools);
561
499
  return this;
562
500
  }
563
- /**
564
- * Set the input schema (required)
565
- *
566
- * All fields MUST have .describe() for LLM understanding!
567
- *
568
- * @param schema - Zod schema for input validation
569
- */
570
501
  schema(schema) {
571
502
  return new _ToolBuilder(cloneMetadata(this.metadata), schema, this._invoke);
572
503
  }
573
- /**
574
- * Set the implementation function (required)
575
- *
576
- * @param invoke - Async function that implements the tool
577
- */
578
504
  implement(invoke) {
579
- const wrappedInvoke = async function(input) {
580
- return invoke.call(this, input);
581
- };
582
- return new _ToolBuilder(cloneMetadata(this.metadata), this._schema, wrappedInvoke);
505
+ return new _ToolBuilder(cloneMetadata(this.metadata), this._schema, wrapInvoke(invoke));
583
506
  }
584
- /**
585
- * Set the implementation function with automatic error handling
586
- *
587
- * Wraps the implementation in a try-catch block and returns a standardized
588
- * result object with success/error information.
589
- *
590
- * @param invoke - Async function that implements the tool
591
- * @returns ToolBuilder with safe result type { success: boolean; data?: T; error?: string }
592
- *
593
- * @example
594
- * ```ts
595
- * const tool = toolBuilder()
596
- * .name('read-file')
597
- * .schema(z.object({ path: z.string() }))
598
- * .implementSafe(async ({ path }) => {
599
- * return await fs.readFile(path, 'utf-8');
600
- * })
601
- * .build();
602
- *
603
- * // Result will be: { success: true, data: "file content" }
604
- * // Or on error: { success: false, error: "ENOENT: no such file..." }
605
- * ```
606
- */
607
507
  implementSafe(invoke) {
608
- const safeInvoke = async function(input) {
609
- try {
610
- const data = await invoke.call(this, input);
611
- return { success: true, data };
612
- } catch (error) {
613
- return {
614
- success: false,
615
- error: error instanceof Error ? error.message : String(error)
616
- };
617
- }
618
- };
619
- const wrappedInvoke = async function(input) {
620
- return safeInvoke.call(this, input);
621
- };
622
508
  return new _ToolBuilder(
623
509
  cloneMetadata(this.metadata),
624
510
  this._schema,
625
- wrappedInvoke
511
+ wrapSafeInvoke(invoke)
626
512
  );
627
513
  }
628
- /**
629
- * Build the tool with validation
630
- *
631
- * Validates:
632
- * - All required fields are present
633
- * - Metadata is valid
634
- * - Schema has descriptions on all fields
635
- *
636
- * @returns The validated tool
637
- * @throws {Error} If validation fails
638
- */
639
514
  build() {
640
- if (!this.metadata.name) {
641
- throw new Error("Tool name is required. Use .name() to set it.");
642
- }
643
- if (!this.metadata.description) {
644
- throw new Error("Tool description is required. Use .description() to set it.");
645
- }
646
- if (!this.metadata.category) {
647
- throw new Error("Tool category is required. Use .category() to set it.");
648
- }
649
- if (!this._schema) {
650
- throw new Error("Tool schema is required. Use .schema() to set it.");
651
- }
652
- if (!this._invoke) {
653
- throw new Error("Tool implementation is required. Use .implement() to set it.");
654
- }
655
- const invoke = this._invoke;
656
- return createTool(
657
- this.metadata,
658
- this._schema,
659
- async function(input) {
660
- return invoke.call(this, input);
661
- }
662
- );
515
+ return buildTool(this.metadata, this._schema, this._invoke);
663
516
  }
664
517
  };
665
518
  function toolBuilder() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.16.36",
3
+ "version": "0.16.38",
4
4
  "description": "Production-ready TypeScript agent framework built on LangGraph with orchestration, middleware, and typed abstractions.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",