@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.
Files changed (61) hide show
  1. package/cli.js +210 -108
  2. package/package.json +6 -4
  3. package/scripts/docs/SCORE_SKILL_REFERENCE.md +142 -0
  4. package/scripts/docs/TOOL_DESCRIPTION_TEMPLATE.md +157 -0
  5. package/scripts/docs/TOOL_UPDATES_SUMMARY.md +208 -0
  6. package/scripts/docs/mcp-localhost-config-guide.md +184 -0
  7. package/scripts/docs/oauth-http-transport.md +96 -0
  8. package/scripts/docs/sas-mcp-tools-reference.md +600 -0
  9. package/scripts/getViyaca.sh +1 -0
  10. package/scripts/optimize_final.py +140 -0
  11. package/scripts/optimize_tools.py +99 -0
  12. package/scripts/setup-skills.js +78 -0
  13. package/scripts/update_descriptions.py +46 -0
  14. package/scripts/viyatls.sh +3 -0
  15. package/skills/sas-find-library-smart/SKILL.md +154 -0
  16. package/skills/sas-list-tables-smart/SKILL.md +127 -0
  17. package/skills/sas-read-and-score/SKILL.md +71 -51
  18. package/skills/sas-read-strategy/SKILL.md +43 -30
  19. package/skills/sas-score-workflow/SKILL.md +65 -34
  20. package/skills/sas-spec-migration/SKILL.md +303 -0
  21. package/src/authpkce.js +219 -0
  22. package/src/createMcpServer.js +11 -8
  23. package/src/expressMcpServer.js +354 -338
  24. package/src/oauthHandlers/authorize.js +46 -0
  25. package/src/oauthHandlers/baseUrl.js +8 -0
  26. package/src/oauthHandlers/callback.js +96 -0
  27. package/src/oauthHandlers/getMetadata.js +27 -0
  28. package/src/oauthHandlers/index.js +7 -0
  29. package/src/oauthHandlers/token.js +37 -0
  30. package/src/processHeaders.js +88 -0
  31. package/src/toolHelpers/_listLibrary.js +0 -1
  32. package/src/toolHelpers/getLogonPayload.js +5 -1
  33. package/src/toolHelpers/refreshToken.js +3 -2
  34. package/src/toolHelpers/refreshTokenOauth.js +3 -3
  35. package/src/toolSet/.claude/settings.local.json +13 -0
  36. package/src/toolSet/devaScore.js +61 -61
  37. package/src/toolSet/findJob.js +1 -1
  38. package/src/toolSet/findJobdef.js +2 -2
  39. package/src/toolSet/findLibrary.js +68 -67
  40. package/src/toolSet/findModel.js +2 -2
  41. package/src/toolSet/findTable.js +3 -2
  42. package/src/toolSet/getEnv.js +8 -4
  43. package/src/toolSet/listJobdefs.js +61 -61
  44. package/src/toolSet/listJobs.js +61 -61
  45. package/src/toolSet/listLibraries.js +78 -78
  46. package/src/toolSet/listModels.js +56 -56
  47. package/src/toolSet/listTables.js +66 -65
  48. package/src/toolSet/modelInfo.js +2 -2
  49. package/src/toolSet/modelScore.js +6 -5
  50. package/src/toolSet/readTable.js +63 -65
  51. package/src/toolSet/runCasProgram.js +7 -6
  52. package/src/toolSet/runJob.js +81 -81
  53. package/src/toolSet/runJobdef.js +82 -82
  54. package/src/toolSet/runMacro.js +81 -80
  55. package/src/toolSet/runProgram.js +4 -8
  56. package/src/toolSet/sasQuery.js +77 -78
  57. package/src/toolSet/scrInfo.js +1 -1
  58. package/src/toolSet/scrScore.js +69 -68
  59. package/src/toolSet/setContext.js +65 -65
  60. package/src/toolSet/superstat.js +61 -59
  61. 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 (using read-table
5
- or sas-query) and then scoring them with a MAS model (using model-score). Use this skill whenever
6
- the user wants to score records from a table, run a model against query results, predict outcomes
7
- for a set of rows, or any combination of fetching data and scoring it. Trigger phrases include:
8
- "score these records", "score results of my query", "run the model on this table",
9
- "predict for these customers", "fetch and score", "read and score", "score rows from",
10
- "run model on table data", or any request that combines reading table data with model prediction.
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
- ## Quick reference
20
+ ## Pre-flight verification
25
21
 
