@sassoftware/sas-score-mcp-serverjs 0.4.0 → 0.4.1

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 (39) hide show
  1. package/cli.js +9 -127
  2. package/package.json +2 -3
  3. package/src/createMcpServer.js +0 -1
  4. package/src/expressMcpServer.js +27 -53
  5. package/src/handleGetDelete.js +3 -6
  6. package/src/hapiMcpServer.js +18 -10
  7. package/src/toolHelpers/_jobSubmit.js +0 -2
  8. package/src/toolHelpers/_listLibrary.js +39 -56
  9. package/src/toolHelpers/getLogonPayload.js +1 -3
  10. package/src/toolSet/devaScore.js +36 -28
  11. package/src/toolSet/findJob.js +49 -23
  12. package/src/toolSet/findJobdef.js +54 -24
  13. package/src/toolSet/findLibrary.js +57 -25
  14. package/src/toolSet/findModel.js +53 -31
  15. package/src/toolSet/findTable.js +54 -25
  16. package/src/toolSet/getEnv.js +38 -20
  17. package/src/toolSet/listJobdefs.js +58 -24
  18. package/src/toolSet/listJobs.js +72 -24
  19. package/src/toolSet/listLibraries.js +47 -37
  20. package/src/toolSet/listModels.js +47 -20
  21. package/src/toolSet/listTables.js +58 -29
  22. package/src/toolSet/makeTools.js +0 -3
  23. package/src/toolSet/modelInfo.js +49 -18
  24. package/src/toolSet/modelScore.js +69 -27
  25. package/src/toolSet/readTable.js +62 -25
  26. package/src/toolSet/runCasProgram.js +43 -23
  27. package/src/toolSet/runJob.js +19 -20
  28. package/src/toolSet/runJobdef.js +23 -21
  29. package/src/toolSet/runMacro.js +20 -20
  30. package/src/toolSet/runProgram.js +71 -24
  31. package/src/toolSet/sasQuery.js +70 -23
  32. package/src/toolSet/scrInfo.js +4 -3
  33. package/src/toolSet/setContext.js +48 -22
  34. package/src/toolSet/tableInfo.js +71 -28
  35. package/skills/mcp-tool-description-optimizer/SKILL.md +0 -129
  36. package/skills/mcp-tool-description-optimizer/references/examples.md +0 -123
  37. package/skills/sas-read-and-score/SKILL.md +0 -91
  38. package/skills/sas-read-strategy/SKILL.md +0 -143
  39. package/skills/sas-score-workflow/SKILL.md +0 -282
@@ -10,33 +10,81 @@ const log = debug('tools');
10
10
 
