@agentforge/core 0.15.6 → 0.15.8

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
@@ -794,21 +794,42 @@ function toolBuilder() {
794
794
  // src/langchain/converter.ts
795
795
  var import_tools = require("@langchain/core/tools");
796
796
  var import_zod_to_json_schema = require("zod-to-json-schema");
797
+ function serializeToolResult(result) {
798
+ if (typeof result === "string") {
799
+ return result;
800
+ }
801
+ if (typeof result === "object" && result !== null) {
802
+ return JSON.stringify(result, null, 2);
803
+ }
804
+ return String(result);
805
+ }
806
+ function isJsonSchemaObject(value) {
807
+ return typeof value === "object" && value !== null && !Array.isArray(value);
808
+ }
809
+ function isJsonSchemaDefinitionMap(value) {
810
+ if (!isJsonSchemaObject(value)) {
811
+ return false;
812
+ }
813
+ return Object.values(value).every(isJsonSchemaObject);
814
+ }
815
+ function extractToolSchema(jsonSchema) {
816
+ if (!isJsonSchemaObject(jsonSchema)) {
817
+ return {};
818
+ }
819
+ const ref = jsonSchema.$ref;
820
+ const definitions = jsonSchema.definitions;
821
+ if (typeof ref !== "string" || !isJsonSchemaDefinitionMap(definitions)) {
822
+ return jsonSchema;
823
+ }
824
+ const refName = ref.replace("#/definitions/", "");
825
+ return definitions[refName] ?? jsonSchema;
826
+ }
797
827
  function toLangChainTool(tool) {
798
828
  return new import_tools.DynamicStructuredTool({
799
829
  name: tool.metadata.name,
800
830
  description: tool.metadata.description,
801
831
  schema: tool.schema,
802
- func: async (input) => {
803
- const result = await tool.invoke(input);
804
- if (typeof result === "string") {
805
- return result;
806
- }
807
- if (typeof result === "object" && result !== null) {
808
- return JSON.stringify(result, null, 2);
809
- }
810
- return String(result);
811
- }
832
+ func: async (input) => serializeToolResult(await tool.invoke(input))
812
833
  });
813
834
  }
814
835
  function toLangChainTools(tools) {
@@ -820,11 +841,7 @@ function getToolJsonSchema(tool) {
820
841
  $refStrategy: "none"
821
842
  // Don't use $ref for nested schemas
822
843
  });
823
- if (jsonSchema.$ref && jsonSchema.definitions) {
824
- const refName = jsonSchema.$ref.replace("#/definitions/", "");
825
- return jsonSchema.definitions[refName] || jsonSchema;
826
- }
827
- return jsonSchema;
844
+ return extractToolSchema(jsonSchema);
828
845
  }
