@sassoftware/sas-score-mcp-serverjs 0.3.18 → 0.4.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.
Files changed (47) hide show
  1. package/cli.js +141 -26
  2. package/package.json +4 -3
  3. package/skills/mcp-tool-description-optimizer/SKILL.md +129 -0
  4. package/skills/mcp-tool-description-optimizer/references/examples.md +123 -0
  5. package/skills/sas-read-and-score/SKILL.md +91 -0
  6. package/skills/sas-read-strategy/SKILL.md +143 -0
  7. package/skills/sas-score-workflow/SKILL.md +282 -0
  8. package/src/createMcpServer.js +1 -0
  9. package/src/expressMcpServer.js +68 -28
  10. package/src/handleGetDelete.js +6 -3
  11. package/src/hapiMcpServer.js +30 -0
  12. package/src/openAPIJson.js +175 -175
  13. package/src/toolHelpers/_jobSubmit.js +2 -0
  14. package/src/toolHelpers/_listLibrary.js +56 -39
  15. package/src/toolHelpers/getLogonPayload.js +9 -7
  16. package/src/toolHelpers/getStoreOpts.js +1 -2
  17. package/src/toolHelpers/getToken.js +0 -1
  18. package/src/toolHelpers/refreshToken.js +48 -45
  19. package/src/toolHelpers/refreshTokenOauth.js +2 -2
  20. package/src/toolHelpers/tlogon.js +9 -0
  21. package/src/toolSet/devaScore.js +30 -38
  22. package/src/toolSet/findJob.js +23 -49
  23. package/src/toolSet/findJobdef.js +24 -54
  24. package/src/toolSet/findLibrary.js +25 -57
  25. package/src/toolSet/findModel.js +31 -53
  26. package/src/toolSet/findTable.js +25 -54
  27. package/src/toolSet/getEnv.js +20 -38
  28. package/src/toolSet/listJobdefs.js +24 -58
  29. package/src/toolSet/listJobs.js +24 -72
  30. package/src/toolSet/listLibraries.js +37 -47
  31. package/src/toolSet/listModels.js +20 -47
  32. package/src/toolSet/listTables.js +29 -58
  33. package/src/toolSet/makeTools.js +3 -0
  34. package/src/toolSet/modelInfo.js +18 -49
  35. package/src/toolSet/modelScore.js +27 -69
  36. package/src/toolSet/readTable.js +25 -62
  37. package/src/toolSet/runCasProgram.js +23 -43
  38. package/src/toolSet/runJob.js +20 -19
  39. package/src/toolSet/runJobdef.js +21 -23
  40. package/src/toolSet/runMacro.js +20 -20
  41. package/src/toolSet/runProgram.js +24 -71
  42. package/src/toolSet/sasQuery.js +23 -70
  43. package/src/toolSet/scrInfo.js +3 -4
  44. package/src/toolSet/setContext.js +22 -48
  45. package/src/toolSet/tableInfo.js +28 -71
  46. package/src/toolHelpers/getOpts.js +0 -51
  47. package/src/toolHelpers/getOptsViya.js +0 -44
