psadk 1.1.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/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +205 -0
- package/build/main/index.d.ts +6 -0
- package/build/main/index.js +23 -0
- package/build/main/lib/ILogger.d.ts +9 -0
- package/build/main/lib/ILogger.js +25 -0
- package/build/main/lib/PSAI.d.ts +29 -0
- package/build/main/lib/PSAI.js +383 -0
- package/build/main/lib/PSAgent.d.ts +215 -0
- package/build/main/lib/PSAgent.js +990 -0
- package/build/main/lib/PSAgentConfig.d.ts +23 -0
- package/build/main/lib/PSAgentConfig.js +3 -0
- package/build/main/lib/PSAgentLogger.d.ts +13 -0
- package/build/main/lib/PSAgentLogger.js +33 -0
- package/build/main/lib/PSAgentTask.d.ts +12 -0
- package/build/main/lib/PSAgentTask.js +30 -0
- package/build/main/lib/PSAgentTool.d.ts +56 -0
- package/build/main/lib/PSAgentTool.js +84 -0
- package/build/main/lib/ai.d.ts +11 -0
- package/build/main/lib/ai.js +127 -0
- package/build/main/lib/async.d.ts +20 -0
- package/build/main/lib/async.js +36 -0
- package/build/main/lib/getServiceToken.d.ts +1 -0
- package/build/main/lib/getServiceToken.js +3 -0
- package/build/main/lib/jwt.d.ts +41 -0
- package/build/main/lib/jwt.js +73 -0
- package/build/main/lib/number.d.ts +43 -0
- package/build/main/lib/number.js +56 -0
- package/build/main/lib/tools/PSAentTool.d.ts +7 -0
- package/build/main/lib/tools/PSAentTool.js +78 -0
- package/build/main/lib/tools/PSArtifactTool copy.d.ts +7 -0
- package/build/main/lib/tools/PSArtifactTool copy.js +78 -0
- package/build/main/lib/tools/PSArtifactTool.d.ts +7 -0
- package/build/main/lib/tools/PSArtifactTool.js +79 -0
- package/build/main/lib/tools/PSSubAgentTool.d.ts +20 -0
- package/build/main/lib/tools/PSSubAgentTool.js +163 -0
- package/build/module/index.d.ts +6 -0
- package/build/module/index.js +7 -0
- package/build/module/lib/PSAI.d.ts +25 -0
- package/build/module/lib/PSAI.js +314 -0
- package/build/module/lib/PSAgent.d.ts +215 -0
- package/build/module/lib/PSAgent.js +992 -0
- package/build/module/lib/async.d.ts +20 -0
- package/build/module/lib/async.js +32 -0
- package/build/module/lib/number.d.ts +43 -0
- package/build/module/lib/number.js +51 -0
- package/package.json +122 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
// import { EmbeddingsInterface } from '@langchain/core/embeddings';
|
|
2
|
+
// fetch-retry can also wrap Node.js's native fetch API implementation:
|
|
3
|
+
const fetch = require('fetch-retry')(global.fetch);
|
|
4
|
+
import { JwtUtils } from './jwt';
|
|
5
|
+
import { PSAgentLogger } from './PSAgentLogger';
|
|
6
|
+
import express from 'express';
|
|
7
|
+
const log = new PSAgentLogger();
|
|
8
|
+
let existingToken = {
|
|
9
|
+
service_token: null,
|
|
10
|
+
refresh_token: null,
|
|
11
|
+
expires: new Date(0),
|
|
12
|
+
service_expires: new Date(0)
|
|
13
|
+
};
|
|
14
|
+
// export default class AIHelper implements EmbeddingsInterface{
|
|
15
|
+
export class PSAI {
|
|
16
|
+
token;
|
|
17
|
+
dimensions;
|
|
18
|
+
baseUrl;
|
|
19
|
+
log;
|
|
20
|
+
clientid;
|
|
21
|
+
constructor(token, baseUrl, log) {
|
|
22
|
+
this.token = token;
|
|
23
|
+
this.baseUrl = baseUrl || process.env.PS_API_URL || '';
|
|
24
|
+
this.clientid = process.env.PS_CLIENT_ID || '';
|
|
25
|
+
this.dimensions = 1536; // default to 1536 dimensions (for text-embedding-3-small)
|
|
26
|
+
this.log = log || new PSAgentLogger();
|
|
27
|
+
}
|
|
28
|
+
getDimensions(embeddingModel = 'text-embedding-3-small') {
|
|
29
|
+
if (embeddingModel === 'text-embedding-3-small') {
|
|
30
|
+
return 1536;
|
|
31
|
+
}
|
|
32
|
+
else if (embeddingModel === 'text-embedding-3-large') {
|
|
33
|
+
return 3072;
|
|
34
|
+
}
|
|
35
|
+
else if (embeddingModel === 'text-embedding-ada-002') {
|
|
36
|
+
return 1536;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return this.dimensions;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async embedQuery(text, embeddingModel = 'text-embedding-3-small') {
|
|
43
|
+
const response = await fetch(`${this.baseUrl}/api/v1/vectors/embeddings`, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'Authorization': `Bearer ${this.token}`,
|
|
48
|
+
'x-client-id': this.clientid || '',
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
input: text,
|
|
52
|
+
model: embeddingModel,
|
|
53
|
+
"dimensions": this.getDimensions(embeddingModel),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
const data = await response.json();
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
this.log.error(`Failed to fetch embedding: ${response.status} ${response.statusText}`, data);
|
|
59
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
60
|
+
}
|
|
61
|
+
return data.data[0].embedding;
|
|
62
|
+
}
|
|
63
|
+
async embedDocuments(text, embeddingModel = 'text-embedding-3-small') {
|
|
64
|
+
const response = await fetch(`${this.baseUrl}/api/v1/vectors/embeddings`, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: {
|
|
67
|
+
'Content-Type': 'application/json',
|
|
68
|
+
'Authorization': `Bearer ${this.token}`,
|
|
69
|
+
'x-client-id': this.clientid || '',
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
input: text,
|
|
73
|
+
model: embeddingModel,
|
|
74
|
+
"dimensions": this.getDimensions(embeddingModel),
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
const data = await response.json();
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
this.log.error(`Failed to fetch embedding: ${response.status} ${response.statusText}`, data);
|
|
80
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
81
|
+
}
|
|
82
|
+
return data.data.map((item) => item.embedding);
|
|
83
|
+
}
|
|
84
|
+
async getModels() {
|
|
85
|
+
const lres = await fetch(`${this.baseUrl}/api/v1/llm/models`, {
|
|
86
|
+
headers: {
|
|
87
|
+
'Authorization': `Bearer ${this.token}`,
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
if (!lres.ok) {
|
|
91
|
+
this.log.error(`Failed to fetch LLM models: ${lres.status} ${lres.statusText}`);
|
|
92
|
+
}
|
|
93
|
+
const { data: models } = await lres.json();
|
|
94
|
+
return models;
|
|
95
|
+
}
|
|
96
|
+
async llm(prompt, model = "o3-mini", systemmsg = "You are a helpful assistant. Answer as concisely as possible.") {
|
|
97
|
+
try {
|
|
98
|
+
const res = await fetch(`${this.baseUrl}/api/v1/llm/chat/completions`, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers: {
|
|
101
|
+
"Content-Type": "application/json",
|
|
102
|
+
"Authorization": `Bearer ${this.token}`,
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
model,
|
|
106
|
+
messages: [
|
|
107
|
+
{ role: "system", content: systemmsg },
|
|
108
|
+
{ role: "user", content: prompt }
|
|
109
|
+
]
|
|
110
|
+
}),
|
|
111
|
+
retries: 3,
|
|
112
|
+
retryOn: function (attempt, error, response) {
|
|
113
|
+
// retry on any network error, or 4xx or 5xx status codes
|
|
114
|
+
if (error !== null || response.status >= 400 && attempt < 4) {
|
|
115
|
+
this.log.warn(`retrying execute agent, attempt number ${attempt + 1}`);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
},
|
|
120
|
+
retryDelay: function (attempt, _error, _response) {
|
|
121
|
+
return Math.pow(2, attempt) * 1000; // 1000, 2000, 4000
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
if (!res.ok) {
|
|
125
|
+
this.log.debug(`Failed to fetch LLM completion: ${res.status} ${res.statusText}`);
|
|
126
|
+
try {
|
|
127
|
+
const errorData = (await res.json());
|
|
128
|
+
this.log.debug(errorData);
|
|
129
|
+
throw new Error(`LLM call failed.\n\n status: ${res.status}, details: ${errorData}`);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
throw new Error(`LLM call failed.\n\n status: ${res.status}, and could not parse error response`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const data = await res.json();
|
|
136
|
+
return data;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.log.debug('Error in llm call:', error);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
static async getServiceToken(options) {
|
|
144
|
+
const { baseurl = process.env.PS_API_URL || '', appkey = process.env.PS_SVC_APP_KEY || '', clientid = process.env.PS_SVC_CLIENT_ID || '', clientsecret = process.env.PS_SVC_CLIENT_SECRET || '' } = options || {};
|
|
145
|
+
if (!baseurl || !appkey || !clientid || !clientsecret) {
|
|
146
|
+
throw new Error('Missing required environment variables for service token retrieval');
|
|
147
|
+
}
|
|
148
|
+
const currentTime = new Date();
|
|
149
|
+
// Check if the existing token is still valid and expires after 20 minutes
|
|
150
|
+
if (existingToken && existingToken.service_token && existingToken.service_expires.getTime() > (currentTime.getTime() + 20 * 60000)) {
|
|
151
|
+
return existingToken.service_token;
|
|
152
|
+
}
|
|
153
|
+
const token = Buffer.from(`${clientid}:${clientsecret}`).toString('base64');
|
|
154
|
+
if (existingToken && existingToken.expires > currentTime) {
|
|
155
|
+
log.debug(`Found existing refresh token: ${existingToken.refresh_token}`);
|
|
156
|
+
const tres = await fetch(`${baseurl}/api/v2/auth/refreshtoken?client=machine`, {
|
|
157
|
+
headers: {
|
|
158
|
+
'Authorization': `Basic ${token}`,
|
|
159
|
+
'app-key': appkey || '',
|
|
160
|
+
'rt': existingToken.refresh_token || ''
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
if (tres.ok) {
|
|
164
|
+
const { accessToken, refreshToken } = (await tres.json());
|
|
165
|
+
const spayload = JwtUtils.decode(accessToken);
|
|
166
|
+
const rpayload = JwtUtils.decode(refreshToken);
|
|
167
|
+
existingToken.service_token = accessToken;
|
|
168
|
+
existingToken.refresh_token = refreshToken;
|
|
169
|
+
existingToken.expires = new Date(rpayload?.exp * 1000);
|
|
170
|
+
existingToken.service_expires = new Date(spayload?.exp * 1000);
|
|
171
|
+
log.debug(`Refreshed service token: expires at ${existingToken.service_expires}`);
|
|
172
|
+
return accessToken;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
log.debug(`Failed to refresh service token, status: ${tres.status}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const tres = await fetch(`${baseurl}/api/v2/auth/login?client=machine&source=custom`, {
|
|
179
|
+
headers: {
|
|
180
|
+
'Authorization': `Basic ${token}`,
|
|
181
|
+
'app-key': appkey || ''
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
const { serviceToken, refreshToken } = (await tres.json());
|
|
185
|
+
const spayload = JwtUtils.decode(serviceToken);
|
|
186
|
+
const rpayload = JwtUtils.decode(refreshToken);
|
|
187
|
+
log.debug(`service token expires: ${JSON.stringify(new Date(spayload?.exp * 1000))}`);
|
|
188
|
+
log.debug(`refresh token expires: ${JSON.stringify(new Date(rpayload?.exp * 1000))}`);
|
|
189
|
+
existingToken.service_token = serviceToken;
|
|
190
|
+
existingToken.refresh_token = refreshToken;
|
|
191
|
+
existingToken.expires = new Date(rpayload?.exp * 1000);
|
|
192
|
+
existingToken.service_expires = new Date(spayload?.exp * 1000);
|
|
193
|
+
return serviceToken;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* fetch access token by launching a local server to listen for the callback
|
|
197
|
+
* @param options - baseUrl and appKey for authentication
|
|
198
|
+
* @returns accessToken and refreshToken
|
|
199
|
+
* @throws error if any required values are missing or if authentication fails
|
|
200
|
+
*/
|
|
201
|
+
static async getAuthToken(options) {
|
|
202
|
+
const { baseurl = options?.baseUrl || process.env.PS_API_URL || '', appkey = options?.appKey || process.env.PS_APP_KEY || '', } = options || {};
|
|
203
|
+
if (baseurl === '' || appkey === '') {
|
|
204
|
+
throw new Error('Missing required values baseUrl & appKey or default environment variables PS_API_URL/PS_APP_KEY for access token retrieval');
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
let isCallbackFinished = false;
|
|
208
|
+
let callBackError = null;
|
|
209
|
+
let accessToken = null;
|
|
210
|
+
let refreshToken = null;
|
|
211
|
+
let appInitialized = false;
|
|
212
|
+
const app = express();
|
|
213
|
+
const router = express.Router();
|
|
214
|
+
router.use(express.json()); // for parsing application/json
|
|
215
|
+
router.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
|
|
216
|
+
router.get('/callback', (req, res) => {
|
|
217
|
+
const status = req.query.status;
|
|
218
|
+
if (status !== "success") {
|
|
219
|
+
log.error(`Authentication failed with status: ${status}`);
|
|
220
|
+
callBackError = `Authentication failed with status: ${status}`;
|
|
221
|
+
isCallbackFinished = true;
|
|
222
|
+
return res.status(400).send('Authentication failed');
|
|
223
|
+
}
|
|
224
|
+
log.debug("Authentication successful.");
|
|
225
|
+
accessToken = req.query["at"];
|
|
226
|
+
refreshToken = req.query["rt"];
|
|
227
|
+
if (!accessToken || !refreshToken) {
|
|
228
|
+
log.error('Missing access token or refresh token in callback');
|
|
229
|
+
callBackError = 'Missing access token or refresh token in callback';
|
|
230
|
+
isCallbackFinished = true;
|
|
231
|
+
return res.status(400).send('Missing tokens');
|
|
232
|
+
}
|
|
233
|
+
callBackError = null;
|
|
234
|
+
isCallbackFinished = true;
|
|
235
|
+
return res.status(200).send('Authentication successful! You can close this window.');
|
|
236
|
+
});
|
|
237
|
+
router.get('/login', async (_req, res) => {
|
|
238
|
+
const rurl = encodeURIComponent('http://localhost:3133/callback');
|
|
239
|
+
const loginUrl = `${baseurl}/api/v2/auth/login?client=desktop&redirect_url=${rurl}`;
|
|
240
|
+
const lres = await fetch(loginUrl, {
|
|
241
|
+
headers: { 'app-key': appkey || '' }
|
|
242
|
+
});
|
|
243
|
+
if (lres.status >= 400) {
|
|
244
|
+
log.error(`Failed to initiate login: ${lres.status} ${lres.statusText}`);
|
|
245
|
+
callBackError = `Failed to initiate login: ${lres.status} ${lres.statusText}`;
|
|
246
|
+
isCallbackFinished = true;
|
|
247
|
+
return res.status(500).send('Failed to initiate login');
|
|
248
|
+
}
|
|
249
|
+
const data = lres.body;
|
|
250
|
+
if (!data) {
|
|
251
|
+
log.error('No response body from login initiation');
|
|
252
|
+
callBackError = 'No response body from login initiation';
|
|
253
|
+
isCallbackFinished = true;
|
|
254
|
+
return res.status(500).send('No response body from login initiation');
|
|
255
|
+
}
|
|
256
|
+
const reader = data.getReader();
|
|
257
|
+
const decoder = new TextDecoder('utf-8');
|
|
258
|
+
let lresText = '';
|
|
259
|
+
while (true) {
|
|
260
|
+
const { done, value } = await reader.read();
|
|
261
|
+
if (done)
|
|
262
|
+
break;
|
|
263
|
+
lresText += decoder.decode(value);
|
|
264
|
+
}
|
|
265
|
+
if (!lresText || lresText.length === 0) {
|
|
266
|
+
log.error('Empty response body from login initiation');
|
|
267
|
+
callBackError = 'Empty response body from login initiation';
|
|
268
|
+
isCallbackFinished = true;
|
|
269
|
+
return res.status(500).send('Empty response body from login initiation');
|
|
270
|
+
}
|
|
271
|
+
log.debug('Redirecting to authentication provider');
|
|
272
|
+
return res.redirect(lresText);
|
|
273
|
+
});
|
|
274
|
+
app.use('', router);
|
|
275
|
+
app.listen(3133, () => {
|
|
276
|
+
log.debug('Listening on port 3133 for OAuth callback');
|
|
277
|
+
appInitialized = true;
|
|
278
|
+
}).on('error', (err) => {
|
|
279
|
+
log.error('Failed to start local server:', err);
|
|
280
|
+
callBackError = `Failed to start local server: ${err.message}`;
|
|
281
|
+
isCallbackFinished = true;
|
|
282
|
+
appInitialized = true;
|
|
283
|
+
});
|
|
284
|
+
do {
|
|
285
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
286
|
+
} while (!appInitialized && !callBackError);
|
|
287
|
+
if (appInitialized) {
|
|
288
|
+
console.log(`Please open the following URL in your browser to authenticate:\n\nhttp://localhost:3133/login\n`);
|
|
289
|
+
// Open the URL in the default browser
|
|
290
|
+
const open = (await import('open')).default;
|
|
291
|
+
await open(`http://localhost:3133/login`);
|
|
292
|
+
do {
|
|
293
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
294
|
+
} while (!isCallbackFinished && !callBackError);
|
|
295
|
+
}
|
|
296
|
+
if (callBackError) {
|
|
297
|
+
throw new Error(callBackError);
|
|
298
|
+
}
|
|
299
|
+
if (!accessToken || !refreshToken) {
|
|
300
|
+
throw new Error('Failed to obtain tokens from callback');
|
|
301
|
+
}
|
|
302
|
+
log.debug(`Obtained access token and refresh token from callback`);
|
|
303
|
+
return {
|
|
304
|
+
accessToken: accessToken,
|
|
305
|
+
refreshToken: refreshToken
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
log.error('Error in getAccessToken:', error);
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUFNBSS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvUFNBSS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxvRUFBb0U7QUFDcEUsdUVBQXVFO0FBQ3ZFLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDbkQsT0FBTyxFQUFFLFFBQVEsRUFBZ0IsTUFBTSxPQUFPLENBQUM7QUFDL0MsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sT0FBOEIsTUFBTSxTQUFTLENBQUM7QUFFckQsTUFBTSxHQUFHLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztBQUVoQyxJQUFJLGFBQWEsR0FLYjtJQUNGLGFBQWEsRUFBRSxJQUFJO0lBQ25CLGFBQWEsRUFBRSxJQUFJO0lBQ25CLE9BQU8sRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDcEIsZUFBZSxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQztDQUM3QixDQUFDO0FBRUYsZ0VBQWdFO0FBQ2hFLE1BQU0sT0FBTyxJQUFJO0lBQ0UsS0FBSyxDQUFTO0lBQ3ZCLFVBQVUsQ0FBUTtJQUNULE9BQU8sQ0FBUztJQUNoQixHQUFHLENBQWdCO0lBQ25CLFFBQVEsQ0FBUztJQUVsQyxZQUFZLEtBQWEsRUFBRSxPQUFnQixFQUFFLEdBQW1CO1FBQzlELElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUN2RCxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQztRQUMvQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxDQUFDLDBEQUEwRDtRQUNsRixJ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
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { PSAgentConfig } from "./PSAgentConfig";
|
|
2
|
+
import { IPSAgentToolResult, PSAgentTool } from "./PSAgentTool";
|
|
3
|
+
import { PSAgentLogger } from "./PSAgentLogger";
|
|
4
|
+
import { z } from "zod/v4";
|
|
5
|
+
import { PSAgentTask } from "./PSAgentTask";
|
|
6
|
+
import type { AgentCard } from "@a2a-js/sdk";
|
|
7
|
+
import { AgentExecutor, RequestContext, ExecutionEventBus, TaskStore } from "@a2a-js/sdk/server";
|
|
8
|
+
import express from "express";
|
|
9
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* PSAgent class to manage AI agents with tools and tasks
|
|
12
|
+
* Implements AgentExecutor interface from A2A SDK
|
|
13
|
+
* Supports starting, resuming, cancelling agents and executing tools
|
|
14
|
+
* Manages agent state, tools, tasks and interactions with A2A platform
|
|
15
|
+
* Includes methods for A2A server setup and event fetching
|
|
16
|
+
*
|
|
17
|
+
* uses the token from config if not PS_API_TOKEN env variable
|
|
18
|
+
* adds x-client-id, x-project-id, x-workspace-id from env variables
|
|
19
|
+
* PS_CLIENT_ID, PS_PROJECT_ID, PS_WORKSPACE_ID respectively for authentication headers
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { PSAI, PSAgent, PSAgentLogger } from 'psadk';
|
|
24
|
+
* import dotenv from 'dotenv';
|
|
25
|
+
* dotenv.config();
|
|
26
|
+
* async function main() {
|
|
27
|
+
* const token = await PSAI.getServiceToken({});
|
|
28
|
+
* const HelloAgent = new PSAgent({
|
|
29
|
+
* name: 'HelloAgent',
|
|
30
|
+
* description: 'A simple hello world agent',
|
|
31
|
+
* system_prompt: 'You are a helpful assistant that greets users.',
|
|
32
|
+
* model: 'gpt-5',
|
|
33
|
+
* tools: [],
|
|
34
|
+
* log: new PSAgentLogger({ level: 'info' }),
|
|
35
|
+
* token: token,
|
|
36
|
+
* port: 41241,
|
|
37
|
+
* });
|
|
38
|
+
* const { app, port } = HelloAgent.getServer();
|
|
39
|
+
* app.listen(port, () => {
|
|
40
|
+
* console.log('HelloAgent is running on http://localhost:${port}');
|
|
41
|
+
* });
|
|
42
|
+
* }
|
|
43
|
+
* main();
|
|
44
|
+
* ```
|
|
45
|
+
* @see PSAgentConfig, PSAgentTool, PSAgentTask
|
|
46
|
+
*
|
|
47
|
+
* @see
|
|
48
|
+
* https://dev.lionis.ai/docs/api/v1/agents/create-agent
|
|
49
|
+
* https://pscode.lioncloud.net/ai-tso/psadk_samples
|
|
50
|
+
* https://a2aproject.com/docs/getting-started/quickstart
|
|
51
|
+
*
|
|
52
|
+
*/
|
|
53
|
+
export declare class PSAgent implements AgentExecutor {
|
|
54
|
+
config: PSAgentConfig;
|
|
55
|
+
private tools;
|
|
56
|
+
private tasks;
|
|
57
|
+
private agentId?;
|
|
58
|
+
private correlationId?;
|
|
59
|
+
private readonly log?;
|
|
60
|
+
private cancelledTasks;
|
|
61
|
+
cancelTask: (taskId: string, _eventBus: ExecutionEventBus) => Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* create a new PSAgent with the given config
|
|
64
|
+
* @param config PSAgentConfig with optional logger
|
|
65
|
+
*/
|
|
66
|
+
constructor(config: PSAgentConfig & {
|
|
67
|
+
log?: PSAgentLogger;
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Get the Agent Class
|
|
71
|
+
* @returns Agent class from config or default "LlmAgent"
|
|
72
|
+
*/
|
|
73
|
+
get AgentClass(): string;
|
|
74
|
+
/**
|
|
75
|
+
* Get the Name of the Agent
|
|
76
|
+
*
|
|
77
|
+
* @returns Name of the agent from config
|
|
78
|
+
*/
|
|
79
|
+
get Name(): string;
|
|
80
|
+
/**
|
|
81
|
+
* Get the Description of the Agent
|
|
82
|
+
* @returns Description of the agent from config
|
|
83
|
+
*/
|
|
84
|
+
get Description(): string;
|
|
85
|
+
/**
|
|
86
|
+
* Get the Instruction(System Prompt) of the Agent
|
|
87
|
+
* @returns Instruction(System prompt) of the agent from config
|
|
88
|
+
*/
|
|
89
|
+
get Instruction(): string;
|
|
90
|
+
/**
|
|
91
|
+
* Get the Model of the Agent
|
|
92
|
+
* @returns Model of the agent from config
|
|
93
|
+
*/
|
|
94
|
+
get Model(): string | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Get the Input Schema of the Agent
|
|
97
|
+
* @returns Input schema of the agent from config
|
|
98
|
+
*/
|
|
99
|
+
get InputSchema(): z.core.JSONSchema.BaseSchema | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Get the Output Schema of the Agent
|
|
102
|
+
* @returns Output schema of the agent from config
|
|
103
|
+
*/
|
|
104
|
+
get OutputSchema(): z.core.JSONSchema.BaseSchema | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Get the Token for the Agent
|
|
107
|
+
* @returns Token of the agent from config
|
|
108
|
+
*/
|
|
109
|
+
get Token(): string | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Set the Token for the Agent
|
|
112
|
+
* @param value Token string to set in config
|
|
113
|
+
*/
|
|
114
|
+
set Token(value: string | undefined);
|
|
115
|
+
/**
|
|
116
|
+
* Get the Tools for the Agent
|
|
117
|
+
* Includes both config tools and dynamically added tools
|
|
118
|
+
* @returns Array of PSAgentTool instances
|
|
119
|
+
*/
|
|
120
|
+
get Tools(): PSAgentTool[];
|
|
121
|
+
/**
|
|
122
|
+
* Get the Tasks for the Agent
|
|
123
|
+
* Includes both config tasks and dynamically added tasks
|
|
124
|
+
* @returns Array of PSAgentTask instances
|
|
125
|
+
*/
|
|
126
|
+
get Tasks(): PSAgentTask[];
|
|
127
|
+
/**
|
|
128
|
+
* Get the Agent ID after starting the agent
|
|
129
|
+
* @returns Agent ID string or undefined if not started
|
|
130
|
+
*/
|
|
131
|
+
get AgentId(): string | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* Get the Correlation ID after starting the agent
|
|
134
|
+
* @returns Correlation ID string or undefined if not started
|
|
135
|
+
*/
|
|
136
|
+
get CorrelationId(): string | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* Add tools to the agent dynamically
|
|
139
|
+
* @param tool PSAgentTool to add to the agent
|
|
140
|
+
*/
|
|
141
|
+
addTool(tool: PSAgentTool): void;
|
|
142
|
+
private getToken;
|
|
143
|
+
private getAuthHeaders;
|
|
144
|
+
private getBaseUrl;
|
|
145
|
+
/**
|
|
146
|
+
* start a new temp agent on the agent platform
|
|
147
|
+
* @param input input to the agent the schema should match InputSchema if provided
|
|
148
|
+
* @param history history of messages for agent context
|
|
149
|
+
* @param log logger to use for logging, defaults to agent's logger
|
|
150
|
+
* @returns Correlation ID of the started agent
|
|
151
|
+
*/
|
|
152
|
+
start(input: Object, history?: any[], log?: PSAgentLogger): Promise<string>;
|
|
153
|
+
/**
|
|
154
|
+
* resume the agent with tool output after a tool execution or human input
|
|
155
|
+
* @param tooloutput output from the tool execution to send back to the agent
|
|
156
|
+
* @returns
|
|
157
|
+
*/
|
|
158
|
+
resume(tooloutput: Record<string, any>): Promise<Record<string, any>>;
|
|
159
|
+
/**
|
|
160
|
+
* deletes the agent running on the platform
|
|
161
|
+
* @param log optional logger to use for logging, defaults to agent's logger
|
|
162
|
+
*/
|
|
163
|
+
cancel(log?: PSAgentLogger): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Gets all the events for the current agent run identified correlation ID
|
|
166
|
+
* @returns Array of event objects for the current agent's correlation ID
|
|
167
|
+
* @see https://dev.lionis.ai/api/v1/events/events?correlationId={{correlation_id}}
|
|
168
|
+
*/
|
|
169
|
+
getEvents(): Promise<Array<Record<string, any>>>;
|
|
170
|
+
/**
|
|
171
|
+
* Invoke the tool with the given name and input
|
|
172
|
+
* @remarks
|
|
173
|
+
* The input object should match the tool's input schema
|
|
174
|
+
*
|
|
175
|
+
* @param toolName name of the tool to execute
|
|
176
|
+
* @param input input object for the tool execution should match tool's input schema
|
|
177
|
+
* @param log logger to use for logging, defaults to agent's logger
|
|
178
|
+
* @returns output from the tool execution or error if any
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* Example input for PSArtifactTool:
|
|
182
|
+
* ```json
|
|
183
|
+
* {
|
|
184
|
+
* "name": "example_artifact",
|
|
185
|
+
* "action": "write",
|
|
186
|
+
* "content": "This is an example artifact content."
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
executeTool(toolName: string, input: Record<string, any>, log?: PSAgentLogger): Promise<IPSAgentToolResult>;
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
* @param requestContext
|
|
194
|
+
* @param eventBus
|
|
195
|
+
* @returns
|
|
196
|
+
*/
|
|
197
|
+
execute(requestContext: RequestContext, eventBus: ExecutionEventBus): Promise<void>;
|
|
198
|
+
private getHostIPAddress;
|
|
199
|
+
/**
|
|
200
|
+
* Port for A2A express server
|
|
201
|
+
* @returns Port number from config or default 41241
|
|
202
|
+
*/
|
|
203
|
+
private getPort;
|
|
204
|
+
/**
|
|
205
|
+
*
|
|
206
|
+
* @param taskStore Optional TaskStore, defaults to InMemoryTaskStore
|
|
207
|
+
* @returns A2A Express app
|
|
208
|
+
*/
|
|
209
|
+
getServer(taskStore?: TaskStore): {
|
|
210
|
+
app: express.Express;
|
|
211
|
+
port: number;
|
|
212
|
+
};
|
|
213
|
+
getAgentCard(): AgentCard;
|
|
214
|
+
static FromConfigFile(config_path: string): PSAgent;
|
|
215
|
+
}
|