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