@sassoftware/sas-score-mcp-serverjs 0.4.1-1 → 0.4.1-17
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/cli.js +210 -108
- package/package.json +6 -4
- 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 +78 -0
- package/scripts/update_descriptions.py +46 -0
- package/scripts/viyatls.sh +3 -0
- package/skills/sas-find-library-smart/SKILL.md +154 -0
- package/skills/sas-list-tables-smart/SKILL.md +127 -0
- package/skills/sas-read-and-score/SKILL.md +71 -51
- package/skills/sas-read-strategy/SKILL.md +43 -30
- package/skills/sas-score-workflow/SKILL.md +65 -34
- package/skills/sas-spec-migration/SKILL.md +303 -0
- package/src/authpkce.js +219 -0
- package/src/createMcpServer.js +11 -8
- package/src/expressMcpServer.js +354 -338
- 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/toolHelpers/_listLibrary.js +0 -1
- package/src/toolHelpers/getLogonPayload.js +5 -1
- 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 -61
- package/src/toolSet/findJob.js +1 -1
- package/src/toolSet/findJobdef.js +2 -2
- package/src/toolSet/findLibrary.js +68 -67
- package/src/toolSet/findModel.js +2 -2
- package/src/toolSet/findTable.js +3 -2
- package/src/toolSet/getEnv.js +8 -4
- package/src/toolSet/listJobdefs.js +61 -61
- package/src/toolSet/listJobs.js +61 -61
- package/src/toolSet/listLibraries.js +78 -78
- package/src/toolSet/listModels.js +56 -56
- package/src/toolSet/listTables.js +66 -65
- package/src/toolSet/modelInfo.js +2 -2
- package/src/toolSet/modelScore.js +6 -5
- package/src/toolSet/readTable.js +63 -65
- package/src/toolSet/runCasProgram.js +7 -6
- package/src/toolSet/runJob.js +81 -81
- package/src/toolSet/runJobdef.js +82 -82
- package/src/toolSet/runMacro.js +81 -80
- package/src/toolSet/runProgram.js +4 -8
- package/src/toolSet/sasQuery.js +77 -78
- package/src/toolSet/scrInfo.js +1 -1
- package/src/toolSet/scrScore.js +69 -68
- package/src/toolSet/setContext.js +65 -65
- package/src/toolSet/superstat.js +61 -59
- package/src/toolSet/tableInfo.js +58 -57
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sas-read-and-score
|
|
3
3
|
description: >
|
|
4
|
-
Guide the full read → score workflow in SAS Viya: reading records from a table
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"score
|
|
9
|
-
"
|
|
10
|
-
|
|
4
|
+
Guide the full read → score workflow in SAS Viya: reading records from a table and then scoring
|
|
5
|
+
them with a MAS model (using sas-score-model-score). Use this skill whenever the user wants to score records
|
|
6
|
+
from a table, run a model against query results, predict outcomes for a set of rows, or any
|
|
7
|
+
combination of fetching data and scoring it. Trigger phrases include: "score these records",
|
|
8
|
+
"score results of my query", "run the model on this table", "predict for these customers",
|
|
9
|
+
"fetch and score", "read and score", "score rows from", "run model on table data", or any request
|
|
10
|
+
that combines reading/querying table data with model prediction.
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# SAS Read → Score Workflow
|
|
@@ -15,68 +15,79 @@ description: >
|
|
|
15
15
|
Orchestrates the full two-step pattern of reading records from a SAS/CAS table and scoring them
|
|
16
16
|
with a deployed MAS model.
|
|
17
17
|
|
|
18
|
-
This skill chains two sub-skills:
|
|
19
|
-
1. **sas-read-strategy** — Choose between `read-table` and `sas-query`
|
|
20
|
-
2. **sas-score-workflow** — Validate model, invoke scoring, present results
|
|
21
|
-
|
|
22
18
|
---
|
|
23
19
|
|
|
24
|
-
##
|
|
20
|
+
## Pre-flight verification
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
**Before attempting to read or score table data:**
|
|
23
|
+
1. **Verify library exists**: Use `sas-find-library-smart` to check the library in CAS first, then SAS if needed
|
|
24
|
+
2. **Verify table exists**: Use `sas-score-find-table` to confirm the table is in the library
|
|
25
|
+
3. **Confirm server location**: Ensure you know which server (CAS or SAS) contains the data
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
- Yes → proceed to score
|
|
32
|
-
- No → pause and use `find-model` / `model-info`
|
|
27
|
+
This ensures consistent behavior with other data access operations.
|
|
33
28
|
|
|
34
|
-
|
|
29
|
+
---
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
## Workflow overview
|
|
37
32
|
|
|
38
|
-
|
|
33
|
+
The typical flow involves:
|
|
34
|
+
1. **Fetch data** — Identify which table/query will provide input records
|
|
35
|
+
2. **Validate model** — Confirm the model exists and understand its input schema
|
|
36
|
+
3. **Score** — Invoke the model on the fetched records
|
|
37
|
+
4. **Present results** — Merge predictions with original data and display
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
---
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
> "Score the first 10 customers in Public.customers with the churn model"
|
|
41
|
+
## Scenario: User already has data
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
If the user provides scenario data directly (e.g., "Score age=45, income=60000 with model X"):
|
|
44
|
+
- Extract the scenario values
|
|
45
|
+
- Validate against model's input schema
|
|
46
|
+
- Invoke scoring
|
|
47
|
+
- Return prediction
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
> "Score high-value customers (spend > 5000) in mylib.sales with the fraud model"
|
|
49
|
+
---
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
2. Apply `sas-score-workflow` → invoke `model-score` and present results
|
|
51
|
+
## Scenario: User wants to score table rows
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
If the user specifies a table (e.g., "Score all customers in Public.customers with model X"):
|
|
54
|
+
- Fetch raw rows (possibly filtered: "where status='active'")
|
|
55
|
+
- Validate model compatibility with input columns
|
|
56
|
+
- Invoke scoring on each row
|
|
57
|
+
- Merge results with original data
|
|
58
|
+
- Display combined table
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
2. Apply `sas-score-workflow` → invoke `model-score` and present result
|
|
60
|
+
---
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
> "Score Public.applicants with the creditRisk2 model"
|
|
62
|
+
## Scenario: User wants to score query results
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
If the user wants to score aggregated/filtered results (e.g., "Score high-value customers (spend > 5000) with model X"):
|
|
65
|
+
- Determine which records meet criteria (aggregation/filtering)
|
|
66
|
+
- Validate model expects these input columns
|
|
67
|
+
- Invoke scoring
|
|
68
|
+
- Merge predictions with summary data
|
|
69
|
+
- Display results
|
|
66
70
|
|
|
67
71
|
---
|
|
68
72
|
|
|
69
|
-
##
|
|
73
|
+
## Scenario: User unfamiliar with model
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
-
|
|
75
|
+
If the user specifies a model name that's new/unknown:
|
|
76
|
+
- Check if model exists
|
|
77
|
+
- Retrieve model schema (inputs, outputs)
|
|
78
|
+
- Show user what inputs the model expects
|
|
79
|
+
- Confirm before proceeding with scoring
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Rules
|
|
76
84
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
- Always validate table/library existence before attempting to read
|
|
86
|
+
- Always check model exists before invoking `sas-score-model-score`
|
|
87
|
+
- Match table columns to model input variables; warn on mismatch
|
|
88
|
+
- If multiple records: score batch if possible; fall back to row-by-row
|
|
89
|
+
- Merge predictions with original data using row index or key column
|
|
90
|
+
- Present results as table with original columns + new prediction columns
|
|
80
91
|
|
|
81
92
|
---
|
|
82
93
|
|
|
@@ -85,7 +96,16 @@ This skill chains two sub-skills:
|
|
|
85
96
|
| Problem | Action |
|
|
86
97
|
|---|---|
|
|
87
98
|
| Table not found | Ask for correct lib.tablename |
|
|
88
|
-
| Model not found |
|
|
89
|
-
| Field
|
|
90
|
-
| Scoring error | Return structured error, suggest model
|
|
91
|
-
| Empty read result |
|
|
99
|
+
| Model not found | Inform user; suggest verifying model name |
|
|
100
|
+
| Field/column mismatch | Show mismatch, ask user to confirm or adjust query |
|
|
101
|
+
| Scoring error | Return structured error, suggest checking model inputs |
|
|
102
|
+
| Empty read result | Inform user, ask if they want to adjust the query/filter |
|
|
103
|
+
| Data type mismatch | Warn user about type conversion, proceed or ask for clarification |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Integration with other skills
|
|
108
|
+
|
|
109
|
+
- **Before this workflow**: Use `sas-find-library-smart` to verify the library exists
|
|
110
|
+
- **For data retrieval**: Use `sas-read-strategy` to choose the right read tool (read-table vs sas-query)
|
|
111
|
+
- **For scoring**: Use `sas-score-workflow` for advanced scoring options beyond MAS models
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sas-read-strategy
|
|
3
3
|
description: >
|
|
4
|
-
Guide the user in choosing the right data retrieval tool: read-table (for raw row access with filters)
|
|
5
|
-
or sas-query (for analytical queries, aggregations, joins). Use this skill when the user wants to
|
|
4
|
+
Guide the user in choosing the right data retrieval tool: sas-score-read-table (for raw row access with filters)
|
|
5
|
+
or sas-score-sas-query (for analytical queries, aggregations, joins). Use this skill when the user wants to
|
|
6
6
|
fetch records from a SAS/CAS table. Trigger phrases include: "read records from", "get data where",
|
|
7
7
|
"fetch rows from", "query the table", "give me the first N records", "aggregate by", "join tables",
|
|
8
8
|
or any request that starts with data retrieval.
|
|
@@ -10,21 +10,25 @@ description: >
|
|
|
10
10
|
|
|
11
11
|
# SAS Read Strategy
|
|
12
12
|
|
|
13
|
-
Guides the decision between `read-table` and `sas-query` based on the user's intent and the nature
|
|
14
|
-
of the data operation.
|
|
15
|
-
|
|
16
|
-
---
|
|
13
|
+
Guides the decision between `sas-score-read-table` and `sas-score-sas-query` based on the user's intent and the nature
|
|
14
|
+
of the data operation. Determines which server contains the data and which retrieval tool is most appropriate.
|
|
17
15
|
|
|
18
16
|
## Determine the server location
|
|
19
17
|
|
|
20
|
-
Before retrieving data,
|
|
18
|
+
Before retrieving data, verify the library and determine which server(s) contain the table:
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
**Step 1: Verify library existence**
|
|
21
|
+
- Use `sas-find-library-smart` skill to check the library in CAS first, then SAS if needed
|
|
22
|
+
- This establishes the correct server and uppercase convention for SAS libraries
|
|
23
|
+
- Informs the user which server contains the library
|
|
24
|
+
|
|
25
|
+
**Step 2: Locate the specific table**
|
|
26
|
+
- Use `sas-score-find-table` to check if the table exists in the library
|
|
27
|
+
- Possible outcomes:
|
|
28
|
+
- If table exists **only in CAS** → set `server: "cas"`
|
|
29
|
+
- If table exists **only in SAS** → set `server: "sas"`
|
|
30
|
+
- If table exists **in both** → ask the user: *"The table exists in both CAS and SAS. Which server would you prefer to query from?"*
|
|
31
|
+
- If table exists **in neither** → inform user and suggest verifying the table name
|
|
28
32
|
|
|
29
33
|
---
|
|
30
34
|
|
|
@@ -37,8 +41,8 @@ Ask yourself: does the user already have the data in hand?
|
|
|
37
41
|
|
|
38
42
|
| User's Intent | Tool | Example |
|
|
39
43
|
|---|---|---|
|
|
40
|
-
| Get specific raw rows, apply simple filter, retrieve first N records | `read-table` | "Show me 10 rows from customers where status='active'" |
|
|
41
|
-
| Aggregate/summarize, calculate, join tables, analytical question | `sas-query` | "Average salary by department", "Count orders by region" |
|
|
44
|
+
| Get specific raw rows, apply simple filter, retrieve first N records | `sas-score-read-table` | "Show me 10 rows from customers where status='active'" |
|
|
45
|
+
| Aggregate/summarize, calculate, join tables, analytical question | `sas-score-sas-query` | "Average salary by department", "Count orders by region" |
|
|
42
46
|
|
|
43
47
|
---
|
|
44
48
|
|
|
@@ -51,17 +55,17 @@ Ask yourself: does the user already have the data in hand?
|
|
|
51
55
|
|
|
52
56
|
**How:**
|
|
53
57
|
```
|
|
54
|
-
read-table({
|
|
58
|
+
sas-score-read-table({
|
|
55
59
|
table: "tablename",
|
|
56
60
|
lib: "libraryname",
|
|
57
|
-
server: "cas" or "sas", // determined from find-table check
|
|
61
|
+
server: "cas" or "sas", // determined from sas-score-find-table check
|
|
58
62
|
limit: N, // default 10, adjust based on user request
|
|
59
63
|
where: "..." // optional SQL WHERE clause
|
|
60
64
|
})
|
|
61
65
|
```
|
|
62
66
|
|
|
63
67
|
**Rules:**
|
|
64
|
-
- Always determine the server first using `find-table`
|
|
68
|
+
- Always determine the server first using `sas-score-find-table`
|
|
65
69
|
- Keep batch size ≤ 50 rows unless the user explicitly requests more
|
|
66
70
|
- If table name is missing, ask: *"Which table should I read from? (format: lib.tablename)"*
|
|
67
71
|
- If library is missing, ask: *"Which library contains the table?"*
|
|
@@ -87,7 +91,7 @@ sas-query({
|
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
**Rules:**
|
|
90
|
-
- Check which server(s) contain the table using `find-table` first
|
|
94
|
+
- Check which server(s) contain the table using `sas-score-find-table` first
|
|
91
95
|
- If table exists in both CAS and SAS, ask user which to query from
|
|
92
96
|
- Parse the user's natural language question into a PROC SQL SELECT statement
|
|
93
97
|
- Ensure SELECT statement is valid SQL syntax
|
|
@@ -102,22 +106,22 @@ sas-query({
|
|
|
102
106
|
**Pattern A — Raw row retrieval**
|
|
103
107
|
> "Show me the first 5 rows from Public.customers"
|
|
104
108
|
|
|
105
|
-
→ `read-table({ table: "customers", lib: "Public", limit: 5 })`
|
|
109
|
+
→ `sas-score-read-table({ table: "customers", lib: "Public", limit: 5 })`
|
|
106
110
|
|
|
107
111
|
**Pattern B — Filtered retrieval**
|
|
108
112
|
> "Get all high-value orders (amount > 5000) from mylib.orders"
|
|
109
113
|
|
|
110
|
-
→ `read-table({ table: "orders", lib: "mylib", where: "amount > 5000" })`
|
|
114
|
+
→ `sas-score-read-table({ table: "orders", lib: "mylib", where: "amount > 5000" })`
|
|
111
115
|
|
|
112
116
|
**Pattern C — Aggregation**
|
|
113
117
|
> "What is the average price by make in Public.cars?"
|
|
114
118
|
|
|
115
|
-
→ `sas-query({ table: "Public.cars", query: "average price by make", sql: "SELECT make, AVG(msrp) AS avg_price FROM Public.cars GROUP BY make" })`
|
|
119
|
+
→ `sas-score-sas-query({ table: "Public.cars", query: "average price by make", sql: "SELECT make, AVG(msrp) AS avg_price FROM Public.cars GROUP BY make" })`
|
|
116
120
|
|
|
117
121
|
**Pattern D — Join + analysis**
|
|
118
122
|
> "Show me total sales by customer in the sales and customers tables"
|
|
119
123
|
|
|
120
|
-
→ `sas-query()` with a JOIN in the generated SQL
|
|
124
|
+
→ `sas-score-sas-query()` with a JOIN in the generated SQL
|
|
121
125
|
|
|
122
126
|
---
|
|
123
127
|
|
|
@@ -125,19 +129,28 @@ sas-query({
|
|
|
125
129
|
|
|
126
130
|
| Problem | Action |
|
|
127
131
|
|---|---|
|
|
128
|
-
|
|
|
132
|
+
| Library not found | Use `sas-find-library-smart` skill to verify the library exists |
|
|
133
|
+
| Table not found in either server | Inform user and suggest checking the table name |
|
|
129
134
|
| Table exists in both CAS and SAS | Ask: *"The table exists in both servers. Which would you prefer: CAS or SAS?"* |
|
|
130
135
|
| Table exists only in one server | Use that server automatically in your request |
|
|
131
|
-
|
|
|
136
|
+
| Table name missing entirely | Ask: *"Which table should I read from?"* |
|
|
132
137
|
| Ambiguous intent (raw vs aggregate) | Ask: *"Do you want individual rows or a summary by some field?"* |
|
|
133
138
|
| Empty result | Inform user, ask to adjust filter or query |
|
|
134
139
|
|
|
135
140
|
---
|
|
136
141
|
|
|
142
|
+
## Integration with other skills
|
|
143
|
+
|
|
144
|
+
- **Before this skill**: Use `sas-find-library-smart` to verify and locate the library
|
|
145
|
+
- **After this skill**: Use `sas-read-and-score` to score the retrieved data
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
137
149
|
## Next steps
|
|
138
150
|
|
|
139
|
-
Once data is retrieved,
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
151
|
+
Once data is retrieved, typical follow-ups include:
|
|
152
|
+
- **Visualize** — present as table or chart
|
|
153
|
+
- **Export** — format and offer download
|
|
154
|
+
- **Analyze further** — ask clarifying questions
|
|
155
|
+
- **Score** — run predictions on the data
|
|
156
|
+
- **Combine** — join with other datasets
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---
|
|
1
|
+
gi ---
|
|
2
2
|
name: sas-score-workflow
|
|
3
3
|
description: >
|
|
4
4
|
Guide the full model scoring workflow: validate model familiarity, route to appropriate scoring tool
|
|
@@ -25,50 +25,67 @@ score <name>.<type> [scenario =<key=value pairs>]
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
**Type determines the routing:**
|
|
28
|
-
- `.job` → route to `run-job` with scoring parameters
|
|
29
|
-
- `.jobdef` → route to `run-jobdef` with scoring parameters
|
|
30
|
-
- `.mas` → route to `model-score` (Model Analytical Service — default)
|
|
31
|
-
- `.scr` → route to `scr-score` (SAS Container Runtime)
|
|
32
|
-
- `.sas` → route to `run-sas-program` to run sas program in folder
|
|
28
|
+
- `.job` → route to `sas-score-run-job` with scoring parameters
|
|
29
|
+
- `.jobdef` → route to `sas-score-run-jobdef` with scoring parameters
|
|
30
|
+
- `.mas` → route to `sas-score-model-score` (Model Analytical Service — default)
|
|
31
|
+
- `.scr` → route to `sas-score-scr-score` (SAS Container Runtime)
|
|
32
|
+
- `.sas` → route to `sas-score-run-sas-program` to run sas program in folder
|
|
33
33
|
|
|
34
34
|
If no type is specified (bare model name), assume `.mas` (MAS model).
|
|
35
35
|
|
|
36
|
-
|
|
37
36
|
---
|
|
38
37
|
|
|
39
38
|
## Type-Based Routing
|
|
40
39
|
|
|
41
|
-
Parse
|
|
40
|
+
### Parse and Strip Model Type
|
|
41
|
+
|
|
42
|
+
When a user provides a model name with a type suffix (e.g., `simplejon.job`, `churn.mas`):
|
|
43
|
+
|
|
44
|
+
1. **Extract the type:** Split on the last dot to identify the type suffix
|
|
45
|
+
- `simplejon.job` → type = `job`, base name = `simplejon`
|
|
46
|
+
- `churn.mas` → type = `mas`, base name = `churn`
|
|
47
|
+
- `fraud_detector.jobdef` → type = `jobdef`, base name = `fraud_detector`
|
|
48
|
+
|
|
49
|
+
2. **Validate the type:** Confirm it matches one of the supported types: `job`, `jobdef`, `mas`, `scr`, `sas`
|
|
50
|
+
- If type is unrecognized, assume `.mas` (default MAS model) and treat the entire input as the model name
|
|
51
|
+
|
|
52
|
+
3. **Strip the type suffix:** Remove the `.type` from the model name before passing to the routing tool
|
|
53
|
+
- **Critical:** Always pass the base name (without the dot and type) to the invoked tool
|
|
54
|
+
- `simplejon.job` → pass `simplejon` to `sas-score-run-job`
|
|
55
|
+
- `churn.mas` → pass `churn` to `sas-score-model-score`
|
|
56
|
+
- `fraud_detector.jobdef` → pass `fraud_detector` to `sas-score-run-jobdef`
|
|
42
57
|
|
|
43
58
|
### Type: `.mas` (Model Aggregation Service)
|
|
44
|
-
- **Tool**: `model-score`
|
|
59
|
+
- **Tool**: `sas-score-model-score`
|
|
45
60
|
- **Use for**: Standard MAS-deployed predictive models
|
|
46
61
|
- **Example**: `score with model churn.mas scenario =age=45,income=60000`
|
|
47
|
-
- **Invocation**: `model-score({ model: "churn", scenario: {...} })`
|
|
62
|
+
- **Invocation**: `sas-score-model-score({ model: "churn", scenario: {...} })`
|
|
48
63
|
|
|
49
64
|
### Type: `.job` (SAS Viya Job)
|
|
50
|
-
- **Tool**: `run-job`
|
|
65
|
+
- **Tool**: `sas-score-run-job`
|
|
51
66
|
- **Use for**: Pre-built scoring jobs with parameters
|
|
52
67
|
- **Example**: `score with model monthly_scorer.job scenario =month=10,year=2025`
|
|
53
|
-
- **Invocation**: `run-job({ name: "monthly_scorer", scenario: {...} })`
|
|
68
|
+
- **Invocation**: `sas-score-run-job({ name: "monthly_scorer", scenario: {...} })`
|
|
54
69
|
|
|
55
70
|
### Type: `.jobdef` (SAS Viya Job Definition)
|
|
56
|
-
- **Tool**: `run-jobdef`
|
|
71
|
+
- **Tool**: `sas-score-run-jobdef`
|
|
57
72
|
- **Use for**: Job definitions that perform scoring logic
|
|
58
73
|
- **Example**: `score with model fraud_detector.jobdef using amount=500,merchant=online`
|
|
59
|
-
- **Invocation**: `run-jobdef({ name: "fraud_detector", scenario: {...} })`
|
|
74
|
+
- **Invocation**: `sas-score-run-jobdef({ name: "fraud_detector", scenario: {...} })`
|
|
60
75
|
|
|
61
76
|
### Type: `.scr` (Score Code Runtime)
|
|
62
|
-
- **Tool**: `scr-score`
|
|
77
|
+
- **Tool**: `sas-score-scr-score`
|
|
63
78
|
- **Use for**: Models deployed in SCR containers (REST endpoints)
|
|
64
79
|
- **Example**: `score https://scr-host/models/loan.scr using age=45,credit=700`
|
|
65
|
-
- **Invocation**: `scr-score({ url: "https://scr-host/models/loan", scenario: {...} })`
|
|
80
|
+
- **Invocation**: `sas-score-scr-score({ url: "https://scr-host/models/loan", scenario: {...} })`
|
|
66
81
|
|
|
67
82
|
### Type: `.sas` (SAS Program / SQL)
|
|
68
|
-
- **Tool**: `run-sas-program`
|
|
83
|
+
- **Tool**: `sas-score-run-sas-program`
|
|
69
84
|
- **Use for**: Custom SAS or SQL scoring code
|
|
70
85
|
- **Example**: `score my_scoring_code.sas using x=1,y=2`
|
|
71
|
-
- **Invocation**: `run-sas-program({ folder: "my_scoring_code", scenario: {...} })`
|
|
86
|
+
- **Invocation**: `sas-score-run-sas-program({ folder: "my_scoring_code", scenario: {...} })`
|
|
87
|
+
|
|
88
|
+
|
|
72
89
|
|
|
73
90
|
---
|
|
74
91
|
|
|
@@ -89,6 +106,13 @@ Accepted formats:
|
|
|
89
106
|
|
|
90
107
|
---
|
|
91
108
|
|
|
109
|
+
## Integration with other skills
|
|
110
|
+
|
|
111
|
+
- **Before scoring table data**: Use `sas-find-library-smart` to verify the library, then `sas-read-strategy` to fetch records
|
|
112
|
+
- **For read + score workflows**: Use `sas-read-and-score` for the complete end-to-end pattern
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
92
116
|
## Step 1 — Check model familiarity before scoring
|
|
93
117
|
|
|
94
118
|
Score immediately if:
|
|
@@ -122,7 +146,7 @@ scenario = [
|
|
|
122
146
|
```
|
|
123
147
|
|
|
124
148
|
**Critical rules:**
|
|
125
|
-
- Loop or call model-score **once per row**.
|
|
149
|
+
- Loop or call sas-score-model-score **once per row**.
|
|
126
150
|
- Field names in the scenario must match the model's expected input variable names **exactly**.
|
|
127
151
|
- If table column names differ from model input names, **flag this to the user** and ask for confirmation before scoring.
|
|
128
152
|
- Example: Table has `age_years`, but model expects `age` → ask user which column maps to which input.
|
|
@@ -136,7 +160,7 @@ Based on the type extracted from the model name, invoke the corresponding tool:
|
|
|
136
160
|
|
|
137
161
|
**For `.mas` (default):**
|
|
138
162
|
```javascript
|
|
139
|
-
model-score({
|
|
163
|
+
sas-score-model-score({
|
|
140
164
|
model: "<modelname>",
|
|
141
165
|
scenario: scenario, // object or array
|
|
142
166
|
uflag: false // set true if you need field names prefixed with _
|
|
@@ -145,7 +169,7 @@ model-score({
|
|
|
145
169
|
|
|
146
170
|
**For `.job`:**
|
|
147
171
|
```javascript
|
|
148
|
-
run-job({
|
|
172
|
+
sas-score-run-job({
|
|
149
173
|
name: "<jobname>",
|
|
150
174
|
scenario: scenario
|
|
151
175
|
})
|
|
@@ -153,7 +177,7 @@ run-job({
|
|
|
153
177
|
|
|
154
178
|
**For `.jobdef`:**
|
|
155
179
|
```javascript
|
|
156
|
-
run-jobdef({
|
|
180
|
+
sas-score-run-jobdef({
|
|
157
181
|
name: "<jobdefname>",
|
|
158
182
|
scenario: scenario
|
|
159
183
|
})
|
|
@@ -161,7 +185,7 @@ run-jobdef({
|
|
|
161
185
|
|
|
162
186
|
**For `.scr`:**
|
|
163
187
|
```javascript
|
|
164
|
-
scr-score({
|
|
188
|
+
sas-score-scr-score({
|
|
165
189
|
url: "<scr_endpoint_url>",
|
|
166
190
|
scenario: scenario
|
|
167
191
|
})
|
|
@@ -169,7 +193,7 @@ scr-score({
|
|
|
169
193
|
|
|
170
194
|
**For `.sas`:**
|
|
171
195
|
```javascript
|
|
172
|
-
run-sas-program({
|
|
196
|
+
sas-score-run-sas-program({
|
|
173
197
|
src: "<sas_or_sql_code>",
|
|
174
198
|
scenario: scenario
|
|
175
199
|
})
|
|
@@ -205,43 +229,43 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
205
229
|
**Flow A — Score rows with MAS model**
|
|
206
230
|
> "Score the first 10 customers in Public.customers with the churn model"
|
|
207
231
|
|
|
208
|
-
1. `read-table` → { table: "Public.customers", limit: 10 }
|
|
209
|
-
2. `model-score` → { model: "churn", scenario: [ ...10 row objects ] }
|
|
232
|
+
1. `sas-score-read-table` → { table: "Public.customers", limit: 10 }
|
|
233
|
+
2. `sas-score-model-score` → { model: "churn", scenario: [ ...10 row objects ] }
|
|
210
234
|
3. Present merged results with prediction + key inputs
|
|
211
235
|
|
|
212
236
|
**Flow B — Score with a scoring job**
|
|
213
237
|
> "Score December sales with the monthly_scorer job using month=12,year=2025"
|
|
214
238
|
|
|
215
|
-
1. `run-job` → { name: "monthly_scorer", scenario: { month: "12", year: "2025" } }
|
|
239
|
+
1. `sas-score-run-job` → { name: "monthly_scorer", scenario: { month: "12", year: "2025" } }
|
|
216
240
|
2. Capture job output and tables
|
|
217
241
|
3. Present results
|
|
218
242
|
|
|
219
243
|
**Flow C — Score with a job definition**
|
|
220
244
|
> "Run fraud detection jobdef on transaction amount=500, merchant=online"
|
|
221
245
|
|
|
222
|
-
1. `run-jobdef` → { name: "fraud_detection", scenario: { amount: "500", merchant: "online" } }
|
|
246
|
+
1. `sas-score-run-jobdef` → { name: "fraud_detection", scenario: { amount: "500", merchant: "online" } }
|
|
223
247
|
2. Capture log, listings, and tables
|
|
224
248
|
3. Present results
|
|
225
249
|
|
|
226
250
|
**Flow D — Score with SCR endpoint**
|
|
227
251
|
> "Score with the loan model at https://scr-host/models/loan using age=45, credit_score=700"
|
|
228
252
|
|
|
229
|
-
1. `scr-score` → { url: "https://scr-host/models/loan", scenario: { age: "45", credit_score: "700" } }
|
|
253
|
+
1. `sas-score-scr-score` → { url: "https://scr-host/models/loan", scenario: { age: "45", credit_score: "700" } }
|
|
230
254
|
2. Capture prediction response
|
|
231
255
|
3. Present result
|
|
232
256
|
|
|
233
257
|
**Flow E — Score results of an analytical query with MAS**
|
|
234
258
|
> "Score high-value customers (spend > 5000) in mylib.sales with the fraud model"
|
|
235
259
|
|
|
236
|
-
1. `sas-query` → { table: "mylib.sales", sql: "SELECT * FROM mylib.sales WHERE spend > 5000" }
|
|
237
|
-
2. `model-score` → { model: "fraud", scenario: [ ...result rows ] }
|
|
260
|
+
1. `sas-score-sas-query` → { table: "mylib.sales", sql: "SELECT * FROM mylib.sales WHERE spend > 5000" }
|
|
261
|
+
2. `sas-score-model-score` → { model: "fraud", scenario: [ ...result rows ] }
|
|
238
262
|
3. Present merged results
|
|
239
263
|
|
|
240
264
|
**Flow F — User supplies scenario data directly**
|
|
241
265
|
> "Score age=45, income=60000, region=South with the churn model"
|
|
242
266
|
|
|
243
267
|
1. Skip read step
|
|
244
|
-
2. `model-score` → { model: "churn", scenario: { age: "45", income: "60000", region: "South" } }
|
|
268
|
+
2. `sas-score-model-score` → { model: "churn", scenario: { age: "45", income: "60000", region: "South" } }
|
|
245
269
|
3. Present result
|
|
246
270
|
|
|
247
271
|
**Flow G — Model unfamiliar, need to confirm**
|
|
@@ -249,7 +273,7 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
249
273
|
|
|
250
274
|
1. Pause — "creditRisk2" is new
|
|
251
275
|
2. Suggest: `find-model` to confirm it exists, `model-info` to get input variables
|
|
252
|
-
3. Once confirmed → `read-table` + `model-score`
|
|
276
|
+
3. Once confirmed → `sas-score-read-table` + `sas-score-model-score`
|
|
253
277
|
|
|
254
278
|
**Flow H — Generic score syntax with type routing**
|
|
255
279
|
> "score with model churn.mas scenario =age=45,income=60000"
|
|
@@ -277,7 +301,14 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
277
301
|
|
|
278
302
|
## Tips
|
|
279
303
|
|
|
280
|
-
- **Batch is better:** Always pass the full set of records in one `model-score` call. Do not loop.
|
|
304
|
+
- **Batch is better:** Always pass the full set of records in one `sas-score-model-score` call. Do not loop.
|
|
281
305
|
- **Confirm mappings:** If column names don't match model inputs, ask before scoring.
|
|
282
306
|
- **Show context:** Include key input columns in the result output so predictions make sense.
|
|
283
307
|
- **Limit output:** For large result sets (>10 rows), ask before showing all.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Integration with other skills
|
|
312
|
+
|
|
313
|
+
- **Before scoring table data**: Use `sas-find-library-smart` to verify the library, then `sas-read-strategy` to fetch records
|
|
314
|
+
- **For read + score workflows**: Use `sas-read-and-score` for the complete end-to-end pattern
|