11
11
  function modelScore(_appContext) {
12
12
  let description = `
13
- model-score — score data using a deployed model on MAS.
13
+ ## model-score — score data using a deployed model on MAS
14
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
15
+ LLM Invocation Guidance (When to use)
16
+ Use THIS tool when:
17
+ - User wants to score data with a model: "score this customer with model churnRisk"
18
+ - User provides input values for prediction: "predict using model creditScore with age=45, income=60000"
19
+ - User wants batch scoring: "score these 10 customers with fraud model"
20
+ - User asks for model predictions: "what does the sales forecast model predict for Q4?"
21
+ - User wants to get predictions: "use the risk model to score this applicant"
22
+ - User provides scenario data for a model: "run model cancer1 with age=45, sex=M"
17
23
 
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
24
+ Do NOT use this tool for:
25
+ - Checking if a model exists (use find-model)
26
+ - Getting model metadata/variables (use model-info)
27
+ - Listing available models (use list-models)
28
+ - Running SAS programs (use run-sas-program)
29
+ - Running jobs (use run-job)
30
+ - Querying tables (use sas-query or read-table)
22
31
 
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 }
32
+ Purpose
33
+ Score user-supplied scenario data using a model published to MAS (Model Aggregation Service) on SAS Viya. Returns predictions, probabilities, scores, and other model outputs merged with the input data.
26
34
 
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 }
35
+ Parameters
36
+ - model (string, required): The name of the model as published to MAS. Must be exact match.
37
+ - scenario (string | object | array, required): Data to score. Accepts:
38
+ - A comma-separated key=value string (e.g., "x=1, y=2")
39
+ - A plain object with field names and values (e.g., {x: 1, y: 2})
40
+ - An array of objects for batch scoring
41
+ - uflag (boolean, default false): When true, returned model field names will be prefixed with an underscore.
30
42
 
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)
43
+ Parsing & Behavior
44
+ - If scenario is a string, the tool parses comma-separated key=value pairs into an object
45
+ - If scenario is an array, supports batch scoring (processes multiple records)
46
+ - Numeric values in strings remain as strings; validate and cast as needed before scoring
36
47
 
37
- ERRORS
38
- Returns predictions, probabilities, scores merged with input data. Returns error if model not found or scoring fails.
39
- `;
48
+ Response Contract
49
+ Returns a JSON object containing:
50
+ - Input fields merged with scoring results
51
+ - Prediction/score field(s) from the model (field names depend on model)
52
+ - Probability fields for classification models (e.g., P_class1, P_class2)
53
+ - Model metadata: model name, version if available
54
+ - _variables_: Variable metadata if uflag=true
55
+ - Error object if scoring fails with error message
56
+
57
+ Disambiguation & Clarification
58
+ - Missing model name: ask "Which model would you like to use for scoring?"
59
+ - Missing scenario data: ask "What input values should I use for scoring?"
60
+ - If model unknown: suggest "Use find-model to verify the model exists or list-models to see available models"
61
+ - If unsure of inputs: suggest "Use model-info to see the required input variables first"
62
+
63
+ Examples (→ mapped params)
64
+ - "score with model churn using age=45, income=60000" → { model: "churn", scenario: { age: "45", income: "60000" }, uflag: false }
65
+ - "predict creditScore for applicant: credit=700, debt=20000" → { model: "creditScore", scenario: { credit: "700", debt: "20000" }, uflag: false }
66
+ - "use fraud model to score transaction amount=500, merchant=online" → { model: "fraud", scenario: { amount: "500", merchant: "online" }, uflag: false }
67
+ - "run model cancer1 with age=45, sex=M, tumor=stage2" → { model: "cancer1", scenario: { age: "45", sex: "M", tumor: "stage2" }, uflag: false }
68
+
69
+ Negative Examples (should NOT call model-score)
70
+ - "find model churnRisk" (use find-model instead)
71
+ - "what inputs does model need?" (use model-info instead)
72
+ - "list all models" (use list-models instead)
73
+ - "run job scoring_job" (use run-job instead)
74
+ - "read table scores from Public" (use read-table instead)
75
+
76
+ Usage Tips
77
+ - Use model-info first to understand required input variables and data types
78
+ - Verify model exists with find-model before attempting to score
79
+ - For batch scoring, provide an array of objects as the scenario parameter
80
+ - Ensure MAS connectivity and credentials are available
81
+
82
+ Related Tools
83
+ - list-models → find-model → model-info → model-score (typical workflow)
84
+ - find-model — to verify model exists before scoring
85
+ - model-info — to understand required inputs and expected outputs
86
+ - list-models — to discover available models
87
+ `;
40
88
 
41
89
 
42
90
  let spec = {
@@ -71,12 +119,6 @@ Returns predictions, probabilities, scores merged with input data. Returns error
71
119
  }, {});
72
120
  }
73
121
  params.scenario= scenarioObj;
74
-
75
- // Drop model extension (e.g., .job, .model)
76
- if (params.model && params.model.includes('.')) {
77
- params.model = params.model.substring(0, params.model.lastIndexOf('.'));
78
- }
79
-
80
122
  log('modelScore params', params);
81
123
  // Check if the params.scenario is a string and parse it
82
124
  let r = await _masScoring(params)
@@ -9,38 +9,75 @@ import _readTable from '../toolHelpers/_readTable.js';
9
9
  function readTable(_appContext) {
10
10
 
11
11
  let describe = `
12
- read-table — retrieve rows from a table in a CAS or SAS library.
12
+ ## read-table — retrieve rows from a table in a CAS or SAS library
13
13
 
14
- USE when: read table, show rows, read from library, filtered data with WHERE
15
- DO NOT USE for: list tables, table structure (use table-info), SQL queries (use sas-query), SAS programs
14
+ LLM Invocation Guidance (When to use)
15
+ Use THIS tool when:
16
+ - User wants to read data from a table: "read table xyz.customers"
17
+ - User wants sample rows: "show me 10 rows from lib.sales"
18
+ - User wants filtered data: "read from mylib.orders where status = 'shipped'"
19
+ - User wants from specific library: "read table cars in sashelp"
20
+ - User wants from specific server: "read table from mylib.employees on sas"
16
21
 
17
- PARAMETERS
18
- - table: string table name (required)
19
- - lib: string caslib or libref (required)
20
- - server: string (default: 'cas') — 'cas' or 'sas'
21
- - start: number (default: 1) — 1-based row index
22
- - limit: number (default: 10) max rows (1-1000)
23
- - where: string — SQL WHERE clause filter
24
- - format: boolean (default: true) — formatted or raw values
22
+ Do NOT use this tool for:
23
+ - Listing tables in a library (use list-tables)
24
+ - Getting table structure/metadata (use table-info)
25
+ - Running SQL queries (use sas-query)
26
+ - Executing SAS programs (use run-sas-program)
27
+ - Running statistical analysis (use appropriate analytics tools)
25
28
 
26
- ROUTING RULES
27
- - "read table cars in Samples" { table: "cars", lib: "Samples", start: 1, limit: 10 }
28
- - "show 25 rows from customers" → { table: "customers", lib: "<lib>", limit: 25, start: 1 }
29
- - "read from mylib.orders where status='shipped'" → { table: "orders", lib: "mylib", where: "status='shipped'", start: 1, limit: 10 }
29
+ Purpose
30
+ Read one or more rows from a specified table in a CAS caslib or SAS libref. Supports pagination, filtering with WHERE clauses, and formatted/raw value display. Use this to inspect table data, sample rows, or retrieve filtered subsets.
31
+
32
+ Parameters
33
+ - table (string, required): Table name to read.
34
+ - lib (string, required): The caslib or libref containing the table.
35
+ - server (string, default 'cas'): Target server: 'cas' or 'sas'.
36
+ - start (number, default 1): 1-based row index to start reading from.
37
+ - limit (number, default 10): Maximum number of rows to return (1-1000 recommended).
38
+ - where (string, optional): SQL-style WHERE clause to filter rows (e.g., "age > 30 AND status = 'active'").
39
+ - format (boolean, default true): When true, return formatted/labeled values; when false return raw values.
40
+ - row (number, optional): Read a single specific row (sets start to this value and limit to 1).
41
+
42
+ Response Contract
43
+ Returns a JSON object containing:
44
+ - rows: Array of row objects with column names as keys
45
+ - total (optional): Total count of rows in table (if available)
46
+ - filtered_count (optional): Count of rows matching WHERE clause (if WHERE used)
47
+ - columns (optional): Column metadata including names and types
48
+ - Empty array if no rows match the criteria
49
+
50
+ Pagination & Filtering
51
+ - First page default: { start: 1, limit: 10 }
52
+ - To get next page: increment start by limit (e.g., { start: 11, limit: 10 })
53
+ - Use WHERE clause for server-side filtering: { where: "age > 30" }
54
+
55
+ Disambiguation & Clarification
56
+ - Missing library: ask "Which library contains the table you want to read?"
57
+ - Missing table: ask "Which table would you like to read?"
58
+ - Ambiguous lib.table format: parse and use as separate parameters
59
+ - Multiple tables: clarify which one (readTable handles one table at a time)
30
60
 
31
- EXAMPLES
61
+ Examples (→ mapped params)
32
62
  - "read table cars in Samples" → { table: "cars", lib: "Samples", start: 1, limit: 10 }
33
- - "show 25 rows from customers" → { table: "customers", lib: "mylib", limit: 25, start: 1 }
63
+ - "show 25 rows from customers" → { table: "customers", lib: <current_lib>, limit: 25, start: 1 }
64
+ - "read orders where status = 'shipped' limit 50" → { table: "orders", lib: <lib>, where: "status = 'shipped'", limit: 50, start: 1 }
65
+ - "read row 15 from employees in mylib on sas" → { table: "employees", lib: "mylib", server: "sas", row: 15 }
66
+ - "get next 10 rows" (after previous {start:1,limit:10}) → { table: <same>, lib: <same>, start: 11, limit: 10 }
34
67
 
35
- NEGATIVE EXAMPLES (do not route here)
36
- - "list tables in Samples" (use list-tables)
37
- - "what columns are in cars" (use table-info)
38
- - "execute SQL query" (use sas-query)
39
- - "run SAS code" (use run-sas-program)
68
+ Negative Examples (should NOT call read-table)
69
+ - "list tables in Samples" (use list-tables instead)
70
+ - "what columns are in the cars table?" (use table-info instead)
71
+ - "execute this SQL query" (use sas-query instead)
72
+ - "run this SAS code" (use run-sas-program instead)
40
73
 
41
- ERRORS
42
- Returns rows array, total count, filtered_count, columns metadata. Empty array if no matches.
43
- `;
74
+ Related Tools
75
+ - list-tables to browse available tables in a library
76
+ - table-info — to inspect table structure, columns, and metadata
77
+ - find-table — to check if a table exists in a library
78
+ - list-libraries — to browse available libraries
79
+ - sas-query — to run complex SQL queries across tables
80
+ `;
44
81
 
45
82
  let specs = {
46
83
  name: 'read-table',
@@ -8,36 +8,56 @@ import _submitCode from '../toolHelpers/_submitCode.js';
8
8
 
9
9
  function runCasProgram(_appContext) {
10
10
  let description = `
11
- run-cas-program — execute a CAS program on SAS Viya server.
11
+ ## run-cas-program
12
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)
13
+ Execute a cas program on a SAS Viya server
15
14
 
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
15
+ Required Parameters
16
+ - src(string, required): The cas program to execute.
22
17
 
23
- ROUTING RULES
24
- - run cas program action echo → { src: action echo }
25
- - execute cas action simple.summary → { src: action simple.summary }
18
+ Optional Parameters:
26
19
 
27
- EXAMPLES
28
- - run cas program action echo { src: action echo }
29
- - cas program sample folder=/Public/models { src: sample, folder: /Public/models }
20
+ - scenario (string | object ,optional): Input values to program/ Accepts:
21
+ - a comma-separated key=value string (e.g. "x=1, y=2"),
22
+ - a JSON object with field names and values (recommended for typed inputs),
30
23
 
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)
24
+ LLM Invocation Guidance
25
+ Use THIS tool when the user wants to run a Cas program on the server:
26
+ - "run cas program 'action echo / code='aaaa'"
27
+ - "cas program 'action echo / code='aaaa'"
28
+ - 'submit cas "action echo / code='aaaa'"'
35
29
 
36
- NOTES
37
- Sends src verbatim without validation. For SAS macros use run-macro. For arbitrary SAS code use run-sas-program.
38
30
 
39
- RESPONSE
40
- Log output and CAS results. If output table specified, returned as markdown table.
31
+ Do NOT use this tool when the user wants:
32
+ - run macro -> use run-macro
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}
41
61
  `;
42
62
 
43
63
  let spec = {
@@ -9,31 +9,30 @@ import _jobSubmit from '../toolHelpers/_jobSubmit.js';
9
9
  function runJob(_appContext) {
10
10
 
11
11
  let description = `
12
- run-job — execute a deployed SAS Viya job.
12
+ ## run-job — execute a deployed SAS Viya job
13
13
 
14
- USE when: run job, execute job, run with parameters
15
- DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro), list/find jobs
14
+ LLM Invocation Guidance (When to use)
15
+ Use THIS tool when:
16
+ - You want to run a registered Job Execution asset by name
17
+ - You have simple parameter inputs to pass to the job
16
18
 
17
- PARAMETERS
18
- - name: string job name (required)
19
- - scenario: string | object input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
19
+ Do NOT use this tool for:
20
+ - Running arbitrary SAS code (use run-sas-program)
21
+ - Invoking pre-defined SAS macros (use run-macro)
22
+ - Listing or finding jobs (use list-jobs / find-job)
20
23
 
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
+ Parameters
25
+ - name (string, required): The job name to execute
26
+ - scenario (string | object, optional): Input values to the job. Accepts:
27
+ - a comma-separated key=value string (e.g. "x=1, y=2")
28
+ - a JSON object with field names and values (recommended)
24
29
 
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} }
30
+ Response
31
+ - Log output, listings, and tables depending on the job’s design. Table outputs will be displayed when present.
28
32
 
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.
33
+ Examples ( mapped params)
34
+ - "run job xyz param1=10,param2=val2" { name: "xyz", scenario: { param1: 10, param2: "val2" } }
35
+ - "run-job name=monthly_etl, scenario=month=10,year=2025" { name: "monthly_etl", scenario: { month: 10, year: 2025 } }
37
36
  `;
38
37
 
39
38
  let spec = {
@@ -6,36 +6,38 @@
6
6
  import { z } from 'zod';
7
7
  import _jobSubmit from '../toolHelpers/_jobSubmit.js';
8
8
 
9
+
9
10
  function runJobdef(_appContext) {
10
11
  // JSON object for LLM/tooling
11
12
 
12
13
  let description = `
13
- run-jobdef — execute a SAS Viya job definition.
14
-
15
- USE when: run jobdef, execute jobdef, run with parameters
16
- DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro), list/find jobdefs
14
+ ## run-jobdef — execute a SAS Viya job definition
17
15
 
18
- PARAMETERS
19
- - name: string — jobdef name (required)
20
- - scenario: string | object input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
16
+ LLM Invocation Guidance (When to use)
17
+ Use THIS tool when:
18
+ - You want to run a registered Job Definition by name
19
+ - You can pass parameters to the job definition
21
20
 
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"} }
21
+ Do NOT use this tool for:
22
+ - Running arbitrary SAS code (use run-program tool)
23
+ - Invoking SAS macros (use run-macro tool)
24
+ - Listing or finding jobdefs (use list-jobdefs tool / find-jobdef tool)
25
25
 
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} }
26
+ Parameters
27
+ - name (string, required): The job definition name to execute
28
+ - scenario (string | object, optional): Input values. Accepts:
29
+ - a comma-separated key=value string (e.g. "x=1, y=2")
30
+ - a JSON object with field names and values (recommended)
29
31
 
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)
32
+ Response
33
+ - Log output, listings, and tables depending on the job definition's design. Table outputs will be displayed when present.
35
34
 
36
- ERRORS
37
- Returns log output, listings, tables from jobdef. Error if jobdef not found.
38
- `;
35
+ Examples (→ mapped params)
36
+ - "jobdef xyz param1=10,param2=val2" → { name: "xyz", scenario: { param1: 10, param2: "val2" } }
37
+ - "run jobdef name=monthly_report, scenario=month=10,year=2025" → { name: "monthly_report", scenario: { month: 10, year: 2025 } }
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
+ `;
39
41
 
40
42
  let spec = {
41
43
  name: 'run-jobdef',
@@ -9,32 +9,32 @@ import _submitCode from '../toolHelpers/_submitCode.js';
9
9
 
10
10
  function runMacro(_appContext) {
11
11
  let description = `
12
- run-macro — submit and execute a SAS macro on SAS Viya server.
12
+ ## run-macro
13
13
 
14
- USE when: run macro, execute macro with parameters
15
- DO NOT USE for: arbitrary SAS code (use run-sas-program), jobs, jobdefs
14
+ Submit and execute a SAS macro on a SAS Viya server by generating and sending SAS code.
16
15
 
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;"
16
+ Inputs
17
+ - macro (string, required): The name of the macro to execute (provide the macro identifier without the leading "%").
18
+ - scenario (string, optional): Parameters or SAS setup code to send before invoking the macro. Accepted formats:
19
+ - Comma-separated key=value pairs (e.g. "x=1, y=abc") — converted to SAS %let statements.
20
+ - Raw SAS macro code (e.g. "%let x=1; %let y=abc;") — passed through unchanged when it already contains SAS macro syntax.
20
21
 
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;" }
22
+ Behavior
23
+ - If \`scenario\` contains SAS macro syntax (contains \`%let\` or other macro markers), it is sent unchanged.
24
+ - Otherwise the tool converts comma-separated parameters into \`%let\` statements (e.g. "x=1,y=abc" → "%let x=1; %let y=abc;") and appends a macro invocation \`%<macro>;\`.
25
+ - The resulting SAS code is submitted via the internal \`_submitCode\` helper and the submission result is returned.
25
26
 
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" }
27
+ Output
28
+ - Returns the response produced by \`_submitCode\`, typically including ods, log, list of tables created by the macro
29
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)
30
+ Usage notes
31
+ - Ensure the target SAS environment has the macro defined
32
+ - This helper does not perform advanced input validation or type coercion — validate parameters before calling when needed.
34
33
 
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
- `;
34
+ Examples
35
+ - run macro \`abc\` with scenario \`x=1, y=2\`
36
+ - run macro \`summarize\` with raw SAS code \`%let x=1; %let y=2;\` (the helper will pass it through unchanged)
37
+ `;
38
38
 
39
39
  let spec = {
40
40
  name: 'run-macro',
@@ -8,37 +8,84 @@ import _submitCode from '../toolHelpers/_submitCode.js';
8
8
 
9
9
  function runProgram(_appContext) {
10
10
  let description = `
11
- run-sas-program — execute SAS code or programs on SAS Viya server.
11
+ ## run-sas-program — execute SAS code or programs on SAS Viya server
12
12
 
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)
13
+ LLM Invocation Guidance (When to use)
14
+ Use THIS tool when the user wants to run a SAS program on the server:
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"
15
21
 
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
22
+ Do NOT use this tool when the user wants:
23
+ - run macro -> use run-macro
24
+ - run job -> use run-job
25
+ - run jobdef -> use run-jobdef
26
+ - list jobs -> use list-jobs
27
+ - list jobdefs -> use list-jobdefs
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
22
33
 
23
- ROUTING RULES
24
- - "run program 'data a; x=1; run;'" { src: "data a; x=1; run;", folder: "", 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 }
34
+ Purpose
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
27
56
 
28
- EXAMPLES
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)
29
64
  - "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 }
65
+ - "program 'data work.a; x=1; run;' output=a limit=50" → { src: "data work.a; x=1; run;", folder: "", output: "a", limit: 50 }
66
+ - "run sas program sample folder=/Public/models output=A limit=50" → { src: "sample", folder: "/Public/models", output: "A", limit: 50 }
67
+ - "run program mycode.sas in /Public with name=John, age=45" → { src: "mycode", folder: "/Public", scenario: { name: "John", age: 45 }, output: "", limit: 100 }
68
+
69
+ Negative Examples (should NOT call run-sas-program)
70
+ - "run macro summarize" (use run-macro instead)
71
+ - "run job monthly_report" (use run-job instead)
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)
31
75
 
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)
76
+ Behavior & Usage Notes
77
+ - Sends the supplied src verbatim to the SAS execution helper
78
+ - For .sas files, specify the file name (with or without .sas extension) and the folder path
79
+ - For invoking pre-defined SAS macros, prefer run-macro which handles %let statements automatically
80
+ - Scenario values are converted to macro variables when provided
81
+ - Be cautious when executing arbitrary code in production environments
38
82
 
39
- ERRORS
40
- Returns log, ods, tables array, data (if output specified). Error if execution fails.
41
- `;
83
+ Related Tools
84
+ - run-macro for executing predefined SAS macros with parameters
85
+ - run-job — for executing registered Job Execution assets
86
+ - sas-query — for natural language SQL queries
87
+ - read-table — for simple data retrieval
88
+ `;
42
89
 
43
90
  let spec = {
44
91
  name: 'run-sas-program',