@aj-archipelago/cortex 1.3.61 β 1.3.62
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/config.js +25 -0
- package/lib/entityConstants.js +2 -13
- package/package.json +1 -1
- package/pathways/system/entity/tools/sys_tool_bing_search.js +2 -0
- package/pathways/system/entity/tools/sys_tool_bing_search_afagent.js +5 -5
- package/server/plugins/azureFoundryAgentsPlugin.js +11 -22
- package/tests/agentic.test.js +1 -1
- package/tests/azureFoundryAgents.test.js +6 -8
package/config.js
CHANGED
|
@@ -483,6 +483,21 @@ var config = convict({
|
|
|
483
483
|
"requestsPerSecond": 10,
|
|
484
484
|
"maxTokenLength": 128000
|
|
485
485
|
},
|
|
486
|
+
"azure-bing-agent": {
|
|
487
|
+
"type": "AZURE-FOUNDRY-AGENTS",
|
|
488
|
+
"url": "{{azureFoundryAgentUrl}}",
|
|
489
|
+
"headers": {
|
|
490
|
+
"Content-Type": "application/json"
|
|
491
|
+
},
|
|
492
|
+
"params": {
|
|
493
|
+
"api-version": "2025-05-01",
|
|
494
|
+
"assistant_id": "{{azureFoundryAgentId}}"
|
|
495
|
+
},
|
|
496
|
+
"requestsPerSecond": 10,
|
|
497
|
+
"maxTokenLength": 32768,
|
|
498
|
+
"maxReturnTokens": 4096,
|
|
499
|
+
"supportsStreaming": false
|
|
500
|
+
}
|
|
486
501
|
},
|
|
487
502
|
env: 'CORTEX_MODELS'
|
|
488
503
|
},
|
|
@@ -592,6 +607,16 @@ var config = convict({
|
|
|
592
607
|
format: String,
|
|
593
608
|
default: null,
|
|
594
609
|
env: 'APPTEK_API_ENDPOINT'
|
|
610
|
+
},
|
|
611
|
+
azureFoundryAgentUrl: {
|
|
612
|
+
format: String,
|
|
613
|
+
default: null,
|
|
614
|
+
env: 'AZURE_FOUNDRY_AGENT_URL'
|
|
615
|
+
},
|
|
616
|
+
azureFoundryAgentId: {
|
|
617
|
+
format: String,
|
|
618
|
+
default: null,
|
|
619
|
+
env: 'AZURE_FOUNDRY_AGENT_ID'
|
|
595
620
|
}
|
|
596
621
|
});
|
|
597
622
|
|
package/lib/entityConstants.js
CHANGED
|
@@ -89,20 +89,9 @@ Before you share online information with the user, you MUST complete all of the
|
|
|
89
89
|
- Never rely solely on snippets, headlines, or auto-generated summaries.
|
|
90
90
|
`,
|
|
91
91
|
|
|
92
|
-
AI_SEARCH_SYNTAX: `#
|
|
92
|
+
AI_SEARCH_SYNTAX: `# AI Search Syntax
|
|
93
93
|
|
|
94
|
-
When creating a query string for your
|
|
95
|
-
|
|
96
|
-
token1 & token2 (AND operator - both tokens must appear)
|
|
97
|
-
token1 | token2 (OR operator - either token may appear (also the default if no operator is specified))
|
|
98
|
-
-token (NOT operator - exclude results with token)
|
|
99
|
-
+token (Require token)
|
|
100
|
-
"term1 term2" (Exact phrase match)
|
|
101
|
-
(token1 + token2) (Override precedence with parentheses)
|
|
102
|
-
|
|
103
|
-
# AI Search Syntax
|
|
104
|
-
|
|
105
|
-
When creating a query string for your non-Bing, index-based search tools, you can use the following AI Search syntax. Important: these tools do not support AND, OR, or NOT strings as operators - you MUST use the syntax below. E.g. you cannot use "term1 AND term2", you must use "term1 + term2".
|
|
94
|
+
When creating a query string for your index-based search tools, you can use the following AI Search syntax. Important: these tools do not support AND, OR, or NOT strings as operators - you MUST use the syntax below. E.g. you cannot use "term1 AND term2", you must use "term1 + term2".
|
|
106
95
|
|
|
107
96
|
token1 + token2 (AND operator - both tokens must appear)
|
|
108
97
|
token1 | token2 (OR operator - either token may appear (also the default if no operator is specified))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aj-archipelago/cortex",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.62",
|
|
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": {
|
|
@@ -8,6 +8,7 @@ import { getSearchResultId } from '../../../../lib/util.js';
|
|
|
8
8
|
export default {
|
|
9
9
|
prompt: [],
|
|
10
10
|
timeout: 300,
|
|
11
|
+
/* This tool is included for legacy reasons - as of August 2025, Azure has deprecated the Bing search API and replaced it with their Foundry Agents API.
|
|
11
12
|
toolDefinition: {
|
|
12
13
|
type: "function",
|
|
13
14
|
icon: "π",
|
|
@@ -42,6 +43,7 @@ export default {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
},
|
|
46
|
+
*/
|
|
45
47
|
|
|
46
48
|
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
47
49
|
|
|
@@ -10,10 +10,10 @@ export default {
|
|
|
10
10
|
timeout: 300,
|
|
11
11
|
toolDefinition: {
|
|
12
12
|
type: "function",
|
|
13
|
-
icon: "
|
|
13
|
+
icon: "π",
|
|
14
14
|
function: {
|
|
15
|
-
name: "
|
|
16
|
-
description: "This tool allows you to search sources on the internet by calling another agent that has Bing search access. Use this for current events, news, fact-checking, and information requiring citation.
|
|
15
|
+
name: "SearchInternet",
|
|
16
|
+
description: "This tool allows you to search sources on the internet by calling another agent that has Bing search access. Use this for current events, news, fact-checking, and information requiring citation. Always call this tool in parallel rather than serially if you have several searches to do as it will be faster.",
|
|
17
17
|
parameters: {
|
|
18
18
|
type: "object",
|
|
19
19
|
properties: {
|
|
@@ -34,8 +34,8 @@ export default {
|
|
|
34
34
|
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
35
35
|
|
|
36
36
|
// Check if Bing API key is available
|
|
37
|
-
const
|
|
38
|
-
if (!
|
|
37
|
+
const servicePrincipalAvailable = !!config.getEnv()["AZURE_SERVICE_PRINCIPAL_CREDENTIALS"];
|
|
38
|
+
if (!servicePrincipalAvailable) {
|
|
39
39
|
throw new Error("Service Principal for Bing Search Agent is not available!");
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -6,8 +6,6 @@ import axios from 'axios';
|
|
|
6
6
|
class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
7
7
|
constructor(pathway, model) {
|
|
8
8
|
super(pathway, model);
|
|
9
|
-
this.agentId = model.agentId;
|
|
10
|
-
this.projectUrl = model.url;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
// Convert to Azure Foundry Agents messages array format
|
|
@@ -72,7 +70,7 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
const requestParameters = {
|
|
75
|
-
assistant_id: this.
|
|
73
|
+
assistant_id: this.assistantId,
|
|
76
74
|
thread: {
|
|
77
75
|
messages: requestMessages
|
|
78
76
|
},
|
|
@@ -97,12 +95,14 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
97
95
|
|
|
98
96
|
// Assemble and execute the request to the Azure Foundry Agents API
|
|
99
97
|
async execute(text, parameters, prompt, cortexRequest) {
|
|
98
|
+
this.baseUrl = cortexRequest.url;
|
|
99
|
+
this.assistantId = cortexRequest.params.assistant_id;
|
|
100
|
+
|
|
100
101
|
const requestParameters = this.getRequestParameters(text, parameters, prompt);
|
|
101
102
|
|
|
102
103
|
// Set up the request for Azure Foundry Agents
|
|
103
|
-
cortexRequest.url = this.
|
|
104
|
+
cortexRequest.url = `${this.baseUrl}/threads/runs`;
|
|
104
105
|
cortexRequest.data = requestParameters;
|
|
105
|
-
cortexRequest.params = { 'api-version': '2025-05-01' }; // Azure API version
|
|
106
106
|
|
|
107
107
|
// Get authentication token and add to headers
|
|
108
108
|
const azureAuthTokenHelper = this.config.get('azureAuthTokenHelper');
|
|
@@ -158,14 +158,14 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
const pollUrl = this.
|
|
161
|
+
const pollUrl = `${this.baseUrl}/threads/${threadId}/runs/${runId}`;
|
|
162
162
|
const pollResponse = await axios.get(pollUrl, {
|
|
163
163
|
headers: {
|
|
164
164
|
'Content-Type': 'application/json',
|
|
165
|
-
...
|
|
165
|
+
...cortexRequest.headers,
|
|
166
166
|
...(authToken && { 'Authorization': `Bearer ${authToken}` })
|
|
167
167
|
},
|
|
168
|
-
params:
|
|
168
|
+
params: cortexRequest.params
|
|
169
169
|
});
|
|
170
170
|
const runStatus = pollResponse?.data;
|
|
171
171
|
|
|
@@ -177,7 +177,7 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
177
177
|
// Check if run is completed
|
|
178
178
|
if (runStatus.status === 'completed') {
|
|
179
179
|
logger.info(`[Azure Foundry Agent] Run completed successfully: ${runId}`);
|
|
180
|
-
return await this.retrieveMessages(threadId
|
|
180
|
+
return await this.retrieveMessages(threadId);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
// Check if run failed
|
|
@@ -212,7 +212,7 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
// Retrieve messages from the completed thread
|
|
215
|
-
async retrieveMessages(threadId
|
|
215
|
+
async retrieveMessages(threadId) {
|
|
216
216
|
try {
|
|
217
217
|
// Add authentication token if available
|
|
218
218
|
const azureAuthTokenHelper = this.config.get('azureAuthTokenHelper');
|
|
@@ -226,7 +226,7 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
const messagesUrl = this.
|
|
229
|
+
const messagesUrl = `${this.baseUrl}/threads/${threadId}/messages`;
|
|
230
230
|
const axiosResponse = await axios.get(messagesUrl, {
|
|
231
231
|
headers: {
|
|
232
232
|
'Content-Type': 'application/json',
|
|
@@ -356,17 +356,6 @@ class AzureFoundryAgentsPlugin extends ModelPlugin {
|
|
|
356
356
|
|
|
357
357
|
prompt && prompt.debugInfo && (prompt.debugInfo += `\n${JSON.stringify(data)}`);
|
|
358
358
|
}
|
|
359
|
-
|
|
360
|
-
// Override the request URL to use the Azure Foundry Agents endpoint
|
|
361
|
-
requestUrl() {
|
|
362
|
-
// The URL should be constructed as: {projectUrl}/threads/runs
|
|
363
|
-
return `${this.projectUrl}/threads/runs`;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Helper method to construct Azure Foundry Agents URLs
|
|
367
|
-
constructAzureUrl(path) {
|
|
368
|
-
return `${this.projectUrl}${path}`;
|
|
369
|
-
}
|
|
370
359
|
}
|
|
371
360
|
|
|
372
361
|
export default AzureFoundryAgentsPlugin;
|
package/tests/agentic.test.js
CHANGED
|
@@ -177,7 +177,7 @@ test.serial('sys_entity_agent handles single-step task', async (t) => {
|
|
|
177
177
|
|
|
178
178
|
// Test multi-step task with tool usage
|
|
179
179
|
test.serial('sys_entity_agent handles multi-step task with tools', async (t) => {
|
|
180
|
-
t.timeout(
|
|
180
|
+
t.timeout(120000); // 120 second timeout for multi-step task
|
|
181
181
|
const response = await testServer.executeOperation({
|
|
182
182
|
query: `
|
|
183
183
|
query TestAgentMultiStep(
|
|
@@ -16,10 +16,12 @@ test.beforeEach(t => {
|
|
|
16
16
|
name: 'azure-foundry-agents',
|
|
17
17
|
type: 'AZURE-FOUNDRY-AGENTS',
|
|
18
18
|
url: 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry',
|
|
19
|
-
agentId: 'asst_testid',
|
|
20
19
|
headers: {
|
|
21
20
|
'Content-Type': 'application/json'
|
|
22
21
|
},
|
|
22
|
+
params: {
|
|
23
|
+
assistant_id: 'asst_testid'
|
|
24
|
+
},
|
|
23
25
|
maxTokenLength: 32768,
|
|
24
26
|
maxReturnTokens: 4096,
|
|
25
27
|
supportsStreaming: true
|
|
@@ -30,12 +32,6 @@ test.beforeEach(t => {
|
|
|
30
32
|
t.context.mockModel = mockModel;
|
|
31
33
|
});
|
|
32
34
|
|
|
33
|
-
test('should initialize with correct agent ID and project URL', t => {
|
|
34
|
-
const { plugin } = t.context;
|
|
35
|
-
t.is(plugin.agentId, 'asst_testid');
|
|
36
|
-
t.is(plugin.projectUrl, 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
35
|
test('should convert Palm format messages to Azure format', t => {
|
|
40
36
|
const { plugin } = t.context;
|
|
41
37
|
const context = 'You are a helpful assistant.';
|
|
@@ -82,6 +78,8 @@ test('should create correct request parameters', t => {
|
|
|
82
78
|
messages: [{ role: 'user', content: text }]
|
|
83
79
|
};
|
|
84
80
|
|
|
81
|
+
plugin.baseUrl = 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry';
|
|
82
|
+
plugin.assistantId = 'asst_testid';
|
|
85
83
|
const result = plugin.getRequestParameters(text, parameters, prompt);
|
|
86
84
|
|
|
87
85
|
t.is(result.assistant_id, 'asst_testid');
|
|
@@ -150,7 +148,7 @@ test('should return empty string for null response', t => {
|
|
|
150
148
|
test('should return correct Azure Foundry Agents endpoint', t => {
|
|
151
149
|
const { plugin } = t.context;
|
|
152
150
|
const url = plugin.requestUrl();
|
|
153
|
-
t.is(url, 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry
|
|
151
|
+
t.is(url, 'https://archipelago-foundry-resource.services.ai.azure.com/api/projects/archipelago-foundry');
|
|
154
152
|
});
|
|
155
153
|
|
|
156
154
|
test('should be able to access azureAuthTokenHelper from config', (t) => {
|