@aj-archipelago/cortex 1.3.63 → 1.3.65
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 +50 -1
- package/lib/entityConstants.js +1 -1
- package/lib/pathwayManager.js +140 -12
- package/package.json +1 -1
- package/pathways/system/entity/memory/shared/sys_memory_helpers.js +1 -1
- package/pathways/system/entity/memory/sys_memory_manager.js +1 -1
- package/pathways/system/entity/sys_entity_agent.js +18 -5
- package/pathways/system/entity/sys_generator_results.js +1 -1
- package/server/graphql.js +173 -8
- package/server/pathwayResolver.js +10 -2
- package/server/plugins/gemini15VisionPlugin.js +3 -1
- package/server/plugins/openAiVisionPlugin.js +3 -1
- package/server/prompt.js +2 -1
- package/server/typeDef.js +1 -1
- package/tests/helpers/sseClient.js +1 -1
- package/tests/unit/core/pathwayManager.test.js +768 -0
- package/tests/unit/plugins/toolCallBufferFiltering.test.js +297 -0
- package/tests/unit/server/graphql.test.js +170 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import OpenAIVisionPlugin from '../../../server/plugins/openAiVisionPlugin.js';
|
|
3
|
+
import Gemini15VisionPlugin from '../../../server/plugins/gemini15VisionPlugin.js';
|
|
4
|
+
import { PathwayResolver } from '../../../server/pathwayResolver.js';
|
|
5
|
+
import { config } from '../../../config.js';
|
|
6
|
+
import { requestState } from '../../../server/requestState.js';
|
|
7
|
+
|
|
8
|
+
// Mock logger to prevent issues in tests
|
|
9
|
+
const mockLogger = {
|
|
10
|
+
debug: () => {},
|
|
11
|
+
info: () => {},
|
|
12
|
+
warn: () => {},
|
|
13
|
+
error: () => {}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Mock the logger module globally
|
|
17
|
+
global.logger = mockLogger;
|
|
18
|
+
|
|
19
|
+
function createResolverWithPlugin(pluginClass, modelName = 'test-model') {
|
|
20
|
+
const pluginToModelType = {
|
|
21
|
+
OpenAIVisionPlugin: 'OPENAI-VISION',
|
|
22
|
+
Gemini15VisionPlugin: 'GEMINI-1.5-VISION'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const modelType = pluginToModelType[pluginClass.name];
|
|
26
|
+
if (!modelType) {
|
|
27
|
+
throw new Error(`Unknown plugin class: ${pluginClass.name}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const pathway = {
|
|
31
|
+
name: 'test-pathway',
|
|
32
|
+
model: modelName,
|
|
33
|
+
prompt: 'test prompt',
|
|
34
|
+
toolCallback: () => {} // Mock tool callback
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const model = {
|
|
38
|
+
name: modelName,
|
|
39
|
+
type: modelType
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const resolver = new PathwayResolver({
|
|
43
|
+
config,
|
|
44
|
+
pathway,
|
|
45
|
+
args: {},
|
|
46
|
+
endpoints: { [modelName]: model }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
resolver.modelExecutor.plugin = new pluginClass(pathway, model);
|
|
50
|
+
return resolver;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
test('OpenAIVisionPlugin - filters undefined tool calls from buffer', async t => {
|
|
54
|
+
const resolver = createResolverWithPlugin(OpenAIVisionPlugin);
|
|
55
|
+
const plugin = resolver.modelExecutor.plugin;
|
|
56
|
+
|
|
57
|
+
// Simulate the scenario where tool calls start at index 1, leaving index 0 undefined
|
|
58
|
+
plugin.toolCallsBuffer[0] = undefined; // This is what causes the issue
|
|
59
|
+
plugin.toolCallsBuffer[1] = {
|
|
60
|
+
id: 'call_1_1234567890',
|
|
61
|
+
type: 'function',
|
|
62
|
+
function: {
|
|
63
|
+
name: 'test_tool',
|
|
64
|
+
arguments: '{"param": "value"}'
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Mock the tool callback to capture what gets passed
|
|
69
|
+
let capturedToolCalls = null;
|
|
70
|
+
plugin.pathwayToolCallback = (args, message, resolver) => {
|
|
71
|
+
capturedToolCalls = message.tool_calls;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Mock requestProgress and pathwayResolver
|
|
75
|
+
const requestProgress = { progress: 0, started: true };
|
|
76
|
+
const pathwayResolver = { args: {} };
|
|
77
|
+
|
|
78
|
+
// Mock requestState to return our resolver
|
|
79
|
+
requestState[plugin.requestId] = { pathwayResolver };
|
|
80
|
+
|
|
81
|
+
// Simulate a tool_calls finish reason
|
|
82
|
+
const event = {
|
|
83
|
+
data: JSON.stringify({
|
|
84
|
+
choices: [{
|
|
85
|
+
finish_reason: 'tool_calls'
|
|
86
|
+
}]
|
|
87
|
+
})
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Process the stream event
|
|
91
|
+
plugin.processStreamEvent(event, requestProgress);
|
|
92
|
+
|
|
93
|
+
// Verify that undefined elements were filtered out
|
|
94
|
+
t.truthy(capturedToolCalls, 'Tool callback should have been called');
|
|
95
|
+
t.is(capturedToolCalls.length, 1, 'Should have filtered out undefined elements');
|
|
96
|
+
t.is(capturedToolCalls[0].function.name, 'test_tool', 'Valid tool call should be preserved');
|
|
97
|
+
|
|
98
|
+
// Clean up
|
|
99
|
+
delete requestState[plugin.requestId];
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('OpenAIVisionPlugin - handles empty buffer gracefully', async t => {
|
|
103
|
+
const resolver = createResolverWithPlugin(OpenAIVisionPlugin);
|
|
104
|
+
const plugin = resolver.modelExecutor.plugin;
|
|
105
|
+
|
|
106
|
+
// Empty buffer
|
|
107
|
+
plugin.toolCallsBuffer = [];
|
|
108
|
+
|
|
109
|
+
// Mock the tool callback
|
|
110
|
+
let callbackCalled = false;
|
|
111
|
+
plugin.pathwayToolCallback = () => {
|
|
112
|
+
callbackCalled = true;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Mock requestProgress and pathwayResolver
|
|
116
|
+
const requestProgress = { progress: 0, started: true };
|
|
117
|
+
const pathwayResolver = { args: {} };
|
|
118
|
+
|
|
119
|
+
// Mock requestState
|
|
120
|
+
requestState[plugin.requestId] = { pathwayResolver };
|
|
121
|
+
|
|
122
|
+
// Simulate a tool_calls finish reason
|
|
123
|
+
const event = {
|
|
124
|
+
data: JSON.stringify({
|
|
125
|
+
choices: [{
|
|
126
|
+
finish_reason: 'tool_calls'
|
|
127
|
+
}]
|
|
128
|
+
})
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Process the stream event
|
|
132
|
+
plugin.processStreamEvent(event, requestProgress);
|
|
133
|
+
|
|
134
|
+
// Verify that callback was not called with empty buffer
|
|
135
|
+
t.falsy(callbackCalled, 'Tool callback should not be called with empty buffer');
|
|
136
|
+
|
|
137
|
+
// Clean up
|
|
138
|
+
delete requestState[plugin.requestId];
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('OpenAIVisionPlugin - filters invalid tool calls', async t => {
|
|
142
|
+
const resolver = createResolverWithPlugin(OpenAIVisionPlugin);
|
|
143
|
+
const plugin = resolver.modelExecutor.plugin;
|
|
144
|
+
|
|
145
|
+
// Create buffer with mixed valid and invalid tool calls
|
|
146
|
+
plugin.toolCallsBuffer[0] = undefined;
|
|
147
|
+
plugin.toolCallsBuffer[1] = {
|
|
148
|
+
id: 'call_1_1234567890',
|
|
149
|
+
type: 'function',
|
|
150
|
+
function: {
|
|
151
|
+
name: 'valid_tool',
|
|
152
|
+
arguments: '{"param": "value"}'
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
plugin.toolCallsBuffer[2] = {
|
|
156
|
+
id: 'call_2_1234567890',
|
|
157
|
+
type: 'function',
|
|
158
|
+
function: {
|
|
159
|
+
name: '', // Invalid: empty name
|
|
160
|
+
arguments: '{"param": "value"}'
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
plugin.toolCallsBuffer[3] = {
|
|
164
|
+
id: 'call_3_1234567890',
|
|
165
|
+
type: 'function',
|
|
166
|
+
function: {
|
|
167
|
+
name: 'another_valid_tool',
|
|
168
|
+
arguments: '{"param": "value"}'
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Mock the tool callback
|
|
173
|
+
let capturedToolCalls = null;
|
|
174
|
+
plugin.pathwayToolCallback = (args, message, resolver) => {
|
|
175
|
+
capturedToolCalls = message.tool_calls;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Mock requestProgress and pathwayResolver
|
|
179
|
+
const requestProgress = { progress: 0, started: true };
|
|
180
|
+
const pathwayResolver = { args: {} };
|
|
181
|
+
|
|
182
|
+
// Mock requestState
|
|
183
|
+
requestState[plugin.requestId] = { pathwayResolver };
|
|
184
|
+
|
|
185
|
+
// Simulate a tool_calls finish reason
|
|
186
|
+
const event = {
|
|
187
|
+
data: JSON.stringify({
|
|
188
|
+
choices: [{
|
|
189
|
+
finish_reason: 'tool_calls'
|
|
190
|
+
}]
|
|
191
|
+
})
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Process the stream event
|
|
195
|
+
plugin.processStreamEvent(event, requestProgress);
|
|
196
|
+
|
|
197
|
+
// Verify that only valid tool calls were passed
|
|
198
|
+
t.truthy(capturedToolCalls, 'Tool callback should have been called');
|
|
199
|
+
t.is(capturedToolCalls.length, 2, 'Should have filtered out invalid elements');
|
|
200
|
+
t.is(capturedToolCalls[0].function.name, 'valid_tool', 'First valid tool call should be preserved');
|
|
201
|
+
t.is(capturedToolCalls[1].function.name, 'another_valid_tool', 'Second valid tool call should be preserved');
|
|
202
|
+
|
|
203
|
+
// Clean up
|
|
204
|
+
delete requestState[plugin.requestId];
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('Gemini15VisionPlugin - filters undefined tool calls from buffer', async t => {
|
|
208
|
+
const resolver = createResolverWithPlugin(Gemini15VisionPlugin);
|
|
209
|
+
const plugin = resolver.modelExecutor.plugin;
|
|
210
|
+
|
|
211
|
+
// Simulate buffer with undefined elements (though less likely with push method)
|
|
212
|
+
plugin.toolCallsBuffer = [
|
|
213
|
+
undefined,
|
|
214
|
+
{
|
|
215
|
+
id: 'call_1_1234567890',
|
|
216
|
+
type: 'function',
|
|
217
|
+
function: {
|
|
218
|
+
name: 'test_tool',
|
|
219
|
+
arguments: '{"param": "value"}'
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
// Mock the tool callback
|
|
225
|
+
let capturedToolCalls = null;
|
|
226
|
+
plugin.pathwayToolCallback = (args, message, resolver) => {
|
|
227
|
+
capturedToolCalls = message.tool_calls;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Mock requestProgress and pathwayResolver
|
|
231
|
+
const requestProgress = { progress: 0, started: true };
|
|
232
|
+
const pathwayResolver = { args: {} };
|
|
233
|
+
|
|
234
|
+
// Mock requestState
|
|
235
|
+
requestState[plugin.requestId] = { pathwayResolver };
|
|
236
|
+
|
|
237
|
+
// Simulate a tool_calls finish reason
|
|
238
|
+
const eventData = {
|
|
239
|
+
candidates: [{
|
|
240
|
+
finishReason: 'STOP'
|
|
241
|
+
}]
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Set hadToolCalls to true to trigger tool_calls finish reason
|
|
245
|
+
plugin.hadToolCalls = true;
|
|
246
|
+
|
|
247
|
+
// Process the stream event
|
|
248
|
+
plugin.processStreamEvent({ data: JSON.stringify(eventData) }, requestProgress);
|
|
249
|
+
|
|
250
|
+
// Verify that undefined elements were filtered out
|
|
251
|
+
t.truthy(capturedToolCalls, 'Tool callback should have been called');
|
|
252
|
+
t.is(capturedToolCalls.length, 1, 'Should have filtered out undefined elements');
|
|
253
|
+
t.is(capturedToolCalls[0].function.name, 'test_tool', 'Valid tool call should be preserved');
|
|
254
|
+
|
|
255
|
+
// Clean up
|
|
256
|
+
delete requestState[plugin.requestId];
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('Gemini15VisionPlugin - handles empty buffer gracefully', async t => {
|
|
260
|
+
const resolver = createResolverWithPlugin(Gemini15VisionPlugin);
|
|
261
|
+
const plugin = resolver.modelExecutor.plugin;
|
|
262
|
+
|
|
263
|
+
// Empty buffer
|
|
264
|
+
plugin.toolCallsBuffer = [];
|
|
265
|
+
|
|
266
|
+
// Mock the tool callback
|
|
267
|
+
let callbackCalled = false;
|
|
268
|
+
plugin.pathwayToolCallback = () => {
|
|
269
|
+
callbackCalled = true;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Mock requestProgress and pathwayResolver
|
|
273
|
+
const requestProgress = { progress: 0, started: true };
|
|
274
|
+
const pathwayResolver = { args: {} };
|
|
275
|
+
|
|
276
|
+
// Mock requestState
|
|
277
|
+
requestState[plugin.requestId] = { pathwayResolver };
|
|
278
|
+
|
|
279
|
+
// Simulate a tool_calls finish reason
|
|
280
|
+
const eventData = {
|
|
281
|
+
candidates: [{
|
|
282
|
+
finishReason: 'STOP'
|
|
283
|
+
}]
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// Set hadToolCalls to true
|
|
287
|
+
plugin.hadToolCalls = true;
|
|
288
|
+
|
|
289
|
+
// Process the stream event
|
|
290
|
+
plugin.processStreamEvent({ data: JSON.stringify(eventData) }, requestProgress);
|
|
291
|
+
|
|
292
|
+
// Verify that callback was not called with empty buffer
|
|
293
|
+
t.falsy(callbackCalled, 'Tool callback should not be called with empty buffer');
|
|
294
|
+
|
|
295
|
+
// Clean up
|
|
296
|
+
delete requestState[plugin.requestId];
|
|
297
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import { getResolvers } from '../../../server/graphql.js';
|
|
4
|
+
|
|
5
|
+
// Mock logger to avoid actual logging during tests
|
|
6
|
+
const mockLogger = {
|
|
7
|
+
info: sinon.stub(),
|
|
8
|
+
debug: sinon.stub(),
|
|
9
|
+
error: sinon.stub(),
|
|
10
|
+
warn: sinon.stub()
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Mock config
|
|
14
|
+
const mockConfig = {
|
|
15
|
+
get: sinon.stub().returns('test-value')
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
test.beforeEach(t => {
|
|
19
|
+
// Reset stubs before each test
|
|
20
|
+
sinon.restore();
|
|
21
|
+
mockLogger.info.resetHistory();
|
|
22
|
+
mockLogger.debug.resetHistory();
|
|
23
|
+
mockLogger.error.resetHistory();
|
|
24
|
+
mockLogger.warn.resetHistory();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('executeWorkspace throws error for legacy format with promptNames', async t => {
|
|
28
|
+
// Mock pathwayManager
|
|
29
|
+
const mockPathwayManager = {
|
|
30
|
+
getLatestPathways: sinon.stub().resolves({
|
|
31
|
+
'test-user': {
|
|
32
|
+
'test-pathway': {
|
|
33
|
+
prompt: ['legacy string prompt 1', 'legacy string prompt 2'], // Legacy format
|
|
34
|
+
systemPrompt: 'Test system prompt'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}),
|
|
38
|
+
isLegacyPromptFormat: sinon.stub().returns(true), // Mock returns true for legacy format
|
|
39
|
+
getResolvers: sinon.stub().returns({ Mutation: {} }) // Mock getResolvers method
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Get the resolvers function (need to mock the import first)
|
|
43
|
+
const resolvers = getResolvers(mockConfig, {}, mockPathwayManager);
|
|
44
|
+
const executeWorkspaceResolver = resolvers.Query.executeWorkspace;
|
|
45
|
+
|
|
46
|
+
// Mock GraphQL context and info
|
|
47
|
+
const mockContextValue = { config: mockConfig };
|
|
48
|
+
const mockInfo = {};
|
|
49
|
+
|
|
50
|
+
// Test arguments - userId, pathwayName, promptNames are the key ones
|
|
51
|
+
const args = {
|
|
52
|
+
userId: 'test-user',
|
|
53
|
+
pathwayName: 'test-pathway',
|
|
54
|
+
promptNames: ['specific-prompt'], // This triggers the check
|
|
55
|
+
text: 'test input'
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Execute the resolver and expect it to throw
|
|
59
|
+
const error = await t.throwsAsync(async () => {
|
|
60
|
+
await executeWorkspaceResolver(null, args, mockContextValue, mockInfo);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Verify the error message
|
|
64
|
+
t.truthy(error);
|
|
65
|
+
t.true(error.message.includes('legacy prompt format'));
|
|
66
|
+
t.true(error.message.includes('unpublish and republish'));
|
|
67
|
+
t.true(error.message.includes('promptNames parameter'));
|
|
68
|
+
t.true(error.message.includes('test-pathway')); // Should include the pathway name
|
|
69
|
+
|
|
70
|
+
// Verify that the pathwayManager methods were called correctly
|
|
71
|
+
t.true(mockPathwayManager.getLatestPathways.calledOnce);
|
|
72
|
+
t.true(mockPathwayManager.isLegacyPromptFormat.calledOnce);
|
|
73
|
+
t.true(mockPathwayManager.isLegacyPromptFormat.calledWith('test-user', 'test-pathway'));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('executeWorkspace does not throw for new format with promptNames', async t => {
|
|
77
|
+
// Mock pathwayManager with new format
|
|
78
|
+
const mockPathwayManager = {
|
|
79
|
+
getLatestPathways: sinon.stub().resolves({
|
|
80
|
+
'test-user': {
|
|
81
|
+
'test-pathway': {
|
|
82
|
+
prompt: [
|
|
83
|
+
{ name: 'Prompt 1', prompt: 'New format prompt 1' },
|
|
84
|
+
{ name: 'Prompt 2', prompt: 'New format prompt 2' }
|
|
85
|
+
], // New format
|
|
86
|
+
systemPrompt: 'Test system prompt'
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}),
|
|
90
|
+
isLegacyPromptFormat: sinon.stub().returns(false), // Mock returns false for new format
|
|
91
|
+
getPathways: sinon.stub().resolves([
|
|
92
|
+
{
|
|
93
|
+
name: 'specific-prompt',
|
|
94
|
+
prompt: [/* mock prompt object */],
|
|
95
|
+
rootResolver: sinon.stub().resolves({ result: 'test result' })
|
|
96
|
+
}
|
|
97
|
+
]),
|
|
98
|
+
getResolvers: sinon.stub().returns({ Mutation: {} }) // Mock getResolvers method
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const resolvers = getResolvers(mockConfig, {}, mockPathwayManager);
|
|
102
|
+
const executeWorkspaceResolver = resolvers.Query.executeWorkspace;
|
|
103
|
+
|
|
104
|
+
const mockContextValue = { config: mockConfig };
|
|
105
|
+
const mockInfo = {};
|
|
106
|
+
|
|
107
|
+
const args = {
|
|
108
|
+
userId: 'test-user',
|
|
109
|
+
pathwayName: 'test-pathway',
|
|
110
|
+
promptNames: ['specific-prompt'],
|
|
111
|
+
text: 'test input'
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// This should not throw an error for new format
|
|
115
|
+
const result = await executeWorkspaceResolver(null, args, mockContextValue, mockInfo);
|
|
116
|
+
|
|
117
|
+
// Should return results without error
|
|
118
|
+
t.truthy(result);
|
|
119
|
+
t.is(typeof result, 'object');
|
|
120
|
+
t.false(Array.isArray(result));
|
|
121
|
+
|
|
122
|
+
// Verify that the pathwayManager methods were called correctly
|
|
123
|
+
t.true(mockPathwayManager.getLatestPathways.calledOnce);
|
|
124
|
+
t.true(mockPathwayManager.isLegacyPromptFormat.calledOnce);
|
|
125
|
+
t.true(mockPathwayManager.getPathways.calledOnce);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('executeWorkspace does not check format when promptNames not provided', async t => {
|
|
129
|
+
// Mock pathwayManager with legacy format
|
|
130
|
+
const mockPathwayManager = {
|
|
131
|
+
getLatestPathways: sinon.stub().resolves({
|
|
132
|
+
'test-user': {
|
|
133
|
+
'test-pathway': {
|
|
134
|
+
prompt: ['legacy string prompt 1', 'legacy string prompt 2'], // Legacy format
|
|
135
|
+
systemPrompt: 'Test system prompt'
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}),
|
|
139
|
+
isLegacyPromptFormat: sinon.stub(), // Should not be called
|
|
140
|
+
getPathway: sinon.stub().resolves({
|
|
141
|
+
rootResolver: sinon.stub().resolves({ result: 'test result' })
|
|
142
|
+
}),
|
|
143
|
+
getResolvers: sinon.stub().returns({ Mutation: {} }) // Mock getResolvers method
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const resolvers = getResolvers(mockConfig, {}, mockPathwayManager);
|
|
147
|
+
const executeWorkspaceResolver = resolvers.Query.executeWorkspace;
|
|
148
|
+
|
|
149
|
+
const mockContextValue = { config: mockConfig };
|
|
150
|
+
const mockInfo = {};
|
|
151
|
+
|
|
152
|
+
const args = {
|
|
153
|
+
userId: 'test-user',
|
|
154
|
+
pathwayName: 'test-pathway',
|
|
155
|
+
// No promptNames provided - should use default behavior
|
|
156
|
+
text: 'test input'
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// This should not throw an error even with legacy format when promptNames not provided
|
|
160
|
+
const result = await executeWorkspaceResolver(null, args, mockContextValue, mockInfo);
|
|
161
|
+
|
|
162
|
+
// Should return results without error
|
|
163
|
+
t.truthy(result);
|
|
164
|
+
t.is(typeof result, 'object');
|
|
165
|
+
t.false(Array.isArray(result));
|
|
166
|
+
|
|
167
|
+
// Verify that isLegacyPromptFormat was NOT called since promptNames wasn't provided
|
|
168
|
+
t.false(mockPathwayManager.isLegacyPromptFormat.called);
|
|
169
|
+
t.true(mockPathwayManager.getPathway.calledOnce);
|
|
170
|
+
});
|