@falai/agent 0.6.8 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -59
- package/dist/adapters/MemoryAdapter.js +2 -2
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/MongoAdapter.js +2 -2
- package/dist/adapters/MongoAdapter.js.map +1 -1
- package/dist/adapters/OpenSearchAdapter.js +7 -7
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +9 -9
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.js +3 -3
- package/dist/adapters/PrismaAdapter.js.map +1 -1
- package/dist/adapters/RedisAdapter.js +2 -2
- package/dist/adapters/RedisAdapter.js.map +1 -1
- package/dist/adapters/SQLiteAdapter.d.ts +3 -3
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +11 -11
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.js +2 -2
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.js +2 -2
- package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js +7 -7
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +9 -9
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +3 -3
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.js +2 -2
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts +3 -3
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +11 -11
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/index.d.ts +1 -1
- package/dist/cjs/adapters/index.d.ts.map +1 -1
- package/dist/cjs/constants/index.d.ts +4 -4
- package/dist/cjs/constants/index.js +5 -5
- package/dist/cjs/core/Agent.d.ts +22 -22
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +160 -152
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/Events.d.ts +6 -6
- package/dist/cjs/core/Events.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +13 -13
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +24 -24
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/ResponseEngine.d.ts +3 -8
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +8 -8
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/Route.d.ts +17 -17
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +33 -33
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +30 -30
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/core/RoutingEngine.js +192 -192
- package/dist/cjs/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/core/Step.d.ts +72 -0
- package/dist/cjs/core/Step.d.ts.map +1 -0
- package/dist/cjs/core/Step.js +150 -0
- package/dist/cjs/core/Step.js.map +1 -0
- package/dist/cjs/core/ToolExecutor.d.ts +5 -5
- package/dist/cjs/core/ToolExecutor.d.ts.map +1 -1
- package/dist/cjs/core/ToolExecutor.js +8 -8
- package/dist/cjs/core/ToolExecutor.js.map +1 -1
- package/dist/cjs/core/Transition.d.ts +14 -14
- package/dist/cjs/core/Transition.d.ts.map +1 -1
- package/dist/cjs/core/Transition.js +48 -19
- package/dist/cjs/core/Transition.js.map +1 -1
- package/dist/cjs/index.d.ts +7 -7
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +8 -8
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +2 -2
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +3 -3
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/persistence.d.ts +5 -5
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/route.d.ts +57 -52
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +27 -27
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/session.js +48 -50
- package/dist/cjs/types/session.js.map +1 -1
- package/dist/cjs/types/tool.d.ts +13 -13
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/id.d.ts +8 -3
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +16 -7
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/constants/index.d.ts +4 -4
- package/dist/constants/index.js +4 -4
- package/dist/core/Agent.d.ts +22 -22
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +162 -154
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/Events.d.ts +6 -6
- package/dist/core/Events.d.ts.map +1 -1
- package/dist/core/PersistenceManager.d.ts +13 -13
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +25 -25
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/ResponseEngine.d.ts +3 -8
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +8 -8
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/Route.d.ts +17 -17
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +33 -33
- package/dist/core/Route.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +30 -30
- package/dist/core/RoutingEngine.d.ts.map +1 -1
- package/dist/core/RoutingEngine.js +193 -193
- package/dist/core/RoutingEngine.js.map +1 -1
- package/dist/core/Step.d.ts +72 -0
- package/dist/core/Step.d.ts.map +1 -0
- package/dist/core/Step.js +146 -0
- package/dist/core/Step.js.map +1 -0
- package/dist/core/ToolExecutor.d.ts +5 -5
- package/dist/core/ToolExecutor.d.ts.map +1 -1
- package/dist/core/ToolExecutor.js +8 -8
- package/dist/core/ToolExecutor.js.map +1 -1
- package/dist/core/Transition.d.ts +14 -14
- package/dist/core/Transition.d.ts.map +1 -1
- package/dist/core/Transition.js +48 -19
- package/dist/core/Transition.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/types/agent.d.ts +8 -8
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +2 -2
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/history.d.ts +3 -3
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/persistence.d.ts +5 -5
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/route.d.ts +57 -52
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/session.d.ts +27 -27
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js +44 -46
- package/dist/types/session.js.map +1 -1
- package/dist/types/tool.d.ts +13 -13
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/id.d.ts +8 -3
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +14 -6
- package/dist/utils/id.js.map +1 -1
- package/docs/ADAPTERS.md +21 -21
- package/docs/AGENT.md +57 -55
- package/docs/API_REFERENCE.md +218 -220
- package/docs/ARCHITECTURE.md +99 -104
- package/docs/CONTEXT_MANAGEMENT.md +81 -88
- package/docs/DOCS.md +18 -18
- package/docs/DOMAINS.md +16 -16
- package/docs/EXAMPLES.md +43 -43
- package/docs/GETTING_STARTED.md +60 -63
- package/docs/PERSISTENCE.md +66 -70
- package/docs/PROVIDERS.md +2 -2
- package/docs/README.md +6 -6
- package/docs/ROUTES.md +218 -220
- package/docs/STEPS.md +883 -0
- package/examples/business-onboarding.ts +84 -81
- package/examples/company-qna-agent.ts +68 -67
- package/examples/custom-database-persistence.ts +87 -89
- package/examples/declarative-agent.ts +32 -32
- package/examples/domain-scoping.ts +18 -18
- package/examples/extracted-data-modification.ts +92 -97
- package/examples/healthcare-agent.ts +89 -91
- package/examples/openai-agent.ts +29 -32
- package/examples/opensearch-persistence.ts +43 -45
- package/examples/persistent-onboarding.ts +65 -66
- package/examples/prisma-persistence.ts +108 -112
- package/examples/prisma-schema.example.prisma +3 -3
- package/examples/redis-persistence.ts +67 -73
- package/examples/route-transitions.ts +71 -47
- package/examples/rules-prohibitions.ts +28 -28
- package/examples/streaming-agent.ts +24 -24
- package/examples/travel-agent.ts +94 -109
- package/package.json +1 -1
- package/src/adapters/MemoryAdapter.ts +3 -3
- package/src/adapters/MongoAdapter.ts +3 -3
- package/src/adapters/OpenSearchAdapter.ts +8 -8
- package/src/adapters/PostgreSQLAdapter.ts +10 -10
- package/src/adapters/PrismaAdapter.ts +4 -4
- package/src/adapters/RedisAdapter.ts +3 -3
- package/src/adapters/SQLiteAdapter.ts +15 -15
- package/src/adapters/index.ts +1 -1
- package/src/constants/index.ts +4 -4
- package/src/core/Agent.ts +210 -206
- package/src/core/Events.ts +12 -12
- package/src/core/PersistenceManager.ts +32 -36
- package/src/core/ResponseEngine.ts +11 -17
- package/src/core/Route.ts +55 -49
- package/src/core/RoutingEngine.ts +244 -252
- package/src/core/Step.ts +197 -0
- package/src/core/ToolExecutor.ts +11 -11
- package/src/core/Transition.ts +72 -26
- package/src/index.ts +8 -8
- package/src/types/agent.ts +8 -8
- package/src/types/ai.ts +2 -2
- package/src/types/history.ts +3 -3
- package/src/types/index.ts +1 -1
- package/src/types/persistence.ts +6 -6
- package/src/types/route.ts +77 -61
- package/src/types/session.ts +75 -78
- package/src/types/tool.ts +17 -17
- package/src/utils/id.ts +15 -6
- package/dist/cjs/core/State.d.ts +0 -72
- package/dist/cjs/core/State.d.ts.map +0 -1
- package/dist/cjs/core/State.js +0 -148
- package/dist/cjs/core/State.js.map +0 -1
- package/dist/core/State.d.ts +0 -72
- package/dist/core/State.d.ts.map +0 -1
- package/dist/core/State.js +0 -144
- package/dist/core/State.js.map +0 -1
- package/docs/STATES.md +0 -888
- package/src/core/State.ts +0 -212
|
@@ -11,10 +11,10 @@ class RoutingEngine {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Optimized decision for single-route scenarios
|
|
14
|
-
* Skips route scoring and only does
|
|
14
|
+
* Skips route scoring and only does step selection
|
|
15
15
|
* @private
|
|
16
16
|
*/
|
|
17
|
-
async
|
|
17
|
+
async decideSingleRouteStep(params) {
|
|
18
18
|
const { route, session, history, agentMeta, ai, context, signal } = params;
|
|
19
19
|
let updatedSession = session;
|
|
20
20
|
const selectedRoute = route;
|
|
@@ -22,237 +22,237 @@ class RoutingEngine {
|
|
|
22
22
|
if (!session.currentRoute || session.currentRoute.id !== route.id) {
|
|
23
23
|
updatedSession = (0, session_1.enterRoute)(session, route.id, route.title);
|
|
24
24
|
if (route.initialData) {
|
|
25
|
-
updatedSession = (0, session_1.
|
|
25
|
+
updatedSession = (0, session_1.mergeCollected)(updatedSession, route.initialData);
|
|
26
26
|
logger_1.logger.debug(`[RoutingEngine] Single-route: Merged initial data:`, route.initialData);
|
|
27
27
|
}
|
|
28
28
|
logger_1.logger.debug(`[RoutingEngine] Single-route: Entered route: ${route.title}`);
|
|
29
29
|
}
|
|
30
|
-
// Get candidate
|
|
31
|
-
const
|
|
32
|
-
? route.
|
|
30
|
+
// Get candidate steps
|
|
31
|
+
const currentStep = updatedSession.currentStep
|
|
32
|
+
? route.getStep(updatedSession.currentStep.id)
|
|
33
33
|
: undefined;
|
|
34
|
-
const candidates = this.
|
|
34
|
+
const candidates = this.getCandidateSteps(route, currentStep, updatedSession.data || {});
|
|
35
35
|
if (candidates.length === 0) {
|
|
36
|
-
logger_1.logger.warn(`[RoutingEngine] Single-route: No valid
|
|
36
|
+
logger_1.logger.warn(`[RoutingEngine] Single-route: No valid steps found`);
|
|
37
37
|
return { selectedRoute, session: updatedSession };
|
|
38
38
|
}
|
|
39
39
|
// If only one candidate, check if route is complete
|
|
40
40
|
if (candidates.length === 1) {
|
|
41
41
|
const isRouteComplete = candidates[0].isRouteComplete;
|
|
42
42
|
if (isRouteComplete) {
|
|
43
|
-
logger_1.logger.debug(`[RoutingEngine] Single-route: Route complete - all data collected,
|
|
44
|
-
// Don't return a
|
|
43
|
+
logger_1.logger.debug(`[RoutingEngine] Single-route: Route complete - all data collected, END_ROUTE reached`);
|
|
44
|
+
// Don't return a selectedStep when route is complete - there's no step to enter
|
|
45
45
|
return {
|
|
46
46
|
selectedRoute,
|
|
47
|
-
|
|
47
|
+
selectedStep: undefined,
|
|
48
48
|
session: updatedSession,
|
|
49
49
|
isRouteComplete: true,
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
|
-
logger_1.logger.debug(`[RoutingEngine] Single-route: Only one valid
|
|
53
|
+
logger_1.logger.debug(`[RoutingEngine] Single-route: Only one valid step: ${candidates[0].step.id}`);
|
|
54
54
|
return {
|
|
55
55
|
selectedRoute,
|
|
56
|
-
|
|
56
|
+
selectedStep: candidates[0].step,
|
|
57
57
|
session: updatedSession,
|
|
58
58
|
isRouteComplete: false,
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
// Multiple candidates - use AI to select best
|
|
62
|
+
// Multiple candidates - use AI to select best step
|
|
63
63
|
const lastUserMessage = (0, event_1.getLastMessageFromHistory)(history);
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
prompt:
|
|
64
|
+
const stepPrompt = this.buildStepSelectionPrompt(route, currentStep, candidates, updatedSession.data || {}, history, lastUserMessage, agentMeta);
|
|
65
|
+
const stepSchema = this.buildStepSelectionSchema(candidates.map((c) => c.step.id));
|
|
66
|
+
const stepResult = await ai.generateMessage({
|
|
67
|
+
prompt: stepPrompt,
|
|
68
68
|
history,
|
|
69
69
|
context,
|
|
70
70
|
signal,
|
|
71
71
|
parameters: {
|
|
72
|
-
jsonSchema:
|
|
73
|
-
schemaName: "
|
|
72
|
+
jsonSchema: stepSchema,
|
|
73
|
+
schemaName: "step_selection",
|
|
74
74
|
},
|
|
75
75
|
});
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
79
|
-
logger_1.logger.debug(`[RoutingEngine] Single-route: AI selected
|
|
80
|
-
logger_1.logger.debug(`[RoutingEngine] Single-route: Reasoning: ${
|
|
76
|
+
const selectedStepId = stepResult.structured?.selectedStepId;
|
|
77
|
+
const selectedStep = candidates.find((c) => c.step.id === selectedStepId)?.step;
|
|
78
|
+
if (selectedStep) {
|
|
79
|
+
logger_1.logger.debug(`[RoutingEngine] Single-route: AI selected step: ${selectedStep.id}`);
|
|
80
|
+
logger_1.logger.debug(`[RoutingEngine] Single-route: Reasoning: ${stepResult.structured?.reasoning}`);
|
|
81
81
|
}
|
|
82
82
|
else {
|
|
83
|
-
logger_1.logger.warn(`[RoutingEngine] Single-route: Invalid
|
|
83
|
+
logger_1.logger.warn(`[RoutingEngine] Single-route: Invalid step ID returned, using first candidate`);
|
|
84
84
|
}
|
|
85
85
|
return {
|
|
86
86
|
selectedRoute,
|
|
87
|
-
|
|
88
|
-
responseDirectives:
|
|
87
|
+
selectedStep: selectedStep || candidates[0].step,
|
|
88
|
+
responseDirectives: stepResult.structured?.responseDirectives,
|
|
89
89
|
session: updatedSession,
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
|
-
* Recursively traverse
|
|
93
|
+
* Recursively traverse step chain to find first non-skipped step or END_ROUTE
|
|
94
94
|
* @private
|
|
95
95
|
*/
|
|
96
|
-
|
|
96
|
+
findFirstValidStepRecursive(currentStep, data, visited) {
|
|
97
97
|
// Prevent infinite loops
|
|
98
|
-
if (visited.has(
|
|
98
|
+
if (visited.has(currentStep.id)) {
|
|
99
99
|
return {};
|
|
100
100
|
}
|
|
101
|
-
visited.add(
|
|
102
|
-
const transitions =
|
|
101
|
+
visited.add(currentStep.id);
|
|
102
|
+
const transitions = currentStep.getTransitions();
|
|
103
103
|
for (const transition of transitions) {
|
|
104
104
|
const target = transition.getTarget();
|
|
105
|
-
// Check for
|
|
105
|
+
// Check for END_ROUTE transition
|
|
106
106
|
if (!target &&
|
|
107
|
-
transition.spec.
|
|
108
|
-
typeof transition.spec.
|
|
109
|
-
// Found
|
|
107
|
+
transition.spec.step &&
|
|
108
|
+
typeof transition.spec.step === "symbol") {
|
|
109
|
+
// Found END_ROUTE - route is complete
|
|
110
110
|
return {
|
|
111
|
-
isRouteComplete: true
|
|
111
|
+
isRouteComplete: true,
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
if (!target)
|
|
115
115
|
continue;
|
|
116
|
-
// If target should NOT be skipped, we found our
|
|
117
|
-
if (!target.shouldSkip(
|
|
118
|
-
logger_1.logger.debug(`[RoutingEngine] Found valid
|
|
116
|
+
// If target should NOT be skipped, we found our step
|
|
117
|
+
if (!target.shouldSkip(data)) {
|
|
118
|
+
logger_1.logger.debug(`[RoutingEngine] Found valid step after skipping: ${target.id}`);
|
|
119
119
|
return {
|
|
120
|
-
|
|
120
|
+
step: target,
|
|
121
121
|
condition: transition.condition,
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
// Target should be skipped too - recurse deeper
|
|
125
|
-
logger_1.logger.debug(`[RoutingEngine] Skipping
|
|
126
|
-
const result = this.
|
|
127
|
-
// If we found something (a valid
|
|
128
|
-
if (result.
|
|
125
|
+
logger_1.logger.debug(`[RoutingEngine] Skipping step ${target.id} (skipIf condition met), continuing traversal...`);
|
|
126
|
+
const result = this.findFirstValidStepRecursive(target, data, visited);
|
|
127
|
+
// If we found something (a valid step or END_ROUTE), return it
|
|
128
|
+
if (result.step || result.isRouteComplete) {
|
|
129
129
|
return result;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
// No valid
|
|
132
|
+
// No valid steps or END_ROUTE found in this branch
|
|
133
133
|
return {};
|
|
134
134
|
}
|
|
135
135
|
/**
|
|
136
|
-
* Identify valid next candidate
|
|
137
|
-
* Returns
|
|
136
|
+
* Identify valid next candidate steps based on current step and collected data
|
|
137
|
+
* Returns step with isRouteComplete flag if route is complete (all steps skipped + has END_ROUTE transition)
|
|
138
138
|
*/
|
|
139
|
-
|
|
139
|
+
getCandidateSteps(route, currentStep, data) {
|
|
140
140
|
const candidates = [];
|
|
141
|
-
if (!
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
144
|
-
// Initial
|
|
145
|
-
const result = this.
|
|
141
|
+
if (!currentStep) {
|
|
142
|
+
const initialStep = route.initialStep;
|
|
143
|
+
if (initialStep.shouldSkip(data)) {
|
|
144
|
+
// Initial step should be skipped - recursively traverse to find first non-skipped step or END_ROUTE
|
|
145
|
+
const result = this.findFirstValidStepRecursive(initialStep, data, new Set());
|
|
146
146
|
if (result.isRouteComplete) {
|
|
147
|
-
// All
|
|
148
|
-
logger_1.logger.debug(`[RoutingEngine] Route complete on entry: all
|
|
147
|
+
// All steps are skipped and we reached END_ROUTE
|
|
148
|
+
logger_1.logger.debug(`[RoutingEngine] Route complete on entry: all steps skipped, END_ROUTE reached`);
|
|
149
149
|
return [
|
|
150
150
|
{
|
|
151
|
-
|
|
151
|
+
step: initialStep,
|
|
152
152
|
condition: "Route complete - all data collected on entry",
|
|
153
153
|
isRouteComplete: true,
|
|
154
154
|
},
|
|
155
155
|
];
|
|
156
156
|
}
|
|
157
|
-
else if (result.
|
|
158
|
-
// Found a non-skipped
|
|
157
|
+
else if (result.step) {
|
|
158
|
+
// Found a non-skipped step
|
|
159
159
|
candidates.push({
|
|
160
|
-
|
|
160
|
+
step: result.step,
|
|
161
161
|
condition: result.condition,
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
requires: result.step.requires,
|
|
163
|
+
collectFields: result.step.collectFields,
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
|
-
// If no
|
|
166
|
+
// If no step found and not complete, fall through to return empty candidates
|
|
167
167
|
}
|
|
168
168
|
else {
|
|
169
169
|
candidates.push({
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
step: initialStep,
|
|
171
|
+
requires: initialStep.requires,
|
|
172
|
+
collectFields: initialStep.collectFields,
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
return candidates;
|
|
176
176
|
}
|
|
177
|
-
const transitions =
|
|
177
|
+
const transitions = currentStep.getTransitions();
|
|
178
178
|
let hasEndRoute = false;
|
|
179
179
|
for (const transition of transitions) {
|
|
180
180
|
const target = transition.getTarget();
|
|
181
|
-
// Check for
|
|
181
|
+
// Check for END_ROUTE transition (no target step)
|
|
182
182
|
if (!target &&
|
|
183
|
-
transition.spec.
|
|
184
|
-
typeof transition.spec.
|
|
183
|
+
transition.spec.step &&
|
|
184
|
+
typeof transition.spec.step === "symbol") {
|
|
185
185
|
hasEndRoute = true;
|
|
186
186
|
continue;
|
|
187
187
|
}
|
|
188
188
|
if (!target)
|
|
189
189
|
continue;
|
|
190
|
-
if (target.shouldSkip(
|
|
191
|
-
logger_1.logger.debug(`[RoutingEngine] Skipping
|
|
192
|
-
// Recursively traverse to find next valid
|
|
193
|
-
const result = this.
|
|
190
|
+
if (target.shouldSkip(data)) {
|
|
191
|
+
logger_1.logger.debug(`[RoutingEngine] Skipping step ${target.id} (skipIf condition met)`);
|
|
192
|
+
// Recursively traverse to find next valid step or END_ROUTE
|
|
193
|
+
const result = this.findFirstValidStepRecursive(target, data, new Set([currentStep.id]) // Already visited current step
|
|
194
194
|
);
|
|
195
195
|
if (result.isRouteComplete) {
|
|
196
196
|
hasEndRoute = true;
|
|
197
197
|
}
|
|
198
|
-
else if (result.
|
|
199
|
-
// Found a non-skipped
|
|
198
|
+
else if (result.step) {
|
|
199
|
+
// Found a non-skipped step deeper in the chain
|
|
200
200
|
candidates.push({
|
|
201
|
-
|
|
201
|
+
step: result.step,
|
|
202
202
|
condition: result.condition || transition.condition,
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
requires: result.step.requires,
|
|
204
|
+
collectFields: result.step.collectFields,
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
207
|
continue;
|
|
208
208
|
}
|
|
209
209
|
candidates.push({
|
|
210
|
-
|
|
210
|
+
step: target,
|
|
211
211
|
condition: transition.condition,
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
requires: target.requires,
|
|
213
|
+
collectFields: target.collectFields,
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
// If no valid candidates found
|
|
217
217
|
if (candidates.length === 0) {
|
|
218
|
-
// If current
|
|
218
|
+
// If current step has END_ROUTE transition, the route is complete
|
|
219
219
|
if (hasEndRoute) {
|
|
220
|
-
logger_1.logger.debug(`[RoutingEngine] Route complete: all
|
|
221
|
-
// Return current
|
|
220
|
+
logger_1.logger.debug(`[RoutingEngine] Route complete: all steps processed, END_ROUTE reached`);
|
|
221
|
+
// Return current step with completion flag
|
|
222
222
|
return [
|
|
223
223
|
{
|
|
224
|
-
|
|
224
|
+
step: currentStep,
|
|
225
225
|
condition: "Route complete - all data collected",
|
|
226
226
|
isRouteComplete: true,
|
|
227
227
|
},
|
|
228
228
|
];
|
|
229
229
|
}
|
|
230
|
-
// Otherwise, stay in current
|
|
231
|
-
if (!
|
|
230
|
+
// Otherwise, stay in current step if it's still valid
|
|
231
|
+
if (!currentStep.shouldSkip(data)) {
|
|
232
232
|
candidates.push({
|
|
233
|
-
|
|
234
|
-
condition: "Continue in current
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
step: currentStep,
|
|
234
|
+
condition: "Continue in current step (no valid transitions)",
|
|
235
|
+
requires: currentStep.requires,
|
|
236
|
+
collectFields: currentStep.collectFields,
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
return candidates;
|
|
241
241
|
}
|
|
242
242
|
/**
|
|
243
|
-
* Full routing orchestration: builds prompt and schema, calls AI, selects route/
|
|
243
|
+
* Full routing orchestration: builds prompt and schema, calls AI, selects route/step,
|
|
244
244
|
* and updates the session (including initialData merge when entering a new route).
|
|
245
245
|
*
|
|
246
|
-
* OPTIMIZATION: If there's only 1 route, skips route scoring and only does
|
|
246
|
+
* OPTIMIZATION: If there's only 1 route, skips route scoring and only does step selection.
|
|
247
247
|
*/
|
|
248
|
-
async
|
|
248
|
+
async decideRouteAndStep(params) {
|
|
249
249
|
const { routes, session, history, agentMeta, ai, context, signal } = params;
|
|
250
250
|
if (routes.length === 0) {
|
|
251
251
|
return { session };
|
|
252
252
|
}
|
|
253
|
-
// OPTIMIZATION: Single route - skip route scoring, only do
|
|
253
|
+
// OPTIMIZATION: Single route - skip route scoring, only do step selection
|
|
254
254
|
if (routes.length === 1) {
|
|
255
|
-
return this.
|
|
255
|
+
return this.decideSingleRouteStep({
|
|
256
256
|
route: routes[0],
|
|
257
257
|
session,
|
|
258
258
|
history,
|
|
@@ -263,37 +263,37 @@ class RoutingEngine {
|
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
265
|
const lastUserMessage = (0, event_1.getLastMessageFromHistory)(history);
|
|
266
|
-
let
|
|
266
|
+
let activeRouteSteps;
|
|
267
267
|
let activeRoute;
|
|
268
268
|
let isRouteComplete = false;
|
|
269
269
|
if (session.currentRoute) {
|
|
270
270
|
activeRoute = routes.find((r) => r.id === session.currentRoute?.id);
|
|
271
271
|
if (activeRoute) {
|
|
272
|
-
const
|
|
273
|
-
? activeRoute.
|
|
272
|
+
const currentStep = session.currentStep
|
|
273
|
+
? activeRoute.getStep(session.currentStep.id)
|
|
274
274
|
: undefined;
|
|
275
|
-
const candidates = this.
|
|
275
|
+
const candidates = this.getCandidateSteps(activeRoute, currentStep, session.data || {});
|
|
276
276
|
// Check if route is complete
|
|
277
277
|
if (candidates.length === 1 && candidates[0].isRouteComplete) {
|
|
278
278
|
isRouteComplete = true;
|
|
279
279
|
logger_1.logger.debug(`[RoutingEngine] Route ${activeRoute.title} is complete - all data collected`);
|
|
280
|
-
// Don't include
|
|
281
|
-
|
|
280
|
+
// Don't include steps in routing if route is complete
|
|
281
|
+
activeRouteSteps = undefined;
|
|
282
282
|
}
|
|
283
283
|
else {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
description: c.
|
|
284
|
+
activeRouteSteps = candidates.map((c) => ({
|
|
285
|
+
stepId: c.step.id,
|
|
286
|
+
description: c.step.description || "",
|
|
287
287
|
condition: c.condition,
|
|
288
|
-
|
|
289
|
-
|
|
288
|
+
requires: c.requires,
|
|
289
|
+
collectFields: c.collectFields,
|
|
290
290
|
}));
|
|
291
|
-
logger_1.logger.debug(`[RoutingEngine] Found ${
|
|
291
|
+
logger_1.logger.debug(`[RoutingEngine] Found ${activeRouteSteps.length} candidate steps for active route`);
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
|
-
const routingSchema = this.buildDynamicRoutingSchema(routes, undefined,
|
|
296
|
-
const routingPrompt = this.buildRoutingPrompt(history, routes, lastUserMessage, agentMeta, session,
|
|
295
|
+
const routingSchema = this.buildDynamicRoutingSchema(routes, undefined, activeRouteSteps);
|
|
296
|
+
const routingPrompt = this.buildRoutingPrompt(history, routes, lastUserMessage, agentMeta, session, activeRouteSteps);
|
|
297
297
|
const routingResult = await ai.generateMessage({
|
|
298
298
|
prompt: routingPrompt,
|
|
299
299
|
history,
|
|
@@ -305,7 +305,7 @@ class RoutingEngine {
|
|
|
305
305
|
},
|
|
306
306
|
});
|
|
307
307
|
let selectedRoute;
|
|
308
|
-
let
|
|
308
|
+
let selectedStep;
|
|
309
309
|
let responseDirectives;
|
|
310
310
|
let updatedSession = session;
|
|
311
311
|
if (routingResult.structured?.routes) {
|
|
@@ -317,12 +317,12 @@ class RoutingEngine {
|
|
|
317
317
|
selectedRoute = routes.find((r) => r.id === decision.routeId);
|
|
318
318
|
responseDirectives = routingResult.structured.responseDirectives;
|
|
319
319
|
if (selectedRoute === activeRoute &&
|
|
320
|
-
routingResult.structured.
|
|
320
|
+
routingResult.structured.selectedStepId &&
|
|
321
321
|
activeRoute) {
|
|
322
|
-
|
|
323
|
-
if (
|
|
324
|
-
logger_1.logger.debug(`[RoutingEngine] AI selected
|
|
325
|
-
logger_1.logger.debug(`[RoutingEngine]
|
|
322
|
+
selectedStep = activeRoute.getStep(routingResult.structured.selectedStepId);
|
|
323
|
+
if (selectedStep) {
|
|
324
|
+
logger_1.logger.debug(`[RoutingEngine] AI selected step: ${selectedStep.id} in active route`);
|
|
325
|
+
logger_1.logger.debug(`[RoutingEngine] Step reasoning: ${routingResult.structured.stepReasoning}`);
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
if (selectedRoute) {
|
|
@@ -331,7 +331,7 @@ class RoutingEngine {
|
|
|
331
331
|
session.currentRoute.id !== selectedRoute.id) {
|
|
332
332
|
updatedSession = (0, session_1.enterRoute)(session, selectedRoute.id, selectedRoute.title);
|
|
333
333
|
if (selectedRoute.initialData) {
|
|
334
|
-
updatedSession = (0, session_1.
|
|
334
|
+
updatedSession = (0, session_1.mergeCollected)(updatedSession, selectedRoute.initialData);
|
|
335
335
|
logger_1.logger.debug(`[RoutingEngine] Merged initial data:`, selectedRoute.initialData);
|
|
336
336
|
}
|
|
337
337
|
logger_1.logger.debug(`[RoutingEngine] Entered route: ${selectedRoute.title}`);
|
|
@@ -340,17 +340,17 @@ class RoutingEngine {
|
|
|
340
340
|
}
|
|
341
341
|
return {
|
|
342
342
|
selectedRoute,
|
|
343
|
-
|
|
343
|
+
selectedStep,
|
|
344
344
|
responseDirectives,
|
|
345
345
|
session: updatedSession,
|
|
346
346
|
isRouteComplete,
|
|
347
347
|
};
|
|
348
348
|
}
|
|
349
349
|
/**
|
|
350
|
-
* Build prompt for
|
|
350
|
+
* Build prompt for step selection within a single route
|
|
351
351
|
* @private
|
|
352
352
|
*/
|
|
353
|
-
|
|
353
|
+
buildStepSelectionPrompt(route, currentStep, candidates, data, history, lastMessage, agentMeta) {
|
|
354
354
|
const pc = new PromptComposer_1.PromptComposer();
|
|
355
355
|
// Add agent metadata
|
|
356
356
|
if (agentMeta?.name || agentMeta?.goal || agentMeta?.description) {
|
|
@@ -364,79 +364,79 @@ class RoutingEngine {
|
|
|
364
364
|
pc.addPersonality(personality);
|
|
365
365
|
// Add route context
|
|
366
366
|
pc.addInstruction(`Active Route: ${route.title}\nDescription: ${route.description || "N/A"}`);
|
|
367
|
-
// Add current
|
|
368
|
-
if (
|
|
369
|
-
pc.addInstruction(`Current
|
|
367
|
+
// Add current step context
|
|
368
|
+
if (currentStep) {
|
|
369
|
+
pc.addInstruction(`Current Step: ${currentStep.id}\nDescription: ${currentStep.description || "N/A"}`);
|
|
370
370
|
}
|
|
371
371
|
else {
|
|
372
|
-
pc.addInstruction("Current
|
|
372
|
+
pc.addInstruction("Current Step: None (entering route)");
|
|
373
373
|
}
|
|
374
|
-
// Add
|
|
375
|
-
if (Object.keys(
|
|
376
|
-
pc.addInstruction(`
|
|
374
|
+
// Add collected data context
|
|
375
|
+
if (Object.keys(data).length > 0) {
|
|
376
|
+
pc.addInstruction(`Collected Data So Far:\n${JSON.stringify(data, null, 2)}`);
|
|
377
377
|
}
|
|
378
378
|
else {
|
|
379
|
-
pc.addInstruction("
|
|
379
|
+
pc.addInstruction("Collected Data: None yet");
|
|
380
380
|
}
|
|
381
381
|
// Add conversation history
|
|
382
382
|
pc.addInteractionHistory(history);
|
|
383
383
|
pc.addLastMessage(lastMessage);
|
|
384
|
-
// Add candidate
|
|
385
|
-
const
|
|
384
|
+
// Add candidate steps
|
|
385
|
+
const stepDescriptions = candidates.map((candidate, idx) => {
|
|
386
386
|
const parts = [
|
|
387
|
-
`${idx + 1}.
|
|
388
|
-
` Description: ${candidate.
|
|
387
|
+
`${idx + 1}. Step ID: ${candidate.step.id}`,
|
|
388
|
+
` Description: ${candidate.step.description || "N/A"}`,
|
|
389
389
|
];
|
|
390
390
|
if (candidate.condition) {
|
|
391
391
|
parts.push(` Condition: ${candidate.condition}`);
|
|
392
392
|
}
|
|
393
|
-
if (candidate.
|
|
394
|
-
parts.push(` Required Data: ${candidate.
|
|
393
|
+
if (candidate.requires && candidate.requires.length > 0) {
|
|
394
|
+
parts.push(` Required Data: ${candidate.requires.join(", ")}`);
|
|
395
395
|
}
|
|
396
|
-
if (candidate.
|
|
397
|
-
parts.push(`
|
|
396
|
+
if (candidate.collectFields && candidate.collectFields.length > 0) {
|
|
397
|
+
parts.push(` Collects: ${candidate.collectFields.join(", ")}`);
|
|
398
398
|
}
|
|
399
399
|
return parts.join("\n");
|
|
400
400
|
});
|
|
401
|
-
pc.addInstruction(`Available
|
|
401
|
+
pc.addInstruction(`Available Steps to Transition To:\n${stepDescriptions.join("\n\n")}`);
|
|
402
402
|
// Add decision instructions
|
|
403
403
|
pc.addInstruction([
|
|
404
|
-
"Task: Decide which
|
|
404
|
+
"Task: Decide which step to transition to based on:",
|
|
405
405
|
"1. The user's current message and intent",
|
|
406
406
|
"2. The conversation history and context",
|
|
407
|
-
"3. The
|
|
408
|
-
"4. The conditions and requirements of each
|
|
407
|
+
"3. The collected data we already have",
|
|
408
|
+
"4. The conditions and requirements of each step",
|
|
409
409
|
"5. The logical flow of the conversation",
|
|
410
410
|
"",
|
|
411
411
|
"Rules:",
|
|
412
|
-
"- If a
|
|
413
|
-
"- If a
|
|
414
|
-
"- Choose the
|
|
415
|
-
"-
|
|
412
|
+
"- If a step has a condition, evaluate whether it's met based on context",
|
|
413
|
+
"- If a step requires data we don't have, consider if we should collect it now",
|
|
414
|
+
"- Choose the step that makes the most sense for moving the conversation forward",
|
|
415
|
+
"- Steps with skipIf conditions that are met have already been filtered out",
|
|
416
416
|
"",
|
|
417
417
|
"Return ONLY JSON matching the provided schema.",
|
|
418
418
|
].join("\n"));
|
|
419
419
|
return pc.build();
|
|
420
420
|
}
|
|
421
421
|
/**
|
|
422
|
-
* Build schema for
|
|
422
|
+
* Build schema for step selection
|
|
423
423
|
* @private
|
|
424
424
|
*/
|
|
425
|
-
|
|
425
|
+
buildStepSelectionSchema(validStepIds) {
|
|
426
426
|
return {
|
|
427
|
-
description: "
|
|
427
|
+
description: "Step transition decision based on conversation context and collected data",
|
|
428
428
|
type: "object",
|
|
429
429
|
properties: {
|
|
430
430
|
reasoning: {
|
|
431
431
|
type: "string",
|
|
432
432
|
nullable: false,
|
|
433
|
-
description: "Brief explanation of why this
|
|
433
|
+
description: "Brief explanation of why this step was selected",
|
|
434
434
|
},
|
|
435
|
-
|
|
435
|
+
selectedStepId: {
|
|
436
436
|
type: "string",
|
|
437
437
|
nullable: false,
|
|
438
|
-
description: "The ID of the selected
|
|
439
|
-
enum:
|
|
438
|
+
description: "The ID of the selected step to transition to",
|
|
439
|
+
enum: validStepIds,
|
|
440
440
|
},
|
|
441
441
|
responseDirectives: {
|
|
442
442
|
type: "array",
|
|
@@ -444,11 +444,11 @@ class RoutingEngine {
|
|
|
444
444
|
description: "Optional bullet points the response should address (concise)",
|
|
445
445
|
},
|
|
446
446
|
},
|
|
447
|
-
required: ["reasoning", "
|
|
447
|
+
required: ["reasoning", "selectedStepId"],
|
|
448
448
|
additionalProperties: false,
|
|
449
449
|
};
|
|
450
450
|
}
|
|
451
|
-
buildDynamicRoutingSchema(routes, extrasSchema,
|
|
451
|
+
buildDynamicRoutingSchema(routes, extrasSchema, activeRouteSteps) {
|
|
452
452
|
const routeIds = routes.map((r) => r.id);
|
|
453
453
|
const routeProperties = {};
|
|
454
454
|
for (const id of routeIds) {
|
|
@@ -485,24 +485,24 @@ class RoutingEngine {
|
|
|
485
485
|
required: ["context", "routes"],
|
|
486
486
|
additionalProperties: false,
|
|
487
487
|
};
|
|
488
|
-
// Add
|
|
489
|
-
if (
|
|
488
|
+
// Add step selection fields if there's an active route with steps
|
|
489
|
+
if (activeRouteSteps && activeRouteSteps.length > 0) {
|
|
490
490
|
base.properties = base.properties || {};
|
|
491
|
-
base.properties.
|
|
491
|
+
base.properties.selectedStepId = {
|
|
492
492
|
type: "string",
|
|
493
493
|
nullable: false,
|
|
494
|
-
description: "The
|
|
495
|
-
enum:
|
|
494
|
+
description: "The step ID to transition to within the active route (required if continuing in current route)",
|
|
495
|
+
enum: activeRouteSteps.map((s) => s.stepId),
|
|
496
496
|
};
|
|
497
|
-
base.properties.
|
|
497
|
+
base.properties.stepReasoning = {
|
|
498
498
|
type: "string",
|
|
499
499
|
nullable: false,
|
|
500
|
-
description: "Brief explanation of why this
|
|
500
|
+
description: "Brief explanation of why this step was selected",
|
|
501
501
|
};
|
|
502
502
|
base.required = [
|
|
503
503
|
...(base.required || []),
|
|
504
|
-
"
|
|
505
|
-
"
|
|
504
|
+
"selectedStepId",
|
|
505
|
+
"stepReasoning",
|
|
506
506
|
];
|
|
507
507
|
}
|
|
508
508
|
if (extrasSchema) {
|
|
@@ -511,7 +511,7 @@ class RoutingEngine {
|
|
|
511
511
|
}
|
|
512
512
|
return base;
|
|
513
513
|
}
|
|
514
|
-
buildRoutingPrompt(history, routes, lastMessage, agentMeta, session,
|
|
514
|
+
buildRoutingPrompt(history, routes, lastMessage, agentMeta, session, activeRouteSteps) {
|
|
515
515
|
const pc = new PromptComposer_1.PromptComposer();
|
|
516
516
|
if (agentMeta?.name || agentMeta?.goal || agentMeta?.description) {
|
|
517
517
|
pc.addAgentMeta({
|
|
@@ -529,45 +529,45 @@ class RoutingEngine {
|
|
|
529
529
|
"Current conversation context:",
|
|
530
530
|
`- Active route: ${session.currentRoute.title} (${session.currentRoute.id})`,
|
|
531
531
|
];
|
|
532
|
-
if (session.
|
|
533
|
-
sessionInfo.push(`- Current
|
|
534
|
-
if (session.
|
|
535
|
-
sessionInfo.push(` "${session.
|
|
532
|
+
if (session.currentStep) {
|
|
533
|
+
sessionInfo.push(`- Current step: ${session.currentStep.id}`);
|
|
534
|
+
if (session.currentStep.description) {
|
|
535
|
+
sessionInfo.push(` "${session.currentStep.description}"`);
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
|
-
if (session.
|
|
539
|
-
sessionInfo.push(`-
|
|
538
|
+
if (session.data && Object.keys(session.data).length > 0) {
|
|
539
|
+
sessionInfo.push(`- Collected data: ${JSON.stringify(session.data)}`);
|
|
540
540
|
}
|
|
541
541
|
sessionInfo.push("Note: User is mid-conversation. They may want to continue current route or switch to a new one based on their intent.");
|
|
542
542
|
pc.addInstruction(sessionInfo.join("\n"));
|
|
543
|
-
// Add available
|
|
544
|
-
if (
|
|
545
|
-
const
|
|
543
|
+
// Add available steps for the active route
|
|
544
|
+
if (activeRouteSteps && activeRouteSteps.length > 0) {
|
|
545
|
+
const stepInfo = [
|
|
546
546
|
"",
|
|
547
|
-
"Available
|
|
547
|
+
"Available steps in active route (choose one to transition to):",
|
|
548
548
|
];
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
if (
|
|
552
|
-
|
|
549
|
+
activeRouteSteps.forEach((step, idx) => {
|
|
550
|
+
stepInfo.push(`${idx + 1}. Step: ${step.stepId}`);
|
|
551
|
+
if (step.description) {
|
|
552
|
+
stepInfo.push(` Description: ${step.description}`);
|
|
553
553
|
}
|
|
554
|
-
if (
|
|
555
|
-
|
|
554
|
+
if (step.condition) {
|
|
555
|
+
stepInfo.push(` Condition: ${step.condition}`);
|
|
556
556
|
}
|
|
557
|
-
if (
|
|
558
|
-
|
|
557
|
+
if (step.requires && step.requires.length > 0) {
|
|
558
|
+
stepInfo.push(` Required data: ${step.requires.join(", ")}`);
|
|
559
559
|
}
|
|
560
|
-
if (
|
|
561
|
-
|
|
560
|
+
if (step.collectFields && step.collectFields.length > 0) {
|
|
561
|
+
stepInfo.push(` Will collect: ${step.collectFields.join(", ")}`);
|
|
562
562
|
}
|
|
563
563
|
});
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
pc.addInstruction(
|
|
564
|
+
stepInfo.push("");
|
|
565
|
+
stepInfo.push("IMPORTANT: You MUST select a step to transition to. Evaluate which step makes the most sense based on:");
|
|
566
|
+
stepInfo.push("- The conversation flow and what's been collected");
|
|
567
|
+
stepInfo.push("- What data is still needed vs already present");
|
|
568
|
+
stepInfo.push("- The logical next step in the conversation");
|
|
569
|
+
stepInfo.push("- Whether conditions for steps are met");
|
|
570
|
+
pc.addInstruction(stepInfo.join("\n"));
|
|
571
571
|
}
|
|
572
572
|
}
|
|
573
573
|
pc.addInteractionHistory(history);
|