@lowdefy/api 0.0.0-experimental-20260420104522 → 0.0.0-experimental-20260420135540
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/routes/agent/callAgent.js +114 -70
- package/package.json +9 -8
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { serializer, type } from '@lowdefy/helpers';
|
|
16
|
+
import { createPhaseLogger } from '@lowdefy/ai-utils';
|
|
16
17
|
import createEvaluateOperators from '../../context/createEvaluateOperators.js';
|
|
17
18
|
import authorizeApiEndpoint from '../endpoints/authorizeApiEndpoint.js';
|
|
18
19
|
import getEndpointConfig from '../endpoints/getEndpointConfig.js';
|
|
@@ -21,18 +22,30 @@ import getAgentConfig from './getAgentConfig.js';
|
|
|
21
22
|
import getAgentResolver from './getAgentResolver.js';
|
|
22
23
|
import getConnectionConfig from '../request/getConnectionConfig.js';
|
|
23
24
|
import getConnection from '../request/getConnection.js';
|
|
24
|
-
async function callAgent(context, { agentId, pageId, messages, conversationId, urlQuery, sharedState }) {
|
|
25
|
+
async function callAgent(context, { agentId, pageId, messages, conversationId, urlQuery, sharedState, phaseLogger: ingressPhaseLogger, turnId }) {
|
|
25
26
|
const { logger } = context;
|
|
26
27
|
context.pageId = pageId;
|
|
27
28
|
context.evaluateOperators = createEvaluateOperators(context);
|
|
29
|
+
// Use the ingress-provided phase logger when present so turnId/turnStart are
|
|
30
|
+
// continuous with the HTTP-ingress logs. Fall back to a fresh logger so
|
|
31
|
+
// internal callers of callAgent still get structured output.
|
|
32
|
+
const phaseLogger = ingressPhaseLogger ?? createPhaseLogger({
|
|
33
|
+
logger,
|
|
34
|
+
agentId,
|
|
35
|
+
pageId,
|
|
36
|
+
conversationId: conversationId ?? undefined,
|
|
37
|
+
turnId
|
|
38
|
+
});
|
|
39
|
+
context.phaseLogger = phaseLogger;
|
|
28
40
|
logger.debug({
|
|
29
41
|
event: 'debug_agent',
|
|
30
42
|
agentId,
|
|
31
43
|
pageId
|
|
32
44
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
phaseLogger.phase('handler.entry');
|
|
46
|
+
const agentConfig = await phaseLogger.time('config.agent.load', ()=>getAgentConfig(context, {
|
|
47
|
+
agentId
|
|
48
|
+
}));
|
|
36
49
|
const agentContext = {
|
|
37
50
|
conversationId: conversationId ?? undefined,
|
|
38
51
|
pageId,
|
|
@@ -41,75 +54,88 @@ async function callAgent(context, { agentId, pageId, messages, conversationId, u
|
|
|
41
54
|
userId: context.user?.sub ?? context.user?.id ?? null
|
|
42
55
|
};
|
|
43
56
|
// Evaluate operators in agent properties (e.g. _user, _secret, _payload)
|
|
44
|
-
agentConfig.properties = context.evaluateOperators({
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
agentConfig.properties = await phaseLogger.time('operators.agent.properties', ()=>context.evaluateOperators({
|
|
58
|
+
input: agentConfig.properties ?? {},
|
|
59
|
+
location: agentConfig.agentId,
|
|
60
|
+
payload: agentContext,
|
|
61
|
+
steps: {}
|
|
62
|
+
}));
|
|
50
63
|
// Load connection config from build artifacts using agent's connectionId
|
|
51
|
-
const connectionConfig = await getConnectionConfig(context, {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
const connectionConfig = await phaseLogger.time('config.connection.load', ()=>getConnectionConfig(context, {
|
|
65
|
+
requestConfig: {
|
|
66
|
+
connectionId: agentConfig.connectionId,
|
|
67
|
+
requestId: agentConfig.agentId,
|
|
68
|
+
'~k': agentConfig['~k']
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
58
71
|
// Get connection plugin from registry
|
|
59
72
|
const connection = getConnection(context, {
|
|
60
73
|
connectionConfig
|
|
61
74
|
});
|
|
62
75
|
// Evaluate operators in connection properties
|
|
63
|
-
const connectionProperties = context.evaluateOperators({
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
const connectionProperties = await phaseLogger.time('operators.connection.properties', ()=>context.evaluateOperators({
|
|
77
|
+
input: connectionConfig.properties || {},
|
|
78
|
+
location: connectionConfig.connectionId,
|
|
79
|
+
payload: {},
|
|
80
|
+
steps: {}
|
|
81
|
+
}));
|
|
69
82
|
// Create connection instance (e.g., Anthropic provider)
|
|
70
|
-
const connectionInstance = connection.create({
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
const connectionInstance = await phaseLogger.time('connection.instantiate', ()=>Promise.resolve(connection.create({
|
|
84
|
+
connection: connectionProperties
|
|
85
|
+
})));
|
|
73
86
|
// Get agent type from plugin registry
|
|
74
87
|
const agentType = getAgentResolver(context, {
|
|
75
88
|
agentConfig
|
|
76
89
|
});
|
|
90
|
+
phaseLogger.phase('resolver.lookup.done', {
|
|
91
|
+
type: agentConfig.type
|
|
92
|
+
});
|
|
77
93
|
// Build resolver context with callEndpoint that allows InternalApi endpoints
|
|
78
94
|
const resolverContext = {
|
|
79
95
|
agentContext,
|
|
96
|
+
phaseLogger,
|
|
80
97
|
evaluateOperators: (input)=>context.evaluateOperators({
|
|
81
98
|
input,
|
|
82
99
|
location: agentConfig.agentId,
|
|
83
100
|
payload: agentContext,
|
|
84
101
|
steps: {}
|
|
85
102
|
}),
|
|
86
|
-
callEndpoint: async (endpointId, { payload, abortSignal })=>{
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
endpointConfig
|
|
103
|
+
callEndpoint: async (endpointId, { payload, abortSignal, kind = 'tool' } = {})=>{
|
|
104
|
+
const prefix = kind === 'hook' ? 'hook.endpoint' : 'tool.endpoint';
|
|
105
|
+
const callLog = phaseLogger.child({
|
|
106
|
+
endpointId,
|
|
107
|
+
kind
|
|
92
108
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
return callLog.time(`${prefix}.exec`, async ()=>{
|
|
110
|
+
const endpointConfig = await callLog.time(`${prefix}.config.load`, ()=>getEndpointConfig(context, {
|
|
111
|
+
endpointId
|
|
112
|
+
}));
|
|
113
|
+
authorizeApiEndpoint(context, {
|
|
114
|
+
endpointConfig
|
|
115
|
+
});
|
|
116
|
+
const routineContext = {
|
|
117
|
+
steps: {},
|
|
118
|
+
payload: payload ?? {},
|
|
119
|
+
arrayIndices: [],
|
|
120
|
+
items: {},
|
|
121
|
+
endpointDepth: 0
|
|
122
|
+
};
|
|
123
|
+
const { error, response, status } = await runRoutine(context, routineContext, {
|
|
124
|
+
routine: endpointConfig.routine
|
|
125
|
+
});
|
|
126
|
+
const success = ![
|
|
127
|
+
'error',
|
|
128
|
+
'reject'
|
|
129
|
+
].includes(status);
|
|
130
|
+
return {
|
|
131
|
+
error: serializer.serialize(error),
|
|
132
|
+
response: serializer.serialize(response),
|
|
133
|
+
status: success ? 'success' : status,
|
|
134
|
+
success
|
|
135
|
+
};
|
|
136
|
+
}, {
|
|
137
|
+
hasPayload: payload != null
|
|
102
138
|
});
|
|
103
|
-
const success = ![
|
|
104
|
-
'error',
|
|
105
|
-
'reject'
|
|
106
|
-
].includes(status);
|
|
107
|
-
return {
|
|
108
|
-
error: serializer.serialize(error),
|
|
109
|
-
response: serializer.serialize(response),
|
|
110
|
-
status: success ? 'success' : status,
|
|
111
|
-
success
|
|
112
|
-
};
|
|
113
139
|
},
|
|
114
140
|
getEndpointConfig: async ({ endpointId })=>{
|
|
115
141
|
return getEndpointConfig(context, {
|
|
@@ -181,28 +207,39 @@ async function callAgent(context, { agentId, pageId, messages, conversationId, u
|
|
|
181
207
|
// Agent-level overrides (like confirm) may still contain operators —
|
|
182
208
|
// handleAgentChat evaluates those via its existing evaluateOperators call.
|
|
183
209
|
const resolvedMcp = [];
|
|
184
|
-
|
|
210
|
+
const mcpSources = agentConfig.mcp ?? [];
|
|
211
|
+
phaseLogger.phase('mcp.sources.resolve.start', {
|
|
212
|
+
sourceCount: mcpSources.length
|
|
213
|
+
});
|
|
214
|
+
for(let i = 0; i < mcpSources.length; i += 1){
|
|
215
|
+
const mcpSource = mcpSources[i];
|
|
185
216
|
if (!type.isNone(mcpSource.connectionId)) {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
requestId: agentConfig.agentId,
|
|
190
|
-
'~k': agentConfig['~k']
|
|
191
|
-
}
|
|
217
|
+
const mcpLog = phaseLogger.child({
|
|
218
|
+
mcpIndex: i,
|
|
219
|
+
connectionId: mcpSource.connectionId
|
|
192
220
|
});
|
|
193
|
-
|
|
194
|
-
|
|
221
|
+
// eslint-disable-next-line no-await-in-loop
|
|
222
|
+
const mcpConfig = await mcpLog.time('mcp.source.resolve', async ()=>{
|
|
223
|
+
const mcpConnConfig = await getConnectionConfig(context, {
|
|
224
|
+
requestConfig: {
|
|
225
|
+
connectionId: mcpSource.connectionId,
|
|
226
|
+
requestId: agentConfig.agentId,
|
|
227
|
+
'~k': agentConfig['~k']
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const mcpConnection = getConnection(context, {
|
|
231
|
+
connectionConfig: mcpConnConfig
|
|
232
|
+
});
|
|
233
|
+
const mcpConnProps = context.evaluateOperators({
|
|
234
|
+
input: mcpConnConfig.properties || {},
|
|
235
|
+
location: mcpConnConfig.connectionId,
|
|
236
|
+
payload: {},
|
|
237
|
+
steps: {}
|
|
238
|
+
});
|
|
239
|
+
return mcpConnection.create({
|
|
240
|
+
connection: mcpConnProps
|
|
241
|
+
});
|
|
195
242
|
});
|
|
196
|
-
const mcpConnProps = context.evaluateOperators({
|
|
197
|
-
input: mcpConnConfig.properties || {},
|
|
198
|
-
location: mcpConnConfig.connectionId,
|
|
199
|
-
payload: {},
|
|
200
|
-
steps: {}
|
|
201
|
-
});
|
|
202
|
-
const mcpConfig = mcpConnection.create({
|
|
203
|
-
connection: mcpConnProps
|
|
204
|
-
});
|
|
205
|
-
// Merge: connection properties as base, agent-level overrides on top
|
|
206
243
|
const { connectionId: _, ...overrides } = mcpSource;
|
|
207
244
|
resolvedMcp.push({
|
|
208
245
|
...mcpConfig,
|
|
@@ -213,6 +250,12 @@ async function callAgent(context, { agentId, pageId, messages, conversationId, u
|
|
|
213
250
|
}
|
|
214
251
|
}
|
|
215
252
|
agentConfig.mcp = resolvedMcp;
|
|
253
|
+
phaseLogger.phase('mcp.sources.resolve.done', {
|
|
254
|
+
resolvedCount: resolvedMcp.length
|
|
255
|
+
});
|
|
256
|
+
phaseLogger.phase('resolver.dispatch.start', {
|
|
257
|
+
type: agentConfig.type
|
|
258
|
+
});
|
|
216
259
|
// Call the agent resolver
|
|
217
260
|
const { response } = await agentType.resolver({
|
|
218
261
|
connection: connectionInstance,
|
|
@@ -222,6 +265,7 @@ async function callAgent(context, { agentId, pageId, messages, conversationId, u
|
|
|
222
265
|
},
|
|
223
266
|
context: resolverContext
|
|
224
267
|
});
|
|
268
|
+
phaseLogger.phase('resolver.dispatch.returned');
|
|
225
269
|
return {
|
|
226
270
|
response
|
|
227
271
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/api",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-20260420135540",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
"dist/*"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@lowdefy/
|
|
38
|
-
"@lowdefy/
|
|
39
|
-
"@lowdefy/
|
|
40
|
-
"@lowdefy/
|
|
41
|
-
"@lowdefy/
|
|
42
|
-
"@lowdefy/
|
|
43
|
-
"@lowdefy/operators
|
|
37
|
+
"@lowdefy/ai-utils": "0.0.0-experimental-20260420135540",
|
|
38
|
+
"@lowdefy/ajv": "0.0.0-experimental-20260420135540",
|
|
39
|
+
"@lowdefy/errors": "0.0.0-experimental-20260420135540",
|
|
40
|
+
"@lowdefy/helpers": "0.0.0-experimental-20260420135540",
|
|
41
|
+
"@lowdefy/node-utils": "0.0.0-experimental-20260420135540",
|
|
42
|
+
"@lowdefy/nunjucks": "0.0.0-experimental-20260420135540",
|
|
43
|
+
"@lowdefy/operators": "0.0.0-experimental-20260420135540",
|
|
44
|
+
"@lowdefy/operators-js": "0.0.0-experimental-20260420135540"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@jest/globals": "28.1.3",
|