@falai/agent 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +117 -1
  2. package/dist/cjs/core/Agent.d.ts +11 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +44 -2
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/Events.d.ts +2 -2
  7. package/dist/cjs/core/Events.d.ts.map +1 -1
  8. package/dist/cjs/core/Events.js +4 -4
  9. package/dist/cjs/core/Events.js.map +1 -1
  10. package/dist/cjs/core/Observation.d.ts.map +1 -1
  11. package/dist/cjs/core/Observation.js +3 -2
  12. package/dist/cjs/core/Observation.js.map +1 -1
  13. package/dist/cjs/core/Route.d.ts.map +1 -1
  14. package/dist/cjs/core/Route.js +3 -4
  15. package/dist/cjs/core/Route.js.map +1 -1
  16. package/dist/cjs/core/State.d.ts +1 -1
  17. package/dist/cjs/core/State.d.ts.map +1 -1
  18. package/dist/cjs/core/State.js +4 -3
  19. package/dist/cjs/core/State.js.map +1 -1
  20. package/dist/cjs/core/Tool.d.ts +1 -0
  21. package/dist/cjs/core/Tool.d.ts.map +1 -1
  22. package/dist/cjs/core/Tool.js +3 -2
  23. package/dist/cjs/core/Tool.js.map +1 -1
  24. package/dist/cjs/index.d.ts +2 -1
  25. package/dist/cjs/index.d.ts.map +1 -1
  26. package/dist/cjs/index.js +7 -1
  27. package/dist/cjs/index.js.map +1 -1
  28. package/dist/cjs/types/agent.d.ts +26 -2
  29. package/dist/cjs/types/agent.d.ts.map +1 -1
  30. package/dist/cjs/types/observation.d.ts +2 -0
  31. package/dist/cjs/types/observation.d.ts.map +1 -1
  32. package/dist/cjs/types/route.d.ts +2 -0
  33. package/dist/cjs/types/route.d.ts.map +1 -1
  34. package/dist/cjs/types/tool.d.ts +6 -2
  35. package/dist/cjs/types/tool.d.ts.map +1 -1
  36. package/dist/cjs/utils/id.d.ts +25 -0
  37. package/dist/cjs/utils/id.d.ts.map +1 -0
  38. package/dist/cjs/utils/id.js +71 -0
  39. package/dist/cjs/utils/id.js.map +1 -0
  40. package/dist/core/Agent.d.ts +11 -0
  41. package/dist/core/Agent.d.ts.map +1 -1
  42. package/dist/core/Agent.js +44 -2
  43. package/dist/core/Agent.js.map +1 -1
  44. package/dist/core/Events.d.ts +2 -2
  45. package/dist/core/Events.d.ts.map +1 -1
  46. package/dist/core/Events.js +4 -4
  47. package/dist/core/Events.js.map +1 -1
  48. package/dist/core/Observation.d.ts.map +1 -1
  49. package/dist/core/Observation.js +3 -2
  50. package/dist/core/Observation.js.map +1 -1
  51. package/dist/core/Route.d.ts.map +1 -1
  52. package/dist/core/Route.js +3 -4
  53. package/dist/core/Route.js.map +1 -1
  54. package/dist/core/State.d.ts +1 -1
  55. package/dist/core/State.d.ts.map +1 -1
  56. package/dist/core/State.js +4 -3
  57. package/dist/core/State.js.map +1 -1
  58. package/dist/core/Tool.d.ts +1 -0
  59. package/dist/core/Tool.d.ts.map +1 -1
  60. package/dist/core/Tool.js +3 -2
  61. package/dist/core/Tool.js.map +1 -1
  62. package/dist/index.d.ts +2 -1
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +2 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/types/agent.d.ts +26 -2
  67. package/dist/types/agent.d.ts.map +1 -1
  68. package/dist/types/observation.d.ts +2 -0
  69. package/dist/types/observation.d.ts.map +1 -1
  70. package/dist/types/route.d.ts +2 -0
  71. package/dist/types/route.d.ts.map +1 -1
  72. package/dist/types/tool.d.ts +6 -2
  73. package/dist/types/tool.d.ts.map +1 -1
  74. package/dist/utils/id.d.ts +25 -0
  75. package/dist/utils/id.d.ts.map +1 -0
  76. package/dist/utils/id.js +65 -0
  77. package/dist/utils/id.js.map +1 -0
  78. package/docs/API_REFERENCE.md +122 -6
  79. package/docs/CONSTRUCTOR_OPTIONS.md +43 -36
  80. package/docs/CONTEXT_MANAGEMENT.md +447 -0
  81. package/docs/GETTING_STARTED.md +2 -0
  82. package/docs/PROVIDERS.md +3 -0
  83. package/examples/declarative-agent.ts +31 -7
  84. package/examples/persistent-onboarding.ts +464 -0
  85. package/package.json +1 -1
  86. package/src/core/Agent.ts +56 -2
  87. package/src/core/Events.ts +6 -4
  88. package/src/core/Observation.ts +3 -3
  89. package/src/core/Route.ts +3 -5
  90. package/src/core/State.ts +5 -4
  91. package/src/core/Tool.ts +4 -3
  92. package/src/index.ts +10 -0
  93. package/src/types/agent.ts +36 -2
  94. package/src/types/observation.ts +2 -0
  95. package/src/types/route.ts +2 -0
  96. package/src/types/tool.ts +6 -2
  97. package/src/utils/id.ts +74 -0
