@sassoftware/sas-score-mcp-serverjs 0.0.2

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.
Files changed (96) hide show
  1. package/.babelrc +6 -0
  2. package/.env +13 -0
  3. package/.env.http +29 -0
  4. package/CHANGES.md +2 -0
  5. package/CONTRIBUTING.md +14 -0
  6. package/ContributorAgreement.txt +56 -0
  7. package/LICENSE +205 -0
  8. package/LICENSES.json +105 -0
  9. package/QUICK_REFERENCE.md +378 -0
  10. package/README.md +267 -0
  11. package/SECURITY.md +31 -0
  12. package/SUPPORT.md +3 -0
  13. package/TOOL_DESCRIPTION_TEMPLATE.md +157 -0
  14. package/TOOL_UPDATES_SUMMARY.md +208 -0
  15. package/cli.js +214 -0
  16. package/labs/.subclass.json +13 -0
  17. package/labs/README.md +4 -0
  18. package/mcpConfigurations/README.md +3 -0
  19. package/mcpConfigurations/http.json +8 -0
  20. package/mcpConfigurations/stdio.json +20 -0
  21. package/mcpConfigurations/stdiodev.json +20 -0
  22. package/mcpserver.png +0 -0
  23. package/openApi.json +106 -0
  24. package/openApi.yaml +84 -0
  25. package/package.json +72 -0
  26. package/sas-mcp-tools-reference.md +600 -0
  27. package/sasCode/sas-sql-query.sas +33 -0
  28. package/sasCode/sas_sql_tool.json +237 -0
  29. package/scripts/getViyaca.sh +8 -0
  30. package/src/core.js +19 -0
  31. package/src/coreSSE.js +14 -0
  32. package/src/corehttp.js +335 -0
  33. package/src/createHttpTransport.js +26 -0
  34. package/src/createMcpServer.js +76 -0
  35. package/src/db/scrModels.js +23 -0
  36. package/src/toolSet/devaScore.js +69 -0
  37. package/src/toolSet/findJob.js +90 -0
  38. package/src/toolSet/findJobdef.js +95 -0
  39. package/src/toolSet/findLibrary.js +100 -0
  40. package/src/toolSet/findModel.js +83 -0
  41. package/src/toolSet/findTable.js +94 -0
  42. package/src/toolSet/getEnv.js +72 -0
  43. package/src/toolSet/listJobdefs.js +96 -0
  44. package/src/toolSet/listJobs.js +110 -0
  45. package/src/toolSet/listLibraries.js +90 -0
  46. package/src/toolSet/listModels.js +83 -0
  47. package/src/toolSet/listTables.js +95 -0
  48. package/src/toolSet/makeTools.js +75 -0
  49. package/src/toolSet/mcp server .png +0 -0
  50. package/src/toolSet/modelInfo.js +87 -0
  51. package/src/toolSet/modelScore.js +131 -0
  52. package/src/toolSet/readTable.js +104 -0
  53. package/src/toolSet/runCasProgram.js +118 -0
  54. package/src/toolSet/runJob.js +81 -0
  55. package/src/toolSet/runJobdef.js +85 -0
  56. package/src/toolSet/runMacro.js +82 -0
  57. package/src/toolSet/runProgram.js +145 -0
  58. package/src/toolSet/sasQuery.js +126 -0
  59. package/src/toolSet/sasQueryTemplate.js +148 -0
  60. package/src/toolSet/sasQueryTemplate2.js +140 -0
  61. package/src/toolSet/scrInfo.js +55 -0
  62. package/src/toolSet/scrScore.js +71 -0
  63. package/src/toolSet/searchAssets.js +52 -0
  64. package/src/toolSet/setContext.js +98 -0
  65. package/src/toolSet/superstat.js +60 -0
  66. package/src/toolSet/tableInfo.js +102 -0
  67. package/src/toolhelpers/_catalogSearch.js +87 -0
  68. package/src/toolhelpers/_getEnv.js +10 -0
  69. package/src/toolhelpers/_itemsData.js +28 -0
  70. package/src/toolhelpers/_jobSubmit.js +78 -0
  71. package/src/toolhelpers/_listJobdefs.js +59 -0
  72. package/src/toolhelpers/_listJobs.js +63 -0
  73. package/src/toolhelpers/_listLibrary.js +56 -0
  74. package/src/toolhelpers/_listModels.js +41 -0
  75. package/src/toolhelpers/_listTables.js +52 -0
  76. package/src/toolhelpers/_masDescribe.js +27 -0
  77. package/src/toolhelpers/_masScoring.js +64 -0
  78. package/src/toolhelpers/_readTable.js +69 -0
  79. package/src/toolhelpers/_scrInfo.js +32 -0
  80. package/src/toolhelpers/_scrScore.js +49 -0
  81. package/src/toolhelpers/_submitCasl.js +34 -0
  82. package/src/toolhelpers/_submitCode.js +96 -0
  83. package/src/toolhelpers/_submitMacro.js +24 -0
  84. package/src/toolhelpers/_tableColumns.js +61 -0
  85. package/src/toolhelpers/_tableInfo.js +72 -0
  86. package/src/toolhelpers/deleteSession.js +13 -0
  87. package/src/toolhelpers/getLogonPayload.js +100 -0
  88. package/src/toolhelpers/getOpts.js +43 -0
  89. package/src/toolhelpers/getOptsViya.js +38 -0
  90. package/src/toolhelpers/getStoreOpts.js +18 -0
  91. package/src/toolhelpers/getToken.js +40 -0
  92. package/src/toolhelpers/refreshToken.js +48 -0
  93. package/test/README.md +63 -0
  94. package/test/listLibraries.test.js +245 -0
  95. package/tool-developer-guide.md +80 -0
  96. package/types.js +25 -0
