@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
|
@@ -1,95 +1,66 @@
|
|
|
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 _listTables from '../toolHelpers/_listTables.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function listTables(_appContext) {
|
|
12
|
-
const log = debug('tools');
|
|
13
|
-
|
|
14
|
-
let description = `
|
|
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
|
-
|
|
40
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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> }
|
|
73
|
-
`;
|
|
74
|
-
|
|
75
|
-
let spec = {
|
|
76
|
-
name: 'list-tables',
|
|
77
|
-
aliases: ['listTables','list tables','list_tables'],
|
|
78
|
-
description: description,
|
|
79
|
-
|
|
80
|
-
schema: {
|
|
81
|
-
'lib': z.string(),
|
|
82
|
-
'server': z.string().default('cas'),
|
|
83
|
-
'limit': z.number().default(10),
|
|
84
|
-
'start': z.number().default(1)
|
|
85
|
-
},
|
|
86
|
-
required: ['lib'],
|
|
87
|
-
handler: async (params) => {
|
|
88
|
-
let r = await _listTables(params);
|
|
89
|
-
return r;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return spec;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export default listTables;
|
|
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 _listTables from '../toolHelpers/_listTables.js';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function listTables(_appContext) {
|
|
12
|
+
const log = debug('tools');
|
|
13
|
+
|
|
14
|
+
let description = `
|
|
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.
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
let spec = {
|
|
47
|
+
name: 'list-tables',
|
|
48
|
+
description: description,
|
|
49
|
+
|
|
50
|
+
inputSchema: z.object({
|
|
51
|
+
lib: z.string(),
|
|
52
|
+
server: z.string().optional(),
|
|
53
|
+
limit: z.number().optional(),
|
|
54
|
+
start: z.number().optional(),
|
|
55
|
+
where: z.string().optional()
|
|
56
|
+
}),
|
|
57
|
+
handler: async (params) => {
|
|
58
|
+
let r = await _listTables(params);
|
|
59
|
+
return r;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return spec;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default listTables;
|
|
66
|
+
|
package/src/toolSet/makeTools.js
CHANGED
package/src/toolSet/modelInfo.js
CHANGED
|
@@ -10,72 +10,39 @@ const log = debug('tools');
|
|
|
10
10
|
|
|
11
11
|
function modelInfo(_appContext) {
|
|
12
12
|
let description = `
|
|
13
|
-
|
|
13
|
+
model-info — retrieve detailed metadata for a deployed model.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
23
|
-
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
|
58
|
-
- "What are the outputs of model sales_forecast?" → { model: "sales_forecast" }
|
|
29
|
+
- "Show variables for myModel" → { model: "myModel" }
|
|
59
30
|
|
|
60
|
-
|
|
61
|
-
- "
|
|
62
|
-
- "
|
|
63
|
-
- "
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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',
|
|
73
|
-
aliases: ['modelInfo','model info','model_info'],
|
|
74
42
|
description: description,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
},
|
|
78
|
-
required: ['model'],
|
|
43
|
+
inputSchema: z.object({
|
|
44
|
+
model: z.string()
|
|
45
|
+
}),
|
|
79
46
|
handler: async (params) => {
|
|
80
47
|
let r = await _masDescribe(params);
|
|
81
48
|
return r;
|
|
@@ -85,3 +52,4 @@ Related Tools
|
|
|
85
52
|
}
|
|
86
53
|
|
|
87
54
|
export default modelInfo;
|
|
55
|
+
|
|
@@ -10,93 +10,44 @@ const log = debug('tools');
|
|
|
10
10
|
|
|
11
11
|
function modelScore(_appContext) {
|
|
12
12
|
let description = `
|
|
13
|
-
|
|
13
|
+
mas-score — score data using a deployed model on MAS.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
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
|
-
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
- model
|
|
37
|
-
-
|
|
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
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
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
|
-
|
|
49
|
-
Returns
|
|
50
|
-
|
|
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 = {
|
|
91
|
-
name: '
|
|
92
|
-
aliases: ['modelScore','model score','model_score'],
|
|
43
|
+
name: 'mas-score',
|
|
93
44
|
description: description,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
|
|
45
|
+
inputSchema:z.object({
|
|
46
|
+
model: z.string(),
|
|
47
|
+
scenario: z.string(),
|
|
48
|
+
uflag: z.boolean().optional()
|
|
49
|
+
}),
|
|
50
|
+
|
|
100
51
|
handler: async (iparams) => {
|
|
101
52
|
let params = {...iparams};
|
|
102
53
|
let scenario = params.scenario;
|
|
@@ -119,6 +70,12 @@ Related Tools
|
|
|
119
70
|
}, {});
|
|
120
71
|
}
|
|
121
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
|
+
|
|
122
79
|
log('modelScore params', params);
|
|
123
80
|
// Check if the params.scenario is a string and parse it
|
|
124
81
|
let r = await _masScoring(params)
|
|
@@ -129,3 +86,4 @@ Related Tools
|
|
|
129
86
|
}
|
|
130
87
|
|
|
131
88
|
export default modelScore;
|
|
89
|
+
|
package/src/toolSet/readTable.js
CHANGED
|
@@ -1,104 +1,63 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import { z } from 'zod';
|
|
6
|
-
import debug from 'debug';
|
|
7
|
-
|
|
8
|
-
import _readTable from '../toolHelpers/_readTable.js';
|
|
9
|
-
function readTable(_appContext) {
|
|
10
|
-
|
|
11
|
-
let describe = `
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- table
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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 }
|
|
67
|
-
|
|
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)
|
|
73
|
-
|
|
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
|
-
`;
|
|
81
|
-
|
|
82
|
-
let specs = {
|
|
83
|
-
name: 'read-table',
|
|
84
|
-
aliases: ['readTable','read table','read_table'],
|
|
85
|
-
description: describe,
|
|
86
|
-
schema: {
|
|
87
|
-
table: z.string(),
|
|
88
|
-
lib: z.string(),
|
|
89
|
-
start: z.number(),
|
|
90
|
-
limit: z.number().default(10),
|
|
91
|
-
server: z.string().default('cas'),
|
|
92
|
-
where: z.string().default(''),
|
|
93
|
-
format: z.boolean().default(true)
|
|
94
|
-
|
|
95
|
-
},
|
|
96
|
-
required: ['table', 'lib'],
|
|
97
|
-
handler: async (params) => {
|
|
98
|
-
let r = await _readTable(params,'query');
|
|
99
|
-
return r;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return specs;
|
|
103
|
-
}
|
|
104
|
-
export default readTable;
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import debug from 'debug';
|
|
7
|
+
|
|
8
|
+
import _readTable from '../toolHelpers/_readTable.js';
|
|
9
|
+
function readTable(_appContext) {
|
|
10
|
+
|
|
11
|
+
let describe = `
|
|
12
|
+
read-table — retrieve rows from a table in a CAS or SAS library.
|
|
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
|
|
16
|
+
|
|
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
|
|
25
|
+
|
|
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 }
|
|
30
|
+
|
|
31
|
+
EXAMPLES
|
|
32
|
+
- "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 }
|
|
34
|
+
|
|
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)
|
|
40
|
+
|
|
41
|
+
ERRORS
|
|
42
|
+
Returns rows array, total count, filtered_count, columns metadata. Empty array if no matches.
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
let specs = {
|
|
46
|
+
name: 'read-table',
|
|
47
|
+
description: describe,
|
|
48
|
+
inputSchema: z.object({
|
|
49
|
+
table: z.string(),
|
|
50
|
+
lib: z.string().optional(),
|
|
51
|
+
start: z.number().optional(),
|
|
52
|
+
limit: z.number().optional(),
|
|
53
|
+
server: z.string().optional(),
|
|
54
|
+
where: z.string().optional()
|
|
55
|
+
}),
|
|
56
|
+
handler: async (params) => {
|
|
57
|
+
let r = await _readTable(params,'query');
|
|
58
|
+
return r;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return specs;
|
|
62
|
+
}
|
|
63
|
+
export default readTable;
|