@@ -8,8 +8,7 @@ import type {
8
8
  } from "../types/observation";
9
9
  import type { RouteRef } from "../types/route";
10
10
  import type { Route } from "./Route";
11
-
12
- let observationIdCounter = 0;
11
+ import { generateObservationId } from "../utils/id";
13
12
 
14
13
  /**
15
14
  * An observation that can trigger disambiguation between routes
@@ -20,7 +19,8 @@ export class Observation implements IObservation {
20
19
  public routes: RouteRef[] = [];
21
20
 
22
21
  constructor(options: ObservationOptions) {
23
- this.id = `observation_${++observationIdCounter}`;
22
+ // Use provided ID or generate a deterministic one from the description
23
+ this.id = options.id || generateObservationId(options.description);
24
24
  this.description = options.description;
25
25
  }
26
26
 
package/src/core/Route.ts CHANGED
@@ -6,8 +6,7 @@ import type { RouteOptions, RouteRef } from "../types/route";
6
6
  import type { Guideline } from "../types/agent";
7
7
 
8
8
  import { State } from "./State";
9
-
10
- let routeIdCounter = 0;
9
+ import { generateRouteId } from "../utils/id";
11
10
 
12
11
  /**
13
12
  * Represents a conversational route/journey
@@ -21,9 +20,8 @@ export class Route<TContext = unknown> {
21
20
  private guidelines: Guideline[] = [];
22
21
 
23
22
  constructor(options: RouteOptions) {
24
- this.id = `route_${++routeIdCounter}_${options.title
25
- .toLowerCase()
26
- .replace(/\s+/g, "_")}`;
23
+ // Use provided ID or generate a deterministic one from the title
24
+ this.id = options.id || generateRouteId(options.title);
27
25
  this.title = options.title;
28
26
  this.description = options.description;
29
27
  this.conditions = options.conditions || [];
package/src/core/State.ts CHANGED
@@ -11,8 +11,7 @@ import type { Guideline } from "../types/agent";
11
11
 
12
12
  import { END_ROUTE } from "../constants";
13
13
  import { Transition } from "./Transition";
14
-
15
- let stateIdCounter = 0;
14
+ import { generateStateId } from "../utils/id";
16
15
 
17
16
  /**
18
17
  * Represents a state within a route
@@ -24,9 +23,11 @@ export class State<TContext = unknown> {
24
23
 
25
24
  constructor(
26
25
  public readonly routeId: string,
27
- public readonly description?: string
26
+ public readonly description?: string,
27
+ customId?: string
28
28
  ) {
29
- this.id = `state_${++stateIdCounter}`;
29
+ // Use provided ID or generate a deterministic one
30
+ this.id = customId || generateStateId(routeId, description);
30
31
  }
31
32
 
32
33
  /**
package/src/core/Tool.ts CHANGED
@@ -8,8 +8,7 @@ import type {
8
8
  ToolRef,
9
9
  ToolResult,
10
10
  } from "../types/tool";
11
-
12
- let toolIdCounter = 0;
11
+ import { generateToolId } from "../utils/id";
13
12
 
14
13
  /**
15
14
  * Define a new tool with type-safe context and arguments
@@ -33,11 +32,13 @@ export function defineTool<TContext, TArgs extends unknown[], TResult>(
33
32
  name: string,
34
33
  handler: ToolHandler<TContext, TArgs, TResult>,
35
34
  options?: {
35
+ id?: string;
36
36
  description?: string;
37
37
  parameters?: unknown;
38
38
  }
39
39
  ): ToolRef<TContext, TArgs, TResult> {
40
- const id = `tool_${++toolIdCounter}_${name}`;
40
+ // Use provided ID or generate a deterministic one from the name
41
+ const id = options?.id || generateToolId(name);
41
42
 
42
43
  return {
43
44
  id,
package/src/index.ts CHANGED
@@ -28,6 +28,14 @@ export type { OpenRouterProviderOptions } from "./providers/OpenRouterProvider";
28
28
  // Constants
29
29
  export { END_ROUTE } from "./constants";
30
30
 
31
+ // Utils
32
+ export {
33
+ generateRouteId,
34
+ generateStateId,
35
+ generateObservationId,
36
+ generateToolId,
37
+ } from "./utils/id";
38
+
31
39
  // Types
32
40
  export type {
33
41
  AgentOptions,
@@ -35,6 +43,8 @@ export type {
35
43
  Guideline,
36
44
  Capability,
37
45
  GuidelineMatch,
46
+ ContextLifecycleHooks,
47
+ ContextProvider,
38
48
  } from "./types/agent";
39
49
  export { CompositionMode } from "./types/agent";
40
50
 
@@ -25,6 +25,34 @@ export enum CompositionMode {
25
25
  */
