@sassoftware/sas-score-mcp-serverjs 1.0.1-10 → 1.0.1-13
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/sas-find-resource-strategy/SKILL.md +29 -8
- package/.skills/sas-list-resource-strategy/SKILL.md +48 -5
- package/.skills/sas-read-strategy/SKILL.md +1 -0
- package/.skills/sas-request-classifier/SKILL.md +6 -5
- package/.skills/sas-score-workflow-strategy/SKILL.md +1 -0
- package/cli.js +2 -10
- package/package.json +4 -5
- package/src/setupSkills.js +1 -1
- package/src/toolSet/modelScore.js +8 -24
- package/src/toolSet/runJob.js +5 -25
- package/src/toolSet/runJobdef.js +5 -25
- package/src/toolSet/scrScore.js +60 -69
- /package/src/{handleGetDelete.js → handleGetDelete.txt} +0 -0
- /package/src/{handleRequest.js → handleRequest.txt} +0 -0
- /package/src/{hapiMcpServer.js → hapiMcpServer.txt} +0 -0
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
name: sas-find-resource-strategy
|
|
3
3
|
description: >
|
|
4
4
|
Unified strategy for finding SAS Viya resources using find tools only. Supports library, table,
|
|
5
|
-
|
|
5
|
+
mas, job, and jobdef lookup with server-aware behavior for CAS/SAS resources. Treat the generic
|
|
6
|
+
term "model" as an alias that may refer to mas, job, or jobdef resources. Use this skill
|
|
6
7
|
whenever the task is to verify whether a resource exists.
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -15,10 +16,16 @@ Use this skill to verify resource existence without using list tools.
|
|
|
15
16
|
Supported resource types:
|
|
16
17
|
- library
|
|
17
18
|
- table
|
|
18
|
-
-
|
|
19
|
+
- mas
|
|
19
20
|
- job
|
|
20
21
|
- jobdef
|
|
21
22
|
|
|
23
|
+
Generic model aliases:
|
|
24
|
+
- `model` with no type defaults to `mas`
|
|
25
|
+
- `model mas` or `mas model` -> `mas`
|
|
26
|
+
- `model job` or `job model` -> `job`
|
|
27
|
+
- `model jobdef` or `jobdef model` -> `jobdef`
|
|
28
|
+
|
|
22
29
|
## Mandatory rule
|
|
23
30
|
|
|
24
31
|
- Use the sas-find-resource strategy to check for the existence of a resource before attempting to read or use it. This ensures that follow-up actions are based on accurate information about resource availability.
|
|
@@ -28,7 +35,7 @@ Supported resource types:
|
|
|
28
35
|
|
|
29
36
|
- Library -> `sas-score-find-library`
|
|
30
37
|
- Table -> `sas-score-find-table`
|
|
31
|
-
-
|
|
38
|
+
- MAS -> `sas-score-find-model`
|
|
32
39
|
- Job -> `sas-score-find-job`
|
|
33
40
|
- Jobdef -> `sas-score-find-jobdef`
|
|
34
41
|
|
|
@@ -60,14 +67,23 @@ If server is not provided:
|
|
|
60
67
|
2. If not found, check SAS (uppercase library) - `sas-score-find-table({ lib: "<LIB>", name: "<table>", server: "sas" })`
|
|
61
68
|
3. If found in both, report both and ask user which server to use for follow-up reads.
|
|
62
69
|
|
|
63
|
-
### Find
|
|
70
|
+
### Find models by type
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
- `
|
|
72
|
+
Support requests in either form:
|
|
73
|
+
- `find model <name>`
|
|
74
|
+
- `find model <type> <name>`
|
|
75
|
+
- `find <type> model <name>`
|
|
76
|
+
|
|
77
|
+
Type routing rules:
|
|
78
|
+
- If type is omitted, assume `mas`
|
|
79
|
+
- `mas` -> use `sas-score-find-model({ name: "<name>" })`
|
|
80
|
+
- `job` -> use `sas-score-find-job({ name: "<name>" })`
|
|
81
|
+
- `jobdef` -> use `sas-score-find-jobdef({ name: "<name>" })`
|
|
67
82
|
|
|
68
83
|
If a model type suffix is provided (for example `.mas`, `.job`, `.jobdef`, `.scr`):
|
|
69
84
|
- For MAS model discovery, strip suffix and look up base name with `sas-score-find-model`.
|
|
70
|
-
- For `.job` and `.jobdef`, use job and jobdef find tools instead of
|
|
85
|
+
- For `.job` and `.jobdef`, use job and jobdef find tools instead of MAS find.
|
|
86
|
+
- For `.scr`, do not use this strategy; route to SCR-specific model handling.
|
|
71
87
|
|
|
72
88
|
### Find job
|
|
73
89
|
|
|
@@ -84,7 +100,7 @@ Use:
|
|
|
84
100
|
Ask one focused question if required fields are missing:
|
|
85
101
|
- Library missing for table lookup: "Which library contains the table?"
|
|
86
102
|
- Table name missing: "Which table name should I check?"
|
|
87
|
-
- Resource type ambiguous: "Do you want me to find a library, table,
|
|
103
|
+
- Resource type ambiguous: "Do you want me to find a library, table, mas, job, or jobdef resource?"
|
|
88
104
|
|
|
89
105
|
## Output format
|
|
90
106
|
|
|
@@ -101,5 +117,10 @@ For not found resources:
|
|
|
101
117
|
- "find library Samples" -> CAS first, then SAS fallback using uppercase.
|
|
102
118
|
- "find table costchange in Samples" -> CAS first, then SAS fallback using uppercase library.
|
|
103
119
|
- "find model breastcancer" -> `sas-score-find-model`.
|
|
120
|
+
- "find model mas breastcancer" -> `sas-score-find-model`.
|
|
121
|
+
- "find mas model breastcancer" -> `sas-score-find-model`.
|
|
122
|
+
- "find model job simplejob" -> `sas-score-find-job`.
|
|
123
|
+
- "find job model simplejob" -> `sas-score-find-job`.
|
|
124
|
+
- "find model jobdef daily_run" -> `sas-score-find-jobdef`.
|
|
104
125
|
- "find job simplejob" -> `sas-score-find-job`.
|
|
105
126
|
- "find jobdef daily_run" -> `sas-score-find-jobdef`.
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
name: sas-list-resource-strategy
|
|
3
3
|
description: >
|
|
4
4
|
Unified strategy for listing SAS Viya resources using list tools. Supports libraries,
|
|
5
|
-
tables,
|
|
5
|
+
tables, mas resources, jobs, and jobdefs. Treat the generic term "model" as an alias that may
|
|
6
|
+
refer to mas, job, or jobdef resources. Always normalize pagination so start and limit are
|
|
6
7
|
never null: default start=1 and limit=10 when not provided.
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -15,10 +16,17 @@ Use this skill to list resources with consistent pagination defaults.
|
|
|
15
16
|
Supported resource types:
|
|
16
17
|
- library
|
|
17
18
|
- table
|
|
18
|
-
-
|
|
19
|
+
- mas
|
|
19
20
|
- job
|
|
20
21
|
- jobdef
|
|
21
22
|
|
|
23
|
+
Generic model aliases:
|
|
24
|
+
- `model` with no type defaults to `mas`
|
|
25
|
+
- `model mas` or `mas model` -> `mas`
|
|
26
|
+
- `model job` or `job model` -> `job`
|
|
27
|
+
- `model jobdef` or `jobdef model` -> `jobdef`
|
|
28
|
+
|
|
29
|
+
|
|
22
30
|
## Mandatory pagination rule
|
|
23
31
|
|
|
24
32
|
For every list operation:
|
|
@@ -37,7 +45,7 @@ limit = (limit == null) ? 10 : limit
|
|
|
37
45
|
|
|
38
46
|
- Library -> `sas-score-list-libraries`
|
|
39
47
|
- Table -> `sas-score-list-table`
|
|
40
|
-
-
|
|
48
|
+
- MAS -> `sas-score-list-models`
|
|
41
49
|
- Job -> `sas-score-list-jobs`
|
|
42
50
|
- Jobdef -> `sas-score-list-jobdefs`
|
|
43
51
|
|
|
@@ -75,7 +83,19 @@ If `lib` is missing, ask: "Which library should I list tables from?"
|
|
|
75
83
|
|
|
76
84
|
### List models
|
|
77
85
|
|
|
78
|
-
|
|
86
|
+
Support requests in either form:
|
|
87
|
+
- `list model`
|
|
88
|
+
- `list models`
|
|
89
|
+
- `list model <type>`
|
|
90
|
+
- `list <type> model`
|
|
91
|
+
|
|
92
|
+
Type routing rules:
|
|
93
|
+
- If type is omitted, assume `mas`
|
|
94
|
+
- `mas` -> use `sas-score-list-models`
|
|
95
|
+
- `job` -> use `sas-score-list-jobs`
|
|
96
|
+
- `jobdef` -> use `sas-score-list-jobdefs`
|
|
97
|
+
|
|
98
|
+
Use for `mas`:
|
|
79
99
|
```
|
|
80
100
|
sas-score-list-models({
|
|
81
101
|
start: 1,
|
|
@@ -83,6 +103,22 @@ sas-score-list-models({
|
|
|
83
103
|
})
|
|
84
104
|
```
|
|
85
105
|
|
|
106
|
+
Use for `job`:
|
|
107
|
+
```
|
|
108
|
+
sas-score-list-jobs({
|
|
109
|
+
start: 1,
|
|
110
|
+
limit: 10
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use for `jobdef`:
|
|
115
|
+
```
|
|
116
|
+
sas-score-list-jobdefs({
|
|
117
|
+
start: 1,
|
|
118
|
+
limit: 10
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
86
122
|
### List jobs
|
|
87
123
|
|
|
88
124
|
Use:
|
|
@@ -106,7 +142,7 @@ sas-score-list-jobdefs({
|
|
|
106
142
|
## Clarifying prompts
|
|
107
143
|
|
|
108
144
|
Ask one focused question if required context is missing:
|
|
109
|
-
- Resource type unclear: "Do you want libraries, tables,
|
|
145
|
+
- Resource type unclear: "Do you want libraries, tables, mas resources, jobs, or jobdefs?"
|
|
110
146
|
- Listing tables without library: "Which library should I list tables from?"
|
|
111
147
|
|
|
112
148
|
## Output and paging
|
|
@@ -118,7 +154,14 @@ Ask one focused question if required context is missing:
|
|
|
118
154
|
## Examples
|
|
119
155
|
|
|
120
156
|
- "list jobs" -> `sas-score-list-jobs({ start: 1, limit: 10 })`
|
|
157
|
+
- "list model" -> `sas-score-list-models({ start: 1, limit: 10 })`
|
|
121
158
|
- "list models" -> `sas-score-list-models({ start: 1, limit: 10 })`
|
|
159
|
+
- "list model mas" -> `sas-score-list-models({ start: 1, limit: 10 })`
|
|
160
|
+
- "list mas model" -> `sas-score-list-models({ start: 1, limit: 10 })`
|
|
161
|
+
- "list model job" -> `sas-score-list-jobs({ start: 1, limit: 10 })`
|
|
162
|
+
- "list job model" -> `sas-score-list-jobs({ start: 1, limit: 10 })`
|
|
163
|
+
- "list model jobdef" -> `sas-score-list-jobdefs({ start: 1, limit: 10 })`
|
|
164
|
+
- "list jobdef model" -> `sas-score-list-jobdefs({ start: 1, limit: 10 })`
|
|
122
165
|
- "list jobdefs" -> `sas-score-list-jobdefs({ start: 1, limit: 10 })`
|
|
123
166
|
- "list tables in Public" -> `sas-score-list-tables({ lib: "Public", start: 1, limit: 10 })`
|
|
124
167
|
- "next jobs" after `{ start: 1, limit: 10 }` -> `sas-score-list-jobs({ start: 11, limit: 10 })`
|
|
@@ -10,6 +10,7 @@ Use this skill to determine what kind of SAS object, workflow, or environment th
|
|
|
10
10
|
## When to use
|
|
11
11
|
Use this skill when the request contains ambiguous domain terms such as:
|
|
12
12
|
- model
|
|
13
|
+
- mas
|
|
13
14
|
- score
|
|
14
15
|
- scoring
|
|
15
16
|
- read
|
|
@@ -29,8 +30,8 @@ Map the user request to the most likely SAS domain and hand off to the correct d
|
|
|
29
30
|
|
|
30
31
|
## Classification targets
|
|
31
32
|
Classify the request into one or more of these categories:
|
|
32
|
-
- Resource existence lookup (library/table/
|
|
33
|
-
- Resource listing (library/table/
|
|
33
|
+
- Resource existence lookup (library/table/mas/job/jobdef, with generic "model" phrasing allowed) -> Route to **sas-find-resource-strategy**
|
|
34
|
+
- Resource listing (library/table/mas/job/jobdef, with generic "model" phrasing allowed) -> Route to **sas-list-resource-strategy**
|
|
34
35
|
- Reading or querying tables → Route to **sas-read-strategy**
|
|
35
36
|
- CAS resource, SAS resource, caslib, or table discovery → Route to **sas-find-library-smart**
|
|
36
37
|
- SAS data, libref, or table discovery → Route to **sas-find-library-smart**
|
|
@@ -47,8 +48,8 @@ Classify the request into one or more of these categories:
|
|
|
47
48
|
3. Decide the most likely SAS domain and matching skill.
|
|
48
49
|
4. If confidence is low, ask one focused clarifying question.
|
|
49
50
|
5. If confidence is high, load and use the relevant skill:
|
|
50
|
-
- **sas-find-resource-strategy** — Unified find-only strategy for library/table/
|
|
51
|
-
- **sas-list-resource-strategy** — Unified list strategy for library/table/
|
|
51
|
+
- **sas-find-resource-strategy** — Unified find-only strategy for library/table/mas/job/jobdef, where "model" may mean mas, job, or jobdef
|
|
52
|
+
- **sas-list-resource-strategy** — Unified list strategy for library/table/mas/job/jobdef, where "model" may mean mas, job, or jobdef, with non-null pagination defaults
|
|
52
53
|
- **sas-find-library-smart** — Find CAS or SAS libraries
|
|
53
54
|
- **sas-list-tables-smart** — Browse tables in a library
|
|
54
55
|
- **sas-read-strategy** — Choose read-table vs. sas-query for data retrieval
|
|
@@ -58,7 +59,7 @@ Classify the request into one or more of these categories:
|
|
|
58
59
|
|
|
59
60
|
## Disambiguation hints
|
|
60
61
|
- "Run" often implies job execution, but may also mean scoring or model invocation. Check for "score" or "model" context.
|
|
61
|
-
- "Model" may refer to MAS
|
|
62
|
+
- "Model" is a generic term that may refer to MAS, job, or jobdef resources in find/list requests. Prefer explicit patterns like `model <type>` or `<type> model`; default bare "model" to MAS unless the surrounding request implies job or jobdef.
|
|
62
63
|
- "Score" may refer to model scoring or job execution. Look for model name or context.
|
|
63
64
|
- "Table" usually suggests CAS or SAS but confirm library name and server context.
|
|
64
65
|
- "Find" — resource lookup. Route to sas-find-resource-strategy.
|
|
@@ -22,6 +22,7 @@ Users can invoke scoring with a unified syntax that automatically routes to the
|
|
|
22
22
|
```
|
|
23
23
|
score with model <name>.<type> [scenario =<key=value pairs>]
|
|
24
24
|
score <name>.<type> [scenario =<key=value pairs>]
|
|
25
|
+
score key=value,... with model <name>.<type>
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
**Type determines the routing:**
|
package/cli.js
CHANGED
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
import coreSSE from './src/coreSSE.js';
|
|
11
11
|
import expressMcpServer from './src/expressMcpServer.js';
|
|
12
|
-
import hapiMcpServer from './src/hapiMcpServer.js';
|
|
13
|
-
|
|
14
12
|
import createMcpServer from './src/createMcpServer.js';
|
|
15
13
|
// import dotenvExpand from 'dotenv-expand';
|
|
16
14
|
import fs from 'fs';
|
|
@@ -468,14 +466,8 @@ if (mcpType === 'stdio') {
|
|
|
468
466
|
|
|
469
467
|
} else {
|
|
470
468
|
console.error('[Note] Starting HTTP MCP server...');
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
await hapiMcpServer(mcpServer, sessionCache, appEnvBase);
|
|
474
|
-
console.error('[Note] Using HAPI HTTP server...')
|
|
475
|
-
} else {
|
|
476
|
-
await expressMcpServer(mcpServer, sessionCache, appEnvBase);
|
|
477
|
-
console.error('[Note] MCP HTTP express server started on port ' + appEnvBase.PORT);
|
|
478
|
-
}
|
|
469
|
+
await expressMcpServer(mcpServer, sessionCache, appEnvBase);
|
|
470
|
+
console.error('[Note] MCP HTTP express server started on port ' + appEnvBase.PORT);
|
|
479
471
|
}
|
|
480
472
|
|
|
481
473
|
// custom reader for .env file to avoid dotenv logging to console
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sassoftware/sas-score-mcp-serverjs",
|
|
3
|
-
"version": "1.0.1-
|
|
3
|
+
"version": "1.0.1-13",
|
|
4
4
|
"description": "A mcp server for SAS Viya",
|
|
5
5
|
"author": "Deva Kumar <deva.kumar@sas.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -51,8 +51,7 @@
|
|
|
51
51
|
"@sassoftware/restaf": "^5.7.2",
|
|
52
52
|
"@sassoftware/restafedit": "^3.10.5",
|
|
53
53
|
"@sassoftware/restaflib": "^5.7.2",
|
|
54
|
-
"
|
|
55
|
-
"axios": "^1.13.2",
|
|
54
|
+
"axios": "^1.13.5",
|
|
56
55
|
"body-parser": "^2.2.1",
|
|
57
56
|
"cors": "^2.8.5",
|
|
58
57
|
"cross-env": "^10.1.0",
|
|
@@ -64,8 +63,8 @@
|
|
|
64
63
|
"node-cache": "^5.1.2",
|
|
65
64
|
"open": "^11.0.0",
|
|
66
65
|
"selfsigned": "^5.2.0",
|
|
67
|
-
"undici": "^7.
|
|
68
|
-
"uuid": "^
|
|
66
|
+
"undici": "^7.24.0",
|
|
67
|
+
"uuid": "^14.0.0",
|
|
69
68
|
"zod": "^4.2.1"
|
|
70
69
|
},
|
|
71
70
|
"devDependencies": {
|
package/src/setupSkills.js
CHANGED
|
@@ -31,7 +31,7 @@ function setupSkills(clientName,agentFolder) {
|
|
|
31
31
|
copyFolderSync(agentsFromPath, agentsToPath);
|
|
32
32
|
|
|
33
33
|
// now copy the skills folder to the destination
|
|
34
|
-
let toPath = path.join(destination, '
|
|
34
|
+
let toPath = path.join(destination, 'skills');
|
|
35
35
|
let fromPath = path.join(__dirname, `../.skills`);
|
|
36
36
|
copyFolderSync(fromPath, toPath);
|
|
37
37
|
|
|
@@ -17,7 +17,7 @@ DO NOT USE for: find model, model metadata, list models, run programs/jobs, quer
|
|
|
17
17
|
|
|
18
18
|
PARAMETERS
|
|
19
19
|
- model: string — model name (required, exact match)
|
|
20
|
-
- scenario:
|
|
20
|
+
- scenario: object — input data as JSON (optional, defaults to {}). Example: {age:45, income:60000}
|
|
21
21
|
- uflag: boolean (default: false) — prefix model fields with underscore when true
|
|
22
22
|
|
|
23
23
|
ROUTING RULES
|
|
@@ -42,34 +42,18 @@ Returns predictions, probabilities, scores merged with input data. Returns error
|
|
|
42
42
|
let spec = {
|
|
43
43
|
name: 'mas-score',
|
|
44
44
|
description: description,
|
|
45
|
-
inputSchema:z.object({
|
|
45
|
+
inputSchema: z.object({
|
|
46
46
|
model: z.string(),
|
|
47
|
-
scenario: z.string(),
|
|
47
|
+
scenario: z.union([z.record(z.any()), z.string()]).optional(),
|
|
48
48
|
uflag: z.boolean().optional()
|
|
49
49
|
}),
|
|
50
50
|
|
|
51
51
|
handler: async (iparams) => {
|
|
52
|
-
let params = {...iparams};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let scenarioObj ={};
|
|
58
|
-
let count = 0;
|
|
59
|
-
if (typeof scenario === 'object') {
|
|
60
|
-
scenarioObj = scenario;
|
|
61
|
-
} else if (Array.isArray(scenario)) {
|
|
62
|
-
scenarioObj = scenario[0];
|
|
63
|
-
} else {
|
|
64
|
-
//console.error('Incoming scenario', scenario);
|
|
65
|
-
scenarioObj = scenario.split(',').reduce((acc, pair) => {
|
|
66
|
-
let [key, value] = pair.split('=');
|
|
67
|
-
acc[key.trim()] = value;
|
|
68
|
-
count++;
|
|
69
|
-
return acc;
|
|
70
|
-
}, {});
|
|
71
|
-
}
|
|
72
|
-
params.scenario= scenarioObj;
|
|
52
|
+
let params = {...iparams};
|
|
53
|
+
if (typeof params.scenario === 'string') {
|
|
54
|
+
try { params.scenario = JSON.parse(params.scenario); } catch { params.scenario = {}; }
|
|
55
|
+
}
|
|
56
|
+
params.scenario = (params.scenario != null && typeof params.scenario === 'object') ? params.scenario : {};
|
|
73
57
|
|
|
74
58
|
// Drop model extension (e.g., .job, .model)
|
|
75
59
|
if (params.model && params.model.includes('.')) {
|
package/src/toolSet/runJob.js
CHANGED
|
@@ -16,7 +16,7 @@ DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro)
|
|
|
16
16
|
|
|
17
17
|
PARAMETERS
|
|
18
18
|
- name: string — job name (required)
|
|
19
|
-
- scenario:
|
|
19
|
+
- scenario: object — input parameters as JSON (optional, defaults to {}). Example: {month:10, year:2025}
|
|
20
20
|
|
|
21
21
|
ROUTING RULES
|
|
22
22
|
- "run job xyz" → { name: "xyz" }
|
|
@@ -41,34 +41,14 @@ Returns log output, listings, tables from job. Error if job not found.
|
|
|
41
41
|
description: description,
|
|
42
42
|
inputSchema: z.object({
|
|
43
43
|
name: z.string(),
|
|
44
|
-
scenario: z.string().optional()
|
|
44
|
+
scenario: z.union([z.record(z.any()), z.string()]).optional()
|
|
45
45
|
}),
|
|
46
46
|
handler: async (params) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let count = 0;
|
|
50
|
-
//
|
|
51
|
-
if (scenario == null) {
|
|
52
|
-
scenarioObj = {};
|
|
53
|
-
} else if (typeof scenario === 'object') {
|
|
54
|
-
scenarioObj = scenario;
|
|
55
|
-
} else if (Array.isArray(scenario)) {
|
|
56
|
-
scenarioObj = scenario[0];
|
|
57
|
-
} else if (typeof scenario === 'string') {
|
|
58
|
-
if (scenario.trim() === '') {
|
|
59
|
-
scenarioObj = {};
|
|
60
|
-
} else {
|
|
61
|
-
// console.error('Incoming scenario', scenario);
|
|
62
|
-
scenarioObj = scenario.split(',').reduce((acc, pair) => {
|
|
63
|
-
let [key, value] = pair.split('=');
|
|
64
|
-
acc[key.trim()] = value;
|
|
65
|
-
count++;
|
|
66
|
-
return acc;
|
|
67
|
-
}, {});
|
|
68
|
-
}
|
|
47
|
+
if (typeof params.scenario === 'string') {
|
|
48
|
+
try { params.scenario = JSON.parse(params.scenario); } catch { params.scenario = {}; }
|
|
69
49
|
}
|
|
50
|
+
params.scenario = (params.scenario != null && typeof params.scenario === 'object') ? params.scenario : {};
|
|
70
51
|
params.type = 'job';
|
|
71
|
-
params.scenario = scenarioObj;
|
|
72
52
|
// Provide runtime context for auth and server settings
|
|
73
53
|
let r = await _jobSubmit(params);
|
|
74
54
|
return r;
|
package/src/toolSet/runJobdef.js
CHANGED
|
@@ -17,7 +17,7 @@ DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro)
|
|
|
17
17
|
|
|
18
18
|
PARAMETERS
|
|
19
19
|
- name: string — jobdef name (required)
|
|
20
|
-
- scenario:
|
|
20
|
+
- scenario: object — input parameters as JSON (optional, defaults to {}). Example: {month:10, year:2025}
|
|
21
21
|
|
|
22
22
|
ROUTING RULES
|
|
23
23
|
- "run jobdef xyz" → { name: "xyz" }
|
|
@@ -42,34 +42,14 @@ Returns log output, listings, tables from jobdef. Error if jobdef not found.
|
|
|
42
42
|
description: description,
|
|
43
43
|
inputSchema: z.object({
|
|
44
44
|
name: z.string(),
|
|
45
|
-
scenario: z.string().optional()
|
|
45
|
+
scenario: z.union([z.record(z.any()), z.string()]).optional()
|
|
46
46
|
}),
|
|
47
47
|
handler: async (params) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
let count = 0;
|
|
51
|
-
//
|
|
52
|
-
if (scenario == null) {
|
|
53
|
-
scenarioObj = {};
|
|
54
|
-
} else if (typeof scenario === 'object') {
|
|
55
|
-
scenarioObj = scenario;
|
|
56
|
-
} else if (Array.isArray(scenario)) {
|
|
57
|
-
scenarioObj = scenario[0];
|
|
58
|
-
} else if (typeof scenario === 'string') {
|
|
59
|
-
if (scenario.trim() === '') {
|
|
60
|
-
scenarioObj = {};
|
|
61
|
-
} else {
|
|
62
|
-
// console.error('Incoming scenario', scenario);
|
|
63
|
-
scenarioObj = scenario.split(',').reduce((acc, pair) => {
|
|
64
|
-
let [key, value] = pair.split('=');
|
|
65
|
-
acc[key.trim()] = value;
|
|
66
|
-
count++;
|
|
67
|
-
return acc;
|
|
68
|
-
}, {});
|
|
69
|
-
}
|
|
48
|
+
if (typeof params.scenario === 'string') {
|
|
49
|
+
try { params.scenario = JSON.parse(params.scenario); } catch { params.scenario = {}; }
|
|
70
50
|
}
|
|
51
|
+
params.scenario = (params.scenario != null && typeof params.scenario === 'object') ? params.scenario : {};
|
|
71
52
|
params.type = 'def';
|
|
72
|
-
params.scenario = scenarioObj;
|
|
73
53
|
// Provide runtime context for auth and server settings
|
|
74
54
|
let r = await _jobSubmit(params);
|
|
75
55
|
return r;
|
package/src/toolSet/scrScore.js
CHANGED
|
@@ -1,70 +1,61 @@
|
|
|
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 _scrScore from '../toolHelpers/_scrScore.js';
|
|
8
|
-
|
|
9
|
-
function scrScore(_appContext) {
|
|
10
|
-
let description = `
|
|
11
|
-
## scr-score
|
|
12
|
-
|
|
13
|
-
Purpose
|
|
14
|
-
Score a scenario using a model deployed as a SCR container in Azure or another host).
|
|
15
|
-
|
|
16
|
-
Inputs
|
|
17
|
-
- url (string, required): SCR model identifier (URL)
|
|
18
|
-
- scenario (
|
|
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
|
-
let r = await _scrScore({ url: url, scenario: scenario , _appContext: _appContext});
|
|
63
|
-
return r;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return spec;
|
|
68
|
-
}
|
|
69
|
-
|
|
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 _scrScore from '../toolHelpers/_scrScore.js';
|
|
8
|
+
|
|
9
|
+
function scrScore(_appContext) {
|
|
10
|
+
let description = `
|
|
11
|
+
## scr-score
|
|
12
|
+
|
|
13
|
+
Purpose
|
|
14
|
+
Score a scenario using a model deployed as a SCR container in Azure or another host).
|
|
15
|
+
|
|
16
|
+
Inputs
|
|
17
|
+
- url (string, required): SCR model identifier (URL)
|
|
18
|
+
- scenario (object, optional): Input values to score as a JSON object (e.g. {age:45, income:60000}). If omitted, defaults to {} and the tool will return the model's input variable definitions.
|
|
19
|
+
|
|
20
|
+
What it returns
|
|
21
|
+
- When scoring: the SCR endpoint response (predictions, probabilities, scores) merged with or alongside the supplied inputs.
|
|
22
|
+
- When \`scenario\` is omitted: metadata describing the model's input variables (names, types, required/optional).
|
|
23
|
+
|
|
24
|
+
Usage notes
|
|
25
|
+
- Run \`scr-info\` first to inspect the expected input variables and types.
|
|
26
|
+
- Prefer structured objects for numeric/date values to avoid type ambiguity; the simple string parser keeps values as strings.
|
|
27
|
+
- Ensure network connectivity and any required credentials for the target SCR service.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
- scrScore with url="loan" and scenario={age:45, income:60000}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
let spec = {
|
|
34
|
+
name: 'scr-score',
|
|
35
|
+
description: description,
|
|
36
|
+
inputSchema: z.object({
|
|
37
|
+
url: z.string(),
|
|
38
|
+
scenario: z.union([z.record(z.any()), z.string()]).optional()
|
|
39
|
+
}),
|
|
40
|
+
|
|
41
|
+
handler: async (params) => {
|
|
42
|
+
let {url, _appContext} = params;
|
|
43
|
+
let scenario = params.scenario;
|
|
44
|
+
if (typeof scenario === 'string') {
|
|
45
|
+
try { scenario = JSON.parse(scenario); } catch { scenario = {}; }
|
|
46
|
+
}
|
|
47
|
+
if (url === null) {
|
|
48
|
+
return { status: { statusCode: 2, msg: `SCR model ${url} was not specified` }, results: {} };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const scenarioObj = (scenario != null && typeof scenario === 'object') ? scenario : {};
|
|
52
|
+
|
|
53
|
+
let r = await _scrScore({ url: url, scenario: scenarioObj, _appContext: _appContext});
|
|
54
|
+
return r;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return spec;
|
|
59
|
+
}
|
|
60
|
+
|
|
70
61
|
export default scrScore;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|