@sassoftware/sas-score-mcp-serverjs 1.0.1-9 → 1.1.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.
- package/.skills/.claude-plugin/plugin.json +59 -0
- package/.skills/agents/sas-score-mcp-serverjs-agent.md +26 -0
- package/.skills/copilot-instructions.md +62 -0
- package/.skills/skills/README.md +204 -0
- package/.skills/skills/detail-strategy/SKILL.md +316 -0
- package/.skills/skills/find-library-server/SKILL.md +62 -0
- package/.skills/skills/find-resources/SKILL.md +66 -0
- package/.skills/skills/list-library/SKILL.md +30 -0
- package/.skills/skills/list-mas-job-jobdef/SKILL.md +31 -0
- package/.skills/skills/list-tables/SKILL.md +30 -0
- package/.skills/skills/read-strategy/SKILL.md +87 -0
- package/.skills/skills/request-routing/SKILL.md +112 -0
- package/.skills/skills/score-cas/SKILL.md +95 -0
- package/.skills/skills/score-job-jobdef/SKILL.md +58 -0
- package/.skills/skills/score-mas-scr/SKILL.md +58 -0
- package/.skills/skills/score-program/SKILL.md +59 -0
- package/.skills/skills/score-strategy/SKILL.md +39 -0
- package/README.md +96 -54
- package/cli.js +11 -13
- package/openApi.yaml +121 -121
- package/package.json +16 -14
- package/scripts/docs/SCORE_SKILL_REFERENCE.md +17 -16
- package/scripts/docs/TOOL_DESCRIPTION_TEMPLATE.md +3 -3
- package/scripts/docs/TOOL_UPDATES_SUMMARY.md +65 -63
- package/scripts/docs/oauth-http-transport.md +2 -2
- package/scripts/docs/sas-mcp-tools-reference.md +43 -32
- package/scripts/plot_msrp_usa.py +49 -0
- package/scripts/refreshtoken.js +58 -0
- package/scripts/runListScr.mjs +16 -0
- package/src/createMcpServer.js +4 -1
- package/src/expressMcpServer.js +47 -49
- package/src/oauthHandlers/authorize.js +4 -1
- package/src/oauthHandlers/baseUrl.js +4 -0
- package/src/oauthHandlers/callback.js +4 -0
- package/src/oauthHandlers/getMetadata.js +4 -0
- package/src/oauthHandlers/index.js +4 -0
- package/src/oauthHandlers/token.js +4 -0
- package/src/openApi.yaml +121 -121
- package/src/processHeaders.js +10 -7
- package/src/setupSkills.js +1 -18
- package/src/toolHelpers/_casScore.js +32 -0
- package/src/toolHelpers/_desc.js +14 -0
- package/src/toolHelpers/_findJob.js +12 -0
- package/src/toolHelpers/_findJobdef.js +10 -0
- package/src/toolHelpers/_findLibrary.js +11 -0
- package/src/toolHelpers/_findMas.js +13 -0
- package/src/toolHelpers/_findScr.js +36 -0
- package/src/toolHelpers/_findTable.js +11 -0
- package/src/toolHelpers/_listJobdefs.js +12 -2
- package/src/toolHelpers/_listJobs.js +19 -8
- package/src/toolHelpers/{_listModels.js → _listMas.js} +4 -4
- package/src/toolHelpers/_listScr.js +13 -0
- package/src/toolHelpers/{_scrInfo.js → _scrDescribe.js} +4 -4
- package/src/toolHelpers/_scrScore.js +2 -2
- package/src/toolHelpers/_submitCasl.js +19 -17
- package/src/toolHelpers/{_tableInfo.js → _tableDescribe.js} +2 -2
- package/src/toolHelpers/getLogonPayload.js +2 -2
- package/src/toolSet/casModelScore.js +93 -0
- package/src/toolSet/casProgramScore.js +105 -0
- package/src/toolSet/devaScore.js +66 -61
- package/src/toolSet/findJob.js +24 -9
- package/src/toolSet/findJobdef.js +22 -19
- package/src/toolSet/findLibrary.js +73 -68
- package/src/toolSet/findMas.js +72 -0
- package/src/toolSet/findScr.js +69 -0
- package/src/toolSet/findTable.js +34 -27
- package/src/toolSet/getEnv.js +6 -6
- package/src/toolSet/jobDescribe.js +65 -0
- package/src/toolSet/jobScore.js +90 -0
- package/src/toolSet/jobdefDescribe.js +67 -0
- package/src/toolSet/jobdefScore.js +85 -0
- package/src/toolSet/listJobdefs.js +70 -61
- package/src/toolSet/listJobs.js +68 -61
- package/src/toolSet/listLibraries.js +84 -78
- package/src/toolSet/listMas.js +71 -0
- package/src/toolSet/listScr.js +62 -0
- package/src/toolSet/listTables.js +78 -66
- package/src/toolSet/{runMacro.js → macroScore.js} +86 -82
- package/src/toolSet/makeTools.js +39 -25
- package/src/toolSet/masDescribe.js +67 -0
- package/src/toolSet/masScore.js +95 -0
- package/src/toolSet/{runProgram.js → programScore.js} +21 -18
- package/src/toolSet/readTable.js +80 -63
- package/src/toolSet/sasQuery.js +83 -77
- package/src/toolSet/scrDescribe.js +55 -0
- package/src/toolSet/scrScore.js +63 -70
- package/src/toolSet/searchAssets.js +1 -1
- package/src/toolSet/setContext.js +70 -65
- package/src/toolSet/superstat.js +61 -61
- package/src/toolSet/tableDescribe.js +65 -0
- package/.agents/sas-score-mcp-serverjs-agent.md +0 -58
- package/.instructions/copilot-instructions.md +0 -201
- package/.instructions/enforce-find-resource-strategy.md +0 -35
- package/.skills/sas-find-library-smart/SKILL.md +0 -155
- package/.skills/sas-find-resource-strategy/SKILL.md +0 -105
- package/.skills/sas-list-resource-strategy/SKILL.md +0 -124
- package/.skills/sas-list-tables-smart/SKILL.md +0 -128
- package/.skills/sas-read-and-score-strategy/SKILL.md +0 -113
- package/.skills/sas-read-strategy/SKILL.md +0 -154
- package/.skills/sas-request-classifier/SKILL.md +0 -74
- package/.skills/sas-score-workflow-strategy/SKILL.md +0 -314
- package/scripts/optimize_final.py +0 -140
- package/scripts/optimize_tools.py +0 -99
- package/scripts/setup-skills.js +0 -34
- package/scripts/update_descriptions.py +0 -46
- package/src/authpkce.js +0 -219
- package/src/handleGetDelete.js +0 -34
- package/src/handleRequest.js +0 -112
- package/src/hapiMcpServer.js +0 -241
- package/src/toolSet/findModel.js +0 -60
- package/src/toolSet/listModels.js +0 -56
- package/src/toolSet/modelInfo.js +0 -55
- package/src/toolSet/modelScore.js +0 -89
- package/src/toolSet/runCasProgram.js +0 -98
- package/src/toolSet/runJob.js +0 -81
- package/src/toolSet/runJobdef.js +0 -82
- package/src/toolSet/scrInfo.js +0 -52
- package/src/toolSet/tableInfo.js +0 -58
package/src/hapiMcpServer.js
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import appServer from "@sassoftware/viya-serverjs";
|
|
6
|
-
import handleRequest from "./handleRequest.js";
|
|
7
|
-
import handleGetDelete from "./handleGetDelete.js";
|
|
8
|
-
import urlOpen from "./urlOpen.js";
|
|
9
|
-
import fs from "fs";
|
|
10
|
-
|
|
11
|
-
async function hapiMcpServer(mcpServer, cache, baseAppEnvContext) {
|
|
12
|
-
|
|
13
|
-
console.error('Starting Hapi MCP server...');
|
|
14
|
-
console.error("[Note]: Hapi MCP server started...", baseAppEnvContext.AUTHFLOW);
|
|
15
|
-
process.env.REDIRECT = `/status`;
|
|
16
|
-
process.env.APPHOST = '0.0.0.0';
|
|
17
|
-
let r = await appServer.asyncCore(mcpHandlers, true, 'app', null);
|
|
18
|
-
console.error('Hapi server running result:', r);
|
|
19
|
-
if (baseAppEnvContext.AUTHFLOW === 'code' && baseAppEnvContext.AUTOLOGON === 'TRUE') {
|
|
20
|
-
await urlOpen(r);
|
|
21
|
-
}
|
|
22
|
-
return r;
|
|
23
|
-
|
|
24
|
-
// add MCP handlers to the app server
|
|
25
|
-
|
|
26
|
-
function mcpHandlers() {
|
|
27
|
-
function getHtml() {
|
|
28
|
-
return `
|
|
29
|
-
<!DOCTYPE html>
|
|
30
|
-
<html lang="en">
|
|
31
|
-
<head>
|
|
32
|
-
<meta charset="UTF-8">
|
|
33
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
34
|
-
<title>sas-score-mcp-server</title>
|
|
35
|
-
<style>
|
|
36
|
-
* {
|
|
37
|
-
margin: 0;
|
|
38
|
-
padding: 0;
|
|
39
|
-
box-sizing: border-box;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
body {
|
|
43
|
-
font-family: Arial, sans-serif;
|
|
44
|
-
height: 100vh;
|
|
45
|
-
overflow: hidden;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
dialog {
|
|
49
|
-
position: fixed;
|
|
50
|
-
left: 50%;
|
|
51
|
-
right: auto;
|
|
52
|
-
top: 0;
|
|
53
|
-
transform: translateX(-50%);
|
|
54
|
-
width: fit-content;
|
|
55
|
-
height: fit-content;
|
|
56
|
-
border: none;
|
|
57
|
-
border-radius: 4px;
|
|
58
|
-
padding: 16px;
|
|
59
|
-
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
dialog::backdrop {
|
|
63
|
-
background-color: rgba(0, 0, 0, 0.1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
dialog h2 {
|
|
67
|
-
font-size: 18px;
|
|
68
|
-
margin-bottom: 12px;
|
|
69
|
-
color: #000;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
dialog p {
|
|
73
|
-
font-family: 'Courier New', monospace;
|
|
74
|
-
font-size: 12px;
|
|
75
|
-
width: fit-content;
|
|
76
|
-
line-height: 1.6;
|
|
77
|
-
color: #333;
|
|
78
|
-
word-wrap: break-word;
|
|
79
|
-
white-space: pre-wrap;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/* Window styling to show it's 10px larger than dialog */
|
|
83
|
-
body::before {
|
|
84
|
-
display: none;
|
|
85
|
-
}
|
|
86
|
-
</style>
|
|
87
|
-
</head>
|
|
88
|
-
<body>
|
|
89
|
-
<dialog open>
|
|
90
|
-
<h2>sas-score-mcp-server</h2>
|
|
91
|
-
<p>The mcp server is now ready for use. </p>
|
|
92
|
-
<p>You can close this window</p>
|
|
93
|
-
<p>For information on the tools see this documentation link:</p>
|
|
94
|
-
<a href="https://github.com/sassoftware/sas-score-mcp-serverjs/wiki " target="_blank">Summary of tools </a>
|
|
95
|
-
</p>
|
|
96
|
-
</dialog>
|
|
97
|
-
</body>
|
|
98
|
-
</html>
|
|
99
|
-
`;
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
let routes = [
|
|
103
|
-
{
|
|
104
|
-
method: ["GET"],
|
|
105
|
-
path: "/health",
|
|
106
|
-
options: {
|
|
107
|
-
handler: async (req, h) => {
|
|
108
|
-
let health = {
|
|
109
|
-
name: "@sassoftware/mcp-server",
|
|
110
|
-
version: baseAppEnvContext.version,
|
|
111
|
-
description: "SAS Viya Sample MCP Server",
|
|
112
|
-
endpoints: {
|
|
113
|
-
mcp: "/mcp",
|
|
114
|
-
health: "/health",
|
|
115
|
-
apiMeta: "/apiMeta"
|
|
116
|
-
},
|
|
117
|
-
usage:
|
|
118
|
-
"Use with MCP Inspector or compatible MCP clients like vscode or your own MCP client",
|
|
119
|
-
};
|
|
120
|
-
console.error("Health check requested, returning:", health);
|
|
121
|
-
return h.response(health).code(200).type('application/json');
|
|
122
|
-
},
|
|
123
|
-
auth: false,
|
|
124
|
-
description: "Help",
|
|
125
|
-
notes: "Help",
|
|
126
|
-
tags: ["mcp"],
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
method: ["GET"],
|
|
131
|
-
path: "/ready",
|
|
132
|
-
options: {
|
|
133
|
-
handler: async (req, h) => {
|
|
134
|
-
let status = {status: 1};
|
|
135
|
-
console.error("Ready check requested, returning:", status);
|
|
136
|
-
return h.response(status).code(200).type('application/json');
|
|
137
|
-
},
|
|
138
|
-
auth: false,
|
|
139
|
-
description: "probe readiness of the server",
|
|
140
|
-
notes: "Help",
|
|
141
|
-
tags: ["mcp"],
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
method: ["GET"],
|
|
146
|
-
path: "/StartUp",
|
|
147
|
-
options: {
|
|
148
|
-
handler: async (req, h) => {
|
|
149
|
-
let status = { status: 1 };
|
|
150
|
-
console.error("Startup check requested, returning:", status);
|
|
151
|
-
return h.response(status).code(200).type('application/json');
|
|
152
|
-
},
|
|
153
|
-
auth: false,
|
|
154
|
-
description: "probe startup of the server",
|
|
155
|
-
notes: "Help",
|
|
156
|
-
tags: ["mcp"],
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
method: ["GET"],
|
|
161
|
-
path: "/apiMeta",
|
|
162
|
-
options: {
|
|
163
|
-
handler: async (req, h) => {
|
|
164
|
-
let spec = openAPIJson();
|
|
165
|
-
return h.response(spec).code(200).type('application/json');
|
|
166
|
-
},
|
|
167
|
-
auth: false,
|
|
168
|
-
description: "API Metadata"
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
method: ["GET"],
|
|
173
|
-
path: "/openapi.json",
|
|
174
|
-
options: {
|
|
175
|
-
handler: async (req, h) => {
|
|
176
|
-
let spec = openAPIJson();
|
|
177
|
-
return h.response(spec).code(200).type('application/json');
|
|
178
|
-
},
|
|
179
|
-
auth: false,
|
|
180
|
-
description: "API Metadata"
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
method: ["GET"],
|
|
185
|
-
path: `/${baseAppEnvContext.contexts.APPNAME}/status`,
|
|
186
|
-
options: {
|
|
187
|
-
handler: async (req, h) => {
|
|
188
|
-
let ht = getHtml();
|
|
189
|
-
return h.response(ht).code(200).type('text/html');
|
|
190
|
-
// return h.abandon;
|
|
191
|
-
},
|
|
192
|
-
auth: false,
|
|
193
|
-
description: "Help",
|
|
194
|
-
notes: "Help",
|
|
195
|
-
tags: ["mcp"],
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
method: ["POST"],
|
|
200
|
-
path: `/mcp`,
|
|
201
|
-
options: {
|
|
202
|
-
handler: async (req, h) => {
|
|
203
|
-
let precontext = req.pre.context;
|
|
204
|
-
let oauthInfo = (precontext != null) ? precontext.credentials : null;
|
|
205
|
-
await handleRequest(mcpServer, cache, req, h, oauthInfo);
|
|
206
|
-
return h.abandon;
|
|
207
|
-
},
|
|
208
|
-
|
|
209
|
-
auth: {
|
|
210
|
-
strategy: "sas",
|
|
211
|
-
mode: 'required'
|
|
212
|
-
},
|
|
213
|
-
description: "The main route for MCP requests",
|
|
214
|
-
notes: "Requires a valid session",
|
|
215
|
-
tags: ["mcp"],
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
method: ["GET", "DELETE"],
|
|
220
|
-
path: `/mcp`,
|
|
221
|
-
|
|
222
|
-
options: {
|
|
223
|
-
handler: async (req, h) => {
|
|
224
|
-
await handleGetDelete(mcpServer, cache, req, h);
|
|
225
|
-
return h.abandon;
|
|
226
|
-
},
|
|
227
|
-
auth: {
|
|
228
|
-
strategy: "session",
|
|
229
|
-
mode: 'try'
|
|
230
|
-
},
|
|
231
|
-
description: "Handle GET and DELETE requests",
|
|
232
|
-
notes: "Will fail if no valid session",
|
|
233
|
-
tags: ["mcp"],
|
|
234
|
-
},
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
];
|
|
238
|
-
return routes;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
export default hapiMcpServer;
|
package/src/toolSet/findModel.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import _listModels from '../toolHelpers/_listModels.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function findModel(_appContext) {
|
|
11
|
-
let description = `
|
|
12
|
-
find-model — locate a specific MAS model deployed to MAS server
|
|
13
|
-
|
|
14
|
-
USE when: find model, does model exist, is model deployed, lookup model, verify model exists
|
|
15
|
-
DO NOT USE for: list models (use list-models), model info/variables (use model-info), score model (use model-score), find table/job/lib (use respective tools), scr models (use scr-info/scr-score)
|
|
16
|
-
|
|
17
|
-
PARAMETERS
|
|
18
|
-
- name: string (required) — model name to locate; if multiple supplied, use first
|
|
19
|
-
|
|
20
|
-
ROUTING RULES
|
|
21
|
-
- "find model <name>" → { name: "<name>" }
|
|
22
|
-
- "does model <name> exist" → { name: "<name>" }
|
|
23
|
-
- "is model <name> deployed" → { name: "<name>" }
|
|
24
|
-
- "lookup/verify model <name>" → { name: "<name>" }
|
|
25
|
-
- "find model" with no name → ask "Which model name would you like to find?"
|
|
26
|
-
- "find all models / list models" → use list-models instead
|
|
27
|
-
- "score model <name>" → use model-score instead
|
|
28
|
-
- "describe model / model info" → use model-info instead
|
|
29
|
-
|
|
30
|
-
EXAMPLES
|
|
31
|
-
- "find model myModel" → { name: "myModel" }
|
|
32
|
-
- "does model churn_score exist" → { name: "churn_score" }
|
|
33
|
-
- "is model riskModel deployed" → { name: "riskModel" }
|
|
34
|
-
- "lookup model claims_fraud_v1" → { name: "claims_fraud_v1" }
|
|
35
|
-
|
|
36
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
37
|
-
- "list models" (use list-models)
|
|
38
|
-
- "score model myModel" (use model-score)
|
|
39
|
-
- "model info for churnRisk" (use model-info)
|
|
40
|
-
|
|
41
|
-
ERRORS
|
|
42
|
-
Returns { models: [] } if not found; { models: [name, ...] } if found. Never hallucinate model names.
|
|
43
|
-
`;
|
|
44
|
-
|
|
45
|
-
let spec = {
|
|
46
|
-
name: 'find-model',
|
|
47
|
-
description: description,
|
|
48
|
-
inputSchema: z.object({
|
|
49
|
-
name: z.string()
|
|
50
|
-
}),
|
|
51
|
-
handler: async (params) => {
|
|
52
|
-
let r = await _listModels(params);
|
|
53
|
-
return r;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return spec;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default findModel;
|
|
60
|
-
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import _listModels from '../toolHelpers/_listModels.js';
|
|
8
|
-
|
|
9
|
-
function listModels(_appContext) {
|
|
10
|
-
let description = `
|
|
11
|
-
list-models — enumerate models published to MAS.
|
|
12
|
-
|
|
13
|
-
USE when: list models, show models, browse models, next page
|
|
14
|
-
DO NOT USE for: find model, model metadata, score model, list jobs/tables/libraries
|
|
15
|
-
|
|
16
|
-
PARAMETERS
|
|
17
|
-
- limit: number (default: 10) — page size
|
|
18
|
-
- start: number (default: 1) — 1-based offset
|
|
19
|
-
|
|
20
|
-
ROUTING RULES
|
|
21
|
-
- "list models" → { start:1, limit:10 }
|
|
22
|
-
- "list 25 models" → { start:1, limit:25 }
|
|
23
|
-
- "next models" → { start: start+limit, limit:10 }
|
|
24
|
-
|
|
25
|
-
EXAMPLES
|
|
26
|
-
- "list models" → { start:1, limit:10 }
|
|
27
|
-
- "list 25 models" → { start:1, limit:25 }
|
|
28
|
-
|
|
29
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
30
|
-
- "find model X" (use find-model)
|
|
31
|
-
- "describe model X" (use model-info)
|
|
32
|
-
- "score model X" (use model-score)
|
|
33
|
-
- "list jobs" (use list-jobs)
|
|
34
|
-
|
|
35
|
-
ERRORS
|
|
36
|
-
Returns empty array if no models found.
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
let spec = {
|
|
40
|
-
name: 'list-models',
|
|
41
|
-
description: description,
|
|
42
|
-
inputSchema: z.object({
|
|
43
|
-
limit: z.number().optional(),
|
|
44
|
-
start: z.number().optional()
|
|
45
|
-
}),
|
|
46
|
-
handler: async (params) => {
|
|
47
|
-
let r = await _listModels(params);
|
|
48
|
-
return r;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return spec;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default listModels;
|
|
56
|
-
|
package/src/toolSet/modelInfo.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import debug from 'debug';
|
|
8
|
-
import _masDescribe from '../toolHelpers/_masDescribe.js';
|
|
9
|
-
const log = debug('tools');
|
|
10
|
-
|
|
11
|
-
function modelInfo(_appContext) {
|
|
12
|
-
let description = `
|
|
13
|
-
model-info — retrieve detailed metadata for a deployed model.
|
|
14
|
-
|
|
15
|
-
USE when: what inputs does model need, describe model, show variables for model, model inputs/outputs
|
|
16
|
-
DO NOT USE for: find model, list models, score model, table/job operations
|
|
17
|
-
|
|
18
|
-
PARAMETERS
|
|
19
|
-
- model: string — model name (required, exact match)
|
|
20
|
-
|
|
21
|
-
ROUTING RULES
|
|
22
|
-
- "what inputs does model X need?" → { model: "X" }
|
|
23
|
-
- "describe model Y" → { model: "Y" }
|
|
24
|
-
- "show variables for Z" → { model: "Z" }
|
|
25
|
-
|
|
26
|
-
EXAMPLES
|
|
27
|
-
- "What inputs does model churnRisk need?" → { model: "churnRisk" }
|
|
28
|
-
- "Describe model creditScore" → { model: "creditScore" }
|
|
29
|
-
- "Show variables for myModel" → { model: "myModel" }
|
|
30
|
-
|
|
31
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
32
|
-
- "list models" (use list-models)
|
|
33
|
-
- "find model X" (use find-model)
|
|
34
|
-
- "score with model X" (use model-score)
|
|
35
|
-
|
|
36
|
-
ERRORS
|
|
37
|
-
Returns model metadata: inputs (name, type, role), outputs (name, type, possible_values), model_type, description.
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
let spec = {
|
|
41
|
-
name: 'model-info',
|
|
42
|
-
description: description,
|
|
43
|
-
inputSchema: z.object({
|
|
44
|
-
model: z.string()
|
|
45
|
-
}),
|
|
46
|
-
handler: async (params) => {
|
|
47
|
-
let r = await _masDescribe(params);
|
|
48
|
-
return r;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return spec;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default modelInfo;
|
|
55
|
-
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import debug from 'debug';
|
|
8
|
-
import _masScoring from '../toolHelpers/_masScoring.js';
|
|
9
|
-
const log = debug('tools');
|
|
10
|
-
|
|
11
|
-
function modelScore(_appContext) {
|
|
12
|
-
let description = `
|
|
13
|
-
mas-score — score data using a deployed model on MAS.
|
|
14
|
-
|
|
15
|
-
USE when: score with model, predict using model, batch scoring, model predictions
|
|
16
|
-
DO NOT USE for: find model, model metadata, list models, run programs/jobs, query tables
|
|
17
|
-
|
|
18
|
-
PARAMETERS
|
|
19
|
-
- model: string — model name (required, exact match)
|
|
20
|
-
- scenario: string | object | array — input data (required). Accepts: "x=1, y=2", {x:1, y:2}, or array of objects
|
|
21
|
-
- uflag: boolean (default: false) — prefix model fields with underscore when true
|
|
22
|
-
|
|
23
|
-
ROUTING RULES
|
|
24
|
-
- "score with model X using a=1, b=2" → { model: "X", scenario: {a:1, b:2}, uflag: false }
|
|
25
|
-
- "predict using model Y with age=45, income=60000" → { model: "Y", scenario: {age:45, income:60000}, uflag: false }
|
|
26
|
-
|
|
27
|
-
EXAMPLES
|
|
28
|
-
- "score with model churn using age=45, income=60000" → { model: "churn", scenario: {age:45, income:60000}, uflag: false }
|
|
29
|
-
- "predict creditScore for credit=700, debt=20000" → { model: "creditScore", scenario: {credit:700, debt:20000}, uflag: false }
|
|
30
|
-
|
|
31
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
32
|
-
- "find model X" (use find-model)
|
|
33
|
-
- "what inputs does model need" (use model-info)
|
|
34
|
-
- "list models" (use list-models)
|
|
35
|
-
- "run job X" (use run-job)
|
|
36
|
-
|
|
37
|
-
ERRORS
|
|
38
|
-
Returns predictions, probabilities, scores merged with input data. Returns error if model not found or scoring fails.
|
|
39
|
-
`;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
let spec = {
|
|
43
|
-
name: 'mas-score',
|
|
44
|
-
description: description,
|
|
45
|
-
inputSchema:z.object({
|
|
46
|
-
model: z.string(),
|
|
47
|
-
scenario: z.string(),
|
|
48
|
-
uflag: z.boolean().optional()
|
|
49
|
-
}),
|
|
50
|
-
|
|
51
|
-
handler: async (iparams) => {
|
|
52
|
-
let params = {...iparams};
|
|
53
|
-
let scenario = params.scenario;
|
|
54
|
-
|
|
55
|
-
// Convert the scenario string to an object
|
|
56
|
-
// Example: "x=1, y=2, z=3" to { x: 1, y: 2, z: 3 }
|
|
57
|
-
let scenarioObj ={};
|
|
58
|
-
let count = 0;
|
|
59
|
-
if (typeof scenario === 'object') {
|
|
60
|
-
scenarioObj = scenario;
|
|
61
|
-
} else if (Array.isArray(scenario)) {
|
|
62
|
-
scenarioObj = scenario[0];
|
|
63
|
-
} else {
|
|
64
|
-
//console.error('Incoming scenario', scenario);
|
|
65
|
-
scenarioObj = scenario.split(',').reduce((acc, pair) => {
|
|
66
|
-
let [key, value] = pair.split('=');
|
|
67
|
-
acc[key.trim()] = value;
|
|
68
|
-
count++;
|
|
69
|
-
return acc;
|
|
70
|
-
}, {});
|
|
71
|
-
}
|
|
72
|
-
params.scenario= scenarioObj;
|
|
73
|
-
|
|
74
|
-
// Drop model extension (e.g., .job, .model)
|
|
75
|
-
if (params.model && params.model.includes('.')) {
|
|
76
|
-
params.model = params.model.substring(0, params.model.lastIndexOf('.'));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
log('modelScore params', params);
|
|
80
|
-
// Check if the params.scenario is a string and parse it
|
|
81
|
-
let r = await _masScoring(params)
|
|
82
|
-
return r;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return spec;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export default modelScore;
|
|
89
|
-
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import _submitCode from '../toolHelpers/_submitCode.js';
|
|
8
|
-
|
|
9
|
-
function runCasProgram(_appContext) {
|
|
10
|
-
let description = `
|
|
11
|
-
run-cas-program — execute a CAS program on SAS Viya server.
|
|
12
|
-
|
|
13
|
-
USE when: run cas program, execute cas, submit cas, cas action
|
|
14
|
-
DO NOT USE for: macros (use run-macro), sas code (use run-sas-program), jobs (use run-job), jobdefs (use run-jobdef)
|
|
15
|
-
|
|
16
|
-
PARAMETERS
|
|
17
|
-
- src: string (required) — CAS program to execute verbatim
|
|
18
|
-
- scenario: string or object (optional) — input parameters
|
|
19
|
-
- folder: string — server folder path for .sas files
|
|
20
|
-
- output: string — table name to return in response
|
|
21
|
-
- limit: number (default: 100) — max rows to return
|
|
22
|
-
|
|
23
|
-
ROUTING RULES
|
|
24
|
-
- run cas program action echo → { src: action echo }
|
|
25
|
-
- execute cas action simple.summary → { src: action simple.summary }
|
|
26
|
-
|
|
27
|
-
EXAMPLES
|
|
28
|
-
- run cas program action echo → { src: action echo }
|
|
29
|
-
- cas program sample folder=/Public/models → { src: sample, folder: /Public/models }
|
|
30
|
-
|
|
31
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
32
|
-
- run sas macro (use run-macro)
|
|
33
|
-
- submit sas code (use run-sas-program)
|
|
34
|
-
- run job X (use run-job)
|
|
35
|
-
|
|
36
|
-
NOTES
|
|
37
|
-
Sends src verbatim without validation. For SAS macros use run-macro. For arbitrary SAS code use run-sas-program.
|
|
38
|
-
|
|
39
|
-
RESPONSE
|
|
40
|
-
Log output and CAS results. If output table specified, returned as markdown table.
|
|
41
|
-
`;
|
|
42
|
-
|
|
43
|
-
let spec = {
|
|
44
|
-
name: 'run-cas-program',
|
|
45
|
-
description: description,
|
|
46
|
-
inputSchema:z.object({
|
|
47
|
-
src: z.string(),
|
|
48
|
-
scenario: z.string(),
|
|
49
|
-
output: z.string().optional,
|
|
50
|
-
folder: z.string().optional,
|
|
51
|
-
limit: z.number().optional
|
|
52
|
-
}),
|
|
53
|
-
|
|
54
|
-
// NOTE: Previously 'required' incorrectly listed 'program' which does not
|
|
55
|
-
// exist in the schema. This prevented execution in some orchestrators that
|
|
56
|
-
// enforce required parameter presence, causing only descriptions to appear.
|
|
57
|
-
// Corrected to 'src'.
|
|
58
|
-
handler: async (params) => {
|
|
59
|
-
let {src, folder, scenario, _appContext} = params;
|
|
60
|
-
// figure out src
|
|
61
|
-
let isrc = src;
|
|
62
|
-
if (folder != null && folder.trim().length > 0) {
|
|
63
|
-
if (isrc.indexOf('.sas') < 0) {
|
|
64
|
-
isrc = isrc + '.sas';
|
|
65
|
-
}
|
|
66
|
-
isrc = `
|
|
67
|
-
filename mcptemp filesrvc folderpath="${folder}";
|
|
68
|
-
%include mcptemp("${isrc}");
|
|
69
|
-
filename mcptemp clear;
|
|
70
|
-
`;
|
|
71
|
-
}
|
|
72
|
-
// figure out macros
|
|
73
|
-
|
|
74
|
-
if (typeof scenario === 'string' && scenario.includes('=')) {
|
|
75
|
-
scenario = scenario.split(',').reduce((acc, pair) => {
|
|
76
|
-
const [k, ...rest] = pair.split('=');
|
|
77
|
-
if (!k) return acc;
|
|
78
|
-
acc[k.trim()] = rest.join('=').trim();
|
|
79
|
-
return acc;
|
|
80
|
-
}, {});
|
|
81
|
-
}
|
|
82
|
-
let iparms = {
|
|
83
|
-
args: scenario,
|
|
84
|
-
output: params.output,
|
|
85
|
-
limit: params.limit,
|
|
86
|
-
src: isrc,
|
|
87
|
-
_appContext: _appContext
|
|
88
|
-
}
|
|
89
|
-
// console.error('iparms', iparms);
|
|
90
|
-
let r = await _submitCode(iparms);
|
|
91
|
-
return r;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return spec;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export default runCasProgram;
|
|
98
|
-
|
package/src/toolSet/runJob.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
import _jobSubmit from '../toolHelpers/_jobSubmit.js';
|
|
8
|
-
|
|
9
|
-
function runJob(_appContext) {
|
|
10
|
-
|
|
11
|
-
let description = `
|
|
12
|
-
run-job — score with a deployed SAS Viya job.
|
|
13
|
-
|
|
14
|
-
USE when: score with job, run job, execute job
|
|
15
|
-
DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro), list/find jobs
|
|
16
|
-
|
|
17
|
-
PARAMETERS
|
|
18
|
-
- name: string — job name (required)
|
|
19
|
-
- scenario: string | object — input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
|
|
20
|
-
|
|
21
|
-
ROUTING RULES
|
|
22
|
-
- "run job xyz" → { name: "xyz" }
|
|
23
|
-
- "run job xyz with param1=10, param2=val2" → { name: "xyz", scenario: {param1:10, param2:"val2"} }
|
|
24
|
-
|
|
25
|
-
EXAMPLES
|
|
26
|
-
- "run job xyz" → { name: "xyz" }
|
|
27
|
-
- "run job monthly_etl with month=10, year=2025" → { name: "monthly_etl", scenario: {month:10, year:2025} }
|
|
28
|
-
|
|
29
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
30
|
-
- "run SAS code" (use run-sas-program)
|
|
31
|
-
- "run macro X" (use run-macro)
|
|
32
|
-
- "list jobs" (use list-jobs)
|
|
33
|
-
- "find job X" (use find-job)
|
|
34
|
-
|
|
35
|
-
ERRORS
|
|
36
|
-
Returns log output, listings, tables from job. Error if job not found.
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
let spec = {
|
|
40
|
-
name: 'run-job',
|
|
41
|
-
description: description,
|
|
42
|
-
inputSchema: z.object({
|
|
43
|
-
name: z.string(),
|
|
44
|
-
scenario: z.string().optional()
|
|
45
|
-
}),
|
|
46
|
-
handler: async (params) => {
|
|
47
|
-
let scenario = params.scenario;
|
|
48
|
-
let scenarioObj = {};
|
|
49
|
-
let count = 0;
|
|
50
|
-
//
|
|
51
|
-
if (scenario == null) {
|
|
52
|
-
scenarioObj = {};
|
|
53
|
-
} else if (typeof scenario === 'object') {
|
|
54
|
-
scenarioObj = scenario;
|
|
55
|
-
} else if (Array.isArray(scenario)) {
|
|
56
|
-
scenarioObj = scenario[0];
|
|
57
|
-
} else if (typeof scenario === 'string') {
|
|
58
|
-
if (scenario.trim() === '') {
|
|
59
|
-
scenarioObj = {};
|
|
60
|
-
} else {
|
|
61
|
-
// console.error('Incoming scenario', scenario);
|
|
62
|
-
scenarioObj = scenario.split(',').reduce((acc, pair) => {
|
|
63
|
-
let [key, value] = pair.split('=');
|
|
64
|
-
acc[key.trim()] = value;
|
|
65
|
-
count++;
|
|
66
|
-
return acc;
|
|
67
|
-
}, {});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
params.type = 'job';
|
|
71
|
-
params.scenario = scenarioObj;
|
|
72
|
-
// Provide runtime context for auth and server settings
|
|
73
|
-
let r = await _jobSubmit(params);
|
|
74
|
-
return r;
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
return spec;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export default runJob;
|
|
81
|
-
|