@falai/agent 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.
Files changed (129) hide show
  1. package/README.md +516 -0
  2. package/dist/constants/index.d.ts +5 -0
  3. package/dist/constants/index.d.ts.map +1 -0
  4. package/dist/constants/index.js +5 -0
  5. package/dist/constants/index.js.map +1 -0
  6. package/dist/core/Agent.d.ts +98 -0
  7. package/dist/core/Agent.d.ts.map +1 -0
  8. package/dist/core/Agent.js +248 -0
  9. package/dist/core/Agent.js.map +1 -0
  10. package/dist/core/DomainRegistry.d.ts +26 -0
  11. package/dist/core/DomainRegistry.d.ts.map +1 -0
  12. package/dist/core/DomainRegistry.js +41 -0
  13. package/dist/core/DomainRegistry.js.map +1 -0
  14. package/dist/core/Events.d.ts +19 -0
  15. package/dist/core/Events.d.ts.map +1 -0
  16. package/dist/core/Events.js +79 -0
  17. package/dist/core/Events.js.map +1 -0
  18. package/dist/core/Observation.d.ts +24 -0
  19. package/dist/core/Observation.d.ts.map +1 -0
  20. package/dist/core/Observation.js +35 -0
  21. package/dist/core/Observation.js.map +1 -0
  22. package/dist/core/PromptBuilder.d.ts +121 -0
  23. package/dist/core/PromptBuilder.d.ts.map +1 -0
  24. package/dist/core/PromptBuilder.js +339 -0
  25. package/dist/core/PromptBuilder.js.map +1 -0
  26. package/dist/core/Route.d.ts +46 -0
  27. package/dist/core/Route.d.ts.map +1 -0
  28. package/dist/core/Route.js +113 -0
  29. package/dist/core/Route.js.map +1 -0
  30. package/dist/core/State.d.ts +50 -0
  31. package/dist/core/State.d.ts.map +1 -0
  32. package/dist/core/State.js +110 -0
  33. package/dist/core/State.js.map +1 -0
  34. package/dist/core/Tool.d.ts +31 -0
  35. package/dist/core/Tool.d.ts.map +1 -0
  36. package/dist/core/Tool.js +33 -0
  37. package/dist/core/Tool.js.map +1 -0
  38. package/dist/core/Transition.d.ts +32 -0
  39. package/dist/core/Transition.d.ts.map +1 -0
  40. package/dist/core/Transition.js +59 -0
  41. package/dist/core/Transition.js.map +1 -0
  42. package/dist/index.d.ts +34 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +26 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/providers/GeminiProvider.d.ts +40 -0
  47. package/dist/providers/GeminiProvider.d.ts.map +1 -0
  48. package/dist/providers/GeminiProvider.js +126 -0
  49. package/dist/providers/GeminiProvider.js.map +1 -0
  50. package/dist/providers/OpenAIProvider.d.ts +42 -0
  51. package/dist/providers/OpenAIProvider.d.ts.map +1 -0
  52. package/dist/providers/OpenAIProvider.js +164 -0
  53. package/dist/providers/OpenAIProvider.js.map +1 -0
  54. package/dist/providers/OpenRouterProvider.d.ts +46 -0
  55. package/dist/providers/OpenRouterProvider.d.ts.map +1 -0
  56. package/dist/providers/OpenRouterProvider.js +171 -0
  57. package/dist/providers/OpenRouterProvider.js.map +1 -0
  58. package/dist/types/agent.d.ts +105 -0
  59. package/dist/types/agent.d.ts.map +1 -0
  60. package/dist/types/agent.js +18 -0
  61. package/dist/types/agent.js.map +1 -0
  62. package/dist/types/ai.d.ts +78 -0
  63. package/dist/types/ai.d.ts.map +1 -0
  64. package/dist/types/ai.js +5 -0
  65. package/dist/types/ai.js.map +1 -0
  66. package/dist/types/history.d.ts +112 -0
  67. package/dist/types/history.d.ts.map +1 -0
  68. package/dist/types/history.js +34 -0
  69. package/dist/types/history.js.map +1 -0
  70. package/dist/types/index.d.ts +14 -0
  71. package/dist/types/index.d.ts.map +1 -0
  72. package/dist/types/index.js +7 -0
  73. package/dist/types/index.js.map +1 -0
  74. package/dist/types/observation.d.ts +25 -0
  75. package/dist/types/observation.d.ts.map +1 -0
  76. package/dist/types/observation.js +5 -0
  77. package/dist/types/observation.js.map +1 -0
  78. package/dist/types/prompt.d.ts +46 -0
  79. package/dist/types/prompt.d.ts.map +1 -0
  80. package/dist/types/prompt.js +16 -0
  81. package/dist/types/prompt.js.map +1 -0
  82. package/dist/types/route.d.ts +59 -0
  83. package/dist/types/route.d.ts.map +1 -0
  84. package/dist/types/route.js +5 -0
  85. package/dist/types/route.js.map +1 -0
  86. package/dist/types/tool.d.ts +46 -0
  87. package/dist/types/tool.d.ts.map +1 -0
  88. package/dist/types/tool.js +5 -0
  89. package/dist/types/tool.js.map +1 -0
  90. package/dist/utils/retry.d.ts +13 -0
  91. package/dist/utils/retry.d.ts.map +1 -0
  92. package/dist/utils/retry.js +70 -0
  93. package/dist/utils/retry.js.map +1 -0
  94. package/docs/API_REFERENCE.md +517 -0
  95. package/docs/CONSTRUCTOR_OPTIONS.md +256 -0
  96. package/docs/CONTRIBUTING.md +481 -0
  97. package/docs/GETTING_STARTED.md +328 -0
  98. package/docs/PROVIDERS.md +472 -0
  99. package/docs/PUBLISHING.md +174 -0
  100. package/docs/README.md +68 -0
  101. package/docs/STRUCTURE.md +32 -0
  102. package/examples/declarative-agent.ts +217 -0
  103. package/examples/healthcare-agent.ts +283 -0
  104. package/examples/openai-agent.ts +167 -0
  105. package/examples/travel-agent.ts +342 -0
  106. package/package.json +73 -0
  107. package/src/constants/index.ts +5 -0
  108. package/src/core/Agent.ts +307 -0
  109. package/src/core/DomainRegistry.ts +50 -0
  110. package/src/core/Events.ts +101 -0
  111. package/src/core/Observation.ts +46 -0
  112. package/src/core/PromptBuilder.ts +511 -0
  113. package/src/core/Route.ts +136 -0
  114. package/src/core/State.ts +153 -0
  115. package/src/core/Tool.ts +54 -0
  116. package/src/core/Transition.ts +66 -0
  117. package/src/index.ts +83 -0
  118. package/src/providers/GeminiProvider.ts +220 -0
  119. package/src/providers/OpenAIProvider.ts +272 -0
  120. package/src/providers/OpenRouterProvider.ts +282 -0
  121. package/src/types/agent.ts +112 -0
  122. package/src/types/ai.ts +85 -0
  123. package/src/types/history.ts +125 -0
  124. package/src/types/index.ts +56 -0
  125. package/src/types/observation.ts +27 -0
  126. package/src/types/prompt.ts +49 -0
  127. package/src/types/route.ts +68 -0
  128. package/src/types/tool.ts +53 -0
  129. package/src/utils/retry.ts +96 -0
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Core Agent implementation
3
+ */
4
+
5
+ import type {
6
+ AgentOptions,
7
+ Term,
8
+ Guideline,
9
+ GuidelineMatch,
10
+ Capability,
11
+ } from "@/types/agent";
12
+ import type { Event, StateRef } from "@/types/index";
13
+ import type { RouteOptions } from "@/types/route";
14
+
15
+ import { Route } from "@/core/Route";
16
+ import { DomainRegistry } from "@/core/DomainRegistry";
17
+ import { PromptBuilder } from "@/core/PromptBuilder";
18
+ import { Observation } from "@/core/Observation";
19
+
20
+ /**
21
+ * Main Agent class with generic context support
22
+ */
23
+ export class Agent<TContext = unknown> {
24
+ private terms: Term[] = [];
25
+ private guidelines: Guideline[] = [];
26
+ private capabilities: Capability[] = [];
27
+ private routes: Route[] = [];
28
+ private observations: Observation[] = [];
29
+ private domainRegistry = new DomainRegistry();
30
+
31
+ /**
32
+ * Dynamic domain property - populated via addDomain
33
+ */
34
+ public readonly domain: Record<string, Record<string, unknown>> = {};
35
+
36
+ constructor(private readonly options: AgentOptions<TContext>) {
37
+ // Initialize with default values
38
+ if (!this.options.maxEngineIterations) {
39
+ this.options.maxEngineIterations = 1;
40
+ }
41
+
42
+ // Initialize from options
43
+ if (options.terms) {
44
+ this.terms = [...options.terms];
45
+ }
46
+
47
+ if (options.guidelines) {
48
+ options.guidelines.forEach((guideline) => {
49
+ this.createGuideline(guideline);
50
+ });
51
+ }
52
+
53
+ if (options.capabilities) {
54
+ options.capabilities.forEach((capability) => {
55
+ this.createCapability(capability);
56
+ });
57
+ }
58
+
59
+ if (options.routes) {
60
+ options.routes.forEach((routeOptions) => {
61
+ this.createRoute(routeOptions);
62
+ });
63
+ }
64
+
65
+ if (options.observations) {
66
+ options.observations.forEach((obsOptions) => {
67
+ const obs = this.createObservation(obsOptions.description);
68
+
69
+ // If route refs were provided, resolve and disambiguate
70
+ if (obsOptions.routeRefs && obsOptions.routeRefs.length > 0) {
71
+ const resolvedRoutes = obsOptions.routeRefs
72
+ .map((ref) => {
73
+ // Try to find route by ID or title
74
+ return this.routes.find((r) => r.id === ref || r.title === ref);
75
+ })
76
+ .filter((r): r is Route => r !== undefined);
77
+
78
+ if (resolvedRoutes.length > 0) {
79
+ obs.disambiguate(resolvedRoutes);
80
+ }
81
+ }
82
+ });
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Get agent name
88
+ */
89
+ get name(): string {
90
+ return this.options.name;
91
+ }
92
+
93
+ /**
94
+ * Get agent description
95
+ */
96
+ get description(): string | undefined {
97
+ return this.options.description;
98
+ }
99
+
100
+ /**
101
+ * Get agent goal
102
+ */
103
+ get goal(): string | undefined {
104
+ return this.options.goal;
105
+ }
106
+
107
+ /**
108
+ * Create a new route (journey)
109
+ */
110
+ createRoute(options: RouteOptions): Route {
111
+ const route = new Route(options);
112
+ this.routes.push(route);
113
+ return route;
114
+ }
115
+
116
+ /**
117
+ * Create a domain term for the glossary
118
+ */
119
+ createTerm(term: Term): this {
120
+ this.terms.push(term);
121
+ return this;
122
+ }
123
+
124
+ /**
125
+ * Create a behavioral guideline
126
+ */
127
+ createGuideline(guideline: Guideline): this {
128
+ const guidelineWithId = {
129
+ ...guideline,
130
+ id: guideline.id || `guideline_${this.guidelines.length}`,
131
+ enabled: guideline.enabled !== false, // Default to true
132
+ };
133
+ this.guidelines.push(guidelineWithId);
134
+ return this;
135
+ }
136
+
137
+ /**
138
+ * Add a capability
139
+ */
140
+ createCapability(capability: Capability): this {
141
+ const capabilityWithId = {
142
+ ...capability,
143
+ id: capability.id || `capability_${this.capabilities.length}`,
144
+ };
145
+ this.capabilities.push(capabilityWithId);
146
+ return this;
147
+ }
148
+
149
+ /**
150
+ * Create an observation for disambiguation
151
+ */
152
+ createObservation(description: string): Observation {
153
+ const observation = new Observation({ description });
154
+ this.observations.push(observation);
155
+ return observation;
156
+ }
157
+
158
+ /**
159
+ * Add a domain with its tools/methods
160
+ */
161
+ addDomain<TName extends string, TDomain extends Record<string, unknown>>(
162
+ name: TName,
163
+ domainObject: TDomain
164
+ ): void {
165
+ this.domainRegistry.register(name, domainObject);
166
+ // Attach to the domain property for easy access
167
+ this.domain[name] = domainObject;
168
+ }
169
+
170
+ /**
171
+ * Generate a response based on history and context
172
+ */
173
+ async respond(params: {
174
+ history: Event[];
175
+ state?: StateRef;
176
+ contextOverride?: Partial<TContext>;
177
+ signal?: AbortSignal;
178
+ }): Promise<{ message: string }> {
179
+ const { history, contextOverride, signal } = params;
180
+
181
+ // Merge context
182
+ const effectiveContext = {
183
+ ...(this.options.context as Record<string, unknown>),
184
+ ...(contextOverride as Record<string, unknown>),
185
+ } as TContext;
186
+
187
+ // Build prompt
188
+ const promptBuilder = new PromptBuilder();
189
+
190
+ // Add agent identity
191
+ if (this.options.description) {
192
+ promptBuilder.addAgentIdentity({
193
+ name: this.options.name,
194
+ description: this.options.description,
195
+ });
196
+ }
197
+
198
+ // Add interaction history
199
+ promptBuilder.addInteractionHistoryForMessageGeneration(history);
200
+
201
+ // Add glossary
202
+ if (this.terms.length > 0) {
203
+ promptBuilder.addGlossary(this.terms);
204
+ }
205
+
206
+ // Add guidelines (convert to GuidelineMatch format, filter enabled only)
207
+ const enabledGuidelines = this.guidelines.filter(
208
+ (g) => g.enabled !== false
209
+ );
210
+ if (enabledGuidelines.length > 0) {
211
+ const guidelineMatches: GuidelineMatch[] = enabledGuidelines.map((g) => ({
212
+ guideline: g,
213
+ }));
214
+ promptBuilder.addGuidelinesForMessageGeneration(guidelineMatches);
215
+ }
216
+
217
+ // Add capabilities
218
+ if (this.capabilities.length > 0) {
219
+ promptBuilder.addCapabilitiesForMessageGeneration(this.capabilities);
220
+ }
221
+
222
+ // Add observations
223
+ if (this.observations.length > 0) {
224
+ const observationsWithRoutes = this.observations
225
+ .map((obs) => ({
226
+ description: obs.description,
227
+ routes: obs.getRoutes().map((routeRef) => {
228
+ const route = this.routes.find((r) => r.id === routeRef.id);
229
+ return { title: route?.title || routeRef.id };
230
+ }),
231
+ }))
232
+ .filter((obs) => obs.routes.length > 0);
233
+
234
+ if (observationsWithRoutes.length > 0) {
235
+ promptBuilder.addObservations(observationsWithRoutes);
236
+ }
237
+ }
238
+
239
+ // Add active routes
240
+ if (this.routes.length > 0) {
241
+ promptBuilder.addActiveRoutes(
242
+ this.routes.map((r) => ({
243
+ title: r.title,
244
+ description: r.description,
245
+ conditions: r.conditions,
246
+ }))
247
+ );
248
+ }
249
+
250
+ // Build final prompt
251
+ const prompt = promptBuilder.build();
252
+
253
+ // Generate message using AI provider
254
+ const result = await this.options.ai.generateMessage({
255
+ prompt,
256
+ history,
257
+ context: effectiveContext,
258
+ signal,
259
+ });
260
+
261
+ return {
262
+ message: result.message,
263
+ };
264
+ }
265
+
266
+ /**
267
+ * Get all routes
268
+ */
269
+ getRoutes(): Route[] {
270
+ return [...this.routes];
271
+ }
272
+
273
+ /**
274
+ * Get all terms
275
+ */
276
+ getTerms(): Term[] {
277
+ return [...this.terms];
278
+ }
279
+
280
+ /**
281
+ * Get all guidelines
282
+ */
283
+ getGuidelines(): Guideline[] {
284
+ return [...this.guidelines];
285
+ }
286
+
287
+ /**
288
+ * Get all capabilities
289
+ */
290
+ getCapabilities(): Capability[] {
291
+ return [...this.capabilities];
292
+ }
293
+
294
+ /**
295
+ * Get all observations
296
+ */
297
+ getObservations(): Observation[] {
298
+ return [...this.observations];
299
+ }
300
+
301
+ /**
302
+ * Get the domain registry
303
+ */
304
+ getDomainRegistry(): DomainRegistry {
305
+ return this.domainRegistry;
306
+ }
307
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Domain registry for organizing agent capabilities by domain
3
+ */
4
+
5
+ /**
6
+ * Registry that holds domain-specific tools and methods
7
+ */
8
+ export class DomainRegistry {
9
+ private domains: Map<string, Record<string, unknown>> = new Map();
10
+
11
+ /**
12
+ * Register a new domain with its methods/tools
13
+ */
14
+ register<TDomain extends Record<string, unknown>>(
15
+ name: string,
16
+ domain: TDomain
17
+ ): void {
18
+ if (this.domains.has(name)) {
19
+ throw new Error(`Domain "${name}" is already registered`);
20
+ }
21
+ this.domains.set(name, domain);
22
+ }
23
+
24
+ /**
25
+ * Get a registered domain
26
+ */
27
+ get<TDomain extends Record<string, unknown>>(
28
+ name: string
29
+ ): TDomain | undefined {
30
+ return this.domains.get(name) as TDomain | undefined;
31
+ }
32
+
33
+ /**
34
+ * Check if a domain is registered
35
+ */
36
+ has(name: string): boolean {
37
+ return this.domains.has(name);
38
+ }
39
+
40
+ /**
41
+ * Get all registered domains as a single object
42
+ */
43
+ all(): Record<string, Record<string, unknown>> {
44
+ const result: Record<string, Record<string, unknown>> = {};
45
+ for (const [name, domain] of this.domains) {
46
+ result[name] = domain;
47
+ }
48
+ return result;
49
+ }
50
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Event utilities and helpers
3
+ */
4
+
5
+ import type {
6
+ Event,
7
+ EmittedEvent,
8
+ MessageEventData,
9
+ ToolEventData,
10
+ ToolCall,
11
+ } from "@/types/history";
12
+ import { EventKind, EventSource } from "@/types/history";
13
+
14
+ /**
15
+ * Adapt an event for inclusion in prompts
16
+ * Transforms event data into a serializable format
17
+ */
18
+ export function adaptEvent(e: Event | EmittedEvent): string {
19
+ let data: unknown = e.data;
20
+
21
+ if (e.kind === EventKind.MESSAGE) {
22
+ const messageData = e.data as MessageEventData;
23
+
24
+ if (messageData.flagged) {
25
+ data = {
26
+ participant: messageData.participant.display_name,
27
+ message: "<N/A>",
28
+ censored: true,
29
+ reasons: messageData.tags,
30
+ };
31
+ } else {
32
+ data = {
33
+ participant: messageData.participant.display_name,
34
+ message: messageData.message,
35
+ };
36
+ }
37
+ }
38
+
39
+ if (e.kind === EventKind.TOOL) {
40
+ const toolData = e.data as ToolEventData;
41
+
42
+ data = {
43
+ tool_calls: toolData.tool_calls.map((tc) => ({
44
+ tool_id: tc.tool_id,
45
+ arguments: tc.arguments,
46
+ result: tc.result.data,
47
+ })),
48
+ };
49
+ }
50
+
51
+ const sourceMap: Record<EventSource, string> = {
52
+ [EventSource.CUSTOMER]: "user",
53
+ [EventSource.CUSTOMER_UI]: "frontend_application",
54
+ [EventSource.HUMAN_AGENT]: "human_service_agent",
55
+ [EventSource.HUMAN_AGENT_ON_BEHALF_OF_AI_AGENT]: "ai_agent",
56
+ [EventSource.AI_AGENT]: "ai_agent",
57
+ [EventSource.SYSTEM]: "system-provided",
58
+ };
59
+
60
+ return JSON.stringify({
61
+ event_kind: e.kind,
62
+ event_source: sourceMap[e.source],
63
+ data,
64
+ });
65
+ }
66
+
67
+ /**
68
+ * Create a message event
69
+ */
70
+ export function createMessageEvent(
71
+ source: EventSource,
72
+ participantName: string,
73
+ message: string
74
+ ): Event<MessageEventData> {
75
+ return {
76
+ kind: EventKind.MESSAGE,
77
+ source,
78
+ data: {
79
+ participant: { display_name: participantName },
80
+ message,
81
+ },
82
+ timestamp: new Date().toISOString(),
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Create a tool event
88
+ */
89
+ export function createToolEvent(
90
+ source: EventSource,
91
+ toolCalls: ToolCall[]
92
+ ): Event<ToolEventData> {
93
+ return {
94
+ kind: EventKind.TOOL,
95
+ source,
96
+ data: {
97
+ tool_calls: toolCalls,
98
+ },
99
+ timestamp: new Date().toISOString(),
100
+ };
101
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Observation for route disambiguation
3
+ */
4
+
5
+ import type {
6
+ Observation as IObservation,
7
+ ObservationOptions,
8
+ } from "@/types/observation";
9
+ import type { RouteRef } from "@/types/route";
10
+ import type { Route } from "@/core/Route";
11
+
12
+ let observationIdCounter = 0;
13
+
14
+ /**
15
+ * An observation that can trigger disambiguation between routes
16
+ */
17
+ export class Observation implements IObservation {
18
+ public readonly id: string;
19
+ public readonly description: string;
20
+ public routes: RouteRef[] = [];
21
+
22
+ constructor(options: ObservationOptions) {
23
+ this.id = `observation_${++observationIdCounter}`;
24
+ this.description = options.description;
25
+ }
26
+
27
+ /**
28
+ * Set routes that this observation can disambiguate between
29
+ */
30
+ disambiguate(routes: (Route | RouteRef)[]): this {
31
+ this.routes = routes.map((r) => {
32
+ if ("getRef" in r) {
33
+ return r.getRef();
34
+ }
35
+ return r;
36
+ });
37
+ return this;
38
+ }
39
+
40
+ /**
41
+ * Get the routes this observation disambiguates
42
+ */
43
+ getRoutes(): RouteRef[] {
44
+ return [...this.routes];
45
+ }
46
+ }