@falai/agent 0.1.3 → 0.1.5
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/README.md +56 -1
- package/dist/cjs/constants/index.d.ts +5 -0
- package/dist/cjs/constants/index.d.ts.map +1 -0
- package/dist/cjs/constants/index.js +8 -0
- package/dist/cjs/constants/index.js.map +1 -0
- package/dist/cjs/core/Agent.d.ts +110 -0
- package/dist/cjs/core/Agent.d.ts.map +1 -0
- package/dist/cjs/core/Agent.js +290 -0
- package/dist/cjs/core/Agent.js.map +1 -0
- package/dist/cjs/core/DomainRegistry.d.ts +26 -0
- package/dist/cjs/core/DomainRegistry.d.ts.map +1 -0
- package/dist/cjs/core/DomainRegistry.js +47 -0
- package/dist/cjs/core/DomainRegistry.js.map +1 -0
- package/dist/cjs/core/Events.d.ts +19 -0
- package/dist/cjs/core/Events.d.ts.map +1 -0
- package/dist/cjs/core/Events.js +84 -0
- package/dist/cjs/core/Events.js.map +1 -0
- package/dist/cjs/core/Observation.d.ts +24 -0
- package/dist/cjs/core/Observation.d.ts.map +1 -0
- package/dist/cjs/core/Observation.js +39 -0
- package/dist/cjs/core/Observation.js.map +1 -0
- package/dist/cjs/core/PromptBuilder.d.ts +125 -0
- package/dist/cjs/core/PromptBuilder.d.ts.map +1 -0
- package/dist/cjs/core/PromptBuilder.js +374 -0
- package/dist/cjs/core/PromptBuilder.js.map +1 -0
- package/dist/cjs/core/Route.d.ts +46 -0
- package/dist/cjs/core/Route.d.ts.map +1 -0
- package/dist/cjs/core/Route.js +111 -0
- package/dist/cjs/core/Route.js.map +1 -0
- package/dist/cjs/core/State.d.ts +50 -0
- package/dist/cjs/core/State.d.ts.map +1 -0
- package/dist/cjs/core/State.js +112 -0
- package/dist/cjs/core/State.js.map +1 -0
- package/dist/cjs/core/Tool.d.ts +32 -0
- package/dist/cjs/core/Tool.d.ts.map +1 -0
- package/dist/cjs/core/Tool.js +37 -0
- package/dist/cjs/core/Tool.js.map +1 -0
- package/dist/cjs/core/Transition.d.ts +32 -0
- package/dist/cjs/core/Transition.d.ts.map +1 -0
- package/dist/cjs/core/Transition.js +59 -0
- package/dist/cjs/core/Transition.js.map +1 -0
- package/dist/cjs/index.d.ts +35 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +55 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/providers/GeminiProvider.d.ts +40 -0
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -0
- package/dist/cjs/providers/GeminiProvider.js +142 -0
- package/dist/cjs/providers/GeminiProvider.js.map +1 -0
- package/dist/cjs/providers/OpenAIProvider.d.ts +42 -0
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -0
- package/dist/cjs/providers/OpenAIProvider.js +242 -0
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -0
- package/dist/cjs/providers/OpenRouterProvider.d.ts +46 -0
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -0
- package/dist/cjs/providers/OpenRouterProvider.js +249 -0
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -0
- package/dist/cjs/types/agent.d.ts +105 -0
- package/dist/cjs/types/agent.d.ts.map +1 -0
- package/dist/cjs/types/agent.js +21 -0
- package/dist/cjs/types/agent.js.map +1 -0
- package/dist/cjs/types/ai.d.ts +102 -0
- package/dist/cjs/types/ai.d.ts.map +1 -0
- package/dist/cjs/types/ai.js +6 -0
- package/dist/cjs/types/ai.js.map +1 -0
- package/dist/cjs/types/history.d.ts +112 -0
- package/dist/cjs/types/history.d.ts.map +1 -0
- package/dist/cjs/types/history.js +37 -0
- package/dist/cjs/types/history.js.map +1 -0
- package/dist/cjs/types/index.d.ts +14 -0
- package/dist/cjs/types/index.d.ts.map +1 -0
- package/dist/cjs/types/index.js +14 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/types/observation.d.ts +27 -0
- package/dist/cjs/types/observation.d.ts.map +1 -0
- package/dist/cjs/types/observation.js +6 -0
- package/dist/cjs/types/observation.js.map +1 -0
- package/dist/cjs/types/prompt.d.ts +46 -0
- package/dist/cjs/types/prompt.d.ts.map +1 -0
- package/dist/cjs/types/prompt.js +19 -0
- package/dist/cjs/types/prompt.js.map +1 -0
- package/dist/cjs/types/route.d.ts +61 -0
- package/dist/cjs/types/route.d.ts.map +1 -0
- package/dist/cjs/types/route.js +6 -0
- package/dist/cjs/types/route.js.map +1 -0
- package/dist/cjs/types/tool.d.ts +46 -0
- package/dist/cjs/types/tool.d.ts.map +1 -0
- package/dist/cjs/types/tool.js +6 -0
- package/dist/cjs/types/tool.js.map +1 -0
- package/dist/cjs/utils/id.d.ts +25 -0
- package/dist/cjs/utils/id.d.ts.map +1 -0
- package/dist/cjs/utils/id.js +71 -0
- package/dist/cjs/utils/id.js.map +1 -0
- package/dist/cjs/utils/retry.d.ts +13 -0
- package/dist/cjs/utils/retry.d.ts.map +1 -0
- package/dist/cjs/utils/retry.js +75 -0
- package/dist/cjs/utils/retry.js.map +1 -0
- package/dist/core/Agent.js +10 -11
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/DomainRegistry.js +3 -1
- package/dist/core/DomainRegistry.js.map +1 -1
- package/dist/core/Events.d.ts +2 -2
- package/dist/core/Events.d.ts.map +1 -1
- package/dist/core/Events.js +4 -4
- package/dist/core/Events.js.map +1 -1
- package/dist/core/Observation.d.ts.map +1 -1
- package/dist/core/Observation.js +4 -5
- package/dist/core/Observation.js.map +1 -1
- package/dist/core/PromptBuilder.js +2 -3
- package/dist/core/PromptBuilder.js.map +1 -1
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +4 -10
- package/dist/core/Route.js.map +1 -1
- package/dist/core/State.d.ts +1 -1
- package/dist/core/State.d.ts.map +1 -1
- package/dist/core/State.js +6 -8
- package/dist/core/State.js.map +1 -1
- package/dist/core/Tool.d.ts +1 -0
- package/dist/core/Tool.d.ts.map +1 -1
- package/dist/core/Tool.js +3 -2
- package/dist/core/Tool.js.map +1 -1
- package/dist/core/Transition.js +0 -4
- package/dist/core/Transition.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/GeminiProvider.js +1 -6
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.js +1 -6
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.js +1 -6
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/types/agent.d.ts +2 -2
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/observation.d.ts +2 -0
- package/dist/types/observation.d.ts.map +1 -1
- package/dist/types/route.d.ts +2 -0
- package/dist/types/route.d.ts.map +1 -1
- package/dist/utils/id.d.ts +25 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +65 -0
- package/dist/utils/id.js.map +1 -0
- package/docs/API_REFERENCE.md +122 -6
- package/docs/CONSTRUCTOR_OPTIONS.md +43 -36
- package/docs/GETTING_STARTED.md +2 -0
- package/docs/PROVIDERS.md +3 -0
- package/examples/declarative-agent.ts +31 -7
- package/package.json +15 -5
- package/src/core/Events.ts +6 -4
- package/src/core/Observation.ts +3 -3
- package/src/core/Route.ts +3 -5
- package/src/core/State.ts +5 -4
- package/src/core/Tool.ts +4 -3
- package/src/index.ts +8 -0
- package/src/types/agent.ts +4 -2
- package/src/types/observation.ts +2 -0
- package/src/types/route.ts +2 -0
- package/src/utils/id.ts +74 -0
package/dist/utils/id.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID generation utilities
|
|
3
|
+
* Provides deterministic ID generation to ensure consistency across server restarts
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generate a deterministic ID from a string by creating a simple hash
|
|
7
|
+
* This ensures the same input always produces the same ID
|
|
8
|
+
*/
|
|
9
|
+
function simpleHash(str) {
|
|
10
|
+
let hash = 0;
|
|
11
|
+
for (let i = 0; i < str.length; i++) {
|
|
12
|
+
const char = str.charCodeAt(i);
|
|
13
|
+
hash = (hash << 5) - hash + char;
|
|
14
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
15
|
+
}
|
|
16
|
+
return Math.abs(hash).toString(36);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sanitize a string for use in an ID
|
|
20
|
+
*/
|
|
21
|
+
function sanitize(str) {
|
|
22
|
+
return str.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generate a deterministic route ID
|
|
26
|
+
* Format: route_{sanitized_title}_{hash}
|
|
27
|
+
*/
|
|
28
|
+
export function generateRouteId(title) {
|
|
29
|
+
const sanitized = sanitize(title);
|
|
30
|
+
const hash = simpleHash(title);
|
|
31
|
+
return `route_${sanitized}_${hash}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate a deterministic state ID
|
|
35
|
+
* Format: state_{sanitized_description}_{hash} or state_{routeId}_{index}
|
|
36
|
+
*/
|
|
37
|
+
export function generateStateId(routeId, description, index) {
|
|
38
|
+
if (description) {
|
|
39
|
+
const sanitized = sanitize(description);
|
|
40
|
+
const hash = simpleHash(`${routeId}_${description}`);
|
|
41
|
+
return `state_${sanitized}_${hash}`;
|
|
42
|
+
}
|
|
43
|
+
// Fallback for states without descriptions
|
|
44
|
+
const suffix = index !== undefined ? index : simpleHash(routeId);
|
|
45
|
+
return `state_${routeId}_${suffix}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate a deterministic observation ID
|
|
49
|
+
* Format: observation_{sanitized_description}_{hash}
|
|
50
|
+
*/
|
|
51
|
+
export function generateObservationId(description) {
|
|
52
|
+
const sanitized = sanitize(description.substring(0, 50)); // Limit length
|
|
53
|
+
const hash = simpleHash(description);
|
|
54
|
+
return `observation_${sanitized}_${hash}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Generate a deterministic tool ID
|
|
58
|
+
* Format: tool_{sanitized_name}_{hash}
|
|
59
|
+
*/
|
|
60
|
+
export function generateToolId(name) {
|
|
61
|
+
const sanitized = sanitize(name);
|
|
62
|
+
const hash = simpleHash(name);
|
|
63
|
+
return `tool_${sanitized}_${hash}`;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;QACjC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,4BAA4B;IAClD,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/B,OAAO,SAAS,SAAS,IAAI,IAAI,EAAE,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,WAAoB,EACpB,KAAc;IAEd,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,OAAO,IAAI,WAAW,EAAE,CAAC,CAAC;QACrD,OAAO,SAAS,SAAS,IAAI,IAAI,EAAE,CAAC;IACtC,CAAC;IACD,2CAA2C;IAC3C,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACjE,OAAO,SAAS,OAAO,IAAI,MAAM,EAAE,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAmB;IACvD,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe;IACzE,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACrC,OAAO,eAAe,SAAS,IAAI,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,QAAQ,SAAS,IAAI,IAAI,EAAE,CAAC;AACrC,CAAC"}
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -129,8 +129,18 @@ Represents a conversation flow with states and transitions.
|
|
|
129
129
|
|
|
130
130
|
```typescript
|
|
131
131
|
new Route(options: RouteOptions)
|
|
132
|
+
|
|
133
|
+
interface RouteOptions {
|
|
134
|
+
id?: string; // Optional custom ID (deterministic ID generated from title if not provided)
|
|
135
|
+
title: string; // Route title
|
|
136
|
+
description?: string; // Route description
|
|
137
|
+
conditions?: string[]; // Conditions that activate this route
|
|
138
|
+
guidelines?: Guideline[]; // Initial guidelines for this route
|
|
139
|
+
}
|
|
132
140
|
```
|
|
133
141
|
|
|
142
|
+
**Note on IDs:** Route IDs are deterministic by default, generated from the title using a hash function. This ensures consistency across server restarts. You can provide a custom ID if you need specific control over the identifier.
|
|
143
|
+
|
|
134
144
|
#### Methods
|
|
135
145
|
|
|
136
146
|
##### `createGuideline(guideline: Guideline): this`
|
|
@@ -223,8 +233,16 @@ Handles disambiguation between multiple routes.
|
|
|
223
233
|
|
|
224
234
|
```typescript
|
|
225
235
|
new Observation(options: ObservationOptions)
|
|
236
|
+
|
|
237
|
+
interface ObservationOptions {
|
|
238
|
+
id?: string; // Optional custom ID (deterministic ID generated from description if not provided)
|
|
239
|
+
description: string; // The observation description
|
|
240
|
+
routeRefs?: string[]; // Route IDs or titles to disambiguate between
|
|
241
|
+
}
|
|
226
242
|
```
|
|
227
243
|
|
|
244
|
+
**Note on IDs:** Observation IDs are deterministic by default, generated from the description using a hash function. This ensures consistency across server restarts.
|
|
245
|
+
|
|
228
246
|
#### Methods
|
|
229
247
|
|
|
230
248
|
##### `disambiguate(routes: (Route | RouteRef)[]): this`
|
|
@@ -326,12 +344,15 @@ defineTool<TContext, TArgs extends unknown[], TReturn>(
|
|
|
326
344
|
name: string,
|
|
327
345
|
handler: ToolHandler<TContext, TArgs, TReturn>,
|
|
328
346
|
options?: {
|
|
347
|
+
id?: string; // Optional custom ID (deterministic ID generated from name if not provided)
|
|
329
348
|
description?: string;
|
|
330
|
-
|
|
349
|
+
parameters?: unknown;
|
|
331
350
|
}
|
|
332
351
|
): ToolRef<TContext, TArgs, TReturn>
|
|
333
352
|
```
|
|
334
353
|
|
|
354
|
+
**Note on IDs:** Tool IDs are deterministic by default, generated from the name using a hash function. This ensures consistency across server restarts.
|
|
355
|
+
|
|
335
356
|
**Example:**
|
|
336
357
|
|
|
337
358
|
```typescript
|
|
@@ -340,7 +361,10 @@ const getTool = defineTool<MyContext, [id: string], Data>(
|
|
|
340
361
|
async ({ context }, id) => {
|
|
341
362
|
return { data: await fetchData(id) };
|
|
342
363
|
},
|
|
343
|
-
{
|
|
364
|
+
{
|
|
365
|
+
id: "custom_get_data_tool", // Optional: provide your own ID
|
|
366
|
+
description: "Fetches data by ID",
|
|
367
|
+
}
|
|
344
368
|
);
|
|
345
369
|
```
|
|
346
370
|
|
|
@@ -353,11 +377,27 @@ Creates a message event for conversation history.
|
|
|
353
377
|
```typescript
|
|
354
378
|
createMessageEvent(
|
|
355
379
|
source: EventSource,
|
|
356
|
-
|
|
357
|
-
message: string
|
|
380
|
+
participantName: string,
|
|
381
|
+
message: string,
|
|
382
|
+
timestamp?: string // Optional: provide custom timestamp (ISO 8601 format)
|
|
358
383
|
): Event
|
|
359
384
|
```
|
|
360
385
|
|
|
386
|
+
**Example:**
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// With auto-generated timestamp
|
|
390
|
+
createMessageEvent(EventSource.CUSTOMER, "Alice", "Hello!");
|
|
391
|
+
|
|
392
|
+
// With custom timestamp (useful for historical data)
|
|
393
|
+
createMessageEvent(
|
|
394
|
+
EventSource.CUSTOMER,
|
|
395
|
+
"Alice",
|
|
396
|
+
"Hello!",
|
|
397
|
+
"2025-10-13T10:30:00Z"
|
|
398
|
+
);
|
|
399
|
+
```
|
|
400
|
+
|
|
361
401
|
---
|
|
362
402
|
|
|
363
403
|
### `createToolEvent()`
|
|
@@ -366,11 +406,28 @@ Creates a tool execution event.
|
|
|
366
406
|
|
|
367
407
|
```typescript
|
|
368
408
|
createToolEvent(
|
|
369
|
-
|
|
370
|
-
|
|
409
|
+
source: EventSource,
|
|
410
|
+
toolCalls: ToolCall[],
|
|
411
|
+
timestamp?: string // Optional: provide custom timestamp (ISO 8601 format)
|
|
371
412
|
): Event
|
|
372
413
|
```
|
|
373
414
|
|
|
415
|
+
**Example:**
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
// With auto-generated timestamp
|
|
419
|
+
createToolEvent(EventSource.AI_AGENT, [
|
|
420
|
+
{ tool_id: "get_data", arguments: { id: "123" }, result: { data: {...} } }
|
|
421
|
+
]);
|
|
422
|
+
|
|
423
|
+
// With custom timestamp
|
|
424
|
+
createToolEvent(
|
|
425
|
+
EventSource.AI_AGENT,
|
|
426
|
+
[{ tool_id: "get_data", arguments: { id: "123" }, result: { data: {...} } }],
|
|
427
|
+
"2025-10-13T10:30:00Z"
|
|
428
|
+
);
|
|
429
|
+
```
|
|
430
|
+
|
|
374
431
|
---
|
|
375
432
|
|
|
376
433
|
### `adaptEvent()`
|
|
@@ -501,6 +558,65 @@ This type represents the structured JSON output that AI providers return when us
|
|
|
501
558
|
|
|
502
559
|
---
|
|
503
560
|
|
|
561
|
+
### ID Generation Utilities
|
|
562
|
+
|
|
563
|
+
Generate deterministic IDs for consistency across server restarts.
|
|
564
|
+
|
|
565
|
+
#### `generateRouteId(title: string): string`
|
|
566
|
+
|
|
567
|
+
Generates a deterministic route ID from a title.
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
import { generateRouteId } from "@falai/agent";
|
|
571
|
+
|
|
572
|
+
const routeId = generateRouteId("User Onboarding");
|
|
573
|
+
// Returns: "route_user_onboarding_{hash}"
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### `generateStateId(routeId: string, description?: string, index?: number): string`
|
|
577
|
+
|
|
578
|
+
Generates a deterministic state ID.
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
import { generateStateId } from "@falai/agent";
|
|
582
|
+
|
|
583
|
+
const stateId = generateStateId("route_123", "Ask for name");
|
|
584
|
+
// Returns: "state_ask_for_name_{hash}"
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
#### `generateObservationId(description: string): string`
|
|
588
|
+
|
|
589
|
+
Generates a deterministic observation ID from a description.
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
import { generateObservationId } from "@falai/agent";
|
|
593
|
+
|
|
594
|
+
const obsId = generateObservationId("User intent is unclear");
|
|
595
|
+
// Returns: "observation_user_intent_is_unclear_{hash}"
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
#### `generateToolId(name: string): string`
|
|
599
|
+
|
|
600
|
+
Generates a deterministic tool ID from a name.
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
import { generateToolId } from "@falai/agent";
|
|
604
|
+
|
|
605
|
+
const toolId = generateToolId("get_user_data");
|
|
606
|
+
// Returns: "tool_get_user_data_{hash}"
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Why Deterministic IDs?**
|
|
610
|
+
|
|
611
|
+
All IDs are generated deterministically using a hash function of their content (title, name, description). This ensures:
|
|
612
|
+
|
|
613
|
+
- **Consistency** - Same input always produces the same ID
|
|
614
|
+
- **Server Restart Safe** - IDs remain stable across application restarts
|
|
615
|
+
- **Persistence Friendly** - Safe to store in databases and reference later
|
|
616
|
+
- **Custom Control** - You can always provide your own IDs when needed
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
504
620
|
## Constants
|
|
505
621
|
|
|
506
622
|
### `END_ROUTE`
|
|
@@ -18,16 +18,16 @@ interface AgentOptions<TContext = unknown> {
|
|
|
18
18
|
// Required
|
|
19
19
|
name: string;
|
|
20
20
|
ai: AiProvider;
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
// Optional metadata
|
|
23
23
|
description?: string;
|
|
24
24
|
goal?: string;
|
|
25
25
|
context?: TContext;
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
// Configuration
|
|
28
28
|
maxEngineIterations?: number;
|
|
29
29
|
compositionMode?: CompositionMode;
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
// Declarative initialization (NEW!)
|
|
32
32
|
terms?: Term[];
|
|
33
33
|
guidelines?: Guideline[];
|
|
@@ -44,43 +44,47 @@ const agent = new Agent({
|
|
|
44
44
|
name: "SupportBot",
|
|
45
45
|
description: "Helpful customer support",
|
|
46
46
|
goal: "Resolve issues efficiently",
|
|
47
|
-
ai: new GeminiProvider({ apiKey: "..." }),
|
|
47
|
+
ai: new GeminiProvider({ apiKey: "...", model: "..." }),
|
|
48
48
|
context: { userId: "123" },
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
terms: [
|
|
51
|
-
{
|
|
51
|
+
{
|
|
52
|
+
name: "SLA",
|
|
53
|
+
description: "Service Level Agreement",
|
|
54
|
+
synonyms: ["response time"],
|
|
55
|
+
},
|
|
52
56
|
],
|
|
53
|
-
|
|
57
|
+
|
|
54
58
|
guidelines: [
|
|
55
59
|
{
|
|
56
60
|
condition: "User is frustrated",
|
|
57
61
|
action: "Show empathy and offer escalation",
|
|
58
62
|
tags: ["support"],
|
|
59
|
-
enabled: true
|
|
60
|
-
}
|
|
63
|
+
enabled: true,
|
|
64
|
+
},
|
|
61
65
|
],
|
|
62
|
-
|
|
66
|
+
|
|
63
67
|
capabilities: [
|
|
64
|
-
{ title: "Ticket Management", description: "Create and track tickets" }
|
|
68
|
+
{ title: "Ticket Management", description: "Create and track tickets" },
|
|
65
69
|
],
|
|
66
|
-
|
|
70
|
+
|
|
67
71
|
routes: [
|
|
68
72
|
{
|
|
69
73
|
title: "Create Ticket",
|
|
70
74
|
description: "Help user create a support ticket",
|
|
71
75
|
conditions: ["User wants to report an issue"],
|
|
72
76
|
guidelines: [
|
|
73
|
-
{ condition: "Issue is urgent", action: "Prioritize immediately" }
|
|
74
|
-
]
|
|
75
|
-
}
|
|
77
|
+
{ condition: "Issue is urgent", action: "Prioritize immediately" },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
76
80
|
],
|
|
77
|
-
|
|
81
|
+
|
|
78
82
|
observations: [
|
|
79
83
|
{
|
|
80
84
|
description: "User mentions problem but unclear what kind",
|
|
81
|
-
routeRefs: ["Create Ticket", "Check Ticket Status"] // By title!
|
|
82
|
-
}
|
|
83
|
-
]
|
|
85
|
+
routeRefs: ["Create Ticket", "Check Ticket Status"], // By title!
|
|
86
|
+
},
|
|
87
|
+
],
|
|
84
88
|
});
|
|
85
89
|
```
|
|
86
90
|
|
|
@@ -92,7 +96,7 @@ const agent = new Agent({
|
|
|
92
96
|
interface RouteOptions {
|
|
93
97
|
// Required
|
|
94
98
|
title: string;
|
|
95
|
-
|
|
99
|
+
|
|
96
100
|
// Optional
|
|
97
101
|
description?: string;
|
|
98
102
|
conditions?: string[];
|
|
@@ -115,16 +119,16 @@ const agent = new Agent({
|
|
|
115
119
|
{
|
|
116
120
|
condition: "User skips a step",
|
|
117
121
|
action: "Gently remind them it's important",
|
|
118
|
-
tags: ["onboarding"]
|
|
122
|
+
tags: ["onboarding"],
|
|
119
123
|
},
|
|
120
124
|
{
|
|
121
125
|
condition: "User seems confused",
|
|
122
126
|
action: "Offer a quick tutorial video",
|
|
123
|
-
tags: ["help"]
|
|
124
|
-
}
|
|
125
|
-
]
|
|
126
|
-
}
|
|
127
|
-
]
|
|
127
|
+
tags: ["help"],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
],
|
|
128
132
|
});
|
|
129
133
|
```
|
|
130
134
|
|
|
@@ -187,18 +191,21 @@ obs.disambiguate([route1, route2]);
|
|
|
187
191
|
## 🎨 Best Practices
|
|
188
192
|
|
|
189
193
|
### Use Declarative When:
|
|
194
|
+
|
|
190
195
|
- ✅ Configuration is **static** and known upfront
|
|
191
196
|
- ✅ Loading config from **JSON/YAML files**
|
|
192
197
|
- ✅ Building **reusable agent templates**
|
|
193
198
|
- ✅ You want **clean, readable initialization**
|
|
194
199
|
|
|
195
200
|
### Use Fluent When:
|
|
201
|
+
|
|
196
202
|
- ✅ Logic is **dynamic** or **conditional**
|
|
197
203
|
- ✅ Building routes with **complex state machines**
|
|
198
204
|
- ✅ Adding features **based on runtime conditions**
|
|
199
205
|
- ✅ You prefer **step-by-step construction**
|
|
200
206
|
|
|
201
207
|
### Mix Both!
|
|
208
|
+
|
|
202
209
|
```typescript
|
|
203
210
|
// Start with static config
|
|
204
211
|
const agent = new Agent({
|
|
@@ -212,7 +219,7 @@ const agent = new Agent({
|
|
|
212
219
|
if (user.isPremium) {
|
|
213
220
|
agent.createGuideline({
|
|
214
221
|
condition: "User asks for priority support",
|
|
215
|
-
action: "Escalate immediately to premium team"
|
|
222
|
+
action: "Escalate immediately to premium team",
|
|
216
223
|
});
|
|
217
224
|
}
|
|
218
225
|
```
|
|
@@ -221,15 +228,15 @@ if (user.isPremium) {
|
|
|
221
228
|
|
|
222
229
|
## 📊 Complete Comparison
|
|
223
230
|
|
|
224
|
-
| Feature
|
|
225
|
-
|
|
226
|
-
| **Terms**
|
|
227
|
-
| **Guidelines**
|
|
228
|
-
| **Capabilities**
|
|
229
|
-
| **Routes**
|
|
230
|
-
| **Route Guidelines** | `route.guidelines: Guideline[]`
|
|
231
|
-
| **Observations**
|
|
232
|
-
| **Disambiguation**
|
|
231
|
+
| Feature | Declarative (Constructor) | Fluent (Methods) |
|
|
232
|
+
| -------------------- | ------------------------------------ | ------------------------------ |
|
|
233
|
+
| **Terms** | `terms: Term[]` | `agent.createTerm(...)` |
|
|
234
|
+
| **Guidelines** | `guidelines: Guideline[]` | `agent.createGuideline(...)` |
|
|
235
|
+
| **Capabilities** | `capabilities: Capability[]` | `agent.createCapability(...)` |
|
|
236
|
+
| **Routes** | `routes: RouteOptions[]` | `agent.createRoute(...)` |
|
|
237
|
+
| **Route Guidelines** | `route.guidelines: Guideline[]` | `route.createGuideline(...)` |
|
|
238
|
+
| **Observations** | `observations: ObservationOptions[]` | `agent.createObservation(...)` |
|
|
239
|
+
| **Disambiguation** | `routeRefs: string[]` | `obs.disambiguate([...])` |
|
|
233
240
|
|
|
234
241
|
---
|
|
235
242
|
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -58,6 +58,7 @@ interface MyContext {
|
|
|
58
58
|
// Create AI provider
|
|
59
59
|
const ai = new GeminiProvider({
|
|
60
60
|
apiKey: process.env.GEMINI_API_KEY!,
|
|
61
|
+
model: "models/gemini-2.5-pro",
|
|
61
62
|
});
|
|
62
63
|
|
|
63
64
|
// Create your agent
|
|
@@ -307,6 +308,7 @@ Increase timeout in provider config:
|
|
|
307
308
|
```typescript
|
|
308
309
|
new GeminiProvider({
|
|
309
310
|
apiKey: "...",
|
|
311
|
+
model: "models/gemini-2.5-flash",
|
|
310
312
|
retryConfig: {
|
|
311
313
|
timeout: 120000, // 2 minutes
|
|
312
314
|
retries: 5,
|
package/docs/PROVIDERS.md
CHANGED
|
@@ -281,6 +281,7 @@ const geminiAgent = new Agent({
|
|
|
281
281
|
name: "Gemini Assistant",
|
|
282
282
|
ai: new GeminiProvider({
|
|
283
283
|
apiKey: process.env.GEMINI_API_KEY!,
|
|
284
|
+
model: "models/gemini-2.5-flash",
|
|
284
285
|
}),
|
|
285
286
|
});
|
|
286
287
|
|
|
@@ -315,10 +316,12 @@ config();
|
|
|
315
316
|
|
|
316
317
|
const geminiProvider = new GeminiProvider({
|
|
317
318
|
apiKey: process.env.GEMINI_API_KEY!,
|
|
319
|
+
model: "models/gemini-2.5-flash",
|
|
318
320
|
});
|
|
319
321
|
|
|
320
322
|
const openaiProvider = new OpenAIProvider({
|
|
321
323
|
apiKey: process.env.OPENAI_API_KEY!,
|
|
324
|
+
model: "gpt-5",
|
|
322
325
|
});
|
|
323
326
|
```
|
|
324
327
|
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* - Terms (glossary)
|
|
7
7
|
* - Guidelines (behavior rules)
|
|
8
8
|
* - Capabilities
|
|
9
|
-
* - Routes with nested guidelines
|
|
10
|
-
* - Observations with route references
|
|
9
|
+
* - Routes with nested guidelines and custom IDs
|
|
10
|
+
* - Observations with route references and custom IDs
|
|
11
|
+
* - Custom timestamps for events
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import {
|
|
@@ -29,13 +30,16 @@ interface HealthcareContext {
|
|
|
29
30
|
patientName: string;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
// Define tools
|
|
33
|
+
// Define tools with custom IDs (optional - IDs are deterministic by default)
|
|
33
34
|
const getInsuranceProviders = defineTool<HealthcareContext, [], string[]>(
|
|
34
35
|
"get_insurance_providers",
|
|
35
36
|
async () => {
|
|
36
37
|
return { data: ["MegaCare Insurance", "HealthFirst", "WellnessPlus"] };
|
|
37
38
|
},
|
|
38
|
-
{
|
|
39
|
+
{
|
|
40
|
+
id: "healthcare_insurance_providers", // Custom ID for persistence
|
|
41
|
+
description: "Retrieves list of accepted insurance providers",
|
|
42
|
+
}
|
|
39
43
|
);
|
|
40
44
|
|
|
41
45
|
const getAvailableSlots = defineTool<
|
|
@@ -53,7 +57,10 @@ const getAvailableSlots = defineTool<
|
|
|
53
57
|
],
|
|
54
58
|
};
|
|
55
59
|
},
|
|
56
|
-
{
|
|
60
|
+
{
|
|
61
|
+
id: "healthcare_available_slots", // Custom ID
|
|
62
|
+
description: "Gets available appointment slots",
|
|
63
|
+
}
|
|
57
64
|
);
|
|
58
65
|
|
|
59
66
|
const getLabResults = defineTool<
|
|
@@ -70,7 +77,10 @@ const getLabResults = defineTool<
|
|
|
70
77
|
},
|
|
71
78
|
};
|
|
72
79
|
},
|
|
73
|
-
{
|
|
80
|
+
{
|
|
81
|
+
id: "healthcare_lab_results", // Custom ID
|
|
82
|
+
description: "Retrieves patient lab results",
|
|
83
|
+
}
|
|
74
84
|
);
|
|
75
85
|
|
|
76
86
|
// Declarative configuration
|
|
@@ -126,6 +136,7 @@ const capabilities: Capability[] = [
|
|
|
126
136
|
|
|
127
137
|
const routes: RouteOptions[] = [
|
|
128
138
|
{
|
|
139
|
+
id: "route_schedule_appointment", // Custom ID ensures consistency across restarts
|
|
129
140
|
title: "Schedule Appointment",
|
|
130
141
|
description: "Helps the patient schedule an appointment",
|
|
131
142
|
conditions: ["The patient wants to schedule an appointment"],
|
|
@@ -139,6 +150,7 @@ const routes: RouteOptions[] = [
|
|
|
139
150
|
],
|
|
140
151
|
},
|
|
141
152
|
{
|
|
153
|
+
id: "route_check_lab_results", // Custom ID
|
|
142
154
|
title: "Check Lab Results",
|
|
143
155
|
description: "Retrieves and explains patient lab results",
|
|
144
156
|
conditions: ["The patient wants to see their lab results"],
|
|
@@ -155,6 +167,7 @@ const routes: RouteOptions[] = [
|
|
|
155
167
|
|
|
156
168
|
const observations: ObservationOptions[] = [
|
|
157
169
|
{
|
|
170
|
+
id: "obs_visit_followup", // Custom ID for tracking
|
|
158
171
|
description:
|
|
159
172
|
"The patient asks to follow up on their visit, but it's not clear in which way",
|
|
160
173
|
routeRefs: ["Schedule Appointment", "Check Lab Results"], // Reference by title
|
|
@@ -172,6 +185,7 @@ const agent = new Agent<HealthcareContext>({
|
|
|
172
185
|
},
|
|
173
186
|
ai: new GeminiProvider({
|
|
174
187
|
apiKey: process.env.GEMINI_API_KEY || "demo-key",
|
|
188
|
+
model: "models/gemini-2.5-flash",
|
|
175
189
|
}),
|
|
176
190
|
// Declarative initialization
|
|
177
191
|
terms,
|
|
@@ -196,19 +210,29 @@ agent
|
|
|
196
210
|
|
|
197
211
|
// Example usage
|
|
198
212
|
async function main() {
|
|
213
|
+
// Create events with custom timestamps (useful for historical data)
|
|
199
214
|
const history = [
|
|
200
215
|
createMessageEvent(
|
|
201
216
|
EventSource.CUSTOMER,
|
|
202
217
|
"Alice",
|
|
203
|
-
"Hi, I need to follow up on my recent visit"
|
|
218
|
+
"Hi, I need to follow up on my recent visit",
|
|
219
|
+
"2025-10-13T14:30:00Z" // Optional custom timestamp
|
|
204
220
|
),
|
|
205
221
|
];
|
|
206
222
|
|
|
207
223
|
const response = await agent.respond({ history });
|
|
208
224
|
console.log("Agent:", response.message);
|
|
225
|
+
console.log("Route chosen:", response.route?.title);
|
|
226
|
+
console.log("Route ID:", response.route?.id); // Custom ID is preserved
|
|
209
227
|
|
|
210
228
|
// The agent will use the observation to disambiguate
|
|
211
229
|
// and ask which type of follow-up the patient needs
|
|
230
|
+
|
|
231
|
+
// Note: Custom IDs ensure consistency across server restarts
|
|
232
|
+
// This is crucial for:
|
|
233
|
+
// - Storing conversation state in databases
|
|
234
|
+
// - Tracking metrics and analytics
|
|
235
|
+
// - Referencing routes in external systems
|
|
212
236
|
}
|
|
213
237
|
|
|
214
238
|
// Uncomment to run:
|
package/package.json
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@falai/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Standalone, strongly-typed AI Agent framework with route DSL and AI provider strategy",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
|
-
"import":
|
|
11
|
-
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/cjs/index.d.ts",
|
|
17
|
+
"default": "./dist/cjs/index.js"
|
|
18
|
+
}
|
|
12
19
|
}
|
|
13
20
|
},
|
|
14
21
|
"files": [
|
|
@@ -31,7 +38,10 @@
|
|
|
31
38
|
},
|
|
32
39
|
"homepage": "https://github.com/gusnips/falai#readme",
|
|
33
40
|
"scripts": {
|
|
34
|
-
"build": "
|
|
41
|
+
"build": "npm run build:esm && npm run build:cjs && npm run fix:cjs",
|
|
42
|
+
"build:esm": "tsc",
|
|
43
|
+
"build:cjs": "tsc --project tsconfig.cjs.json",
|
|
44
|
+
"fix:cjs": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
|
|
35
45
|
"dev": "tsc --watch",
|
|
36
46
|
"typecheck": "tsc --noEmit",
|
|
37
47
|
"lint": "eslint src/**/*.ts",
|
package/src/core/Events.ts
CHANGED
|
@@ -70,7 +70,8 @@ export function adaptEvent(e: Event | EmittedEvent): string {
|
|
|
70
70
|
export function createMessageEvent(
|
|
71
71
|
source: EventSource,
|
|
72
72
|
participantName: string,
|
|
73
|
-
message: string
|
|
73
|
+
message: string,
|
|
74
|
+
timestamp?: string
|
|
74
75
|
): Event<MessageEventData> {
|
|
75
76
|
return {
|
|
76
77
|
kind: EventKind.MESSAGE,
|
|
@@ -79,7 +80,7 @@ export function createMessageEvent(
|
|
|
79
80
|
participant: { display_name: participantName },
|
|
80
81
|
message,
|
|
81
82
|
},
|
|
82
|
-
timestamp: new Date().toISOString(),
|
|
83
|
+
timestamp: timestamp || new Date().toISOString(),
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -88,7 +89,8 @@ export function createMessageEvent(
|
|
|
88
89
|
*/
|
|
89
90
|
export function createToolEvent(
|
|
90
91
|
source: EventSource,
|
|
91
|
-
toolCalls: ToolCall[]
|
|
92
|
+
toolCalls: ToolCall[],
|
|
93
|
+
timestamp?: string
|
|
92
94
|
): Event<ToolEventData> {
|
|
93
95
|
return {
|
|
94
96
|
kind: EventKind.TOOL,
|
|
@@ -96,6 +98,6 @@ export function createToolEvent(
|
|
|
96
98
|
data: {
|
|
97
99
|
tool_calls: toolCalls,
|
|
98
100
|
},
|
|
99
|
-
timestamp: new Date().toISOString(),
|
|
101
|
+
timestamp: timestamp || new Date().toISOString(),
|
|
100
102
|
};
|
|
101
103
|
}
|
package/src/core/Observation.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|