@@ -12,64 +12,35 @@ function listTables(_appContext) {
12
12
  const log = debug('tools');
13
13
 
14
14
  let description = `
15
- ## list-tables — enumerate tables within a specific CAS or SAS library
16
-
17
- LLM Invocation Guidance (When to use)
18
- Use THIS tool when the user explicitly wants the tables inside ONE library:
19
- - "list tables in Samples"
20
- - "show tables in sashelp"
21
- - "list cas tables in Public"
22
- - "list 25 tables in Samples"
23
- - "next tables" (after a prior listTables call)
24
-
25
- Do NOT use this tool to list the following
26
- - lib -> use list-libraries
27
- - list models -> use list-models
28
- - list jobs -> use list-jobs
29
- - list jobdefs -> use list-jobdefs
30
- - Finding whether a library exists (use find-library)
31
- - Describing a single table's columns or metadata (use table-info)
32
- - Reading table data rows (use read-table)
33
- - Listing jobs/models (other specialized tools)
34
-
35
- Purpose
36
- Return the names (and possibly lightweight metadata) of tables contained in a specified library (CAS caslib or SAS libref).
37
-
38
- Parameters
39
- - lib (string, required): Library to inspect (e.g. "Samples", "sashelp").
40
- - server (cas|sas, default 'cas'): Target environment; default when unspecified is CAS.
41
- - limit (number, default 10): Page size.
42
- - start (number, default 1): 1-based offset for pagination.
43
- - where (string, optional): Filter expression (if supported by backend) or ignored safely.
44
-
45
- Response Contract
46
- - JSON: { tables: string[] [, start:number]? }
47
- - tables array is empty when no matches.
48
- - Include start = start + limit when length === limit (possible more pages).
49
-
50
- Pagination Examples
51
- - First page: { lib:'Samples', start:1, limit:10 }
52
- - Next page: { lib:'Samples', start:11, limit:10 }
53
-
54
- Disambiguation & Clarification
55
- - Missing library name → ask: "Which library do you want to list tables from?"
56
- - Input only "list tables" → ask for the library unless prior context supplies one.
57
- - If user mentions multiple libs ("tables in Public and Samples") → request a single library.
58
-
59
- Negative Examples (should NOT call list-tables)
60
- - "list libs" (list-libraries)
61
- - "find lib Public" (find-library)
62
- - "describe table cars" (table-info)
63
- - "read table cars from sashelp" (read-table)
64
-
65
- Usage Tips
66
- - After listing, call table-info to inspect structure or read-table for sample data.
67
- - Keep limit moderate; page for very large libraries.
68
-
69
- Examples (→ mapped params)
70
- - "list tables in samples" → { lib:"samples", start:1, limit:10 }
71
- - "show 25 tables in sashelp" → { lib:"sashelp", limit:25, start:1 }
72
- - "next tables" (after previous {start:1,limit:10}) → { start:11, limit:10, lib:<previousLib> }
15
+ list-tables — enumerate tables within a library.
16
+
17
+ USE when: list tables in <lib>, show tables in <lib>, next page
18
+ DO NOT USE for: find table, list libraries, get table structure (use table-info), read data (use read-table)
19
+
20
+ PARAMETERS
21
+ - lib: string library to inspect (required)
22
+ - server: string (default: 'cas') — 'cas' or 'sas'
23
+ - limit: number (default: 10) page size
24
+ - start: number (default: 1) — 1-based offset
25
+ - where: string optional filter expression
26
+
27
+ ROUTING RULES
28
+ - "list tables in Samples" → { lib: "Samples", start: 1, limit: 10 }
29
+ - "list 25 tables in sashelp" → { lib: "sashelp", limit: 25, start: 1 }
30
+ - "list cas tables in Public" { lib: "Public", server: "cas", start: 1, limit: 10 }
31
+
32
+ EXAMPLES
33
+ - "list tables in Samples" → { lib: "Samples", start: 1, limit: 10 }
34
+ - "show 25 tables in sashelp" → { lib: "sashelp", limit: 25, start: 1 }
35
+
36
+ NEGATIVE EXAMPLES (do not route here)
37
+ - "list libs" (use list-libraries)
38
+ - "find lib Public" (use find-library)
39
+ - "describe table cars" (use table-info)
40
+ - "read table cars" (use read-table)
41
+
42
+ ERRORS
43
+ Returns empty array if no tables found.
73
44
  `;
74
45
 
75
46
  let spec = {
@@ -30,6 +30,7 @@ import findJobdef from './findJobdef.js';
30
30
 
31
31
  import sasQuery from './sasQuery.js';
32
32
  import setContext from './setContext.js';
33
+ //import scoreSkill from './scoreSkill.js';
33
34
 
34
35
  function makeTools(_appContext) {
35
36
  // wrap all tools with
@@ -64,6 +65,8 @@ function makeTools(_appContext) {
64
65
  findJobdef(_appContext),
65
66
  runJobdef(_appContext),
66
67
 
68
+ //scoreSkill(_appContext),
69
+
67
70
  devaScore(_appContext),
68
71
  setContext(_appContext)
69
72
 
@@ -10,63 +10,32 @@ const log = debug('tools');
10
10
 
11
11
  function modelInfo(_appContext) {
12
12
  let description = `
13
- ## model-info — retrieve detailed metadata for a deployed model
13
+ model-info — retrieve detailed metadata for a deployed model.
14
14
 
15
- LLM Invocation Guidance (When to use)
16
- Use THIS tool when:
17
- - User wants input/output variable information: "What inputs does model X need?"
18
- - User wants to understand model variables: "Describe model myModel"
19
- - User wants data types and roles: "Show me the variables for myModel"
20
- - User wants to prepare data for scoring: "What are the required inputs for model sales_forecast?"
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
21
17
 
22
- Do NOT use this tool for:
23
- - Checking if a model exists (use find-model)
24
- - Listing available models (use list-models)
25
- - Scoring a model (use model-score)
26
- - Looking up tables or jobs (use respective find/list tools)
18
+ PARAMETERS
19
+ - model: string model name (required, exact match)
27
20
 
28
- Purpose
29
- Retrieve detailed metadata for a model deployed to MAS (Model Aggregation Service). This includes input variable names, data types, roles/usage, ranges, and output variable information. Use this before scoring to understand what data the model requires.
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" }
30
25
 
31
- Parameters
32
- - model (string, required): The name of the model as published to MAS. Must be exact match.
33
-
34
- Response Contract
35
- Returns a JSON object containing model metadata, typically including:
36
- - name: The model name
37
- - inputs: Array of input variable objects with:
38
- - name: Variable name
39
- - type: Data type (numeric, character, etc.)
40
- - role: Role in model (input, key, etc.)
41
- - allowed_values or range: Optional constraints
42
- - outputs: Array of output/prediction objects with:
43
- - name: Prediction/output variable name
44
- - type: Data type
45
- - possible_values: For classification models, the class labels
46
- - model_type: Type of model (regression, classification, etc.)
47
- - description: Optional model description
48
-
49
- Disambiguation & Clarification
50
- - If model name is missing: ask "Which model would you like to see information for?"
51
- - If user says "variables" without specifying model: ask "Which model would you like the variables for?"
52
- - Multiple model requests: handle one at a time
53
-
54
- Examples (→ mapped params)
26
+ EXAMPLES
55
27
  - "What inputs does model churnRisk need?" → { model: "churnRisk" }
56
28
  - "Describe model creditScore" → { model: "creditScore" }
57
- - "Show the variables for myModel" → { model: "myModel" }
58
- - "What are the outputs of model sales_forecast?" → { model: "sales_forecast" }
29
+ - "Show variables for myModel" → { model: "myModel" }
59
30
 
60
- Negative Examples (should NOT call model-info)
61
- - "List all available models" (use list-models instead)
62
- - "Find model cancer" (use find-model instead)
63
- - "Score this customer with model churnRisk" (use model-score instead)
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)
64
35
 
65
- Related Tools
66
- - list-models find-model model-info model-score (typical workflow)
67
- - find-model — to check if a specific model exists
68
- - model-score — to score data using the model
69
- `;
36
+ ERRORS
37
+ Returns model metadata: inputs (name, type, role), outputs (name, type, possible_values), model_type, description.
38
+ `;
70
39
 
71
40
  let spec = {
72
41
  name: 'model-info',
@@ -10,81 +10,33 @@ 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
- 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"
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
23
17
 
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)
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
31
22
 
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.
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 }
34
26
 
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.
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 }
42
30
 
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
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)
47
36
 
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
- `;
37
+ ERRORS
38
+ Returns predictions, probabilities, scores merged with input data. Returns error if model not found or scoring fails.
39
+ `;
88
40
 
89
41
 
90
42
  let spec = {
@@ -119,6 +71,12 @@ Related Tools
119
71
  }, {});
120
72
  }
121
73
  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
+
122
80
  log('modelScore params', params);
123
81
  // Check if the params.scenario is a string and parse it
124
82
  let r = await _masScoring(params)
@@ -9,75 +9,38 @@ 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
- 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"
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
21
16
 
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)
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
28
25
 
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)
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 }
60
30
 
61
- Examples (→ mapped params)
31
+ EXAMPLES
62
32
  - "read table cars in Samples" → { table: "cars", lib: "Samples", start: 1, limit: 10 }
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 }
33
+ - "show 25 rows from customers" → { table: "customers", lib: "mylib", limit: 25, start: 1 }
67
34
 
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)
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)
73
40
 
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
- `;
41
+ ERRORS
42
+ Returns rows array, total count, filtered_count, columns metadata. Empty array if no matches.
43
+ `;
81
44
 
82
45
  let specs = {
83
46
  name: 'read-table',
@@ -8,56 +8,36 @@ import _submitCode from '../toolHelpers/_submitCode.js';
8
8
 
9
9
  function runCasProgram(_appContext) {
10
10
  let description = `
11
- ## run-cas-program
11
+ run-cas-program — execute a CAS program on SAS Viya server.
12
12
 
13
- Execute a cas program on a SAS Viya server
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
- Required Parameters
16
- - src(string, required): The cas program to execute.
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
- Optional Parameters:
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
- - 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),
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
- 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'"'
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
- 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}
39
+ RESPONSE
40
+ Log output and CAS results. If output table specified, returned as markdown table.
61
41
  `;
62
42
 
63
43
  let spec = {
@@ -9,30 +9,31 @@ 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
- 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
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
18
16
 
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)
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
- 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)
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
- Response
31
- - Log output, listings, and tables depending on the job’s design. Table outputs will be displayed when present.
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
- 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 } }
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 = {
@@ -6,38 +6,36 @@
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
- ## run-jobdef — execute a SAS Viya job definition
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
15
17
 
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
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
- 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)
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
- 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)
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
- Response
33
- - Log output, listings, and tables depending on the job definition's design. Table outputs will be displayed when present.
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
- 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
- `;
36
+ ERRORS
37
+ Returns log output, listings, tables from jobdef. Error if jobdef not found.
38
+ `;
41
39
 
42
40
  let spec = {
43
41
  name: 'run-jobdef',