@falai/agent 1.0.1 → 1.0.2
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/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +1 -3
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +8 -9
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/core/RoutingEngine.js +29 -23
- package/dist/cjs/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +7 -0
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/routing.d.ts +0 -4
- package/dist/cjs/types/routing.d.ts.map +1 -1
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +1 -3
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +8 -9
- package/dist/core/RoutingEngine.d.ts.map +1 -1
- package/dist/core/RoutingEngine.js +29 -23
- package/dist/core/RoutingEngine.js.map +1 -1
- package/dist/types/agent.d.ts +7 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/routing.d.ts +0 -4
- package/dist/types/routing.d.ts.map +1 -1
- package/docs/README.md +6 -17
- package/docs/api/README.md +12 -16
- package/docs/architecture/data-extraction-flow.md +0 -1
- package/docs/core/agent/context-management.md +6 -6
- package/docs/core/agent/session-management.md +3 -4
- package/docs/core/routing/intelligent-routing.md +12 -8
- package/docs/guides/getting-started/README.md +10 -13
- package/docs/guides/migration/response-modal-refactor.md +2 -2
- package/package.json +1 -1
- package/src/core/Agent.ts +1 -3
- package/src/core/RoutingEngine.ts +63 -50
- package/src/types/agent.ts +7 -0
- package/src/types/routing.ts +0 -5
package/docs/api/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Complete API documentation for `@falai/agent`. This framework provides a strongl
|
|
|
9
9
|
- **[AI Routing System](../core/routing/intelligent-routing.md)** - Intelligent route and step selection
|
|
10
10
|
- **[Route DSL](../core/conversation-flows/route-dsl.md)** - Declarative conversation flow design
|
|
11
11
|
- **[Data Collection](../core/conversation-flows/data-collection.md)** - Schema-driven data extraction
|
|
12
|
-
- **[Tool
|
|
12
|
+
- **[Tool Definition](../core/tools/tool-definition.md)** - Tool creation and configuration
|
|
13
13
|
- **[Session Storage](../core/persistence/session-storage.md)** - Persistence and session management
|
|
14
14
|
- **[AI Providers](../core/ai-integration/providers.md)** - Provider integrations and configuration
|
|
15
15
|
|
|
@@ -127,7 +127,7 @@ Main agent class for managing conversational AI with agent-level data collection
|
|
|
127
127
|
new Agent<TContext, TData>(options: AgentOptions<TContext, TData>)
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
See
|
|
130
|
+
See `AgentOptions` type definition for full details.
|
|
131
131
|
|
|
132
132
|
#### Methods
|
|
133
133
|
|
|
@@ -632,7 +632,7 @@ return response.message;
|
|
|
632
632
|
- If all steps are skipped (due to `skipIf` conditions), the route can complete immediately on entry
|
|
633
633
|
- Use `agent.getData(session)` to retrieve all collected data
|
|
634
634
|
|
|
635
|
-
See also: [
|
|
635
|
+
See also: [Database Integration Example](../../examples/integrations/database-integration.ts)
|
|
636
636
|
|
|
637
637
|
##### `respondStream(input: RespondInput<TContext>): AsyncGenerator<StreamChunk>`
|
|
638
638
|
|
|
@@ -808,7 +808,7 @@ await db.agentMessages.create({
|
|
|
808
808
|
});
|
|
809
809
|
```
|
|
810
810
|
|
|
811
|
-
**See Also:** [streaming-
|
|
811
|
+
**See Also:** [streaming-responses.ts](../../examples/advanced-patterns/streaming-responses.ts) for comprehensive examples.
|
|
812
812
|
|
|
813
813
|
#### Properties
|
|
814
814
|
|
|
@@ -1461,7 +1461,7 @@ Route this step belongs to (readonly).
|
|
|
1461
1461
|
|
|
1462
1462
|
Tools provide a powerful way to execute custom logic, access external APIs, and enrich conversation context before AI response generation.
|
|
1463
1463
|
|
|
1464
|
-
**See Also:** [
|
|
1464
|
+
**See Also:** [Tool Definition](../core/tools/tool-definition.md) - Complete guide to tool creation and configuration
|
|
1465
1465
|
|
|
1466
1466
|
---
|
|
1467
1467
|
|
|
@@ -1642,7 +1642,7 @@ const provider = new OpenRouterProvider({
|
|
|
1642
1642
|
});
|
|
1643
1643
|
```
|
|
1644
1644
|
|
|
1645
|
-
**See Also:** [Providers
|
|
1645
|
+
**See Also:** [AI Providers](../core/ai-integration/providers.md) for detailed provider comparison and configuration examples.
|
|
1646
1646
|
|
|
1647
1647
|
---
|
|
1648
1648
|
|
|
@@ -1789,9 +1789,7 @@ Handles route and step selection logic for conversation orchestration.
|
|
|
1789
1789
|
new RoutingEngine<TContext, TData>(options?: RoutingEngineOptions)
|
|
1790
1790
|
|
|
1791
1791
|
interface RoutingEngineOptions {
|
|
1792
|
-
|
|
1793
|
-
switchThreshold?: number; // Default: 70 (0-100)
|
|
1794
|
-
maxCandidates?: number; // Default: 5
|
|
1792
|
+
routeSwitchMargin?: number; // Default: 15 (0-100)
|
|
1795
1793
|
}
|
|
1796
1794
|
```
|
|
1797
1795
|
|
|
@@ -1927,9 +1925,9 @@ const agent = new Agent({
|
|
|
1927
1925
|
});
|
|
1928
1926
|
```
|
|
1929
1927
|
|
|
1930
|
-
**Schema Example:** See [examples/prisma-schema.example.prisma](
|
|
1928
|
+
**Schema Example:** See [examples/prisma-schema.example.prisma](../../examples/persistence/prisma-schema.example.prisma)
|
|
1931
1929
|
|
|
1932
|
-
**Full Example:** See [examples/
|
|
1930
|
+
**Full Example:** See [examples/database-persistence.ts](../../examples/persistence/database-persistence.ts)
|
|
1933
1931
|
|
|
1934
1932
|
---
|
|
1935
1933
|
|
|
@@ -1972,7 +1970,7 @@ const agent = new Agent({
|
|
|
1972
1970
|
|
|
1973
1971
|
**Install:** `npm install ioredis` or `npm install redis`
|
|
1974
1972
|
|
|
1975
|
-
**Full Example:** See [examples/redis-persistence.ts](
|
|
1973
|
+
**Full Example:** See [examples/redis-persistence.ts](../../examples/persistence/redis-persistence.ts)
|
|
1976
1974
|
|
|
1977
1975
|
---
|
|
1978
1976
|
|
|
@@ -2185,8 +2183,6 @@ const agent = new Agent({
|
|
|
2185
2183
|
|
|
2186
2184
|
**Perfect for:** Full-text search, analytics, time-series analysis, AWS OpenSearch Service, Elasticsearch 7.x users
|
|
2187
2185
|
|
|
2188
|
-
**Full Example:** See [examples/opensearch-persistence.ts](../examples/opensearch-persistence.ts)
|
|
2189
|
-
|
|
2190
2186
|
---
|
|
2191
2187
|
|
|
2192
2188
|
### `MemoryAdapter`
|
|
@@ -2310,8 +2306,8 @@ interface PersistenceAdapter {
|
|
|
2310
2306
|
|
|
2311
2307
|
**See Also:**
|
|
2312
2308
|
|
|
2313
|
-
- [
|
|
2314
|
-
- [
|
|
2309
|
+
- [Session Storage](../core/persistence/session-storage.md) - Session persistence patterns
|
|
2310
|
+
- [Database Adapters](../core/persistence/adapters.md) - Adapter comparison and details
|
|
2315
2311
|
|
|
2316
2312
|
---
|
|
2317
2313
|
|
|
@@ -360,4 +360,3 @@ This results in natural, efficient conversations that respect user time.
|
|
|
360
360
|
**Next Steps:**
|
|
361
361
|
- [Route Configuration](../core/conversation-flows/routes.md)
|
|
362
362
|
- [Step Configuration](../core/conversation-flows/steps.md)
|
|
363
|
-
- [Schema Design](../guides/building-agents/schema-design.md)
|
|
@@ -773,10 +773,10 @@ hooks: {
|
|
|
773
773
|
|
|
774
774
|
## 📚 Related Resources
|
|
775
775
|
|
|
776
|
-
- [Complete Example: Persistent Onboarding](
|
|
777
|
-
- [API Reference: AgentOptions](
|
|
778
|
-
- [API Reference: ContextLifecycleHooks](
|
|
779
|
-
- [Getting Started](
|
|
776
|
+
- [Complete Example: Persistent Onboarding](../../../examples/advanced-patterns/persistent-onboarding.ts)
|
|
777
|
+
- [API Reference: AgentOptions](../../api/overview.md#agentoptions)
|
|
778
|
+
- [API Reference: ContextLifecycleHooks](../../api/overview.md#contextlifecyclehooks)
|
|
779
|
+
- [Getting Started](../../guides/getting-started/README.md)
|
|
780
780
|
|
|
781
781
|
---
|
|
782
782
|
|
|
@@ -784,8 +784,8 @@ hooks: {
|
|
|
784
784
|
|
|
785
785
|
If you're still having issues:
|
|
786
786
|
|
|
787
|
-
1. Check the [examples](
|
|
788
|
-
2. Review the [API Reference](
|
|
787
|
+
1. Check the [examples](../../../examples/) for working implementations
|
|
788
|
+
2. Review the [API Reference](../../api/README.md) for detailed type information
|
|
789
789
|
3. Open an issue on GitHub with your use case
|
|
790
790
|
|
|
791
791
|
**Remember:** The key to persistent conversations is:
|
|
@@ -631,10 +631,9 @@ This framework draws inspiration from:
|
|
|
631
631
|
|
|
632
632
|
## Further Reading
|
|
633
633
|
|
|
634
|
-
- [Getting Started Guide](
|
|
635
|
-
- [
|
|
636
|
-
- [API Reference](
|
|
637
|
-
- [Examples](../examples/) - Real-world implementations
|
|
634
|
+
- [Getting Started Guide](../../guides/getting-started/README.md) - Build your first agent
|
|
635
|
+
- [Context Management](./context-management.md) - Context providers and updates
|
|
636
|
+
- [API Reference](../../api/README.md) - Complete API documentation
|
|
638
637
|
|
|
639
638
|
---
|
|
640
639
|
|
|
@@ -376,14 +376,19 @@ if (routes.length === 1) {
|
|
|
376
376
|
}
|
|
377
377
|
```
|
|
378
378
|
|
|
379
|
-
###
|
|
379
|
+
### Sticky Route Switching
|
|
380
380
|
|
|
381
|
-
|
|
381
|
+
When the agent is already on a route, it won't switch unless an alternative route scores higher by a configurable margin. This prevents flip-flopping on marginal score differences:
|
|
382
382
|
|
|
383
383
|
```typescript
|
|
384
|
-
const
|
|
384
|
+
const agent = new Agent({
|
|
385
|
+
// ...
|
|
386
|
+
routeSwitchMargin: 15, // default: 15, range 0-100
|
|
387
|
+
});
|
|
385
388
|
```
|
|
386
389
|
|
|
390
|
+
A margin of 15 means the best alternative must outscore the current route by at least 15 points before a switch occurs.
|
|
391
|
+
|
|
387
392
|
## Error Handling & Resilience
|
|
388
393
|
|
|
389
394
|
### Backup Model Support
|
|
@@ -408,13 +413,12 @@ Robust validation ensures system stability:
|
|
|
408
413
|
|
|
409
414
|
## Configuration Options
|
|
410
415
|
|
|
411
|
-
### Routing
|
|
416
|
+
### Routing Configuration
|
|
412
417
|
|
|
413
418
|
```typescript
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
maxCandidates: 5, // Limit AI evaluation candidates
|
|
419
|
+
const agent = new Agent({
|
|
420
|
+
// ...
|
|
421
|
+
routeSwitchMargin: 15, // Score margin before switching routes (0-100, default: 15)
|
|
418
422
|
});
|
|
419
423
|
```
|
|
420
424
|
|
|
@@ -717,27 +717,24 @@ console.log(response2.message); // Agent remembers: "Your name is Alice"
|
|
|
717
717
|
|
|
718
718
|
### Level 2: Core Concepts
|
|
719
719
|
|
|
720
|
-
- **[Schema-Driven Extraction](
|
|
721
|
-
- **[Session Management](
|
|
722
|
-
- **[
|
|
720
|
+
- **[Schema-Driven Extraction](../../../examples/core-concepts/schema-driven-extraction.ts)** - Advanced data collection patterns
|
|
721
|
+
- **[Session Management](../../../examples/core-concepts/session-management.ts)** - Multi-turn conversations
|
|
722
|
+
- **[Modern Streaming API](../../../examples/core-concepts/modern-streaming-api.ts)** - Streaming with the modern API
|
|
723
723
|
|
|
724
724
|
### Level 3: Conversation Flows
|
|
725
725
|
|
|
726
|
-
- **[
|
|
727
|
-
- **[Data-Driven Flows](../conversation-flows/data-driven-flows.ts)** - Conditional logic and requirements
|
|
728
|
-
- **[Branching](../conversation-flows/branching/README.md)** - Non-linear conversations
|
|
726
|
+
- **[Completion Transitions](../../../examples/conversation-flows/completion-transitions.ts)** - Route completion and transitions
|
|
729
727
|
|
|
730
728
|
### Level 4: Advanced Features
|
|
731
729
|
|
|
732
|
-
- **[
|
|
733
|
-
- **[
|
|
734
|
-
- **[Multi-Turn Conversations](../advanced-patterns/multi-turn-conversations.ts)** - Complex dialogues
|
|
730
|
+
- **[Knowledge-Based Agent](../../../examples/advanced-patterns/knowledge-based-agent.ts)** - Domain-specific knowledge bases
|
|
731
|
+
- **[Route Lifecycle Hooks](../../../examples/advanced-patterns/route-lifecycle-hooks.ts)** - Custom route behavior
|
|
735
732
|
|
|
736
733
|
### Level 5: Production
|
|
737
734
|
|
|
738
|
-
- **[Server
|
|
739
|
-
- **[Database Persistence](
|
|
740
|
-
- **[Streaming Responses](
|
|
735
|
+
- **[Server Session Management](../../../examples/integrations/server-session-management.ts)** - Server-side sessions
|
|
736
|
+
- **[Database Persistence](../../../examples/persistence/custom-adapter.ts)** - Custom storage adapters
|
|
737
|
+
- **[Streaming Responses](../../../examples/advanced-patterns/streaming-responses.ts)** - Real-time UX
|
|
741
738
|
|
|
742
739
|
---
|
|
743
740
|
|
|
@@ -783,7 +780,7 @@ console.log("Provider:", agent.options.provider.name);
|
|
|
783
780
|
### Getting Help
|
|
784
781
|
|
|
785
782
|
- 📖 **[Full Documentation](../../README.md)** - Complete API reference
|
|
786
|
-
- 💬 **[Examples Directory](
|
|
783
|
+
- 💬 **[Examples Directory](../../../examples/)** - Working code samples
|
|
787
784
|
- 🐛 **[GitHub Issues](https://github.com/falai-dev/agent/issues)** - Report bugs
|
|
788
785
|
- 💡 **[Discussions](https://github.com/falai-dev/agent/discussions)** - Ask questions
|
|
789
786
|
|
|
@@ -513,6 +513,6 @@ The modern `stream()` API is the recommended approach for new streaming implemen
|
|
|
513
513
|
---
|
|
514
514
|
|
|
515
515
|
**Need Help?**
|
|
516
|
-
- Check the [examples](
|
|
516
|
+
- Check the [examples](../../../examples/) directory for complete working examples
|
|
517
517
|
- Review the [API documentation](../../api/) for detailed method signatures
|
|
518
|
-
- Look at the [streaming examples](
|
|
518
|
+
- Look at the [streaming examples](../../../examples/advanced-patterns/streaming-responses.ts) for side-by-side comparisons
|
package/package.json
CHANGED
package/src/core/Agent.ts
CHANGED
|
@@ -126,9 +126,7 @@ export class Agent<TContext = any, TData = any> {
|
|
|
126
126
|
|
|
127
127
|
// Initialize routing engine
|
|
128
128
|
this.routingEngine = new RoutingEngine<TContext, TData>({
|
|
129
|
-
|
|
130
|
-
allowRouteSwitch: true,
|
|
131
|
-
switchThreshold: 70,
|
|
129
|
+
routeSwitchMargin: options.routeSwitchMargin,
|
|
132
130
|
});
|
|
133
131
|
|
|
134
132
|
// Initialize ResponseModal for handling all response generation
|
|
@@ -2,7 +2,6 @@ import type {
|
|
|
2
2
|
Event,
|
|
3
3
|
AgentOptions,
|
|
4
4
|
StructuredSchema,
|
|
5
|
-
RoutingDecision,
|
|
6
5
|
SessionState,
|
|
7
6
|
AiProvider,
|
|
8
7
|
TemplateContext,
|
|
@@ -36,9 +35,12 @@ export interface RoutingDecisionOutput {
|
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
export interface RoutingEngineOptions {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Score margin the best alternative route must exceed the current route's score
|
|
40
|
+
* by before the agent switches routes. Prevents flip-flopping on marginal differences.
|
|
41
|
+
* @default 15
|
|
42
|
+
*/
|
|
43
|
+
routeSwitchMargin?: number;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
export interface BuildStepSelectionPromptParams<
|
|
@@ -746,7 +748,8 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
|
|
|
746
748
|
const optimalRoute = this.selectOptimalRoute(
|
|
747
749
|
eligibleRoutes,
|
|
748
750
|
updatedSession.data || {},
|
|
749
|
-
routingResult.structured.routes
|
|
751
|
+
routingResult.structured.routes,
|
|
752
|
+
updatedSession.currentRoute?.id
|
|
750
753
|
);
|
|
751
754
|
|
|
752
755
|
// If no optimal route found, check why
|
|
@@ -908,42 +911,68 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
|
|
|
908
911
|
* @returns Route that should be prioritized for continuation
|
|
909
912
|
*/
|
|
910
913
|
selectOptimalRoute(
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
914
|
+
routes: Route<TContext, TData>[],
|
|
915
|
+
data: Partial<TData>,
|
|
916
|
+
routeScores: Record<string, number>,
|
|
917
|
+
currentRouteId?: string
|
|
918
|
+
): Route<TContext, TData> | undefined {
|
|
919
|
+
const completionStatus = this.getRouteCompletionStatus(routes, data);
|
|
920
|
+
const switchMargin = this.options?.routeSwitchMargin ?? 15;
|
|
921
|
+
|
|
922
|
+
// Create weighted scores combining AI intent scores with completion progress
|
|
923
|
+
const weightedScores: Array<{ route: Route<TContext, TData>; score: number }> = [];
|
|
924
|
+
|
|
925
|
+
for (const route of routes) {
|
|
926
|
+
const aiScore = routeScores[route.id] || 0;
|
|
927
|
+
const completionProgress = completionStatus.get(route.id) || 0;
|
|
928
|
+
|
|
929
|
+
// ALWAYS skip fully completed routes to prevent re-entering finished tasks
|
|
930
|
+
if (completionProgress >= 1.0) {
|
|
931
|
+
logger.debug(
|
|
932
|
+
`[RoutingEngine] Excluding completed route: ${route.title} (100% complete)`
|
|
933
|
+
);
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
919
936
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
937
|
+
// Boost partially complete routes that match user intent
|
|
938
|
+
let weightedScore = aiScore;
|
|
939
|
+
if (completionProgress > 0 && completionProgress < 1.0) {
|
|
940
|
+
weightedScore += (completionProgress * 20); // Up to 20 point boost
|
|
941
|
+
}
|
|
923
942
|
|
|
924
|
-
|
|
925
|
-
// Users should not be forced back into completed routes
|
|
926
|
-
if (completionProgress >= 1.0) {
|
|
927
|
-
logger.debug(
|
|
928
|
-
`[RoutingEngine] Excluding completed route: ${route.title} (100% complete)`
|
|
929
|
-
);
|
|
930
|
-
continue;
|
|
943
|
+
weightedScores.push({ route, score: weightedScore });
|
|
931
944
|
}
|
|
932
945
|
|
|
933
|
-
//
|
|
934
|
-
|
|
935
|
-
if (completionProgress > 0 && completionProgress < 1.0) {
|
|
936
|
-
// Boost score for partially complete routes
|
|
937
|
-
weightedScore += (completionProgress * 20); // Up to 20 point boost
|
|
938
|
-
}
|
|
946
|
+
// Sort by weighted score descending
|
|
947
|
+
weightedScores.sort((a, b) => b.score - a.score);
|
|
939
948
|
|
|
940
|
-
weightedScores.
|
|
941
|
-
|
|
949
|
+
if (weightedScores.length === 0) {
|
|
950
|
+
return undefined;
|
|
951
|
+
}
|
|
942
952
|
|
|
943
|
-
|
|
944
|
-
|
|
953
|
+
// Apply sticky routing: if there's a current route, only switch if the
|
|
954
|
+
// best alternative exceeds the current route's score by the configured margin
|
|
955
|
+
if (currentRouteId) {
|
|
956
|
+
const currentEntry = weightedScores.find(e => e.route.id === currentRouteId);
|
|
957
|
+
const bestEntry = weightedScores[0];
|
|
958
|
+
|
|
959
|
+
if (currentEntry && bestEntry.route.id !== currentRouteId) {
|
|
960
|
+
if (bestEntry.score < currentEntry.score + switchMargin) {
|
|
961
|
+
logger.debug(
|
|
962
|
+
`[RoutingEngine] Staying on current route: ${currentEntry.route.title} ` +
|
|
963
|
+
`(current: ${currentEntry.score}, best alternative: ${bestEntry.score}, ` +
|
|
964
|
+
`margin required: ${switchMargin})`
|
|
965
|
+
);
|
|
966
|
+
return currentEntry.route;
|
|
967
|
+
}
|
|
968
|
+
logger.debug(
|
|
969
|
+
`[RoutingEngine] Switching route: ${currentEntry.route.title} → ${bestEntry.route.title} ` +
|
|
970
|
+
`(current: ${currentEntry.score}, alternative: ${bestEntry.score}, ` +
|
|
971
|
+
`margin: ${switchMargin})`
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
945
975
|
|
|
946
|
-
if (weightedScores.length > 0) {
|
|
947
976
|
logger.debug(
|
|
948
977
|
`[RoutingEngine] Selected optimal route: ${weightedScores[0].route.title} ` +
|
|
949
978
|
`(AI: ${routeScores[weightedScores[0].route.id]}, ` +
|
|
@@ -953,9 +982,6 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
|
|
|
953
982
|
return weightedScores[0].route;
|
|
954
983
|
}
|
|
955
984
|
|
|
956
|
-
return undefined;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
985
|
/**
|
|
960
986
|
* Build prompt for step selection within a single route
|
|
961
987
|
* @private
|
|
@@ -1380,17 +1406,4 @@ export class RoutingEngine<TContext = unknown, TData = unknown> {
|
|
|
1380
1406
|
return pc.build();
|
|
1381
1407
|
}
|
|
1382
1408
|
|
|
1383
|
-
decideRouteFromScores(output: RoutingDecision): {
|
|
1384
|
-
routeId: string;
|
|
1385
|
-
maxScore: number;
|
|
1386
|
-
} {
|
|
1387
|
-
// Optionally limit candidates and apply switching threshold
|
|
1388
|
-
const entries = Object.entries(output.routes).sort((a, b) => b[1] - a[1]);
|
|
1389
|
-
const limited = this.options?.maxCandidates
|
|
1390
|
-
? entries.slice(0, this.options.maxCandidates)
|
|
1391
|
-
: entries;
|
|
1392
|
-
const [topId, topScore] = limited[0] || ["", 0];
|
|
1393
|
-
// switchThreshold is enforced by caller when a current route exists
|
|
1394
|
-
return { routeId: topId, maxScore: topScore };
|
|
1395
|
-
}
|
|
1396
1409
|
}
|
package/src/types/agent.ts
CHANGED
|
@@ -114,6 +114,13 @@ export interface AgentOptions<TContext = unknown, TData = unknown> {
|
|
|
114
114
|
schema?: StructuredSchema;
|
|
115
115
|
/** Initial data to pre-populate when creating the agent */
|
|
116
116
|
initialData?: Partial<TData>;
|
|
117
|
+
/**
|
|
118
|
+
* Margin (0-100) the best alternative route must exceed the current route's score
|
|
119
|
+
* by before the agent switches. Higher values make the agent "stickier" to the
|
|
120
|
+
* current route. Set to 0 to switch whenever any route scores higher.
|
|
121
|
+
* @default 15
|
|
122
|
+
*/
|
|
123
|
+
routeSwitchMargin?: number;
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
/**
|
package/src/types/routing.ts
CHANGED
|
@@ -8,11 +8,6 @@ export interface RoutingDecision {
|
|
|
8
8
|
contextUpdate?: Record<string, unknown>;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export interface RoutingDecisionWithRoute extends RoutingDecision {
|
|
12
|
-
selectedRouteId: string;
|
|
13
|
-
maxScore: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
export interface RoutingSchemaOptions {
|
|
17
12
|
extrasSchema?: StructuredSchema;
|
|
18
13
|
}
|