@@ -0,0 +1,59 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import restaf from '@sassoftware/restaf';
6
+
7
+
8
+ async function _listJobdefs(params) {
9
+ let { limit, start, name, _appContext } = params;
10
+
11
+ let store = restaf.initStore(_appContext.storeConfig);
12
+ let msg = await store.logon(_appContext.logonPayload);
13
+
14
+ try {
15
+ let { jobDefinitions } = await store.addServices('jobDefinitions');
16
+ let payload = {
17
+ qs: {
18
+ limit: (limit != null) ? limit : 10,
19
+ start: start - 1
20
+ }
21
+ };
22
+
23
+ if (name != null && name.trim().length > 0) {
24
+ payload.qs = {
25
+ filter: `eq(name, '${name}')`
26
+ }
27
+ }
28
+ let jobDefList = await store.apiCall(jobDefinitions.links('job-definitions'), payload);
29
+ if (jobDefList.itemsList().size === 0) {
30
+ return { content: [{ type: 'text', text: 'No jobDefinitions found' }] };
31
+ }
32
+
33
+ let names = {};
34
+ jobDefList.itemsList().map((id, n) => {
35
+ let jname = jobDefList.items(id, 'name');
36
+ let p = jobDefList.items(id, 'data', 'parameters');
37
+ if (names[jname] == null) {
38
+ names[jname] = { parameters: (p == null) ? {} : p.toJS() };
39
+ }
40
+ });
41
+
42
+ let response = {jobDefinitions: Object.keys(names)};
43
+ if (name != null) {
44
+ response = { name: name, parameters: names[name].parameters };
45
+ }
46
+
47
+ return {
48
+ content: [{ type: 'text', text: JSON.stringify(response) }],
49
+ structuredContent: response,
50
+ hint: (Object.keys(names).length === (limit || 10)) ? `next page start=${(start || 1) + (limit || 10)}` : undefined
51
+ };
52
+ } catch (err) {
53
+ console.error('Error in _listJobdefs', err);
54
+ return { isError: true, content: [{ type: 'text', text: `Error retrieving job definitions: ${err}` }] };
55
+
56
+ }
57
+ }
58
+
59
+ export default _listJobdefs;
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import restaf from '@sassoftware/restaf';
7
+
8
+ async function _listJobs(params) {
9
+ let { limit, start, name, _appContext } = params;
10
+
11
+ let store = restaf.initStore(_appContext.storeConfig);
12
+ let msg = await store.logon(_appContext.logonPayload);
13
+
14
+
15
+ let { jobExecution } = await store.addServices('jobExecution');
16
+ try {
17
+ let payload = {
18
+ qs: {
19
+ limit: (limit != null) ? limit : 10,
20
+ start: start - 1
21
+ }
22
+ };
23
+
24
+ if (name != null && name.trim().length > 0) {
25
+ payload.qs = {
26
+ filter: `eq(name, '${name}')`
27
+ }
28
+ }
29
+ console.error('payload', JSON.stringify(payload, null, 2));
30
+ let jobList = await store.apiCall(jobExecution.links('jobs'), payload);
31
+ if (jobList.itemsList().size === 0) {
32
+ return { content: [{ type: 'text', text: 'No jobs found' }] };
33
+ }
34
+
35
+ let names = {};
36
+
37
+ jobList.itemsList().map((id, n) => {
38
+ let jname = jobList.items(id, 'data', 'jobRequest', 'name');
39
+
40
+ if (names[jname] == null) {
41
+ let value = jobList.items(id, 'data', 'jobRequest', 'jobDefinition', 'parameters');
42
+ names[jname] = {parameters: (value == null) ? {} : value.toJS() };
43
+ }
44
+ });
45
+
46
+ let response = {jobs: Object.keys(names)};
47
+
48
+ if (name != null) {
49
+ response = { name: name, parameters: names[name].parameters };
50
+ };
51
+ return {
52
+ content: [{ type: 'text', text: JSON.stringify(response) }],
53
+ structuredContent: response,
54
+ hint: (Object.keys(names).length === (limit || 10)) ? `next page start=${(start || 1) + (limit || 10)}` : undefined
55
+ };
56
+ } catch (err) {
57
+ console.error('Error in _listJobs', err);
58
+ return { isError: true, content: [{ type: 'text', text: `Error retrieving jobs: ${err}` }] };
59
+
60
+ }
61
+ }
62
+
63
+ export default _listJobs;
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import restafedit from '@sassoftware/restafedit';
7
+ import deleteSession from './deleteSession.js';
8
+
9
+ async function _listLibrary(params ){
10
+
11
+ let { server, limit, start, name, _appContext } = params;
12
+
13
+ let config = {
14
+ casServerName: _appContext.cas,
15
+ computeContext: _appContext.sas,
16
+ source: (server === 'sas') ? 'compute' : server,
17
+ table: null
18
+ };
19
+
20
+ try {
21
+ // setup request control
22
+ let appControl = await restafedit.setup(
23
+ _appContext.logonPayload,
24
+ config
25
+ ,null,{},'user',{}, {}, _appContext.storeConfig
26
+ );
27
+
28
+ // query parameters
29
+ let payload = {
30
+ qs: {
31
+ limit: (limit != null) ? limit : 10,
32
+ start: start - 1
33
+ }
34
+ };
35
+
36
+ if (name != null) {
37
+ payload.qs = {
38
+ filter: `eq(name, '${name}')`
39
+ }
40
+ }
41
+
42
+ let items = await restafedit.getLibraryList(appControl, payload);
43
+ let response = {libraries: items};
44
+ await deleteSession(appControl);
45
+
46
+ return { content: [{ type: 'text', text: JSON.stringify(response) }],
47
+ structuredContent: response
48
+ };
49
+ } catch (err) {
50
+ console.error(JSON.stringify(err));
51
+ await deleteSession(appControl);
52
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
53
+ }
54
+ }
55
+
56
+ export default _listLibrary;
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import restaf from '@sassoftware/restaf';
7
+
8
+ async function _listModels(params) {
9
+ let { limit, start , name, _appContext} = params;;
10
+ // setup
11
+
12
+ let store = restaf.initStore(_appContext.storeConfig);
13
+
14
+ try {
15
+ await store.logon(_appContext.logonPayload);
16
+ let { microanalyticScore } = await store.addServices('microanalyticScore');
17
+ let payload = {
18
+ qs: {
19
+ limit: Math.max(limit,1),
20
+ start: Math.max(start-1, 0)
21
+ }
22
+ }
23
+ if (name != null) {
24
+ payload.qs = {
25
+ filter: `eq(name, '${name}')`
26
+ }
27
+ }
28
+ let result = await store.apiCall(microanalyticScore.links('modules'), payload);
29
+ if (result.itemsList().size === 0) {
30
+ return { content: [{ type: 'text', text: `No models exist in MAS server` }]};
31
+ }
32
+ let list = {models: result.itemsList().toJS()};
33
+ return { content: [{ type: 'text', text: JSON.stringify(list) }],
34
+ structuredContent: list
35
+ };
36
+ } catch (err) {
37
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
38
+ }
39
+ }
40
+
41
+ export default _listModels;
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import restafedit from '@sassoftware/restafedit';
7
+
8
+ async function _listTables(params) {
9
+ let { server, lib, limit, start, name, _appContext} = params;
10
+
11
+ let config = {
12
+ casServerName: _appContext.cas,
13
+ computeContext: _appContext.sas,
14
+ source: (server === 'sas') ? 'compute' : server,
15
+ table: null
16
+ };
17
+
18
+ try {
19
+ let appControl = await restafedit.setup(
20
+ _appContext.logonPayload,
21
+ config,
22
+ null,/* create a session */
23
+ {},
24
+ 'user',
25
+ _appContext.storeConfig
26
+ );
27
+
28
+ let payload = {
29
+ qs: {
30
+ limit: (typeof limit === 'number') ? limit : 10, // Use provided limit or default to 10
31
+ start: (typeof start === 'number') ? Math.max(0, start - 1) : 0,
32
+ }
33
+ };
34
+
35
+ if (name != null) {
36
+ // Normalize to upper-case to match table name casing in CAS (e.g. COSTCHANGE)
37
+ const nameVal = ('' + name).toUpperCase();
38
+ payload.qs.filter = `eq(name, '${nameVal}')`;
39
+ }
40
+
41
+ let items = await restafedit.getTableList(lib, appControl, payload);
42
+ let response = {tables: items};
43
+ return {content: [{ type: 'text', text: JSON.stringify(response) }],
44
+ structuredContent: response};
45
+ } catch (err) {
46
+ console.error(JSON.stringify(err));
47
+ return {isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] }
48
+ }
49
+
50
+ };
51
+
52
+ export default _listTables;
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import restaflib from '@sassoftware/restaflib';
6
+ import restaf from '@sassoftware/restaf';
7
+
8
+ async function _masDescribe(params) {
9
+ // setup
10
+ let {model, _appContext} = params;
11
+ let { masSetup, masDescribe } = restaflib;
12
+ let store = restaf.initStore(_appContext.storeConfig);
13
+
14
+ try {
15
+ let masControl = await masSetup(store, [model], _appContext.logonPayload);
16
+ let describe = await masDescribe(masControl, model, null,true);
17
+ let response = {decription: describe};
18
+ return { content: [{ type: 'text', text: JSON.stringify(response) }],
19
+ structuredContent: response
20
+ };
21
+ } catch (err) {
22
+ console.error(err);
23
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
24
+ }
25
+ }
26
+
27
+ export default _masDescribe;
@@ -0,0 +1,64 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import restaflib from '@sassoftware/restaflib';
6
+ import restaf from '@sassoftware/restaf';
7
+
8
+
9
+ async function _masScoring(params) {
10
+
11
+ // setup
12
+ let {model, scenario, uflag, _appContext} = params;
13
+ let { masSetup, masDescribe, masRun } = restaflib;
14
+ let store = restaf.initStore(_appContext.storeConfig);
15
+
16
+ let inputs = {};
17
+ let masControl;
18
+
19
+ try {
20
+
21
+ masControl = await masSetup(store, [model], _appContext.logonPayload);
22
+ let describe = await masDescribe(masControl, model);
23
+ let inputs = {};
24
+ let types = {};
25
+ describe.forEach(d => {
26
+ inputs[d.name] = null;
27
+ types[d.name] = d.type;
28
+ });
29
+
30
+ if (scenario === null) {
31
+ // if scenario is empty, return the inputs
32
+ return { content: [{ type: 'text', text: JSON.stringify(inputs) }] };
33
+ }
34
+ let iscenario = {};
35
+
36
+ for (let v in inputs) {
37
+ let v1 = (uflag === true) ? v.substring(0, v.length - 1) : v;
38
+ let t = (scenario[v1] == null) ? null : scenario[v1];
39
+ t = (types[v] === 'decimal' && typeof t === 'string' ) ? parseFloat(t) : t;
40
+ iscenario[v] = t;
41
+ }
42
+
43
+ let result = await masRun(store, masControl, model, iscenario);
44
+
45
+ // add a unique key for the result
46
+
47
+ let r = {...result, ...iscenario};
48
+ let t = '';
49
+ let sep = ''
50
+ for (let k in r) {
51
+ t += sep + k + '=' + r[k];
52
+ sep = ', ';
53
+ }
54
+
55
+ return { content: [{ type: 'text', text: JSON.stringify(r)}], structuredContent: r};
56
+
57
+ } catch (err) {
58
+ console.error('Error in _masScoring:', err);
59
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: { statusCode: 2, msg: err } }) }] };
60
+ }
61
+ }
62
+
63
+ export default _masScoring;
64
+
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import restafedit from '@sassoftware/restafedit';
6
+ import deleteSession from './deleteSession.js';
7
+
8
+ async function _readTable(params) {
9
+ let { table, lib, start, limit, server, format, where, _appContext } = params;
10
+
11
+
12
+ if (table.includes('.')) {
13
+ let parts = table.split('.');
14
+ lib = parts[0];
15
+ table = parts[1];
16
+ }
17
+ let itable = { name: table };
18
+ if (server === 'cas') {
19
+ itable.caslib = lib;
20
+ } else {
21
+ itable.libref = lib;
22
+ }
23
+ let config = {
24
+ casServerName: _appContext.cas,
25
+ computeContext: _appContext.sas,
26
+ source: (server === 'sas') ? 'compute' : server,
27
+ casServer: _appContext.cas,
28
+ table: itable,
29
+
30
+ initialFetch: {
31
+ qs: {
32
+ start: (start == null) ? 0 : start - 1, // Adjust for 0-based index
33
+ limit: limit,
34
+ format: format || false,
35
+ where: where || ''
36
+ }
37
+ }
38
+ };
39
+
40
+ let appControl = {};
41
+ try {
42
+ appControl = await restafedit.setup(
43
+ _appContext.logonPayload,
44
+ config,
45
+ null,/* create a sessiion */
46
+ {},
47
+ 'user',
48
+ _appContext.storeConfig
49
+ );
50
+
51
+ await restafedit.scrollTable('first', appControl);
52
+
53
+ let outdata = appControl.state.data.map((d) => {
54
+ delete d._rowIndex;
55
+ delete d._modified;
56
+ delete d._index_;
57
+ return d;
58
+ });
59
+ let tabled = { tabled: outdata };
60
+ let t = (limit === 1) ? JSON.stringify(outdata[0]) : JSON.stringify(tabled);
61
+ return { content: [{ type: 'text', text: t }], structuredContent: tabled };
62
+
63
+ } catch (err) {
64
+ await deleteSession(appControl);
65
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }],
66
+ };
67
+ }
68
+ }
69
+ export default _readTable;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import axios from 'axios';
7
+
8
+ async function _scrInfo(params) {
9
+ let {url} = params;
10
+ let config = {
11
+ method: 'GET',
12
+ url: url + '/apiMeta/api',
13
+ headers: {
14
+ 'Accept': 'application/json'
15
+ }
16
+ }
17
+ try {
18
+ console.error('[Note] Config:', config);
19
+ let response = await axios(config);
20
+ console.error('[Note] Response status:', response.status);
21
+ let r = {
22
+ input: response.data.components.schemas.SCRInput.properties.data.properties,
23
+ output: response.data.components.schemas.SCROutput.properties.data.properties
24
+ };
25
+ console.error('[Note] Response data:', JSON.stringify(r, null, 2));
26
+ return {content: [{ type: 'text', text: JSON.stringify(r)}], structuredContent: r};
27
+ }
28
+ catch (error) {
29
+ return {isError: true,content: [{ type: 'text', text: JSON.stringify(error) }]};
30
+ }
31
+ }
32
+ export default _scrInfo;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import axios from 'axios';
7
+
8
+
9
+ async function _scrScore(params) {
10
+ let { url, scenario} = params;
11
+
12
+
13
+ let data = scenario.split(',').reduce((acc, pair) => {
14
+ let [key, value] = pair.split('=');
15
+ acc[key.trim()] = value.trim();
16
+ return acc;
17
+ }, {});
18
+
19
+ let config = {
20
+ method: 'POST',
21
+ url: url,
22
+ headers: {
23
+ 'Content-Type': 'application/json',
24
+ 'Accept': 'application/json'
25
+ },
26
+ data: data
27
+ };
28
+
29
+ try {
30
+ console.error('[Note] Config:', config);
31
+ let response = await axios(config);
32
+ console.error('[Note] Response status:', response.status);
33
+ console.error('[Note] Response data:', response.data);
34
+ let t = ' ';
35
+ let sep = ''
36
+ for (let k in r) {
37
+ t += sep + k + '=' + r[k];
38
+ sep = ', ';
39
+ }
40
+ console.error('t', t);
41
+ let r = { ...response.data, ...scenario }; // merge the response with the scenario and add a unique key
42
+ return { content: [{ type: 'text', text: JSON.stringify(r) }], structuredContent: r };
43
+
44
+ }
45
+ catch (error) {
46
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(error) }] };
47
+ }
48
+ }
49
+ export default _scrScore;
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import restaflib from '@sassoftware/restaflib';
6
+
7
+ async function _submitCasl(params) {
8
+ let { src, args, _appContext } = params;
9
+
10
+ let store = restaf.initStore(_appContext.storeConfig);
11
+
12
+ let session = await restaflib.casSetup(store, _appContext.logonPayload, null, _appContext.cas);
13
+ if (session == null) {
14
+ return {content: [{ type: 'text', text: 'Could not create a cas session' }]};
15
+ }
16
+
17
+ try {
18
+ try {
19
+ let r = await caslRun(store, session, src, (args == null) ? {} : args, true);
20
+ await store.apiCall( session.links( 'delete' ) );
21
+
22
+ return {content: [{ type: 'text', text: JSON.stringify(r.items()) }], structuredContent: r.items() };
23
+ } catch (err) {
24
+ console.error(err);
25
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
26
+ }
27
+ }
28
+ catch (err) {
29
+ console.error(err);
30
+ await store.apiCall( session.links( 'delete' ) );
31
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err) }] };
32
+ }
33
+ }
34
+ export default _submitCasl;
@@ -0,0 +1,96 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import restaf from '@sassoftware/restaf';
6
+ import restaflib from '@sassoftware/restaflib';
7
+
8
+
9
+ async function _submitCode(params) {
10
+ let { output, limit, args, src, _appContext } = params;
11
+ try {
12
+ // setup
13
+ let store = restaf.initStore(_appContext.storeConfig);
14
+
15
+ // get compute sessio, run sas code and retrieve result
16
+
17
+ let computeSession = await restaflib.computeSetup(store, _appContext.sas, _appContext.logonPayload);
18
+ let computeSummary = await restaflib.computeRun(store, computeSession, src, args);
19
+
20
+ let jobStatus = computeSummary.SASJobStatus;
21
+ let structuredOutput = {};
22
+ if (jobStatus === 'failed' || jobStatus === 'error' || jobStatus === 'running') {
23
+ let msg = `Job ended with status of ${jobStatus}. Please check the log for errors.`;
24
+ let log = await computeResults(store, computeSummary, 'log');
25
+ let status = { status: { statusCode: 2, msg: msg } };
26
+ structuredOutput = { status, log: log2html(log) };
27
+ }
28
+ else {
29
+ let ods = await restaflib.computeResults(store, computeSummary, "ods");
30
+ let log = await restaflib.computeResults(store, computeSummary, "log");
31
+ let listing = await restaflib.computeResults(store, computeSummary, "listing");
32
+ let tables = await restaflib.computeResults(store, computeSummary, 'tables');
33
+ let cc = jobStatus === 'warning' ? 1 : 0;
34
+ let status = { status: { statusCode: cc, msg: `Job completed with status ${jobStatus}` } };
35
+
36
+ let rows = [];
37
+ let notes = ' ';
38
+ let tabled = [];
39
+ if (output != null && output.trim().length > 0 && output.trim().toLowerCase() !== 'none') {
40
+ if (tables.includes(output.toUpperCase()) === false) {
41
+ let msg = `The requested output table ${output} was not found in the response.
42
+ Please check the tables element for available tables.`;
43
+ notes = { status: { statusCode: 1, msg: msg } };
44
+ } else {
45
+ let tpayload = {
46
+ qs: {
47
+ limit: (limit != null) ? limit : 100,
48
+ start: 0
49
+ }
50
+ }
51
+ rows = await restaflib.computeFetchData(store, computeSummary, output, null, tpayload);
52
+ let schema = rows.schema;
53
+ let data = rows.rows;
54
+ tabled = data.map(row => {
55
+ let obj = {};
56
+ schema.forEach((col, index) => {
57
+ obj[col.name] = row[index];
58
+ });
59
+ return obj; });
60
+ }
61
+ }
62
+ structuredOutput = { status, ods, log: log2html(log), listing: log2html(listing), tables: tables, output: output, tabled: tabled, notes: notes };
63
+ }
64
+ // add output tables next
65
+
66
+ // cleanup
67
+ await store.apiCall(computeSession.links('delete'));
68
+
69
+ // return results in the format the LLM expects
70
+
71
+ return {
72
+ content: [{ type: 'text', text: JSON.stringify(structuredOutput) }],
73
+ structuredContent: structuredOutput
74
+ };
75
+ }
76
+ catch (error) {
77
+ // Oops! Something went wrong
78
+ console.error(`Error in _submitCode: ${JSON.stringify(error)}`);
79
+ let e = { error: error };
80
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(e) }], structuredContent: e };
81
+ }
82
+ function log2html(log) {
83
+ let logText = '';
84
+ // eslint-disable-next-line array-callback-return
85
+ log.map((data) => {
86
+ let line = data.line.replace(/(\r\n|\n|\r)/gm, "");
87
+ if (line.length === 0) {
88
+ logText = logText + '\n';
89
+ } else { }
90
+ logText = logText + line + '\n';
91
+ });
92
+ return logText;
93
+ };
94
+ }
95
+
96
+ export default _submitCode;
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import _submitCode from './_submitCode.js';
7
+
8
+ async function _submitMacro(params) {
9
+ let {macro, scenario, _appContext} = params;
10
+ try {
11
+ let src = ` %${macro};$scenario; `;
12
+ // setup
13
+ let iparams = {src: src, _appContext: _appContext};
14
+ return await _submitCode( iparams);
15
+ }
16
+ catch (error) {
17
+ // Oops! Something went wrong
18
+ console.error(`Error in _submitCode: ${JSON.stringify(error)}`);
19
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(error) }] }
20
+ }
21
+ };
22
+
23
+
24
+ export default _submitMacro;