26
26
  import type { ObservationOptions } from "./observation";
27
27
 
28
+ /**
29
+ * Context lifecycle hooks for managing state persistence
30
+ */
31
+ export interface ContextLifecycleHooks<TContext = unknown> {
32
+ /**
33
+ * Called before respond() to get fresh context
34
+ * Useful for loading context from a database or cache
35
+ */
36
+ beforeRespond?: (currentContext: TContext) => Promise<TContext> | TContext;
37
+
38
+ /**
39
+ * Called after context is updated via updateContext() or tool execution
40
+ * Useful for persisting context to a database or cache
41
+ */
42
+ onContextUpdate?: (
43
+ newContext: TContext,
44
+ previousContext: TContext
45
+ ) => Promise<void> | void;
46
+ }
47
+
48
+ /**
49
+ * Context provider function for always-fresh context
50
+ * Alternative to static context, useful for loading from external sources
51
+ */
52
+ export type ContextProvider<TContext = unknown> = () =>
53
+ | Promise<TContext>
54
+ | TContext;
55
+
28
56
  /**
29
57
  * Options for creating an Agent
30
58
  */
@@ -37,6 +65,10 @@ export interface AgentOptions<TContext = unknown> {
37
65
  goal?: string;
38
66
  /** Default context data available to the agent */
39
67
  context?: TContext;
68
+ /** Context provider function for always-fresh context (alternative to static context) */
69
+ contextProvider?: ContextProvider<TContext>;
70
+ /** Lifecycle hooks for context management */
71
+ hooks?: ContextLifecycleHooks<TContext>;
40
72
  /** AI provider strategy for generating responses */
41
73
  ai: AiProvider;
42
74
  /** Maximum number of processing iterations per request */
@@ -82,7 +114,8 @@ export interface Guideline {
82
114
  /** Tags for organizing and filtering guidelines */
83
115
  tags?: string[];
84
116
  /** Tools available when following this guideline */
85
- tools?: ToolRef<unknown, unknown[], unknown>[];
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ tools?: ToolRef<any, any[], any>[];
86
119
  /** Additional metadata */
87
120
  metadata?: Record<string, unknown>;
88
121
  }
@@ -98,7 +131,8 @@ export interface Capability {
98
131
  /** Description of what the capability does */
99
132
  description: string;
100
133
  /** Tools used by this capability */
101
- tools?: ToolRef<unknown, unknown[], unknown>[];
134
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
135
+ tools?: ToolRef<any, any[], any>[];
102
136
  }
103
137
 
104
138
  /**
@@ -20,6 +20,8 @@ export interface Observation {
20
20
  * Options for creating an observation
21
21
  */
22
22
  export interface ObservationOptions {
23
+ /** Custom ID for the observation (optional - will generate deterministic ID from description if not provided) */
24
+ id?: string;
23
25
  /** The observation description */
24
26
  description: string;
25
27
  /** Route IDs or titles to disambiguate between (can be set later with disambiguate()) */
@@ -31,6 +31,8 @@ import type { Guideline } from "./agent";
31
31
  * Options for creating a route
32
32
  */
33
33
  export interface RouteOptions {
34
+ /** Custom ID for the route (optional - will generate deterministic ID from title if not provided) */
35
+ id?: string;
34
36
  /** Title of the route */
35
37
  title: string;
36
38
  /** Description of what this route accomplishes */
package/src/types/tool.ts CHANGED
@@ -10,6 +10,8 @@ import type { Event, StateRef } from "./index";
10
10
  export interface ToolContext<TContext = unknown> {
11
11
  /** The agent's context data */
12
12
  context: TContext;
13
+ /** Update the agent's context (triggers lifecycle hooks if configured) */
14
+ updateContext: (updates: Partial<TContext>) => Promise<void>;
13
15
  /** Current state reference (if in a route) */
14
16
  state?: StateRef;
15
17
  /** Interaction history */
@@ -21,9 +23,11 @@ export interface ToolContext<TContext = unknown> {
21
23
  /**
22
24
  * Result returned by a tool
23
25
  */
24
- export interface ToolResult<TData = unknown> {
26
+ export interface ToolResult<TData = unknown, TContext = unknown> {
25
27
  /** The result data */
26
28
  data: TData;
29
+ /** Optional context update to be merged with current context */
30
+ contextUpdate?: Partial<TContext>;
27
31
  /** Optional metadata about the execution */
28
32
  meta?: Record<string, unknown>;
29
33
  }
@@ -34,7 +38,7 @@ export interface ToolResult<TData = unknown> {
34
38
  export type ToolHandler<TContext, TArgs extends unknown[], TResult> = (
35
39
  context: ToolContext<TContext>,
36
40
  ...args: TArgs
37
- ) => Promise<ToolResult<TResult>> | ToolResult<TResult>;
41
+ ) => Promise<ToolResult<TResult, TContext>> | ToolResult<TResult, TContext>;
38
42
 
39
43
  /**
40
44
  * Reference to a defined tool
@@ -0,0 +1,74 @@
1
+ /**
2
+ * ID generation utilities
3
+ * Provides deterministic ID generation to ensure consistency across server restarts
4
+ */
5
+
6
+ /**
7
+ * Generate a deterministic ID from a string by creating a simple hash
8
+ * This ensures the same input always produces the same ID
9
+ */
10
+ function simpleHash(str: string): string {
11
+ let hash = 0;
12
+ for (let i = 0; i < str.length; i++) {
13
+ const char = str.charCodeAt(i);
14
+ hash = (hash << 5) - hash + char;
15
+ hash = hash & hash; // Convert to 32-bit integer
16
+ }
17
+ return Math.abs(hash).toString(36);
18
+ }
19
+
20
+ /**
21
+ * Sanitize a string for use in an ID
22
+ */
23
+ function sanitize(str: string): string {
24
+ return str.toLowerCase().replace(/[^a-z0-9]+/g, "_");
25
+ }
26
+
27
+ /**
28
+ * Generate a deterministic route ID
29
+ * Format: route_{sanitized_title}_{hash}
30
+ */
31
+ export function generateRouteId(title: string): string {
32
+ const sanitized = sanitize(title);
33
+ const hash = simpleHash(title);
34
+ return `route_${sanitized}_${hash}`;
35
+ }
36
+
37
+ /**
38
+ * Generate a deterministic state ID
39
+ * Format: state_{sanitized_description}_{hash} or state_{routeId}_{index}
40
+ */
41
+ export function generateStateId(
42
+ routeId: string,
43
+ description?: string,
44
+ index?: number
45
+ ): string {
46
+ if (description) {
47
+ const sanitized = sanitize(description);
48
+ const hash = simpleHash(`${routeId}_${description}`);
49
+ return `state_${sanitized}_${hash}`;
50
+ }
51
+ // Fallback for states without descriptions
52
+ const suffix = index !== undefined ? index : simpleHash(routeId);
53
+ return `state_${routeId}_${suffix}`;
54
+ }
55
+
56
+ /**
57
+ * Generate a deterministic observation ID
58
+ * Format: observation_{sanitized_description}_{hash}
59
+ */
60
+ export function generateObservationId(description: string): string {
61
+ const sanitized = sanitize(description.substring(0, 50)); // Limit length
62
+ const hash = simpleHash(description);
63
+ return `observation_${sanitized}_${hash}`;
64
+ }
65
+
66
+ /**
67
+ * Generate a deterministic tool ID
68
+ * Format: tool_{sanitized_name}_{hash}
69
+ */
70
+ export function generateToolId(name: string): string {
71
+ const sanitized = sanitize(name);
72
+ const hash = simpleHash(name);
73
+ return `tool_${sanitized}_${hash}`;
74
+ }