26
- 1. **Does the user already have data in hand?**
27
- - Yes skip to Step 2 (scoring)
28
- - No use `sas-read-strategy` to fetch data
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
- 2. **Is the model name familiar?**
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
- 3. **Invoke model-score** with the fetched data
29
+ ---
35
30
 
36
- 4. **Merge results** and present as a table
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
- ## Common flows
39
+ ---
41
40
 
42
- **Flow A Score rows from a table directly**
43
- > "Score the first 10 customers in Public.customers with the churn model"
41
+ ## Scenario: User already has data
44
42
 
45
- 1. Apply `sas-read-strategy` use `read-table` to fetch 10 rows
46
- 2. Apply `sas-score-workflow` invoke `model-score` and present results
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
- **Flow B — Score results of an analytical query**
49
- > "Score high-value customers (spend > 5000) in mylib.sales with the fraud model"
49
+ ---
50
50
 
51
- 1. Apply `sas-read-strategy` use `sas-query` for aggregation
52
- 2. Apply `sas-score-workflow` → invoke `model-score` and present results
51
+ ## Scenario: User wants to score table rows
53
52
 
54
- **Flow C User supplies scenario data directly**
55
- > "Score age=45, income=60000, region=South with the churn model"
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
- 1. Skip read strategy
58
- 2. Apply `sas-score-workflow` → invoke `model-score` and present result
60
+ ---
59
61
 
60
- **Flow D Model unfamiliar**
61
- > "Score Public.applicants with the creditRisk2 model"
62
+ ## Scenario: User wants to score query results
62
63
 
63
- 1. Model unfamiliar use `find-model` to verify existence
64
- 2. Apply `sas-read-strategy` to fetch data
65
- 3. Apply `sas-score-workflow` to score
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
- ## For detailed guidance
73
+ ## Scenario: User unfamiliar with model
70
74
 
71
- - **Read strategy decisions?** See `sas-read-strategy` skill
72
- - **Scoring validation and presentation?** See `sas-score-workflow` skill
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
- **Flow D — Model unfamiliar**
75
- > "Score Public.applicants with the creditRisk2 model"
81
+ ---
82
+
83
+ ## Rules
76
84
 
77
- 1. Pause "creditRisk2" is new
78
- 2. Suggest: `find-model` to confirm it exists, `model-info` to get input variables
79
- 3. Once confirmed `read-table` + `model-score`
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 | Suggest find-model |
89
- | Field name mismatch | Show mismatch, ask user to confirm mapping |
90
- | Scoring error | Return structured error, suggest model-info |
91
- | Empty read result | Tell user, ask if they want to adjust the query/filter |
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, check which server(s) contain the table:
18
+ Before retrieving data, verify the library and determine which server(s) contain the table:
21
19
 
22
- 1. **Check both servers**: Use `find-table` to check if the table exists in CAS and/or SAS
23
- 2. **Decide server placement**:
24
- - If table exists **only in CAS** set `server: "cas"`
25
- - If table exists **only in SAS** set `server: "sas"`
26
- - If table exists **in both** → ask the user: *"The table exists in both CAS and SAS. Which server would you prefer to query from?"*
27
- - If table exists **in neither** → inform user and ask which library to search in
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
- | Table not found in either server | Ask: *"Which library contains the table? (e.g., Public, Samples, mylib)"* |
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
- | Library not found | Ask: *"Which library contains the table? (e.g., Public, Samples, mylib)"* |
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, decide the next action based on context:
140
- - If user wants to **score** the data move to `sas-score-workflow`
141
- - If user wants to **visualize** present as table or chart
142
- - If user wants to **export** format and offer download
143
- - If user wants to **analyze further** → ask clarifying questions
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 the model name to extract the type suffix and route accordingly:
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