829
846
  function getToolDescription(tool) {
830
847
  const { metadata } = tool;
@@ -2194,46 +2211,84 @@ function createToolSimulator(config) {
2194
2211
 
2195
2212
  // src/langgraph/state.ts
2196
2213
  var import_langgraph = require("@langchain/langgraph");
2214
+ function entriesOf(value) {
2215
+ return Object.entries(value);
2216
+ }
2217
+ function keysOf(value) {
2218
+ return Object.keys(value);
2219
+ }
2220
+ function hasOwnProperty(value, key) {
2221
+ return Object.prototype.hasOwnProperty.call(value, key);
2222
+ }
2223
+ function useLatestValue(_left, right) {
2224
+ return right;
2225
+ }
2226
+ function setStateValue(target, key, value) {
2227
+ target[key] = value;
2228
+ }
2229
+ function setStateDefinitionValue(target, key, value) {
2230
+ target[key] = value;
2231
+ }
2232
+ function createChannel(channelConfig) {
2233
+ if (channelConfig.reducer) {
2234
+ return (0, import_langgraph.Annotation)({
2235
+ reducer: channelConfig.reducer,
2236
+ default: channelConfig.default
2237
+ });
2238
+ }
2239
+ if (channelConfig.default) {
2240
+ return (0, import_langgraph.Annotation)({
2241
+ reducer: useLatestValue,
2242
+ default: channelConfig.default
2243
+ });
2244
+ }
2245
+ return (0, import_langgraph.Annotation)();
2246
+ }
2197
2247
  function createStateAnnotation(config) {
2198
2248
  const stateDefinition = {};
2199
- for (const [key, channelConfig] of Object.entries(config)) {
2200
- if (channelConfig.reducer) {
2201
- stateDefinition[key] = (0, import_langgraph.Annotation)({
2202
- reducer: channelConfig.reducer,
2203
- default: channelConfig.default
2204
- });
2205
- } else if (channelConfig.default) {
2206
- stateDefinition[key] = (0, import_langgraph.Annotation)({
2207
- reducer: (_left, right) => right,
2208
- default: channelConfig.default
2209
- });
2210
- } else {
2211
- stateDefinition[key] = (0, import_langgraph.Annotation)();
2212
- }
2249
+ for (const [key, channelConfig] of entriesOf(config)) {
2250
+ setStateDefinitionValue(
2251
+ stateDefinition,
2252
+ key,
2253
+ createChannel(channelConfig)
2254
+ );
2213
2255
  }
2214
2256
  return import_langgraph.Annotation.Root(stateDefinition);
2215
2257
  }
2216
2258
  function validateState(state, config) {
2217
2259
  const validated = {};
2218
- for (const [key, channelConfig] of Object.entries(config)) {
2219
- if (channelConfig.schema && key in state) {
2220
- validated[key] = channelConfig.schema.parse(state[key]);
2221
- } else if (key in state) {
2222
- validated[key] = state[key];
2260
+ for (const [key, channelConfig] of entriesOf(config)) {
2261
+ if (channelConfig.schema && hasOwnProperty(state, key)) {
2262
+ setStateValue(
2263
+ validated,
2264
+ key,
2265
+ channelConfig.schema.parse(state[key])
2266
+ );
2267
+ } else if (hasOwnProperty(state, key)) {
2268
+ setStateValue(validated, key, state[key]);
2223
2269
  } else if (channelConfig.default) {
2224
- validated[key] = channelConfig.default();
2270
+ setStateValue(validated, key, channelConfig.default());
2225
2271
  }
2226
2272
  }
2227
2273
  return validated;
2228
2274
  }
2229
2275
  function mergeState(currentState, update, config) {
2230
2276
  const merged = { ...currentState };
2231
- for (const [key, value] of Object.entries(update)) {
2277
+ for (const key of keysOf(update)) {
2278
+ const value = update[key];
2232
2279
  const channelConfig = config[key];
2233
- if (channelConfig?.reducer && key in merged) {
2234
- merged[key] = channelConfig.reducer(merged[key], value);
2280
+ const reducer = channelConfig?.reducer;
2281
+ if (reducer && hasOwnProperty(merged, key)) {
2282
+ setStateValue(
2283
+ merged,
2284
+ key,
2285
+ reducer(
2286
+ merged[key],
2287
+ value
2288
+ )
2289
+ );
2235
2290
  } else {
2236
- merged[key] = value;
2291
+ setStateValue(merged, key, value);
2237
2292
  }
2238
2293
  }
2239
2294
  return merged;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { z, ZodType, ZodTypeDef } from 'zod';
1
+ import { z, ZodTypeAny, output, ZodType, ZodTypeDef } from 'zod';
2
2
  import { DynamicStructuredTool } from '@langchain/core/tools';
3
- import { AnnotationRoot, StateDefinition, StateGraph, END, MemorySaver, BaseCheckpointSaver, CheckpointTuple } from '@langchain/langgraph';
3
+ import { AnnotationRoot, BaseChannel, StateGraph, END, MemorySaver, BaseCheckpointSaver, CheckpointTuple } from '@langchain/langgraph';
4
4
  import { RunnableConfig } from '@langchain/core/runnables';
5
5
 
6
6
  /**
@@ -1794,6 +1794,13 @@ declare function createToolSimulator(config: ToolSimulatorConfig): {
1794
1794
  * ```
1795
1795
  */
1796
1796
 
1797
+ type RuntimeSchema<TInput = unknown> = z.ZodSchema<TInput>;
1798
+ type JsonSchemaObject = Record<string, unknown>;
1799
+ interface LangChainConvertibleTool<TInput = unknown, TOutput = unknown> {
1800
+ metadata: ToolMetadata;
1801
+ schema: RuntimeSchema<TInput>;
1802
+ invoke(input: TInput): Promise<TOutput>;
1803
+ }
1797
1804
  /**
1798
1805
  * Convert an AgentForge tool to a LangChain DynamicStructuredTool
1799
1806
  *
@@ -1826,7 +1833,7 @@ declare function createToolSimulator(config: ToolSimulatorConfig): {
1826
1833
  * });
1827
1834
  * ```
1828
1835
  */
1829
- declare function toLangChainTool(tool: Tool<any, any>): DynamicStructuredTool<any>;
1836
+ declare function toLangChainTool<TInput, TOutput>(tool: Tool<TInput, TOutput>): DynamicStructuredTool<RuntimeSchema<TInput>, TInput, TInput, string>;
1830
1837
  /**
1831
1838
  * Convert multiple AgentForge tools to LangChain tools
1832
1839
  *
@@ -1844,7 +1851,7 @@ declare function toLangChainTool(tool: Tool<any, any>): DynamicStructuredTool<an
1844
1851
  * });
1845
1852
  * ```
1846
1853
  */
1847
- declare function toLangChainTools(tools: Tool<any, any>[]): DynamicStructuredTool<any>[];
1854
+ declare function toLangChainTools(tools: readonly LangChainConvertibleTool[]): DynamicStructuredTool[];
1848
1855
  /**
1849
1856
  * Get the JSON Schema representation of a tool's input schema
1850
1857
  *
@@ -1859,7 +1866,7 @@ declare function toLangChainTools(tools: Tool<any, any>[]): DynamicStructuredToo
1859
1866
  * console.log(JSON.stringify(schema, null, 2));
1860
1867
  * ```
1861
1868
  */
1862
- declare function getToolJsonSchema(tool: Tool<any, any>): Record<string, any>;
1869
+ declare function getToolJsonSchema<TInput, TOutput>(tool: Tool<TInput, TOutput>): JsonSchemaObject;
1863
1870
  /**
1864
1871
  * Get tool metadata in a format suitable for LLM prompts
1865
1872
  *
@@ -1880,7 +1887,7 @@ declare function getToolJsonSchema(tool: Tool<any, any>): Record<string, any>;
1880
1887
  * // ...
1881
1888
  * ```
1882
1889
  */
1883
- declare function getToolDescription(tool: Tool<any, any>): string;
1890
+ declare function getToolDescription<TInput, TOutput>(tool: Tool<TInput, TOutput>): string;
1884
1891
 
1885
1892
  /**
1886
1893
  * LangGraph State Utilities
@@ -1894,11 +1901,11 @@ declare function getToolDescription(tool: Tool<any, any>): string;
1894
1901
  /**
1895
1902
  * State channel configuration with optional Zod schema validation
1896
1903
  */
1897
- interface StateChannelConfig<T = any, U = T> {
1904
+ interface StateChannelConfig<T = unknown, U = T> {
1898
1905
  /**
1899
1906
  * Optional Zod schema for runtime validation
1900
1907
  */
1901
- schema?: ZodType<T, ZodTypeDef, any>;
1908
+ schema?: ZodType<T, ZodTypeDef, unknown>;
1902
1909
  /**
1903
1910
  * Optional reducer function for aggregating updates
1904
1911
  */
@@ -1912,6 +1919,52 @@ interface StateChannelConfig<T = any, U = T> {
1912
1919
  */
1913
1920
  description?: string;
1914
1921
  }
1922
+ type StateChannelConfigLike = {
1923
+ schema?: ZodTypeAny;
1924
+ reducer?: (left: never, right: never) => unknown;
1925
+ default?: () => unknown;
1926
+ description?: string;
1927
+ };
1928
+ type StateConfigMap = Record<string, StateChannelConfigLike>;
1929
+ type IsExact<TLeft, TRight> = [
1930
+ TLeft
1931
+ ] extends [TRight] ? ([TRight] extends [TLeft] ? true : false) : false;
1932
+ type HasReducer<TChannel extends StateChannelConfigLike> = TChannel extends {
1933
+ reducer: (left: unknown, right: unknown) => unknown;
1934
+ } ? true : false;
1935
+ type SchemaValue<TChannel extends StateChannelConfigLike> = TChannel extends {
1936
+ schema: infer TSchema extends ZodTypeAny;
1937
+ } ? output<TSchema> : never;
1938
+ type DefaultValue<TChannel extends StateChannelConfigLike> = TChannel extends {
1939
+ default: () => infer TValue;
1940
+ } ? TValue : never;
1941
+ type ReducerValue<TChannel extends StateChannelConfigLike> = TChannel extends {
1942
+ reducer: (left: infer TValue, right: unknown) => infer TResult;
1943
+ } ? IsExact<TValue, TResult> extends true ? TValue : never : never;
1944
+ type ReducerUpdate<TChannel extends StateChannelConfigLike> = TChannel extends {
1945
+ reducer: (left: unknown, right: infer TUpdate) => unknown;
1946
+ } ? TUpdate : never;
1947
+ type ChannelValue<TChannel extends StateChannelConfigLike> = HasReducer<TChannel> extends true ? ReducerValue<TChannel> : [SchemaValue<TChannel>] extends [never] ? [DefaultValue<TChannel>] extends [never] ? unknown : DefaultValue<TChannel> : SchemaValue<TChannel>;
1948
+ type ChannelUpdate<TChannel extends StateChannelConfigLike> = HasReducer<TChannel> extends true ? ReducerUpdate<TChannel> : ChannelValue<TChannel>;
1949
+ type StateShape<TConfig extends StateConfigMap> = {
1950
+ [K in keyof TConfig]: ChannelValue<TConfig[K]>;
1951
+ };
1952
+ type StateUpdateShape<TConfig extends StateConfigMap> = {
1953
+ [K in keyof TConfig]?: ChannelUpdate<TConfig[K]>;
1954
+ };
1955
+ type StateChannelDefinition<TChannel extends StateChannelConfigLike> = BaseChannel<ChannelValue<TChannel>, ChannelUpdate<TChannel>>;
1956
+ type StateAnnotationDefinition<TConfig extends StateConfigMap> = {
1957
+ [K in keyof TConfig]: StateChannelDefinition<TConfig[K]>;
1958
+ };
1959
+ type DefaultedKeys<TConfig extends StateConfigMap> = {
1960
+ [K in keyof TConfig]-?: TConfig[K] extends {
1961
+ default: () => ChannelValue<TConfig[K]>;
1962
+ } ? K : never;
1963
+ }[keyof TConfig];
1964
+ type InputStateKeys<TConfig extends StateConfigMap, TState> = Extract<keyof TConfig, keyof TState>;
1965
+ type ValidatedState<TConfig extends StateConfigMap, TState extends Partial<Record<keyof TConfig, unknown>>> = {
1966
+ [K in InputStateKeys<TConfig, TState> | DefaultedKeys<TConfig>]: ChannelValue<TConfig[K]>;
1967
+ };
1915
1968
  /**
1916
1969
  * Create a type-safe state annotation with optional Zod validation
1917
1970
  *
@@ -1942,7 +1995,7 @@ interface StateChannelConfig<T = any, U = T> {
1942
1995
  * type State = typeof AgentState.State;
1943
1996
  * ```
1944
1997
  */
1945
- declare function createStateAnnotation<T extends Record<string, StateChannelConfig>>(config: T): AnnotationRoot<StateDefinition>;
1998
+ declare function createStateAnnotation<TConfig extends StateConfigMap>(config: TConfig): AnnotationRoot<StateAnnotationDefinition<TConfig>>;
1946
1999
  /**
1947
2000
  * Validate state against Zod schemas
1948
2001
  *
@@ -1964,7 +2017,7 @@ declare function createStateAnnotation<T extends Record<string, StateChannelConf
1964
2017
  * );
1965
2018
  * ```
1966
2019
  */
1967
- declare function validateState<T extends Record<string, StateChannelConfig>>(state: Record<string, any>, config: T): Record<string, any>;
2020
+ declare function validateState<TConfig extends StateConfigMap, TState extends Partial<Record<keyof TConfig, unknown>>>(state: TState, config: TConfig): ValidatedState<TConfig, TState>;
1968
2021
  /**
1969
2022
  * Merge state updates using configured reducers
1970
2023
  *
@@ -1989,7 +2042,7 @@ declare function validateState<T extends Record<string, StateChannelConfig>>(sta
1989
2042
  * // Result: { messages: ['a', 'b', 'c'] }
1990
2043
  * ```
1991
2044
  */
1992
- declare function mergeState<T extends Record<string, StateChannelConfig>>(currentState: Record<string, any>, update: Record<string, any>, config: T): Record<string, any>;
2045
+ declare function mergeState<TConfig extends StateConfigMap>(currentState: Partial<StateShape<TConfig>>, update: StateUpdateShape<TConfig>, config: TConfig): Partial<StateShape<TConfig>>;
1993
2046
 
1994
2047
  /**
1995
2048
  * Sequential Workflow Builder
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { z, ZodType, ZodTypeDef } from 'zod';
1
+ import { z, ZodTypeAny, output, ZodType, ZodTypeDef } from 'zod';
2
2
  import { DynamicStructuredTool } from '@langchain/core/tools';
3
- import { AnnotationRoot, StateDefinition, StateGraph, END, MemorySaver, BaseCheckpointSaver, CheckpointTuple } from '@langchain/langgraph';
3
+ import { AnnotationRoot, BaseChannel, StateGraph, END, MemorySaver, BaseCheckpointSaver, CheckpointTuple } from '@langchain/langgraph';
4
4
  import { RunnableConfig } from '@langchain/core/runnables';
5
5
 
6
6
  /**
@@ -1794,6 +1794,13 @@ declare function createToolSimulator(config: ToolSimulatorConfig): {
1794
1794
  * ```
1795
1795
  */
1796
1796
 
1797
+ type RuntimeSchema<TInput = unknown> = z.ZodSchema<TInput>;
1798
+ type JsonSchemaObject = Record<string, unknown>;
1799
+ interface LangChainConvertibleTool<TInput = unknown, TOutput = unknown> {
1800
+ metadata: ToolMetadata;
1801
+ schema: RuntimeSchema<TInput>;
1802
+ invoke(input: TInput): Promise<TOutput>;
1803
+ }
1797
1804
  /**
1798
1805
  * Convert an AgentForge tool to a LangChain DynamicStructuredTool
1799
1806
  *
@@ -1826,7 +1833,7 @@ declare function createToolSimulator(config: ToolSimulatorConfig): {
1826
1833
  * });
1827
1834
  * ```
1828
1835
  */
1829
- declare function toLangChainTool(tool: Tool<any, any>): DynamicStructuredTool<any>;
1836
+ declare function toLangChainTool<TInput, TOutput>(tool: Tool<TInput, TOutput>): DynamicStructuredTool<RuntimeSchema<TInput>, TInput, TInput, string>;
1830
1837
  /**
1831
1838
  * Convert multiple AgentForge tools to LangChain tools
1832
1839
  *
@@ -1844,7 +1851,7 @@ declare function toLangChainTool(tool: Tool<any, any>): DynamicStructuredTool<an
1844
1851
  * });
1845
1852
  * ```
1846
1853
  */
1847
- declare function toLangChainTools(tools: Tool<any, any>[]): DynamicStructuredTool<any>[];
1854
+ declare function toLangChainTools(tools: readonly LangChainConvertibleTool[]): DynamicStructuredTool[];
1848
1855
  /**
1849
1856
  * Get the JSON Schema representation of a tool's input schema
1850
1857
  *
@@ -1859,7 +1866,7 @@ declare function toLangChainTools(tools: Tool<any, any>[]): DynamicStructuredToo
1859
1866
  * console.log(JSON.stringify(schema, null, 2));
1860
1867
  * ```
1861
1868
  */
1862
- declare function getToolJsonSchema(tool: Tool<any, any>): Record<string, any>;
1869
+ declare function getToolJsonSchema<TInput, TOutput>(tool: Tool<TInput, TOutput>): JsonSchemaObject;
1863
1870
  /**
1864
1871
  * Get tool metadata in a format suitable for LLM prompts
1865
1872
  *
@@ -1880,7 +1887,7 @@ declare function getToolJsonSchema(tool: Tool<any, any>): Record<string, any>;
1880
1887
  * // ...
1881
1888
  * ```
1882
1889
  */
1883
- declare function getToolDescription(tool: Tool<any, any>): string;
1890
+ declare function getToolDescription<TInput, TOutput>(tool: Tool<TInput, TOutput>): string;
1884
1891
 
1885
1892
  /**
1886
1893
  * LangGraph State Utilities
@@ -1894,11 +1901,11 @@ declare function getToolDescription(tool: Tool<any, any>): string;
1894
1901
  /**
1895
1902
  * State channel configuration with optional Zod schema validation
1896
1903
  */
1897
- interface StateChannelConfig<T = any, U = T> {
1904
+ interface StateChannelConfig<T = unknown, U = T> {
1898
1905
  /**
1899
1906
  * Optional Zod schema for runtime validation
1900
1907
  */
1901
- schema?: ZodType<T, ZodTypeDef, any>;
1908
+ schema?: ZodType<T, ZodTypeDef, unknown>;
1902
1909
  /**
1903
1910
  * Optional reducer function for aggregating updates
1904
1911
  */
@@ -1912,6 +1919,52 @@ interface StateChannelConfig<T = any, U = T> {
1912
1919
  */
1913
1920
  description?: string;
1914
1921
  }
1922
+ type StateChannelConfigLike = {
1923
+ schema?: ZodTypeAny;
1924
+ reducer?: (left: never, right: never) => unknown;
1925
+ default?: () => unknown;
1926
+ description?: string;
1927
+ };
1928
+ type StateConfigMap = Record<string, StateChannelConfigLike>;
1929
+ type IsExact<TLeft, TRight> = [
1930
+ TLeft
1931
+ ] extends [TRight] ? ([TRight] extends [TLeft] ? true : false) : false;
1932
+ type HasReducer<TChannel extends StateChannelConfigLike> = TChannel extends {
1933
+ reducer: (left: unknown, right: unknown) => unknown;
1934
+ } ? true : false;
1935
+ type SchemaValue<TChannel extends StateChannelConfigLike> = TChannel extends {
1936
+ schema: infer TSchema extends ZodTypeAny;
1937
+ } ? output<TSchema> : never;
1938
+ type DefaultValue<TChannel extends StateChannelConfigLike> = TChannel extends {
1939
+ default: () => infer TValue;
1940
+ } ? TValue : never;
1941
+ type ReducerValue<TChannel extends StateChannelConfigLike> = TChannel extends {
1942
+ reducer: (left: infer TValue, right: unknown) => infer TResult;
1943
+ } ? IsExact<TValue, TResult> extends true ? TValue : never : never;
1944
+ type ReducerUpdate<TChannel extends StateChannelConfigLike> = TChannel extends {
1945
+ reducer: (left: unknown, right: infer TUpdate) => unknown;
1946
+ } ? TUpdate : never;
1947
+ type ChannelValue<TChannel extends StateChannelConfigLike> = HasReducer<TChannel> extends true ? ReducerValue<TChannel> : [SchemaValue<TChannel>] extends [never] ? [DefaultValue<TChannel>] extends [never] ? unknown : DefaultValue<TChannel> : SchemaValue<TChannel>;
1948
+ type ChannelUpdate<TChannel extends StateChannelConfigLike> = HasReducer<TChannel> extends true ? ReducerUpdate<TChannel> : ChannelValue<TChannel>;
1949
+ type StateShape<TConfig extends StateConfigMap> = {
1950
+ [K in keyof TConfig]: ChannelValue<TConfig[K]>;
1951
+ };
1952
+ type StateUpdateShape<TConfig extends StateConfigMap> = {
1953
+ [K in keyof TConfig]?: ChannelUpdate<TConfig[K]>;
1954
+ };
1955
+ type StateChannelDefinition<TChannel extends StateChannelConfigLike> = BaseChannel<ChannelValue<TChannel>, ChannelUpdate<TChannel>>;
1956
+ type StateAnnotationDefinition<TConfig extends StateConfigMap> = {
1957
+ [K in keyof TConfig]: StateChannelDefinition<TConfig[K]>;
1958
+ };
1959
+ type DefaultedKeys<TConfig extends StateConfigMap> = {
1960
+ [K in keyof TConfig]-?: TConfig[K] extends {
1961
+ default: () => ChannelValue<TConfig[K]>;
1962
+ } ? K : never;
1963
+ }[keyof TConfig];
1964
+ type InputStateKeys<TConfig extends StateConfigMap, TState> = Extract<keyof TConfig, keyof TState>;
1965
+ type ValidatedState<TConfig extends StateConfigMap, TState extends Partial<Record<keyof TConfig, unknown>>> = {
1966
+ [K in InputStateKeys<TConfig, TState> | DefaultedKeys<TConfig>]: ChannelValue<TConfig[K]>;
1967
+ };
1915
1968
  /**
1916
1969
  * Create a type-safe state annotation with optional Zod validation
1917
1970
  *
@@ -1942,7 +1995,7 @@ interface StateChannelConfig<T = any, U = T> {
1942
1995
  * type State = typeof AgentState.State;
1943
1996
  * ```
1944
1997
  */
1945
- declare function createStateAnnotation<T extends Record<string, StateChannelConfig>>(config: T): AnnotationRoot<StateDefinition>;
1998
+ declare function createStateAnnotation<TConfig extends StateConfigMap>(config: TConfig): AnnotationRoot<StateAnnotationDefinition<TConfig>>;
1946
1999
  /**
1947
2000
  * Validate state against Zod schemas
1948
2001
  *
@@ -1964,7 +2017,7 @@ declare function createStateAnnotation<T extends Record<string, StateChannelConf
1964
2017
  * );
1965
2018
  * ```
1966
2019
  */
1967
- declare function validateState<T extends Record<string, StateChannelConfig>>(state: Record<string, any>, config: T): Record<string, any>;
2020
+ declare function validateState<TConfig extends StateConfigMap, TState extends Partial<Record<keyof TConfig, unknown>>>(state: TState, config: TConfig): ValidatedState<TConfig, TState>;
1968
2021
  /**
1969
2022
  * Merge state updates using configured reducers
1970
2023
  *
@@ -1989,7 +2042,7 @@ declare function validateState<T extends Record<string, StateChannelConfig>>(sta
1989
2042
  * // Result: { messages: ['a', 'b', 'c'] }
1990
2043
  * ```
1991
2044
  */
1992
- declare function mergeState<T extends Record<string, StateChannelConfig>>(currentState: Record<string, any>, update: Record<string, any>, config: T): Record<string, any>;
2045
+ declare function mergeState<TConfig extends StateConfigMap>(currentState: Partial<StateShape<TConfig>>, update: StateUpdateShape<TConfig>, config: TConfig): Partial<StateShape<TConfig>>;
1993
2046
 
1994
2047
  /**
1995
2048
  * Sequential Workflow Builder
package/dist/index.js CHANGED
@@ -619,21 +619,42 @@ function toolBuilder() {
619
619
  // src/langchain/converter.ts
620
620
  import { DynamicStructuredTool } from "@langchain/core/tools";
621
621
  import { zodToJsonSchema } from "zod-to-json-schema";
622
+ function serializeToolResult(result) {
623
+ if (typeof result === "string") {
624
+ return result;
625
+ }
626
+ if (typeof result === "object" && result !== null) {
627
+ return JSON.stringify(result, null, 2);
628
+ }
629
+ return String(result);
630
+ }
631
+ function isJsonSchemaObject(value) {
632
+ return typeof value === "object" && value !== null && !Array.isArray(value);
633
+ }
634
+ function isJsonSchemaDefinitionMap(value) {
635
+ if (!isJsonSchemaObject(value)) {
636
+ return false;
637
+ }
638
+ return Object.values(value).every(isJsonSchemaObject);
639
+ }
640
+ function extractToolSchema(jsonSchema) {
641
+ if (!isJsonSchemaObject(jsonSchema)) {
642
+ return {};
643
+ }
644
+ const ref = jsonSchema.$ref;
645
+ const definitions = jsonSchema.definitions;
646
+ if (typeof ref !== "string" || !isJsonSchemaDefinitionMap(definitions)) {
647
+ return jsonSchema;
648
+ }
649
+ const refName = ref.replace("#/definitions/", "");
650
+ return definitions[refName] ?? jsonSchema;
651
+ }
622
652
  function toLangChainTool(tool) {
623
653
  return new DynamicStructuredTool({
624
654
  name: tool.metadata.name,
625
655
  description: tool.metadata.description,
626
656
  schema: tool.schema,
627
- func: async (input) => {
628
- const result = await tool.invoke(input);
629
- if (typeof result === "string") {
630
- return result;
631
- }
632
- if (typeof result === "object" && result !== null) {
633
- return JSON.stringify(result, null, 2);
634
- }
635
- return String(result);
636
- }
657
+ func: async (input) => serializeToolResult(await tool.invoke(input))
637
658
  });
638
659
  }
639
660
  function toLangChainTools(tools) {
@@ -645,11 +666,7 @@ function getToolJsonSchema(tool) {
645
666
  $refStrategy: "none"
646
667
  // Don't use $ref for nested schemas
647
668
  });
648
- if (jsonSchema.$ref && jsonSchema.definitions) {
649
- const refName = jsonSchema.$ref.replace("#/definitions/", "");
650
- return jsonSchema.definitions[refName] || jsonSchema;
651
- }
652
- return jsonSchema;
669
+ return extractToolSchema(jsonSchema);
653
670
  }
654
671
  function getToolDescription(tool) {
655
672
  const { metadata } = tool;
@@ -2019,46 +2036,84 @@ function createToolSimulator(config) {
2019
2036
 
2020
2037
  // src/langgraph/state.ts
2021
2038
  import { Annotation } from "@langchain/langgraph";
2039
+ function entriesOf(value) {
2040
+ return Object.entries(value);
2041
+ }
2042
+ function keysOf(value) {
2043
+ return Object.keys(value);
2044
+ }
2045
+ function hasOwnProperty(value, key) {
2046
+ return Object.prototype.hasOwnProperty.call(value, key);
2047
+ }
2048
+ function useLatestValue(_left, right) {
2049
+ return right;
2050
+ }
2051
+ function setStateValue(target, key, value) {
2052
+ target[key] = value;
2053
+ }
2054
+ function setStateDefinitionValue(target, key, value) {
2055
+ target[key] = value;
2056
+ }
2057
+ function createChannel(channelConfig) {
2058
+ if (channelConfig.reducer) {
2059
+ return Annotation({
2060
+ reducer: channelConfig.reducer,
2061
+ default: channelConfig.default
2062
+ });
2063
+ }
2064
+ if (channelConfig.default) {
2065
+ return Annotation({
2066
+ reducer: useLatestValue,
2067
+ default: channelConfig.default
2068
+ });
2069
+ }
2070
+ return Annotation();
2071
+ }
2022
2072
  function createStateAnnotation(config) {
2023
2073
  const stateDefinition = {};
2024
- for (const [key, channelConfig] of Object.entries(config)) {
2025
- if (channelConfig.reducer) {
2026
- stateDefinition[key] = Annotation({
2027
- reducer: channelConfig.reducer,
2028
- default: channelConfig.default
2029
- });
2030
- } else if (channelConfig.default) {
2031
- stateDefinition[key] = Annotation({
2032
- reducer: (_left, right) => right,
2033
- default: channelConfig.default
2034
- });
2035
- } else {
2036
- stateDefinition[key] = Annotation();
2037
- }
2074
+ for (const [key, channelConfig] of entriesOf(config)) {
2075
+ setStateDefinitionValue(
2076
+ stateDefinition,
2077
+ key,
2078
+ createChannel(channelConfig)
2079
+ );
2038
2080
  }
2039
2081
  return Annotation.Root(stateDefinition);
2040
2082
  }
2041
2083
  function validateState(state, config) {
2042
2084
  const validated = {};
2043
- for (const [key, channelConfig] of Object.entries(config)) {
2044
- if (channelConfig.schema && key in state) {
2045
- validated[key] = channelConfig.schema.parse(state[key]);
2046
- } else if (key in state) {
2047
- validated[key] = state[key];
2085
+ for (const [key, channelConfig] of entriesOf(config)) {
2086
+ if (channelConfig.schema && hasOwnProperty(state, key)) {
2087
+ setStateValue(
2088
+ validated,
2089
+ key,
2090
+ channelConfig.schema.parse(state[key])
2091
+ );
2092
+ } else if (hasOwnProperty(state, key)) {
2093
+ setStateValue(validated, key, state[key]);
2048
2094
  } else if (channelConfig.default) {
2049
- validated[key] = channelConfig.default();
2095
+ setStateValue(validated, key, channelConfig.default());
2050
2096
  }
2051
2097
  }
2052
2098
  return validated;
2053
2099
  }
2054
2100
  function mergeState(currentState, update, config) {
2055
2101
  const merged = { ...currentState };
2056
- for (const [key, value] of Object.entries(update)) {
2102
+ for (const key of keysOf(update)) {
2103
+ const value = update[key];
2057
2104
  const channelConfig = config[key];
2058
- if (channelConfig?.reducer && key in merged) {
2059
- merged[key] = channelConfig.reducer(merged[key], value);
2105
+ const reducer = channelConfig?.reducer;
2106
+ if (reducer && hasOwnProperty(merged, key)) {
2107
+ setStateValue(
2108
+ merged,
2109
+ key,
2110
+ reducer(
2111
+ merged[key],
2112
+ value
2113
+ )
2114
+ );
2060
2115
  } else {
2061
- merged[key] = value;
2116
+ setStateValue(merged, key, value);
2062
2117
  }
2063
2118
  }
2064
2119
  return merged;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.15.6",
3
+ "version": "0.15.8",
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",