@falai/agent 0.3.0 → 0.3.10

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 (49) hide show
  1. package/README.md +158 -9
  2. package/dist/cjs/core/Agent.d.ts +12 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +37 -1
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/DomainRegistry.d.ts +10 -0
  7. package/dist/cjs/core/DomainRegistry.d.ts.map +1 -1
  8. package/dist/cjs/core/DomainRegistry.js +25 -0
  9. package/dist/cjs/core/DomainRegistry.js.map +1 -1
  10. package/dist/cjs/core/PromptBuilder.d.ts +9 -1
  11. package/dist/cjs/core/PromptBuilder.d.ts.map +1 -1
  12. package/dist/cjs/core/PromptBuilder.js +49 -2
  13. package/dist/cjs/core/PromptBuilder.js.map +1 -1
  14. package/dist/cjs/core/Route.d.ts +16 -0
  15. package/dist/cjs/core/Route.d.ts.map +1 -1
  16. package/dist/cjs/core/Route.js +22 -0
  17. package/dist/cjs/core/Route.js.map +1 -1
  18. package/dist/cjs/types/route.d.ts +6 -0
  19. package/dist/cjs/types/route.d.ts.map +1 -1
  20. package/dist/core/Agent.d.ts +12 -0
  21. package/dist/core/Agent.d.ts.map +1 -1
  22. package/dist/core/Agent.js +37 -1
  23. package/dist/core/Agent.js.map +1 -1
  24. package/dist/core/DomainRegistry.d.ts +10 -0
  25. package/dist/core/DomainRegistry.d.ts.map +1 -1
  26. package/dist/core/DomainRegistry.js +25 -0
  27. package/dist/core/DomainRegistry.js.map +1 -1
  28. package/dist/core/PromptBuilder.d.ts +9 -1
  29. package/dist/core/PromptBuilder.d.ts.map +1 -1
  30. package/dist/core/PromptBuilder.js +49 -2
  31. package/dist/core/PromptBuilder.js.map +1 -1
  32. package/dist/core/Route.d.ts +16 -0
  33. package/dist/core/Route.d.ts.map +1 -1
  34. package/dist/core/Route.js +22 -0
  35. package/dist/core/Route.js.map +1 -1
  36. package/dist/types/route.d.ts +6 -0
  37. package/dist/types/route.d.ts.map +1 -1
  38. package/docs/API_REFERENCE.md +99 -2
  39. package/docs/CONSTRUCTOR_OPTIONS.md +178 -37
  40. package/docs/GETTING_STARTED.md +10 -2
  41. package/examples/business-onboarding.ts +707 -0
  42. package/examples/domain-scoping.ts +266 -0
  43. package/examples/rules-prohibitions.ts +258 -0
  44. package/package.json +1 -1
  45. package/src/core/Agent.ts +46 -1
  46. package/src/core/DomainRegistry.ts +30 -0
  47. package/src/core/PromptBuilder.ts +70 -3
  48. package/src/core/Route.ts +28 -0
  49. package/src/types/route.ts +6 -0
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Domain Scoping Example
3
+ *
4
+ * This example demonstrates how to use domain scoping to restrict which tools
5
+ * are available in different conversation routes for security and clarity.
6
+ */
7
+
8
+ import { Agent, createMessageEvent, EventSource } from "../src/index";
9
+ import { GeminiProvider } from "../src/providers/GeminiProvider";
10
+
11
+ // Initialize AI provider
12
+ const ai = new GeminiProvider({
13
+ apiKey: process.env.GEMINI_API_KEY || "your-api-key-here",
14
+ model: "gemini-2.0-flash-exp",
15
+ });
16
+
17
+ // Create agent
18
+ const agent = new Agent({
19
+ name: "Multi-Domain Assistant",
20
+ description:
21
+ "An assistant that handles different tasks with domain-scoped tools",
22
+ ai,
23
+ });
24
+
25
+ // Register different domains with their tools
26
+ agent.addDomain("scraping", {
27
+ scrapeSite: async (url: string) => {
28
+ console.log(`[Scraping] Scraping site: ${url}`);
29
+ return { success: true, data: "Scraped content..." };
30
+ },
31
+ extractData: async (html: string, selector: string) => {
32
+ console.log(`[Scraping] Extracting data with selector: ${selector}`);
33
+ return { elements: [] };
34
+ },
35
+ });
36
+
37
+ agent.addDomain("calendar", {
38
+ scheduleEvent: async (date: Date, title: string, description?: string) => {
39
+ console.log(`[Calendar] Scheduling event: ${title} on ${date}`);
40
+ return { eventId: "evt_123", success: true };
41
+ },
42
+ listEvents: async (startDate: Date, endDate: Date) => {
43
+ console.log(`[Calendar] Listing events from ${startDate} to ${endDate}`);
44
+ return { events: [] };
45
+ },
46
+ cancelEvent: async (eventId: string) => {
47
+ console.log(`[Calendar] Cancelling event: ${eventId}`);
48
+ return { success: true };
49
+ },
50
+ });
51
+
52
+ agent.addDomain("payment", {
53
+ processPayment: async (amount: number, currency: string) => {
54
+ console.log(`[Payment] Processing payment: ${amount} ${currency}`);
55
+ return { transactionId: "txn_456", success: true };
56
+ },
57
+ refund: async (transactionId: string) => {
58
+ console.log(`[Payment] Processing refund for: ${transactionId}`);
59
+ return { success: true };
60
+ },
61
+ checkBalance: async () => {
62
+ console.log(`[Payment] Checking balance`);
63
+ return { balance: 1000, currency: "USD" };
64
+ },
65
+ });
66
+
67
+ agent.addDomain("analytics", {
68
+ trackEvent: async (
69
+ eventName: string,
70
+ properties: Record<string, unknown>
71
+ ) => {
72
+ console.log(`[Analytics] Tracking event: ${eventName}`, properties);
73
+ return { success: true };
74
+ },
75
+ generateReport: async (
76
+ reportType: string,
77
+ dateRange: { start: Date; end: Date }
78
+ ) => {
79
+ console.log(`[Analytics] Generating ${reportType} report`);
80
+ return { report: {} };
81
+ },
82
+ });
83
+
84
+ // Create routes with domain scoping
85
+ agent.createRoute({
86
+ title: "Data Collection",
87
+ description: "Collect and process web data",
88
+ conditions: ["User wants to scrape or extract data from websites"],
89
+ domains: ["scraping"], // ✅ Only scraping tools available
90
+ });
91
+
92
+ agent.createRoute({
93
+ title: "Schedule Meeting",
94
+ description: "Book and manage appointments",
95
+ conditions: ["User wants to schedule, view, or cancel events"],
96
+ domains: ["calendar"], // ✅ Only calendar tools available
97
+ });
98
+
99
+ agent.createRoute({
100
+ title: "Checkout Process",
101
+ description: "Process purchases and payments",
102
+ conditions: ["User wants to make a purchase or payment"],
103
+ domains: ["payment", "analytics"], // ✅ Multiple domains allowed
104
+ });
105
+
106
+ agent.createRoute({
107
+ title: "Customer Support",
108
+ description: "Answer general questions and provide help",
109
+ conditions: ["User has general questions or needs support"],
110
+ domains: [], // ✅ No tools available (conversation only)
111
+ });
112
+
113
+ agent.createRoute({
114
+ title: "Admin Support",
115
+ description: "Administrative tasks with full access",
116
+ conditions: ["User is admin and needs full system access"],
117
+ // domains not specified = all domains available
118
+ });
119
+
120
+ // Example conversations
121
+ async function demonstrateScoping() {
122
+ console.log("\n=== Domain Scoping Demo ===\n");
123
+
124
+ // Example 1: Data Collection route - only scraping tools available
125
+ console.log("1️⃣ Example: User wants to scrape data");
126
+ const history1 = [
127
+ createMessageEvent(
128
+ EventSource.CUSTOMER,
129
+ "Alice",
130
+ "Can you scrape the homepage of example.com?"
131
+ ),
132
+ ];
133
+
134
+ const response1 = await agent.respond({ history: history1 });
135
+ console.log(`Route chosen: ${response1.route?.title}`);
136
+ console.log(`Available tools in this route: scraping only`);
137
+ console.log(`Response: ${response1.message}\n`);
138
+
139
+ // Example 2: Schedule Meeting route - only calendar tools available
140
+ console.log("2️⃣ Example: User wants to schedule a meeting");
141
+ const history2 = [
142
+ createMessageEvent(
143
+ EventSource.CUSTOMER,
144
+ "Bob",
145
+ "Schedule a meeting for tomorrow at 2pm"
146
+ ),
147
+ ];
148
+
149
+ const response2 = await agent.respond({ history: history2 });
150
+ console.log(`Route chosen: ${response2.route?.title}`);
151
+ console.log(`Available tools in this route: calendar only`);
152
+ console.log(`Response: ${response2.message}\n`);
153
+
154
+ // Example 3: Customer Support route - NO tools available
155
+ console.log("3️⃣ Example: User has a general question");
156
+ const history3 = [
157
+ createMessageEvent(
158
+ EventSource.CUSTOMER,
159
+ "Charlie",
160
+ "What are your business hours?"
161
+ ),
162
+ ];
163
+
164
+ const response3 = await agent.respond({ history: history3 });
165
+ console.log(`Route chosen: ${response3.route?.title}`);
166
+ console.log(`Available tools in this route: none (conversation only)`);
167
+ console.log(`Response: ${response3.message}\n`);
168
+
169
+ // Example 4: Admin Support route - ALL tools available (for demo purposes)
170
+ console.log("4️⃣ Example: Admin needs full access");
171
+ const history4 = [
172
+ createMessageEvent(
173
+ EventSource.CUSTOMER,
174
+ "Admin",
175
+ "I need to generate a report and process a refund"
176
+ ),
177
+ ];
178
+
179
+ const response4 = await agent.respond({ history: history4 });
180
+ console.log(`Route chosen: ${response4.route?.title}`);
181
+ console.log(`Available tools in this route: all domains`);
182
+ console.log(`Response: ${response4.message}\n`);
183
+ }
184
+
185
+ // Benefits demonstration
186
+ console.log(`
187
+ 🔒 Security Benefits:
188
+ - Customer Support route cannot accidentally call payment.processPayment()
189
+ - Data Collection route cannot access calendar.scheduleEvent()
190
+ - Each route has minimum necessary permissions
191
+
192
+ ⚡ Performance Benefits:
193
+ - AI only sees relevant tools for each route
194
+ - Faster decision making with reduced context
195
+ - Clearer intent and fewer errors
196
+
197
+ 🎯 Clarity Benefits:
198
+ - Routes clearly document their capabilities
199
+ - Easy to audit what each route can do
200
+ - Better debugging when tools are called
201
+ `);
202
+
203
+ // Inspect route configurations
204
+ console.log("\n📋 Route Configurations:\n");
205
+ for (const route of agent.getRoutes()) {
206
+ const domains = route.getDomains();
207
+ const domainsText =
208
+ domains === undefined
209
+ ? "all domains"
210
+ : domains.length === 0
211
+ ? "no tools (conversation only)"
212
+ : domains.join(", ");
213
+
214
+ console.log(`• ${route.title}: ${domainsText}`);
215
+ }
216
+
217
+ // Validate tool calls (example helper function)
218
+ function validateToolCall(toolName: string, routeTitle: string): boolean {
219
+ const route = agent.getRoutes().find((r) => r.title === routeTitle);
220
+ if (!route) return false;
221
+
222
+ const allowedDomains = route.getDomains();
223
+
224
+ // If undefined, all domains allowed
225
+ if (allowedDomains === undefined) return true;
226
+
227
+ // If empty array, no tools allowed
228
+ if (allowedDomains.length === 0) return false;
229
+
230
+ // Check if tool's domain is in allowed list
231
+ const [domain] = toolName.split(".");
232
+ return allowedDomains.includes(domain);
233
+ }
234
+
235
+ console.log("\n✅ Validation Examples:");
236
+ console.log(
237
+ `- scraping.scrapeSite in "Data Collection": ${validateToolCall(
238
+ "scraping.scrapeSite",
239
+ "Data Collection"
240
+ )}`
241
+ );
242
+ console.log(
243
+ `- calendar.scheduleEvent in "Data Collection": ${validateToolCall(
244
+ "calendar.scheduleEvent",
245
+ "Data Collection"
246
+ )}`
247
+ );
248
+ console.log(
249
+ `- payment.processPayment in "Customer Support": ${validateToolCall(
250
+ "payment.processPayment",
251
+ "Customer Support"
252
+ )}`
253
+ );
254
+ console.log(
255
+ `- analytics.trackEvent in "Admin Support": ${validateToolCall(
256
+ "analytics.trackEvent",
257
+ "Admin Support"
258
+ )}`
259
+ );
260
+
261
+ // Run demonstration
262
+ if (import.meta.url === `file://${process.argv[1]}`) {
263
+ demonstrateScoping().catch(console.error);
264
+ }
265
+
266
+ export { agent };
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Rules & Prohibitions Example
3
+ *
4
+ * Demonstrates how to use rules and prohibitions to control agent behavior
5
+ * in different conversation routes (e.g., WhatsApp bot with different styles)
6
+ */
7
+
8
+ import { Agent, createMessageEvent, EventSource } from "../src/index";
9
+ import { GeminiProvider } from "../src/providers/GeminiProvider";
10
+
11
+ // Initialize AI provider
12
+ const ai = new GeminiProvider({
13
+ apiKey: process.env.GEMINI_API_KEY || "your-api-key-here",
14
+ model: "gemini-2.0-flash-exp",
15
+ });
16
+
17
+ // Create WhatsApp support bot with different styles per route
18
+ const agent = new Agent({
19
+ name: "SupportBot",
20
+ description: "Customer support assistant for WhatsApp",
21
+ ai,
22
+ });
23
+
24
+ // Route 1: Quick Support - Short, direct messages
25
+ agent.createRoute({
26
+ title: "Quick Support",
27
+ description: "Fast answers for common questions",
28
+ conditions: ["User has a simple question", "User wants quick help"],
29
+ rules: [
30
+ "Keep messages extremely short (1-2 lines maximum)",
31
+ "Use bullet points for lists",
32
+ "Maximum 1 emoji per message 👍",
33
+ "Be direct and to the point",
34
+ ],
35
+ prohibitions: [
36
+ "Never send long paragraphs",
37
+ "Do not over-explain",
38
+ "Never use more than 2 emojis",
39
+ "Do not ask follow-up questions unless necessary",
40
+ ],
41
+ });
42
+
43
+ // Route 2: Sales Consultation - Conversational, engaging
44
+ agent.createRoute({
45
+ title: "Sales Consultation",
46
+ description: "Help customer discover needs and present solutions",
47
+ conditions: [
48
+ "User is interested in buying",
49
+ "User wants product information",
50
+ ],
51
+ rules: [
52
+ "Ask open-ended questions to discover needs",
53
+ "Use storytelling when presenting solutions",
54
+ "Emoji to reinforce positive emotions 😊✨",
55
+ "Present value before mentioning price",
56
+ "Make customer feel special and understood",
57
+ ],
58
+ prohibitions: [
59
+ "Never talk about price before showing value",
60
+ "Do not pressure or push",
61
+ "Avoid technical jargon",
62
+ "Never send more than 2 messages without waiting for response",
63
+ "Do not make promises you cannot keep",
64
+ ],
65
+ });
66
+
67
+ // Route 3: Technical Support - Detailed, step-by-step
68
+ agent.createRoute({
69
+ title: "Technical Support",
70
+ description: "Help with technical issues and troubleshooting",
71
+ conditions: ["User has technical problem", "User needs step-by-step help"],
72
+ rules: [
73
+ "Provide clear, numbered steps",
74
+ "Use simple language for technical concepts",
75
+ "Confirm understanding after each major step",
76
+ "Offer screenshots or visual aids when helpful",
77
+ "Be patient and thorough",
78
+ ],
79
+ prohibitions: [
80
+ "Never skip steps or assume knowledge",
81
+ "Do not use excessive technical terms without explanation",
82
+ "Never blame the user for the issue",
83
+ "Do not rush through explanations",
84
+ ],
85
+ });
86
+
87
+ // Route 4: Emergency Support - Calm, reassuring, action-oriented
88
+ agent.createRoute({
89
+ title: "Emergency Support",
90
+ description: "Handle urgent customer issues",
91
+ conditions: ["Customer is frustrated", "Urgent issue", "Service down"],
92
+ rules: [
93
+ "Acknowledge the urgency immediately",
94
+ "Express empathy and understanding",
95
+ "Provide concrete next steps",
96
+ "Set clear expectations on resolution time",
97
+ "Keep customer updated",
98
+ ],
99
+ prohibitions: [
100
+ "Never downplay the customer's concern",
101
+ "Do not use emojis (keep it professional)",
102
+ 'Never say "calm down" or similar dismissive phrases',
103
+ "Do not transfer without explaining why",
104
+ "Never make excuses or blame others",
105
+ ],
106
+ });
107
+
108
+ // Route 5: General Chat - Friendly, casual, helpful
109
+ agent.createRoute({
110
+ title: "General Chat",
111
+ description: "Casual conversation and general questions",
112
+ conditions: ["User is just chatting", "Greeting", "General question"],
113
+ rules: [
114
+ "Be friendly and conversational",
115
+ "Use emojis naturally 😊",
116
+ "Mirror the customer's tone and energy",
117
+ "Keep it light and positive",
118
+ ],
119
+ prohibitions: [
120
+ "Do not be overly formal",
121
+ "Never ignore the customer's mood",
122
+ "Do not push products unless asked",
123
+ ],
124
+ });
125
+
126
+ // Demonstration function
127
+ async function demonstrateRulesAndProhibitions() {
128
+ console.log("\n=== Rules & Prohibitions Demo ===\n");
129
+
130
+ // Example 1: Quick Support - Should be short and direct
131
+ console.log("1️⃣ Quick Support Route (short, direct)");
132
+ const history1 = [
133
+ createMessageEvent(
134
+ EventSource.CUSTOMER,
135
+ "Alice",
136
+ "What are your business hours?"
137
+ ),
138
+ ];
139
+
140
+ const response1 = await agent.respond({ history: history1 });
141
+ console.log(`Route: ${response1.route?.title}`);
142
+ console.log(`Response: ${response1.message}`);
143
+ console.log(`Expected: Short, direct, max 1 emoji\n`);
144
+
145
+ // Example 2: Sales Consultation - Should be engaging and value-focused
146
+ console.log("2️⃣ Sales Consultation Route (conversational, value-first)");
147
+ const history2 = [
148
+ createMessageEvent(
149
+ EventSource.CUSTOMER,
150
+ "Bob",
151
+ "I'm interested in your premium plan"
152
+ ),
153
+ ];
154
+
155
+ const response2 = await agent.respond({ history: history2 });
156
+ console.log(`Route: ${response2.route?.title}`);
157
+ console.log(`Response: ${response2.message}`);
158
+ console.log(`Expected: Ask about needs, show value before price\n`);
159
+
160
+ // Example 3: Technical Support - Should be detailed and step-by-step
161
+ console.log("3️⃣ Technical Support Route (detailed, step-by-step)");
162
+ const history3 = [
163
+ createMessageEvent(
164
+ EventSource.CUSTOMER,
165
+ "Charlie",
166
+ "My app keeps crashing when I try to login"
167
+ ),
168
+ ];
169
+
170
+ const response3 = await agent.respond({ history: history3 });
171
+ console.log(`Route: ${response3.route?.title}`);
172
+ console.log(`Response: ${response3.message}`);
173
+ console.log(`Expected: Clear steps, simple language, patient\n`);
174
+
175
+ // Example 4: Emergency Support - Should be calm and action-oriented
176
+ console.log("4️⃣ Emergency Support Route (urgent, professional)");
177
+ const history4 = [
178
+ createMessageEvent(
179
+ EventSource.CUSTOMER,
180
+ "Diana",
181
+ "This is urgent! My payment failed and I need access NOW!"
182
+ ),
183
+ ];
184
+
185
+ const response4 = await agent.respond({ history: history4 });
186
+ console.log(`Route: ${response4.route?.title}`);
187
+ console.log(`Response: ${response4.message}`);
188
+ console.log(`Expected: Acknowledge urgency, no emojis, concrete steps\n`);
189
+
190
+ // Example 5: General Chat - Should be friendly and casual
191
+ console.log("5️⃣ General Chat Route (friendly, casual)");
192
+ const history5 = [
193
+ createMessageEvent(EventSource.CUSTOMER, "Eve", "Hey! How's it going?"),
194
+ ];
195
+
196
+ const response5 = await agent.respond({ history: history5 });
197
+ console.log(`Route: ${response5.route?.title}`);
198
+ console.log(`Response: ${response5.message}`);
199
+ console.log(`Expected: Friendly, emojis, mirrors customer tone\n`);
200
+ }
201
+
202
+ // Inspect route configurations
203
+ console.log("\n📋 Route Configurations:\n");
204
+ for (const route of agent.getRoutes()) {
205
+ console.log(`\n🛤️ ${route.title}`);
206
+
207
+ const rules = route.getRules();
208
+ if (rules.length > 0) {
209
+ console.log(` ✅ Rules (${rules.length}):`);
210
+ rules.forEach((rule, i) => console.log(` ${i + 1}. ${rule}`));
211
+ }
212
+
213
+ const prohibitions = route.getProhibitions();
214
+ if (prohibitions.length > 0) {
215
+ console.log(` ❌ Prohibitions (${prohibitions.length}):`);
216
+ prohibitions.forEach((prohibition, i) =>
217
+ console.log(` ${i + 1}. ${prohibition}`)
218
+ );
219
+ }
220
+ }
221
+
222
+ // Benefits explanation
223
+ console.log(`
224
+ \n💡 Benefits of Rules & Prohibitions:
225
+
226
+ 1️⃣ **Context-Specific Behavior**
227
+ - Each route can have completely different communication styles
228
+ - WhatsApp support: short messages
229
+ - Sales: engaging, story-driven
230
+ - Technical: detailed, step-by-step
231
+
232
+ 2️⃣ **Brand Consistency**
233
+ - Rules ensure the agent always follows brand guidelines
234
+ - Prohibitions prevent off-brand behavior
235
+ - Different routes for different contexts
236
+
237
+ 3️⃣ **User Experience**
238
+ - Emergency route: professional, no emojis
239
+ - General chat: friendly, casual
240
+ - Technical support: patient, thorough
241
+
242
+ 4️⃣ **Automatic Enforcement**
243
+ - Rules are applied in the AI prompt automatically
244
+ - No manual checking needed
245
+ - Consistent behavior across all conversations
246
+
247
+ 5️⃣ **Easy to Update**
248
+ - Change rules without changing code
249
+ - A/B test different communication styles
250
+ - Iterate based on customer feedback
251
+ `);
252
+
253
+ // Run demonstration
254
+ if (import.meta.url === `file://${process.argv[1]}`) {
255
+ demonstrateRulesAndProhibitions().catch(console.error);
256
+ }
257
+
258
+ export { agent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@falai/agent",
3
- "version": "0.3.0",
3
+ "version": "0.3.10",
4
4
  "description": "Standalone, strongly-typed AI Agent framework with route DSL and AI provider strategy",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
package/src/core/Agent.ts CHANGED
@@ -295,17 +295,26 @@ export class Agent<TContext = unknown> {
295
295
  }
296
296
  }
