1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.default = createClient;
|
7 |
|
8 | var _lodash = require('lodash');
|
9 |
|
10 | var _lodash2 = _interopRequireDefault(_lodash);
|
11 |
|
12 | var _request = require('./request');
|
13 |
|
14 | var _request2 = _interopRequireDefault(_request);
|
15 |
|
16 | var _debug = require('debug');
|
17 |
|
18 | var _debug2 = _interopRequireDefault(_debug);
|
19 |
|
20 | var _interpreter = require('./interpreter');
|
21 |
|
22 | var _defaults = require('./defaults');
|
23 |
|
24 | var _defaults2 = _interopRequireDefault(_defaults);
|
25 |
|
26 | var _jwtDecode2 = require('jwt-decode');
|
27 |
|
28 | var _jwtDecode3 = _interopRequireDefault(_jwtDecode2);
|
29 |
|
30 | var _time = require('./time');
|
31 |
|
32 | var _time2 = _interopRequireDefault(_time);
|
33 |
|
34 | var _constants = require('./constants');
|
35 |
|
36 | var _errors = require('./errors');
|
37 |
|
38 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
39 |
|
40 | var debug = (0, _debug2.default)('craft-ai:client');
|
41 |
|
42 | function resolveAfterTimeout(timeout) {
|
43 | return new Promise(function (resolve) {
|
44 | return setTimeout(function () {
|
45 | return resolve();
|
46 | }, timeout);
|
47 | });
|
48 | }
|
49 |
|
50 |
|
51 | var SIMPLE_HTTP_URL_REGEX = /^https?:\/\/.*$/;
|
52 |
|
53 | function isUrl(url) {
|
54 | return SIMPLE_HTTP_URL_REGEX.test(url);
|
55 | }
|
56 |
|
57 | function createClient(tokenOrCfg) {
|
58 | var cfg = _lodash2.default.defaults({}, _lodash2.default.isString(tokenOrCfg) ? { token: tokenOrCfg } : tokenOrCfg, _defaults2.default);
|
59 |
|
60 |
|
61 | if (!_lodash2.default.has(cfg, 'token') || !_lodash2.default.isString(cfg.token)) {
|
62 | throw new _errors.CraftAiBadRequestError('Bad Request, unable to create a client with no or invalid token provided.');
|
63 | }
|
64 | try {
|
65 | var _jwtDecode = (0, _jwtDecode3.default)(cfg.token),
|
66 | owner = _jwtDecode.owner,
|
67 | platform = _jwtDecode.platform,
|
68 | project = _jwtDecode.project;
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | cfg.owner = cfg.owner || owner;
|
74 | cfg.project = cfg.project || project;
|
75 | cfg.url = cfg.url || platform;
|
76 | } catch (e) {
|
77 | throw new _errors.CraftAiCredentialsError();
|
78 | }
|
79 | if (!_lodash2.default.has(cfg, 'url') || !isUrl(cfg.url)) {
|
80 | throw new _errors.CraftAiBadRequestError('Bad Request, unable to create a client with no or invalid url provided.');
|
81 | }
|
82 | if (!_lodash2.default.has(cfg, 'project') || !_lodash2.default.isString(cfg.project)) {
|
83 | throw new _errors.CraftAiBadRequestError('Bad Request, unable to create a client with no or invalid project provided.');
|
84 | } else {
|
85 | var splittedProject = cfg.project.split('/');
|
86 | if (splittedProject.length >= 2) {
|
87 | cfg.owner = splittedProject[0];
|
88 | cfg.project = splittedProject[1];
|
89 | }
|
90 | }
|
91 | if (!_lodash2.default.has(cfg, 'owner') || !_lodash2.default.isString(cfg.owner)) {
|
92 | throw new _errors.CraftAiBadRequestError('Bad Request, unable to create a client with no or invalid owner provided.');
|
93 | }
|
94 | if (cfg.proxy != null && !isUrl(cfg.proxy)) {
|
95 | throw new _errors.CraftAiBadRequestError('Bad Request, unable to create a client with an invalid proxy url provided.');
|
96 | }
|
97 |
|
98 | debug('Creating a client instance for project \'' + cfg.owner + '/' + cfg.project + '\' on \'' + cfg.url + '\'.');
|
99 |
|
100 | var request = (0, _request2.default)(cfg);
|
101 |
|
102 |
|
103 | var instance = {
|
104 | cfg: cfg,
|
105 | createAgent: function createAgent(configuration) {
|
106 | var id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
107 |
|
108 | if (_lodash2.default.isUndefined(configuration) || !_lodash2.default.isObject(configuration)) {
|
109 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to create an agent with no or invalid configuration provided.'));
|
110 | }
|
111 |
|
112 | if (!_lodash2.default.isUndefined(id) && !_constants.AGENT_ID_ALLOWED_REGEXP.test(id)) {
|
113 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to create an agent with invalid agent id. It must only contain characters in "a-zA-Z0-9_-" and must be a string between 1 and ' + _constants.AGENT_ID_MAX_LENGTH + ' characters.'));
|
114 | }
|
115 |
|
116 | return request({
|
117 | method: 'POST',
|
118 | path: '/agents',
|
119 | body: {
|
120 | id: id,
|
121 | configuration: configuration
|
122 | }
|
123 | }).then(function (_ref) {
|
124 | var body = _ref.body;
|
125 |
|
126 | debug('Agent \'' + body.id + '\' created.');
|
127 | return body;
|
128 | });
|
129 | },
|
130 | getAgent: function getAgent(agentId) {
|
131 | if (!_constants.AGENT_ID_ALLOWED_REGEXP.test(agentId)) {
|
132 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get an agent with invalid agent id. It must only contain characters in "a-zA-Z0-9_-" and cannot be the empty string.'));
|
133 | }
|
134 |
|
135 | return request({
|
136 | method: 'GET',
|
137 | path: '/agents/' + agentId
|
138 | }).then(function (_ref2) {
|
139 | var body = _ref2.body;
|
140 | return body;
|
141 | });
|
142 | },
|
143 | listAgents: function listAgents(agentId) {
|
144 | return request({
|
145 | method: 'GET',
|
146 | path: '/agents'
|
147 | }).then(function (_ref3) {
|
148 | var body = _ref3.body;
|
149 | return body.agentsList;
|
150 | });
|
151 | },
|
152 | deleteAgent: function deleteAgent(agentId) {
|
153 | if (_lodash2.default.isUndefined(agentId)) {
|
154 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to delete an agent with no agentId provided.'));
|
155 | }
|
156 |
|
157 | return request({
|
158 | method: 'DELETE',
|
159 | path: '/agents/' + agentId
|
160 | }).then(function (_ref4) {
|
161 | var body = _ref4.body;
|
162 |
|
163 | debug('Agent \'' + agentId + '\' deleted');
|
164 | return body;
|
165 | });
|
166 | },
|
167 | destroyAgent: function destroyAgent(agentId) {
|
168 | (0, _constants.deprecation)('client.destroyAgent', 'client.deleteAgent');
|
169 | return this.deleteAgent(agentId);
|
170 | },
|
171 | getAgentContext: function getAgentContext(agentId) {
|
172 | var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
173 |
|
174 | if (_lodash2.default.isUndefined(agentId)) {
|
175 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get the agent context with no agentId provided.'));
|
176 | }
|
177 | var posixTimestamp = (0, _time2.default)(t).timestamp;
|
178 | if (_lodash2.default.isUndefined(posixTimestamp)) {
|
179 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get the agent context with an invalid timestamp provided.'));
|
180 | }
|
181 |
|
182 | return request({
|
183 | method: 'GET',
|
184 | path: '/agents/' + agentId + '/context/state',
|
185 | query: {
|
186 | t: posixTimestamp
|
187 | }
|
188 | }).then(function (_ref5) {
|
189 | var body = _ref5.body;
|
190 | return body;
|
191 | });
|
192 | },
|
193 | addAgentContextOperations: function addAgentContextOperations(agentId, operations) {
|
194 | if (_lodash2.default.isUndefined(agentId)) {
|
195 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to add agent context operations with no agentId provided.'));
|
196 | }
|
197 | if (!_lodash2.default.isArray(operations)) {
|
198 |
|
199 | operations = [operations];
|
200 | }
|
201 | operations = _lodash2.default.compact(operations);
|
202 |
|
203 | if (!operations.length) {
|
204 | var message = 'No operation to add to the agent ' + cfg.owner + '/' + cfg.project + '/' + agentId + ' context.';
|
205 |
|
206 | debug(message);
|
207 |
|
208 | return Promise.resolve({ message: message });
|
209 | }
|
210 |
|
211 | return (0, _lodash2.default)(operations).map(function (_ref6) {
|
212 | var context = _ref6.context,
|
213 | timestamp = _ref6.timestamp;
|
214 | return {
|
215 | context: context,
|
216 | timestamp: (0, _time2.default)(timestamp).timestamp
|
217 | };
|
218 | }).orderBy('timestamp').chunk(cfg.operationsChunksSize).reduce(function (p, chunk) {
|
219 | return p.then(function () {
|
220 | return request({
|
221 | method: 'POST',
|
222 | path: '/agents/' + agentId + '/context',
|
223 | body: chunk
|
224 | });
|
225 | });
|
226 | }, Promise.resolve()).then(function () {
|
227 | var message = 'Successfully added ' + operations.length + ' operation(s) to the agent ' + cfg.owner + '/' + cfg.project + '/' + agentId + ' context.';
|
228 | debug(message);
|
229 | return { message: message };
|
230 | });
|
231 | },
|
232 | getAgentContextOperations: function getAgentContextOperations(agentId) {
|
233 | var _this = this;
|
234 |
|
235 | var start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
236 | var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
|
237 |
|
238 | if (_lodash2.default.isUndefined(agentId)) {
|
239 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get agent context operations with no agentId provided.'));
|
240 | }
|
241 | var startTimestamp = void 0;
|
242 | if (start) {
|
243 | startTimestamp = (0, _time2.default)(start).timestamp;
|
244 | if (_lodash2.default.isUndefined(startTimestamp)) {
|
245 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get agent context operations with an invalid \'start\' timestamp provided.'));
|
246 | }
|
247 | }
|
248 | var endTimestamp = void 0;
|
249 | if (end) {
|
250 | endTimestamp = (0, _time2.default)(end).timestamp;
|
251 | if (_lodash2.default.isUndefined(endTimestamp)) {
|
252 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get agent context operations with an invalid \'end\' timestamp provided.'));
|
253 | }
|
254 | }
|
255 |
|
256 | var requestFollowingPages = function requestFollowingPages(_ref7) {
|
257 | var operations = _ref7.operations,
|
258 | nextPageUrl = _ref7.nextPageUrl;
|
259 |
|
260 | if (!nextPageUrl) {
|
261 | return Promise.resolve(operations);
|
262 | }
|
263 | return request({ url: nextPageUrl }, _this).then(function (_ref8) {
|
264 | var body = _ref8.body,
|
265 | nextPageUrl = _ref8.nextPageUrl;
|
266 | return requestFollowingPages({
|
267 | operations: operations.concat(body),
|
268 | nextPageUrl: nextPageUrl
|
269 | });
|
270 | });
|
271 | };
|
272 |
|
273 | return request({
|
274 | method: 'GET',
|
275 | path: '/agents/' + agentId + '/context',
|
276 | query: {
|
277 | start: startTimestamp,
|
278 | end: endTimestamp
|
279 | }
|
280 | }).then(function (_ref9) {
|
281 | var body = _ref9.body,
|
282 | nextPageUrl = _ref9.nextPageUrl;
|
283 | return requestFollowingPages({
|
284 | operations: body,
|
285 | nextPageUrl: nextPageUrl
|
286 | });
|
287 | });
|
288 | },
|
289 | getAgentStateHistory: function getAgentStateHistory(agentId) {
|
290 | var start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
291 | var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
|
292 |
|
293 | if (_lodash2.default.isUndefined(agentId)) {
|
294 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get agent state history with no agentId provided.'));
|
295 | }
|
296 | var startTimestamp = void 0;
|
297 | if (start) {
|
298 | startTimestamp = (0, _time2.default)(start).timestamp;
|
299 | if (_lodash2.default.isUndefined(startTimestamp)) {
|
300 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get agent state history with an invalid \'start\' timestamp provided.'));
|
301 | }
|
302 | }
|
303 | var endTimestamp = void 0;
|
304 | if (end) {
|
305 | endTimestamp = (0, _time2.default)(end).timestamp;
|
306 | if (_lodash2.default.isUndefined(endTimestamp)) {
|
307 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to get agent state history with an invalid \'end\' timestamp provided.'));
|
308 | }
|
309 | }
|
310 |
|
311 | var requestFollowingPages = function requestFollowingPages(_ref10) {
|
312 | var stateHistory = _ref10.stateHistory,
|
313 | nextPageUrl = _ref10.nextPageUrl;
|
314 |
|
315 | if (!nextPageUrl) {
|
316 | return Promise.resolve(stateHistory);
|
317 | }
|
318 | return request({ url: nextPageUrl }).then(function (_ref11) {
|
319 | var body = _ref11.body,
|
320 | nextPageUrl = _ref11.nextPageUrl;
|
321 | return requestFollowingPages({
|
322 | stateHistory: stateHistory.concat(body),
|
323 | nextPageUrl: nextPageUrl
|
324 | });
|
325 | });
|
326 | };
|
327 |
|
328 | return request({
|
329 | method: 'GET',
|
330 | path: '/agents/' + agentId + '/context/state/history',
|
331 | query: {
|
332 | start: startTimestamp,
|
333 | end: endTimestamp
|
334 | }
|
335 | }).then(function (_ref12) {
|
336 | var body = _ref12.body,
|
337 | nextPageUrl = _ref12.nextPageUrl;
|
338 | return requestFollowingPages({
|
339 | stateHistory: body,
|
340 | nextPageUrl: nextPageUrl
|
341 | });
|
342 | });
|
343 | },
|
344 | getAgentInspectorUrl: function getAgentInspectorUrl(agentId) {
|
345 | var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
346 |
|
347 | (0, _constants.deprecation)('client.getAgentInspectorUrl', 'client.getSharedAgentInspectorUrl');
|
348 | return this.getSharedAgentInspectorUrl(agentId, t);
|
349 | },
|
350 | getSharedAgentInspectorUrl: function getSharedAgentInspectorUrl(agentId) {
|
351 | var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
352 |
|
353 | return request({
|
354 | method: 'GET',
|
355 | path: '/agents/' + agentId + '/shared'
|
356 | }).then(function (_ref13) {
|
357 | var body = _ref13.body;
|
358 |
|
359 | if (_lodash2.default.isUndefined(t)) {
|
360 | return body.shortUrl;
|
361 | } else {
|
362 | var posixTimestamp = (0, _time2.default)(t).timestamp;
|
363 | return body.shortUrl + '?t=' + posixTimestamp;
|
364 | }
|
365 | });
|
366 | },
|
367 | deleteSharedAgentInspectorUrl: function deleteSharedAgentInspectorUrl(agentId) {
|
368 | return request({
|
369 | method: 'DELETE',
|
370 | path: '/agents/' + agentId + '/shared'
|
371 | }).then(function () {
|
372 | debug('Delete shared inspector link for agent "' + agentId + '".');
|
373 | });
|
374 | },
|
375 | getAgentDecisionTree: function getAgentDecisionTree(agentId) {
|
376 | var t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
377 | var version = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _constants.DEFAULT_DECISION_TREE_VERSION;
|
378 |
|
379 | if (_lodash2.default.isUndefined(agentId)) {
|
380 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to retrieve an agent decision tree with no agentId provided.'));
|
381 | }
|
382 | var posixTimestamp = (0, _time2.default)(t).timestamp;
|
383 | if (_lodash2.default.isUndefined(posixTimestamp)) {
|
384 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to retrieve an agent decision tree with an invalid timestamp provided.'));
|
385 | }
|
386 |
|
387 | var agentDecisionTreeRequest = function agentDecisionTreeRequest() {
|
388 | return request({
|
389 | method: 'GET',
|
390 | path: '/agents/' + agentId + '/decision/tree',
|
391 | query: {
|
392 | t: posixTimestamp
|
393 | },
|
394 | headers: {
|
395 | 'x-craft-ai-tree-version': version
|
396 | }
|
397 | }).then(function (_ref14) {
|
398 | var body = _ref14.body;
|
399 | return body;
|
400 | });
|
401 | };
|
402 |
|
403 | if (!cfg.decisionTreeRetrievalTimeout) {
|
404 |
|
405 | return agentDecisionTreeRequest();
|
406 | } else {
|
407 | var start = Date.now();
|
408 | return Promise.race([agentDecisionTreeRequest().catch(function (error) {
|
409 | var requestDuration = Date.now() - start;
|
410 | var expectedRetryDuration = requestDuration + 2000;
|
411 | var timeoutBeforeRetrying = cfg.decisionTreeRetrievalTimeout - requestDuration - expectedRetryDuration;
|
412 | if (error instanceof _errors.CraftAiLongRequestTimeOutError && timeoutBeforeRetrying > 0) {
|
413 |
|
414 | return resolveAfterTimeout(timeoutBeforeRetrying).then(function () {
|
415 | return agentDecisionTreeRequest();
|
416 | });
|
417 | } else {
|
418 | return Promise.reject(error);
|
419 | }
|
420 | }), resolveAfterTimeout(cfg.decisionTreeRetrievalTimeout).then(function () {
|
421 | throw new _errors.CraftAiLongRequestTimeOutError();
|
422 | })]);
|
423 | }
|
424 | },
|
425 | computeAgentDecision: function computeAgentDecision(agentId, t) {
|
426 | for (var _len = arguments.length, contexts = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
427 | contexts[_key - 2] = arguments[_key];
|
428 | }
|
429 |
|
430 | if (_lodash2.default.isUndefined(agentId)) {
|
431 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to compute an agent decision with no agentId provided.'));
|
432 | }
|
433 | var posixTimestamp = (0, _time2.default)(t).timestamp;
|
434 | if (_lodash2.default.isUndefined(posixTimestamp)) {
|
435 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to compute an agent decision with no or invalid timestamp provided.'));
|
436 | }
|
437 | if (_lodash2.default.isUndefined(contexts) || _lodash2.default.size(contexts) === 0) {
|
438 | return Promise.reject(new _errors.CraftAiBadRequestError('Bad Request, unable to compute an agent decision with no context provided.'));
|
439 | }
|
440 |
|
441 | return request({
|
442 | method: 'GET',
|
443 | path: '/agents/' + agentId + '/decision/tree',
|
444 | query: {
|
445 | t: posixTimestamp
|
446 | }
|
447 | }).then(function (_ref15) {
|
448 | var body = _ref15.body;
|
449 |
|
450 | var decision = _interpreter.decide.apply(undefined, [body].concat(contexts));
|
451 | decision.timestamp = posixTimestamp;
|
452 | return decision;
|
453 | });
|
454 | }
|
455 | };
|
456 |
|
457 | return instance;
|
458 | } |
\ | No newline at end of file |