@sassoftware/sas-score-mcp-serverjs 0.4.1 → 1.0.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/.skills/agents/sas-viya-scoring-expert.md +58 -0
- package/.skills/copilot-instructions.md +155 -0
- package/.skills/skills/sas-find-library-smart/SKILL.md +154 -0
- package/.skills/skills/sas-list-tables-smart/SKILL.md +127 -0
- package/.skills/skills/sas-read-and-score/SKILL.md +111 -0
- package/.skills/skills/sas-read-strategy/SKILL.md +156 -0
- package/.skills/skills/sas-request-classifier/SKILL.md +69 -0
- package/.skills/skills/sas-score-workflow/SKILL.md +314 -0
- package/cli.js +311 -70
- package/package.json +7 -7
- package/scripts/docs/SCORE_SKILL_REFERENCE.md +142 -0
- package/scripts/docs/TOOL_DESCRIPTION_TEMPLATE.md +157 -0
- package/scripts/docs/TOOL_UPDATES_SUMMARY.md +208 -0
- package/scripts/docs/mcp-localhost-config-guide.md +184 -0
- package/scripts/docs/oauth-http-transport.md +96 -0
- package/scripts/docs/sas-mcp-tools-reference.md +600 -0
- package/scripts/getViyaca.sh +1 -0
- package/scripts/optimize_final.py +140 -0
- package/scripts/optimize_tools.py +99 -0
- package/scripts/setup-skills.js +34 -0
- package/scripts/update_descriptions.py +46 -0
- package/scripts/viyatls.sh +3 -0
- package/src/authpkce.js +219 -0
- package/src/createMcpServer.js +16 -5
- package/src/expressMcpServer.js +350 -308
- package/src/handleGetDelete.js +6 -3
- package/src/hapiMcpServer.js +10 -18
- package/src/oauthHandlers/authorize.js +46 -0
- package/src/oauthHandlers/baseUrl.js +8 -0
- package/src/oauthHandlers/callback.js +96 -0
- package/src/oauthHandlers/getMetadata.js +27 -0
- package/src/oauthHandlers/index.js +7 -0
- package/src/oauthHandlers/token.js +37 -0
- package/src/processHeaders.js +88 -0
- package/src/setupSkills.js +46 -0
- package/src/toolHelpers/_jobSubmit.js +2 -0
- package/src/toolHelpers/_listLibrary.js +55 -39
- package/src/toolHelpers/getLogonPayload.js +7 -1
- package/src/toolHelpers/readCerts.js +4 -4
- package/src/toolHelpers/refreshToken.js +3 -2
- package/src/toolHelpers/refreshTokenOauth.js +3 -3
- package/src/toolSet/.claude/settings.local.json +13 -0
- package/src/toolSet/devaScore.js +61 -69
- package/src/toolSet/findJob.js +38 -71
- package/src/toolSet/findJobdef.js +28 -59
- package/src/toolSet/findLibrary.js +68 -100
- package/src/toolSet/findModel.js +35 -58
- package/src/toolSet/findTable.js +31 -60
- package/src/toolSet/getEnv.js +30 -45
- package/src/toolSet/listJobdefs.js +61 -96
- package/src/toolSet/listJobs.js +61 -110
- package/src/toolSet/listLibraries.js +78 -90
- package/src/toolSet/listModels.js +56 -83
- package/src/toolSet/listTables.js +66 -95
- package/src/toolSet/makeTools.js +1 -0
- package/src/toolSet/modelInfo.js +22 -54
- package/src/toolSet/modelScore.js +35 -77
- package/src/toolSet/readTable.js +63 -104
- package/src/toolSet/runCasProgram.js +32 -52
- package/src/toolSet/runJob.js +24 -24
- package/src/toolSet/runJobdef.js +26 -29
- package/src/toolSet/runMacro.js +82 -82
- package/src/toolSet/runProgram.js +32 -84
- package/src/toolSet/sasQuery.js +77 -126
- package/src/toolSet/sasQueryTemplate.js +4 -5
- package/src/toolSet/sasQueryTemplate2.js +4 -5
- package/src/toolSet/scrInfo.js +4 -7
- package/src/toolSet/scrScore.js +69 -70
- package/src/toolSet/searchAssets.js +5 -6
- package/src/toolSet/setContext.js +65 -92
- package/src/toolSet/superstat.js +61 -60
- package/src/toolSet/tableInfo.js +58 -102
|
@@ -8,74 +8,53 @@ import _submitCode from '../toolHelpers/_submitCode.js';
|
|
|
8
8
|
|
|
9
9
|
function runCasProgram(_appContext) {
|
|
10
10
|
let description = `
|
|
11
|
-
|
|
11
|
+
run-cas-program — execute a CAS program on SAS Viya server.
|
|
12
12
|
|
|
13
|
-
|
|
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)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
- src
|
|
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
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
ROUTING RULES
|
|
24
|
+
- run cas program action echo → { src: action echo }
|
|
25
|
+
- execute cas action simple.summary → { src: action simple.summary }
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
EXAMPLES
|
|
28
|
+
- run cas program action echo → { src: action echo }
|
|
29
|
+
- cas program sample folder=/Public/models → { src: sample, folder: /Public/models }
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- 'submit cas "action echo / code='aaaa'"'
|
|
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)
|
|
29
35
|
|
|
36
|
+
NOTES
|
|
37
|
+
Sends src verbatim without validation. For SAS macros use run-macro. For arbitrary SAS code use run-sas-program.
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- submit sas -> use run-sas-program
|
|
34
|
-
- run job -> use run-job
|
|
35
|
-
- run sas -> use run-sas-program
|
|
36
|
-
- run jobdef -> use run-jobdef
|
|
37
|
-
- run job -> use run-job
|
|
38
|
-
- list jobs -> use list-jobs
|
|
39
|
-
- list jobdefs -> use list-jobdefs
|
|
40
|
-
- find job -> use find-job
|
|
41
|
-
- find jobdef -> use find-jobdef
|
|
42
|
-
- find model -> use find-model
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Behavior & usage notes
|
|
46
|
-
- This tool sends the supplied \`src\` verbatim to the SAS execution helper. It does not modify or validate the SAS code.
|
|
47
|
-
- For invoking pre-defined SAS macros, prefer the \`runMacro\` helper which converts simple parameter formats into \`%let\` statements and invokes the macro cleanly.
|
|
48
|
-
- Be cautious when executing arbitrary code — validate or sanitize inputs in untrusted environments.
|
|
49
|
-
|
|
50
|
-
Response
|
|
51
|
-
- If output is specified and the specified table exists in the response, display the data as a markdown table.
|
|
52
|
-
Examples
|
|
53
|
-
- run program "data a; x=1; run;" - this is the simplest usage -- {src= "data a; x=1; run;", folder=" ", output=" ", limit=100}
|
|
54
|
-
- program "data work.a; x=1; run;" output=a limit=50 -- {src= "data work.a; x=1; run;", folder=" ", output="a", limit=50}
|
|
55
|
-
|
|
56
|
-
- run program sample folder=/Public/models output=A limit=50 -- {src= "sample", folder="/Public/models", output="A", limit=50}
|
|
57
|
-
- run program sample folder=/Public/models scenario="name='John', age=45" output=a limit=50 -- {src= "sample", folder="/Public/models", scenario: {name: "John", age: 45}, output="a", limit=50}
|
|
58
|
-
- run program sample folder=/Public/models with scenario name=John,age=45 output=a limit=50 -- {src= "sample.sas", folder="/Public/models", scenario: {name: "John", age: 45}, output="a", limit=50}
|
|
59
|
-
- this should be the same as the previous example and is just a different syntax. The result should be
|
|
60
|
-
{program: "sample", folder: "/Public/models", scenario: {name: "John", age: 45}, output: "a", limit: 50}
|
|
39
|
+
RESPONSE
|
|
40
|
+
Log output and CAS results. If output table specified, returned as markdown table.
|
|
61
41
|
`;
|
|
62
42
|
|
|
63
43
|
let spec = {
|
|
64
|
-
name: 'run-
|
|
65
|
-
aliases: ['Program','run program'],
|
|
44
|
+
name: 'run-cas-program',
|
|
66
45
|
description: description,
|
|
67
|
-
|
|
46
|
+
inputSchema:z.object({
|
|
68
47
|
src: z.string(),
|
|
69
|
-
scenario: z.
|
|
70
|
-
output: z.string().
|
|
71
|
-
folder: z.string().
|
|
72
|
-
limit: z.number().
|
|
73
|
-
},
|
|
48
|
+
scenario: z.string(),
|
|
49
|
+
output: z.string().optional,
|
|
50
|
+
folder: z.string().optional,
|
|
51
|
+
limit: z.number().optional
|
|
52
|
+
}),
|
|
53
|
+
|
|
74
54
|
// NOTE: Previously 'required' incorrectly listed 'program' which does not
|
|
75
55
|
// exist in the schema. This prevented execution in some orchestrators that
|
|
76
56
|
// enforce required parameter presence, causing only descriptions to appear.
|
|
77
57
|
// Corrected to 'src'.
|
|
78
|
-
required: ['src'],
|
|
79
58
|
handler: async (params) => {
|
|
80
59
|
let {src, folder, scenario, _appContext} = params;
|
|
81
60
|
// figure out src
|
|
@@ -116,3 +95,4 @@ Examples
|
|
|
116
95
|
}
|
|
117
96
|
|
|
118
97
|
export default runCasProgram;
|
|
98
|
+
|
package/src/toolSet/runJob.js
CHANGED
|
@@ -9,41 +9,40 @@ import _jobSubmit from '../toolHelpers/_jobSubmit.js';
|
|
|
9
9
|
function runJob(_appContext) {
|
|
10
10
|
|
|
11
11
|
let description = `
|
|
12
|
-
|
|
12
|
+
run-job — score with a deployed SAS Viya job.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- You want to run a registered Job Execution asset by name
|
|
17
|
-
- You have simple parameter inputs to pass to the job
|
|
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
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- Listing or finding jobs (use list-jobs / find-job)
|
|
17
|
+
PARAMETERS
|
|
18
|
+
- name: string — job name (required)
|
|
19
|
+
- scenario: string | object — input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- a comma-separated key=value string (e.g. "x=1, y=2")
|
|
28
|
-
- a JSON object with field names and values (recommended)
|
|
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"} }
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
-
|
|
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} }
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
- "run
|
|
35
|
-
- "run
|
|
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.
|
|
36
37
|
`;
|
|
37
38
|
|
|
38
39
|
let spec = {
|
|
39
|
-
aliases: ['run job', 'run-job', 'runjob'],
|
|
40
40
|
name: 'run-job',
|
|
41
41
|
description: description,
|
|
42
|
-
|
|
42
|
+
inputSchema: z.object({
|
|
43
43
|
name: z.string(),
|
|
44
|
-
scenario: z.
|
|
45
|
-
},
|
|
46
|
-
required: ['name'],
|
|
44
|
+
scenario: z.string().optional()
|
|
45
|
+
}),
|
|
47
46
|
handler: async (params) => {
|
|
48
47
|
let scenario = params.scenario;
|
|
49
48
|
let scenarioObj = {};
|
|
@@ -79,3 +78,4 @@ Examples (→ mapped params)
|
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
export default runJob;
|
|
81
|
+
|
package/src/toolSet/runJobdef.js
CHANGED
|
@@ -6,48 +6,44 @@
|
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import _jobSubmit from '../toolHelpers/_jobSubmit.js';
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
function runJobdef(_appContext) {
|
|
11
10
|
// JSON object for LLM/tooling
|
|
12
11
|
|
|
13
12
|
let description = `
|
|
14
|
-
|
|
13
|
+
run-jobdef — score with a deployed SAS Viya job definition.
|
|
14
|
+
|
|
15
|
+
USE when: score with jobdef, run jobdef, execute jobdef
|
|
16
|
+
DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro), list/find jobdefs
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
- You can pass parameters to the job definition
|
|
18
|
+
PARAMETERS
|
|
19
|
+
- name: string — jobdef name (required)
|
|
20
|
+
- scenario: string | object — input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- Listing or finding jobdefs (use list-jobdefs tool / find-jobdef tool)
|
|
22
|
+
ROUTING RULES
|
|
23
|
+
- "run jobdef xyz" → { name: "xyz" }
|
|
24
|
+
- "run jobdef xyz with param1=10, param2=val2" → { name: "xyz", scenario: {param1:10, param2:"val2"} }
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
- a comma-separated key=value string (e.g. "x=1, y=2")
|
|
30
|
-
- a JSON object with field names and values (recommended)
|
|
26
|
+
EXAMPLES
|
|
27
|
+
- "run jobdef xyz" → { name: "xyz" }
|
|
28
|
+
- "run jobdef monthly_report with month=10, year=2025" → { name: "monthly_report", scenario: {month:10, year:2025} }
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
-
|
|
30
|
+
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
+
- "run SAS code" (use run-sas-program)
|
|
32
|
+
- "run macro X" (use run-macro)
|
|
33
|
+
- "list jobdefs" (use list-jobdefs)
|
|
34
|
+
- "find jobdef X" (use find-jobdef)
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- "run-jobdef xyz param1=10,param2=val2" → { name: "xyz", scenario: { param1: 10, param2: "val2" } }
|
|
39
|
-
- "jobdef name=monthly_report, scenario=month=10,year=2025" → { name: "monthly_report", scenario: { month: 10, year: 2025 }
|
|
40
|
-
`;
|
|
36
|
+
ERRORS
|
|
37
|
+
Returns log output, listings, tables from jobdef. Error if jobdef not found.
|
|
38
|
+
`;
|
|
41
39
|
|
|
42
40
|
let spec = {
|
|
43
|
-
|
|
44
|
-
aliases: ['jobDef','jobdef','jobdef'],
|
|
41
|
+
name: 'run-jobdef',
|
|
45
42
|
description: description,
|
|
46
|
-
|
|
43
|
+
inputSchema: z.object({
|
|
47
44
|
name: z.string(),
|
|
48
|
-
scenario: z.
|
|
49
|
-
},
|
|
50
|
-
required: ['name'],
|
|
45
|
+
scenario: z.string().optional()
|
|
46
|
+
}),
|
|
51
47
|
handler: async (params) => {
|
|
52
48
|
let scenario = params.scenario;
|
|
53
49
|
let scenarioObj = {};
|
|
@@ -83,3 +79,4 @@ Examples (→ mapped params)
|
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
export default runJobdef;
|
|
82
|
+
|
package/src/toolSet/runMacro.js
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
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
|
-
|
|
10
|
-
function runMacro(_appContext) {
|
|
11
|
-
let description = `
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
let spec = {
|
|
40
|
-
name: 'run-macro',
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.
|
|
61
|
-
.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
+
|
|
10
|
+
function runMacro(_appContext) {
|
|
11
|
+
let description = `
|
|
12
|
+
run-macro — submit and execute a SAS macro on SAS Viya server.
|
|
13
|
+
|
|
14
|
+
USE when: run macro, execute macro with parameters
|
|
15
|
+
DO NOT USE for: arbitrary SAS code (use run-sas-program), jobs, jobdefs
|
|
16
|
+
|
|
17
|
+
PARAMETERS
|
|
18
|
+
- macro: string — macro name without "%" (required)
|
|
19
|
+
- scenario: string — parameters or setup code (optional). Accepts: "x=1, y=abc" or "%let x=1; %let y=abc;"
|
|
20
|
+
|
|
21
|
+
ROUTING RULES
|
|
22
|
+
- "run macro abc" → { macro: "abc", scenario: "" }
|
|
23
|
+
- "run macro abc with x=1, y=2" → { macro: "abc", scenario: "x=1, y=2" }
|
|
24
|
+
- "run macro xyz with %let a=1; %let b=2;" → { macro: "xyz", scenario: "%let a=1; %let b=2;" }
|
|
25
|
+
|
|
26
|
+
EXAMPLES
|
|
27
|
+
- "run macro abc" → { macro: "abc", scenario: "" }
|
|
28
|
+
- "run macro summarize with x=1, y=2" → { macro: "summarize", scenario: "x=1, y=2" }
|
|
29
|
+
|
|
30
|
+
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
+
- "run SAS code" (use run-sas-program)
|
|
32
|
+
- "run job X" (use run-job)
|
|
33
|
+
- "run jobdef X" (use run-jobdef)
|
|
34
|
+
|
|
35
|
+
ERRORS
|
|
36
|
+
Returns log, ods, tables created by macro. Auto-converts "x=1, y=2" to "%let x=1; %let y=2;" format.
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
let spec = {
|
|
40
|
+
name: 'run-macro',
|
|
41
|
+
description: description,
|
|
42
|
+
|
|
43
|
+
inputSchema: z.object({
|
|
44
|
+
macro: z.string(),
|
|
45
|
+
scenario: z.string().optional()
|
|
46
|
+
}),
|
|
47
|
+
|
|
48
|
+
handler: async (params) => {
|
|
49
|
+
const scenarioRaw = (params.scenario || '').trim();
|
|
50
|
+
let setup = '';
|
|
51
|
+
if (scenarioRaw) {
|
|
52
|
+
// If the scenario already contains macro syntax, send it through unchanged
|
|
53
|
+
const hasMacroSyntax = /%let\b|%[a-zA-Z_]\w*\s*\(|%[a-zA-Z_]\w*\s*;/.test(scenarioRaw) || scenarioRaw.includes('%');
|
|
54
|
+
if (hasMacroSyntax) {
|
|
55
|
+
setup = scenarioRaw;
|
|
56
|
+
} else {
|
|
57
|
+
// Convert "x=1,y=abc" -> "%let x=1; %let y=abc;"
|
|
58
|
+
setup = scenarioRaw.split(',')
|
|
59
|
+
.map(p => p.trim())
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.map(p => {
|
|
62
|
+
const [k, ...rest] = p.split('=');
|
|
63
|
+
if (!k) return '';
|
|
64
|
+
const key = k.trim();
|
|
65
|
+
const val = rest.join('=').trim();
|
|
66
|
+
return `%let ${key}=${val};`;
|
|
67
|
+
})
|
|
68
|
+
.filter(Boolean)
|
|
69
|
+
.join(' ');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const src = `${setup} %${params.macro};`;
|
|
73
|
+
params.src = src;
|
|
74
|
+
let r = await _submitCode(params);
|
|
75
|
+
return r;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return spec;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default runMacro;
|
|
82
|
+
|
|
@@ -8,101 +8,48 @@ import _submitCode from '../toolHelpers/_submitCode.js';
|
|
|
8
8
|
|
|
9
9
|
function runProgram(_appContext) {
|
|
10
10
|
let description = `
|
|
11
|
-
|
|
11
|
+
run-sas-program — execute SAS code or programs on SAS Viya server.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- "run program 'data a; x=1; run;'"
|
|
16
|
-
- "execute this SAS code: proc print data=sashelp.cars; run;"
|
|
17
|
-
- "program 'data work.a; x=1; run;' output=a limit=50"
|
|
18
|
-
- "run sas program sample folder=/Public/models output=A limit=50"
|
|
19
|
-
- "run sas program with parameters name=John, age=45"
|
|
20
|
-
- "execute SAS file myprogram.sas from /Public folder"
|
|
13
|
+
USE when: run program, execute SAS code, run .sas file
|
|
14
|
+
DO NOT USE for: macros (use run-macro), jobs (use run-job), jobdefs (use run-jobdef), SQL queries (use sas-query), read data (use read-table)
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
- find job -> use find-job
|
|
29
|
-
- find jobdef -> use find-jobdef
|
|
30
|
-
- find model -> use find-model
|
|
31
|
-
- Query tables with SQL -> use sas-query
|
|
32
|
-
- Read table data -> use read-table
|
|
16
|
+
PARAMETERS
|
|
17
|
+
- src: string — SAS code or .sas filename (required)
|
|
18
|
+
- folder: string (default: '') — server folder path for .sas files
|
|
19
|
+
- scenario: string | object — parameter values. Accepts: "x=1, y=2" or {x:1, y:2}
|
|
20
|
+
- output: string (default: '') — table name to return (case-sensitive)
|
|
21
|
+
- limit: number (default: 100) — max rows from output
|
|
33
22
|
|
|
34
|
-
|
|
35
|
-
Execute SAS code or programs on a SAS Viya server. Can run inline SAS code or execute .sas files stored on the server. Supports parameter passing via scenario values and can return output tables.
|
|
36
|
-
|
|
37
|
-
Parameters
|
|
38
|
-
- src (string, required): The SAS program to execute. Can be either:
|
|
39
|
-
- Inline SAS code as a string (e.g., "data a; x=1; run;")
|
|
40
|
-
- Name of a .sas file stored on the server (used with folder parameter)
|
|
41
|
-
- folder (string, default ''): Server folder path where the .sas file is located (e.g., "/Public/models")
|
|
42
|
-
- scenario (string | object, optional): Input parameter values. Accepts:
|
|
43
|
-
- Comma-separated key=value string (e.g., "x=1, y=2")
|
|
44
|
-
- JSON object with field names and values (recommended)
|
|
45
|
-
- output (string, default ''): Table name to return in response (case-sensitive)
|
|
46
|
-
- limit (number, default 100): Maximum number of rows to return from output table
|
|
47
|
-
|
|
48
|
-
Response Contract
|
|
49
|
-
Returns a JSON object containing:
|
|
50
|
-
- log: Execution log from SAS
|
|
51
|
-
- ods: ODS output if generated
|
|
52
|
-
- tables: Array of table names created during execution
|
|
53
|
-
- data: If output parameter specified, returns the table data (up to limit rows)
|
|
54
|
-
- error: Error message if execution fails
|
|
55
|
-
- Empty content if no results produced
|
|
56
|
-
|
|
57
|
-
Disambiguation & Clarification
|
|
58
|
-
- Missing SAS code: ask "What SAS program or code would you like to execute?"
|
|
59
|
-
- Inline code vs file unclear: ask "Do you want to run inline SAS code or execute a .sas file from the server?"
|
|
60
|
-
- If output table not returned: clarify "The output table name is case-sensitive. Did you specify the exact name?"
|
|
61
|
-
- If unclear about parameters: ask "What parameter values should I pass to the program?"
|
|
62
|
-
|
|
63
|
-
Examples (→ mapped params)
|
|
23
|
+
ROUTING RULES
|
|
64
24
|
- "run program 'data a; x=1; run;'" → { src: "data a; x=1; run;", folder: "", output: "", limit: 100 }
|
|
65
|
-
- "
|
|
66
|
-
- "run
|
|
67
|
-
- "run program mycode.sas in /Public with name=John, age=45" → { src: "mycode", folder: "/Public", scenario: { name: "John", age: 45 }, output: "", limit: 100 }
|
|
25
|
+
- "run sas program sample folder=/Public/models" → { src: "sample", folder: "/Public/models", output: "", limit: 100 }
|
|
26
|
+
- "run program with name=John, age=45" → { src: "<code>", scenario: {name:"John", age:45}, output: "", limit: 100 }
|
|
68
27
|
|
|
69
|
-
|
|
70
|
-
- "run
|
|
71
|
-
- "run
|
|
72
|
-
- "run jobdef etl_process" (use run-jobdef instead)
|
|
73
|
-
- "how many customers by region in Public.customers" (use sas-query instead)
|
|
74
|
-
- "read 10 rows from cars" (use read-table instead)
|
|
28
|
+
EXAMPLES
|
|
29
|
+
- "run program 'data a; x=1; run;'" → { src: "data a; x=1; run;", folder: "", output: "", limit: 100 }
|
|
30
|
+
- "run sas file sample in /Public" → { src: "sample", folder: "/Public", output: "", limit: 100 }
|
|
75
31
|
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
32
|
+
NEGATIVE EXAMPLES (do not route here)
|
|
33
|
+
- "run macro X" (use run-macro)
|
|
34
|
+
- "run job X" (use run-job)
|
|
35
|
+
- "run jobdef X" (use run-jobdef)
|
|
36
|
+
- "SQL query" (use sas-query)
|
|
37
|
+
- "read table" (use read-table)
|
|
82
38
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- sas-query — for natural language SQL queries
|
|
87
|
-
- read-table — for simple data retrieval
|
|
88
|
-
`;
|
|
39
|
+
ERRORS
|
|
40
|
+
Returns log, ods, tables array, data (if output specified). Error if execution fails.
|
|
41
|
+
`;
|
|
89
42
|
|
|
90
43
|
let spec = {
|
|
91
|
-
name: 'run-
|
|
92
|
-
aliases: ['Program','run program'],
|
|
44
|
+
name: 'run-program',
|
|
93
45
|
description: description,
|
|
94
|
-
|
|
46
|
+
inputSchema: z.object({
|
|
95
47
|
src: z.string(),
|
|
96
|
-
scenario: z.
|
|
97
|
-
output: z.string().
|
|
98
|
-
folder: z.string().
|
|
99
|
-
limit: z.number().
|
|
100
|
-
},
|
|
101
|
-
// NOTE: Previously 'required' incorrectly listed 'program' which does not
|
|
102
|
-
// exist in the schema. This prevented execution in some orchestrators that
|
|
103
|
-
// enforce required parameter presence, causing only descriptions to appear.
|
|
104
|
-
// Corrected to 'src'.
|
|
105
|
-
required: ['src'],
|
|
48
|
+
scenario: z.string().optional(),
|
|
49
|
+
output: z.string().optional(),
|
|
50
|
+
folder: z.string().optional(),
|
|
51
|
+
limit: z.number().optional()
|
|
52
|
+
}),
|
|
106
53
|
handler: async (params) => {
|
|
107
54
|
let {src, folder, scenario, _appContext} = params;
|
|
108
55
|
// figure out src
|
|
@@ -143,3 +90,4 @@ Related Tools
|
|
|
143
90
|
}
|
|
144
91
|
|
|
145
92
|
export default runProgram;
|
|
93
|
+
|