297
297
 
298
- // Add active routes
298
+ // Add active routes with their rules and prohibitions
299
299
  if (this.routes.length > 0) {
300
300
  promptBuilder.addActiveRoutes(
301
301
  this.routes.map((r) => ({
302
302
  title: r.title,
303
303
  description: r.description,
304
304
  conditions: r.conditions,
305
+ domains: r.getDomains(),
306
+ rules: r.getRules(),
307
+ prohibitions: r.getProhibitions(),
305
308
  }))
306
309
  );
307
310
  }
308
311
 
312
+ // Add domains (tools) information if any domains are registered
313
+ const allDomains = this.domainRegistry.all();
314
+ if (Object.keys(allDomains).length > 0) {
315
+ promptBuilder.addDomains(allDomains);
316
+ }
317
+
309
318
  // Add JSON response schema instructions
310
319
  promptBuilder.addJsonResponseSchema();
311
320
 
@@ -414,4 +423,40 @@ export class Agent<TContext = unknown> {
414
423
  getDomainRegistry(): DomainRegistry {
415
424
  return this.domainRegistry;
416
425
  }
426
+
427
+ /**
428
+ * Get allowed domains for a specific route
429
+ * @param routeId - Route ID to check
430
+ * @returns Filtered domains object, or all domains if route has no restrictions
431
+ */
432
+ getDomainsForRoute(routeId: string): Record<string, Record<string, unknown>> {
433
+ const route = this.routes.find((r) => r.id === routeId);
434
+
435
+ if (!route) {
436
+ // Route not found, return all domains
437
+ return this.domainRegistry.all();
438
+ }
439
+
440
+ const allowedDomains = route.getDomains();
441
+ return this.domainRegistry.getFiltered(allowedDomains);
442
+ }
443
+
444
+ /**
445
+ * Get allowed domains for a specific route by title
446
+ * @param routeTitle - Route title to check
447
+ * @returns Filtered domains object, or all domains if route has no restrictions
448
+ */
449
+ getDomainsForRouteByTitle(
450
+ routeTitle: string
451
+ ): Record<string, Record<string, unknown>> {
452
+ const route = this.routes.find((r) => r.title === routeTitle);
453
+
454
+ if (!route) {
455
+ // Route not found, return all domains
456
+ return this.domainRegistry.all();
457
+ }
458
+
459
+ const allowedDomains = route.getDomains();
460
+ return this.domainRegistry.getFiltered(allowedDomains);
461
+ }
417
462
  }
@@ -47,4 +47,34 @@ export class DomainRegistry {
47
47
  }
48
48
  return result;
49
49
  }
50
+
51
+ /**
52
+ * Get filtered domains by names
53
+ * @param allowedNames - Array of domain names to include (undefined = all domains)
54
+ * @returns Object with only the specified domains
55
+ */
56
+ getFiltered(
57
+ allowedNames?: string[]
58
+ ): Record<string, Record<string, unknown>> {
59
+ // If no filter specified, return all domains
60
+ if (!allowedNames) {
61
+ return this.all();
62
+ }
63
+
64
+ const result: Record<string, Record<string, unknown>> = {};
65
+ for (const name of allowedNames) {
66
+ const domain = this.domains.get(name);
67
+ if (domain) {
68
+ result[name] = domain;
69
+ }
70
+ }
71
+ return result;
72
+ }
73
+
74
+ /**
75
+ * Get list of all registered domain names
76
+ */
77
+ getDomainNames(): string[] {
78
+ return Array.from(this.domains.keys());
79
+ }
50
80
  }