@aj-archipelago/cortex 1.3.46 → 1.3.47
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aj-archipelago/cortex",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.47",
|
|
4
4
|
"description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// sys_entity_agent.js
|
|
2
2
|
// Agentic extension of the entity system that uses OpenAI's tool calling API
|
|
3
|
+
const MAX_TOOL_CALLS = 50;
|
|
4
|
+
|
|
3
5
|
import { callPathway, callTool, say } from '../../../lib/pathwayTools.js';
|
|
4
6
|
import logger from '../../../lib/logger.js';
|
|
5
7
|
import { config } from '../../../config.js';
|
|
6
8
|
import { chatArgsHasImageUrl, removeOldImageAndFileContent } from '../../../lib/util.js';
|
|
7
|
-
import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
|
|
8
9
|
import { Prompt } from '../../../server/prompt.js';
|
|
9
10
|
import { getToolsForEntity, loadEntityConfig } from './tools/shared/sys_entity_tools.js';
|
|
10
11
|
|
|
@@ -41,153 +42,173 @@ export default {
|
|
|
41
42
|
const { tool_calls } = message;
|
|
42
43
|
const pathwayResolver = resolver;
|
|
43
44
|
const { entityTools, entityToolsOpenAiFormat } = args;
|
|
45
|
+
|
|
46
|
+
pathwayResolver.toolCallCount = (pathwayResolver.toolCallCount || 0);
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
const
|
|
48
|
+
const preToolCallMessages = JSON.parse(JSON.stringify(args.chatHistory || []));
|
|
49
|
+
const finalMessages = JSON.parse(JSON.stringify(preToolCallMessages));
|
|
47
50
|
|
|
48
51
|
if (tool_calls) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
if (pathwayResolver.toolCallCount < MAX_TOOL_CALLS) {
|
|
53
|
+
// Execute tool calls in parallel but with isolated message histories
|
|
54
|
+
const toolResults = await Promise.all(tool_calls.map(async (toolCall) => {
|
|
55
|
+
try {
|
|
56
|
+
if (!toolCall?.function?.arguments) {
|
|
57
|
+
throw new Error('Invalid tool call structure: missing function arguments');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const toolArgs = JSON.parse(toolCall.function.arguments);
|
|
61
|
+
const toolFunction = toolCall.function.name.toLowerCase();
|
|
62
|
+
|
|
63
|
+
// Create an isolated copy of messages for this tool
|
|
64
|
+
const toolMessages = JSON.parse(JSON.stringify(preToolCallMessages));
|
|
65
|
+
|
|
66
|
+
// Get the tool definition to check for icon
|
|
67
|
+
const toolDefinition = entityTools[toolFunction]?.definition;
|
|
68
|
+
const toolIcon = toolDefinition?.icon || '🛠️';
|
|
69
|
+
|
|
70
|
+
// Report status to the user
|
|
71
|
+
const toolUserMessage = toolArgs.userMessage || `Executing tool: ${toolCall.function.name} - ${JSON.stringify(toolArgs)}`;
|
|
72
|
+
const messageWithIcon = toolIcon ? `${toolIcon} ${toolUserMessage}` : toolUserMessage;
|
|
73
|
+
await say(pathwayResolver.rootRequestId || pathwayResolver.requestId, `${messageWithIcon}\n\n`, 1000, false);
|
|
74
|
+
|
|
75
|
+
const toolResult = await callTool(toolFunction, {
|
|
76
|
+
...args,
|
|
77
|
+
...toolArgs,
|
|
78
|
+
toolFunction,
|
|
79
|
+
chatHistory: toolMessages,
|
|
80
|
+
stream: false
|
|
81
|
+
}, entityTools, pathwayResolver);
|
|
82
|
+
|
|
83
|
+
// Tool calls and results need to be paired together in the message history
|
|
84
|
+
// Add the tool call to the isolated message history
|
|
85
|
+
toolMessages.push({
|
|
86
|
+
role: "assistant",
|
|
87
|
+
content: "",
|
|
88
|
+
tool_calls: [{
|
|
89
|
+
id: toolCall.id,
|
|
90
|
+
type: "function",
|
|
91
|
+
function: {
|
|
92
|
+
name: toolCall.function.name,
|
|
93
|
+
arguments: JSON.stringify(toolArgs)
|
|
94
|
+
}
|
|
95
|
+
}]
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Add the tool result to the isolated message history
|
|
99
|
+
const toolResultContent = typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult?.result || toolResult);
|
|
55
100
|
|
|
56
|
-
const toolArgs = JSON.parse(toolCall.function.arguments);
|
|
57
|
-
const toolFunction = toolCall.function.name.toLowerCase();
|
|
58
|
-
|
|
59
|
-
// Create an isolated copy of messages for this tool
|
|
60
|
-
const toolMessages = JSON.parse(JSON.stringify(initialMessages));
|
|
61
|
-
|
|
62
|
-
// Get the tool definition to check for icon
|
|
63
|
-
const toolDefinition = entityTools[toolFunction]?.definition;
|
|
64
|
-
const toolIcon = toolDefinition?.icon || '🛠️';
|
|
65
|
-
|
|
66
|
-
// Report status to the user
|
|
67
|
-
const toolUserMessage = toolArgs.userMessage || `Executing tool: ${toolCall.function.name} - ${JSON.stringify(toolArgs)}`;
|
|
68
|
-
const messageWithIcon = toolIcon ? `${toolIcon} ${toolUserMessage}` : toolUserMessage;
|
|
69
|
-
await say(pathwayResolver.rootRequestId || pathwayResolver.requestId, `${messageWithIcon}\n\n`, 1000, false);
|
|
70
|
-
|
|
71
|
-
const toolResult = await callTool(toolFunction, {
|
|
72
|
-
...args,
|
|
73
|
-
...toolArgs,
|
|
74
|
-
toolFunction,
|
|
75
|
-
chatHistory: toolMessages,
|
|
76
|
-
stream: false
|
|
77
|
-
}, entityTools, pathwayResolver);
|
|
78
|
-
|
|
79
|
-
// Tool calls and results need to be paired together in the message history
|
|
80
|
-
// Add the tool call to the isolated message history
|
|
81
|
-
toolMessages.push({
|
|
82
|
-
role: "assistant",
|
|
83
|
-
content: "",
|
|
84
|
-
tool_calls: [{
|
|
85
|
-
id: toolCall.id,
|
|
86
|
-
type: "function",
|
|
87
|
-
function: {
|
|
88
|
-
name: toolCall.function.name,
|
|
89
|
-
arguments: JSON.stringify(toolArgs)
|
|
90
|
-
}
|
|
91
|
-
}]
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Add the tool result to the isolated message history
|
|
95
|
-
const toolResultContent = typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult?.result || toolResult);
|
|
96
|
-
|
|
97
|
-
toolMessages.push({
|
|
98
|
-
role: "tool",
|
|
99
|
-
tool_call_id: toolCall.id,
|
|
100
|
-
name: toolCall.function.name,
|
|
101
|
-
content: toolResultContent
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// Add the screenshots using OpenAI image format
|
|
105
|
-
if (toolResult?.toolImages && toolResult.toolImages.length > 0) {
|
|
106
101
|
toolMessages.push({
|
|
107
|
-
role: "
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
text: "The tool with id " + toolCall.id + " has also supplied you with these images."
|
|
112
|
-
},
|
|
113
|
-
...toolResult.toolImages.map(toolImage => ({
|
|
114
|
-
type: "image_url",
|
|
115
|
-
image_url: {
|
|
116
|
-
url: `data:image/png;base64,${toolImage}`
|
|
117
|
-
}
|
|
118
|
-
}))
|
|
119
|
-
]
|
|
102
|
+
role: "tool",
|
|
103
|
+
tool_call_id: toolCall.id,
|
|
104
|
+
name: toolCall.function.name,
|
|
105
|
+
content: toolResultContent
|
|
120
106
|
});
|
|
121
|
-
}
|
|
122
107
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
name:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
108
|
+
// Add the screenshots using OpenAI image format
|
|
109
|
+
if (toolResult?.toolImages && toolResult.toolImages.length > 0) {
|
|
110
|
+
toolMessages.push({
|
|
111
|
+
role: "user",
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: "The tool with id " + toolCall.id + " has also supplied you with these images."
|
|
116
|
+
},
|
|
117
|
+
...toolResult.toolImages.map(toolImage => ({
|
|
118
|
+
type: "image_url",
|
|
119
|
+
image_url: {
|
|
120
|
+
url: `data:image/png;base64,${toolImage}`
|
|
121
|
+
}
|
|
122
|
+
}))
|
|
123
|
+
]
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
success: true,
|
|
129
|
+
result: toolResult,
|
|
130
|
+
toolCall,
|
|
131
|
+
toolArgs,
|
|
132
|
+
toolFunction,
|
|
133
|
+
messages: toolMessages
|
|
134
|
+
};
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logger.error(`Error executing tool ${toolCall?.function?.name || 'unknown'}: ${error.message}`);
|
|
137
|
+
|
|
138
|
+
// Create error message history
|
|
139
|
+
const errorMessages = JSON.parse(JSON.stringify(preToolCallMessages));
|
|
140
|
+
errorMessages.push({
|
|
141
|
+
role: "assistant",
|
|
142
|
+
content: "",
|
|
143
|
+
tool_calls: [{
|
|
144
|
+
id: toolCall.id,
|
|
145
|
+
type: "function",
|
|
146
|
+
function: {
|
|
147
|
+
name: toolCall.function.name,
|
|
148
|
+
arguments: JSON.stringify(toolCall.function.arguments)
|
|
149
|
+
}
|
|
150
|
+
}]
|
|
151
|
+
});
|
|
152
|
+
errorMessages.push({
|
|
153
|
+
role: "tool",
|
|
154
|
+
tool_call_id: toolCall.id,
|
|
155
|
+
name: toolCall.function.name,
|
|
156
|
+
content: `Error: ${error.message}`
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
success: false,
|
|
161
|
+
error: error.message,
|
|
162
|
+
toolCall,
|
|
163
|
+
toolArgs: toolCall?.function?.arguments ? JSON.parse(toolCall.function.arguments) : {},
|
|
164
|
+
toolFunction: toolCall?.function?.name?.toLowerCase() || 'unknown',
|
|
165
|
+
messages: errorMessages
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
// Merge all message histories in order
|
|
171
|
+
for (const result of toolResults) {
|
|
172
|
+
try {
|
|
173
|
+
if (!result?.messages) {
|
|
174
|
+
logger.error('Invalid tool result structure, skipping message history update');
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Add only the new messages from this tool's history
|
|
179
|
+
const newMessages = result.messages.slice(preToolCallMessages.length);
|
|
180
|
+
finalMessages.push(...newMessages);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
logger.error(`Error merging message history for tool result: ${error.message}`);
|
|
173
183
|
}
|
|
184
|
+
}
|
|
174
185
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
logger.error(`Error merging message history for tool result: ${error.message}`);
|
|
186
|
+
// Check if any tool calls failed
|
|
187
|
+
const failedTools = toolResults.filter(result => !result.success);
|
|
188
|
+
if (failedTools.length > 0) {
|
|
189
|
+
logger.warn(`Some tool calls failed: ${failedTools.map(t => t.error).join(', ')}`);
|
|
180
190
|
}
|
|
181
|
-
}
|
|
182
191
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
pathwayResolver.toolCallCount = (pathwayResolver.toolCallCount || 0) + toolResults.length;
|
|
193
|
+
|
|
194
|
+
} else {
|
|
195
|
+
finalMessages.push({
|
|
196
|
+
role: "user",
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: "text",
|
|
200
|
+
text: "This agent has reached the maximum number of tool calls - no more tool calls will be executed."
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
|
|
187
205
|
}
|
|
188
206
|
|
|
189
207
|
args.chatHistory = finalMessages;
|
|
190
208
|
|
|
209
|
+
// clear any accumulated pathwayResolver errors from the tools
|
|
210
|
+
pathwayResolver.errors = [];
|
|
211
|
+
|
|
191
212
|
return await pathwayResolver.promptAndParse({
|
|
192
213
|
...args,
|
|
193
214
|
tools: entityToolsOpenAiFormat,
|
|
@@ -89,12 +89,24 @@ class PathwayResolver {
|
|
|
89
89
|
responseData = await this.executePathway(args);
|
|
90
90
|
}
|
|
91
91
|
catch (error) {
|
|
92
|
+
this.errors.push(error.message || error.toString());
|
|
92
93
|
publishRequestProgress({
|
|
93
94
|
requestId: this.rootRequestId || this.requestId,
|
|
94
95
|
progress: 1,
|
|
95
96
|
data: '',
|
|
96
97
|
info: '',
|
|
97
|
-
error:
|
|
98
|
+
error: this.errors.join(', ')
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!responseData) {
|
|
104
|
+
publishRequestProgress({
|
|
105
|
+
requestId: this.rootRequestId || this.requestId,
|
|
106
|
+
progress: 1,
|
|
107
|
+
data: '',
|
|
108
|
+
info: '',
|
|
109
|
+
error: this.errors.join(', ')
|
|
98
110
|
});
|
|
99
111
|
return;
|
|
100
112
|
}
|
|
@@ -113,7 +125,8 @@ class PathwayResolver {
|
|
|
113
125
|
progress: Math.min(completedCount, totalCount) / totalCount,
|
|
114
126
|
// Clients expect these to be strings
|
|
115
127
|
data: JSON.stringify(responseData || ''),
|
|
116
|
-
info: this.tool || ''
|
|
128
|
+
info: this.tool || '',
|
|
129
|
+
error: this.errors.join(', ') || ''
|
|
117
130
|
});
|
|
118
131
|
}
|
|
119
132
|
}
|
|
@@ -84,7 +84,14 @@ class OpenAIVisionPlugin extends OpenAIChatPlugin {
|
|
|
84
84
|
const { length, units } = this.getLength(content);
|
|
85
85
|
const displayContent = this.shortenContent(content);
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
let logMessage = `message ${index + 1}: role: ${message.role}, ${units}: ${length}, content: "${displayContent}"`;
|
|
88
|
+
|
|
89
|
+
// Add tool calls to log if they exist
|
|
90
|
+
if (message.role === 'assistant' && message.tool_calls) {
|
|
91
|
+
logMessage += `, tool_calls: ${JSON.stringify(message.tool_calls)}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
logger.verbose(logMessage);
|
|
88
95
|
totalLength += length;
|
|
89
96
|
totalUnits = units;
|
|
90
97
|
});
|