@falai/agent 0.1.4 → 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/core/Events.d.ts +2 -2
- package/dist/cjs/core/Events.d.ts.map +1 -1
- package/dist/cjs/core/Events.js +4 -4
- package/dist/cjs/core/Events.js.map +1 -1
- package/dist/cjs/core/Observation.d.ts.map +1 -1
- package/dist/cjs/core/Observation.js +3 -2
- package/dist/cjs/core/Observation.js.map +1 -1
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +3 -4
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/State.d.ts +1 -1
- package/dist/cjs/core/State.d.ts.map +1 -1
- package/dist/cjs/core/State.js +4 -3
- package/dist/cjs/core/State.js.map +1 -1
- package/dist/cjs/core/Tool.d.ts +1 -0
- package/dist/cjs/core/Tool.d.ts.map +1 -1
- package/dist/cjs/core/Tool.js +3 -2
- package/dist/cjs/core/Tool.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +2 -2
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/observation.d.ts +2 -0
- package/dist/cjs/types/observation.d.ts.map +1 -1
- package/dist/cjs/types/route.d.ts +2 -0
- package/dist/cjs/types/route.d.ts.map +1 -1
- 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/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 +3 -2
- package/dist/core/Observation.js.map +1 -1
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +3 -4
- 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 +4 -3
- 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/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/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 +1 -1
- 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
|
@@ -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
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
|
|
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
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
package/src/types/agent.ts
CHANGED
|
@@ -82,7 +82,8 @@ export interface Guideline {
|
|
|
82
82
|
/** Tags for organizing and filtering guidelines */
|
|
83
83
|
tags?: string[];
|
|
84
84
|
/** Tools available when following this guideline */
|
|
85
|
-
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
+
tools?: ToolRef<any, any[], any>[];
|
|
86
87
|
/** Additional metadata */
|
|
87
88
|
metadata?: Record<string, unknown>;
|
|
88
89
|
}
|
|
@@ -98,7 +99,8 @@ export interface Capability {
|
|
|
98
99
|
/** Description of what the capability does */
|
|
99
100
|
description: string;
|
|
100
101
|
/** Tools used by this capability */
|
|
101
|
-
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
+
tools?: ToolRef<any, any[], any>[];
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
/**
|
package/src/types/observation.ts
CHANGED
|
@@ -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()) */
|
package/src/types/route.ts
CHANGED
|
@@ -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/utils/id.ts
ADDED
|
@@ -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
|
+
}
|