@lexq/cli 0.1.14 → 0.1.15
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/dist/index.js +67 -60
- package/dist/mcp/register.js +58 -51
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -910,7 +910,7 @@ function buildUpdateBody2(opts) {
|
|
|
910
910
|
import "commander";
|
|
911
911
|
function registerDeployCommands(program) {
|
|
912
912
|
const deploy = program.command("deploy").description("Deployment lifecycle and history");
|
|
913
|
-
deploy.command("publish").description("Publish a DRAFT version (DRAFT \u2192 ACTIVE)").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to publish").
|
|
913
|
+
deploy.command("publish").description("Publish a DRAFT version (DRAFT \u2192 ACTIVE)").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to publish").requiredOption("--memo <memo>", "Publish Deployment memo").action(async (opts) => {
|
|
914
914
|
try {
|
|
915
915
|
const globalOpts = program.opts();
|
|
916
916
|
await apiRequest(
|
|
@@ -921,7 +921,7 @@ function registerDeployCommands(program) {
|
|
|
921
921
|
baseUrl: globalOpts.baseUrl,
|
|
922
922
|
dryRun: globalOpts.dryRun,
|
|
923
923
|
verbose: globalOpts.verbose,
|
|
924
|
-
body: { memo: opts.memo
|
|
924
|
+
body: { memo: opts.memo }
|
|
925
925
|
}
|
|
926
926
|
);
|
|
927
927
|
console.log(`\u2713 Version ${opts.versionId} published.`);
|
|
@@ -930,7 +930,7 @@ function registerDeployCommands(program) {
|
|
|
930
930
|
process.exit(1);
|
|
931
931
|
}
|
|
932
932
|
});
|
|
933
|
-
deploy.command("live").description("Deploy an ACTIVE version to live traffic").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to deploy").
|
|
933
|
+
deploy.command("live").description("Deploy an ACTIVE version to live traffic").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--version-id <versionId>", "Version ID to deploy").requiredOption("--memo <memo>", "Live Deployment memo").action(async (opts) => {
|
|
934
934
|
try {
|
|
935
935
|
const globalOpts = program.opts();
|
|
936
936
|
await apiRequest("POST", `policy-groups/${opts.groupId}/deploy`, {
|
|
@@ -938,7 +938,7 @@ function registerDeployCommands(program) {
|
|
|
938
938
|
baseUrl: globalOpts.baseUrl,
|
|
939
939
|
dryRun: globalOpts.dryRun,
|
|
940
940
|
verbose: globalOpts.verbose,
|
|
941
|
-
body: { versionId: opts.versionId, memo: opts.memo
|
|
941
|
+
body: { versionId: opts.versionId, memo: opts.memo }
|
|
942
942
|
});
|
|
943
943
|
console.log(`\u2713 Version ${opts.versionId} deployed to live.`);
|
|
944
944
|
} catch (error) {
|
|
@@ -946,7 +946,7 @@ function registerDeployCommands(program) {
|
|
|
946
946
|
process.exit(1);
|
|
947
947
|
}
|
|
948
948
|
});
|
|
949
|
-
deploy.command("rollback").description("Rollback to the previous deployed version").requiredOption("--group-id <groupId>", "Policy group ID").
|
|
949
|
+
deploy.command("rollback").description("Rollback to the previous deployed version").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--memo <memo>", "Rollback reason").option("--force", "Skip confirmation prompt").action(async (opts) => {
|
|
950
950
|
try {
|
|
951
951
|
const globalOpts = program.opts();
|
|
952
952
|
if (!opts.force) {
|
|
@@ -964,7 +964,7 @@ function registerDeployCommands(program) {
|
|
|
964
964
|
baseUrl: globalOpts.baseUrl,
|
|
965
965
|
dryRun: globalOpts.dryRun,
|
|
966
966
|
verbose: globalOpts.verbose,
|
|
967
|
-
body: { memo: opts.memo
|
|
967
|
+
body: { memo: opts.memo }
|
|
968
968
|
});
|
|
969
969
|
console.log(`\u2713 Group ${opts.groupId} rolled back.`);
|
|
970
970
|
} catch (error) {
|
|
@@ -972,7 +972,7 @@ function registerDeployCommands(program) {
|
|
|
972
972
|
process.exit(1);
|
|
973
973
|
}
|
|
974
974
|
});
|
|
975
|
-
deploy.command("undeploy").description("Remove the live version from a group").requiredOption("--group-id <groupId>", "Policy group ID").
|
|
975
|
+
deploy.command("undeploy").description("Remove the live version from a group").requiredOption("--group-id <groupId>", "Policy group ID").requiredOption("--memo <memo>", "Undeploy reason").option("--force", "Skip confirmation prompt").action(async (opts) => {
|
|
976
976
|
try {
|
|
977
977
|
const globalOpts = program.opts();
|
|
978
978
|
if (!opts.force) {
|
|
@@ -990,7 +990,7 @@ function registerDeployCommands(program) {
|
|
|
990
990
|
baseUrl: globalOpts.baseUrl,
|
|
991
991
|
dryRun: globalOpts.dryRun,
|
|
992
992
|
verbose: globalOpts.verbose,
|
|
993
|
-
body: { memo: opts.memo
|
|
993
|
+
body: { memo: opts.memo }
|
|
994
994
|
});
|
|
995
995
|
console.log(`\u2713 Group ${opts.groupId} undeployed.`);
|
|
996
996
|
} catch (error) {
|
|
@@ -1553,7 +1553,7 @@ ${data.totalElements} total \xB7 page ${data.pageNo + 1}/${data.totalPages}`);
|
|
|
1553
1553
|
process.exit(1);
|
|
1554
1554
|
}
|
|
1555
1555
|
});
|
|
1556
|
-
history.command("get").description("Get execution detail").requiredOption("--id <
|
|
1556
|
+
history.command("get").description("Get execution detail").requiredOption("--id <traceId>", "Trace ID").action(async (opts) => {
|
|
1557
1557
|
try {
|
|
1558
1558
|
const globalOpts = program.opts();
|
|
1559
1559
|
const data = await apiRequest(
|
|
@@ -1973,10 +1973,10 @@ function registerGroupTools(server, callApi) {
|
|
|
1973
1973
|
name: z.string().describe("Group name (unique among non-ARCHIVED)"),
|
|
1974
1974
|
priority: z.number().int().min(0).describe("Execution priority (lower = higher)"),
|
|
1975
1975
|
description: z.string().optional().describe("Group description"),
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1976
|
+
activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
|
|
1977
|
+
activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
|
|
1978
|
+
executionLimit: z.number().int().min(1).optional().describe("Max rule executions (required when mode is MAX_N)"),
|
|
1979
|
+
activationGroup: z.string().optional().describe("Activation group name")
|
|
1980
1980
|
}
|
|
1981
1981
|
},
|
|
1982
1982
|
async (args) => {
|
|
@@ -1985,12 +1985,10 @@ function registerGroupTools(server, callApi) {
|
|
|
1985
1985
|
priority: args.priority
|
|
1986
1986
|
};
|
|
1987
1987
|
if (args.description !== void 0) body.description = args.description;
|
|
1988
|
-
if (args.
|
|
1989
|
-
|
|
1990
|
-
if (args.
|
|
1991
|
-
|
|
1992
|
-
if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
|
|
1993
|
-
if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
|
|
1988
|
+
if (args.activationMode !== void 0) body.activationMode = args.activationMode;
|
|
1989
|
+
if (args.activationStrategy !== void 0) body.activationStrategy = args.activationStrategy;
|
|
1990
|
+
if (args.executionLimit !== void 0) body.executionLimit = args.executionLimit;
|
|
1991
|
+
if (args.activationGroup !== void 0) body.activationGroup = args.activationGroup;
|
|
1994
1992
|
return callApi("POST", "policy-groups", { body });
|
|
1995
1993
|
}
|
|
1996
1994
|
);
|
|
@@ -1998,16 +1996,16 @@ function registerGroupTools(server, callApi) {
|
|
|
1998
1996
|
"lexq_groups_update",
|
|
1999
1997
|
{
|
|
2000
1998
|
title: "Update Policy Group",
|
|
2001
|
-
description: "Update
|
|
1999
|
+
description: "Update a policy group. This is a full replacement \u2014 omitted optional fields will be set to null on the server.",
|
|
2002
2000
|
inputSchema: {
|
|
2003
2001
|
groupId: z.string().uuid().describe("Policy group ID"),
|
|
2004
2002
|
name: z.string().optional().describe("New name"),
|
|
2005
2003
|
priority: z.number().int().min(0).optional().describe("New priority"),
|
|
2006
2004
|
description: z.string().optional().describe("New description"),
|
|
2007
2005
|
status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2006
|
+
activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
|
|
2007
|
+
activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
|
|
2008
|
+
executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
|
|
2011
2009
|
}
|
|
2012
2010
|
},
|
|
2013
2011
|
async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
|
|
@@ -2186,17 +2184,21 @@ function registerRuleTools(server, callApi) {
|
|
|
2186
2184
|
"lexq_rules_create",
|
|
2187
2185
|
{
|
|
2188
2186
|
title: "Create Rule",
|
|
2189
|
-
description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
|
|
2187
|
+
description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
|
|
2188
|
+
|
|
2189
|
+
Note: Rules can reference fact keys that are not yet registered in Fact Definitions. The engine allows this for flexibility. However, registering facts via lexq_facts_create is recommended \u2014 it enables type validation, the Console UI autocomplete, and the dry-run requirements analyzer.
|
|
2190
|
+
|
|
2190
2191
|
Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
|
|
2191
|
-
Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
|
|
2192
|
+
Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
|
|
2192
2193
|
Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
|
|
2193
|
-
|
|
2194
|
+
|
|
2194
2195
|
Actions: [{ type, parameters }]
|
|
2195
|
-
|
|
2196
|
+
|
|
2196
2197
|
Action parameter schemas:
|
|
2197
2198
|
- DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT) }
|
|
2198
2199
|
- POINT: { refVar: string, targetVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT), integrationId: uuid }
|
|
2199
|
-
- COUPON_ISSUE: { couponId: string, integrationId: uuid }
|
|
2200
|
+
- COUPON_ISSUE: { couponId: string, integrationId: uuid }
|
|
2201
|
+
- BLOCK: { reason: string }
|
|
2200
2202
|
- NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
|
|
2201
2203
|
- WEBHOOK: { url: string, method: "POST" }
|
|
2202
2204
|
- SET_FACT: { key: string, value: string|number|boolean }
|
|
@@ -2367,7 +2369,7 @@ function registerDeployTools(server, callApi) {
|
|
|
2367
2369
|
inputSchema: {
|
|
2368
2370
|
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
2369
2371
|
versionId: z5.string().uuid().describe("Version ID to publish"),
|
|
2370
|
-
memo: z5.string().
|
|
2372
|
+
memo: z5.string().min(1).describe("Publish Deployment memo (required)")
|
|
2371
2373
|
}
|
|
2372
2374
|
},
|
|
2373
2375
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
|
|
@@ -2380,7 +2382,7 @@ function registerDeployTools(server, callApi) {
|
|
|
2380
2382
|
inputSchema: {
|
|
2381
2383
|
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
2382
2384
|
versionId: z5.string().uuid().describe("Version ID to deploy"),
|
|
2383
|
-
memo: z5.string().
|
|
2385
|
+
memo: z5.string().min(1).describe("Live Deployment memo (required)")
|
|
2384
2386
|
}
|
|
2385
2387
|
},
|
|
2386
2388
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
|
|
@@ -2464,10 +2466,8 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
2464
2466
|
{
|
|
2465
2467
|
title: "Dry Run",
|
|
2466
2468
|
description: `Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
Always dry-run before publishing to validate rule behavior.`,
|
|
2469
|
+
Example input: { "facts": { "payment_amount": 100000, "customer_tier": "VIP" } }
|
|
2470
|
+
Always dry-run before publishing to validate rule behavior.`,
|
|
2471
2471
|
inputSchema: {
|
|
2472
2472
|
versionId: z6.string().uuid().describe("Policy version ID to test against"),
|
|
2473
2473
|
facts: z6.string().describe('JSON string of facts object, e.g. {"payment_amount":100000}'),
|
|
@@ -2516,14 +2516,21 @@ Always dry-run before publishing to validate rule behavior.`,
|
|
|
2516
2516
|
"lexq_simulation_start",
|
|
2517
2517
|
{
|
|
2518
2518
|
title: "Start Simulation",
|
|
2519
|
-
description: `Start a batch simulation against historical
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2519
|
+
description: `Start a batch simulation against historical or uploaded data.
|
|
2520
|
+
|
|
2521
|
+
dataset.type: "HISTORICAL" or "UPLOADED"
|
|
2522
|
+
dataset.source (when HISTORICAL): "EXECUTION_LOGS"
|
|
2523
|
+
dataset.from / dataset.to: date range (yyyy-MM-dd, when HISTORICAL)
|
|
2524
|
+
options.maxRecords: number (max 100000, default 10000)
|
|
2525
|
+
options.baselinePolicyVersionId: uuid (optional, for comparison)
|
|
2526
|
+
options.includeRuleStats: boolean
|
|
2527
|
+
|
|
2528
|
+
Example body:
|
|
2529
|
+
{
|
|
2530
|
+
"policyVersionId": "<uuid>",
|
|
2531
|
+
"dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2025-01-01", "to": "2025-01-31" },
|
|
2532
|
+
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
|
|
2533
|
+
}`,
|
|
2527
2534
|
inputSchema: {
|
|
2528
2535
|
body: z6.string().describe("JSON string of SimulationRequest")
|
|
2529
2536
|
}
|
|
@@ -2595,16 +2602,15 @@ Example body:
|
|
|
2595
2602
|
{
|
|
2596
2603
|
title: "Upload Dataset",
|
|
2597
2604
|
description: `Upload inline CSV or JSON content as a simulation dataset.
|
|
2598
|
-
The content is uploaded to S3 and a path is returned.
|
|
2599
|
-
Use this path in simulation start with dataset type UPLOADED.
|
|
2600
|
-
|
|
2601
|
-
CSV example:
|
|
2602
|
-
user_id,payment_amount
|
|
2603
|
-
user_001,150000
|
|
2604
|
-
user_002,50000
|
|
2605
|
-
|
|
2606
|
-
JSON example:
|
|
2607
|
-
[{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
|
|
2605
|
+
The content is uploaded to S3 and a path is returned.
|
|
2606
|
+
Use this path in simulation start with dataset type UPLOADED.
|
|
2607
|
+
|
|
2608
|
+
CSV example:
|
|
2609
|
+
user_id,payment_amount
|
|
2610
|
+
user_001,150000
|
|
2611
|
+
user_002,50000
|
|
2612
|
+
|
|
2613
|
+
JSON example: [{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
|
|
2608
2614
|
inputSchema: {
|
|
2609
2615
|
content: z6.string().describe("CSV or JSON content as string"),
|
|
2610
2616
|
filename: z6.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
|
|
@@ -2667,10 +2673,10 @@ function registerHistoryTools(server, callApi) {
|
|
|
2667
2673
|
title: "Get Execution Detail",
|
|
2668
2674
|
description: "Get full execution detail including request facts, result traces, and decision traces.",
|
|
2669
2675
|
inputSchema: {
|
|
2670
|
-
|
|
2676
|
+
traceId: z7.string().describe("Trace ID from execution history")
|
|
2671
2677
|
}
|
|
2672
2678
|
},
|
|
2673
|
-
async ({
|
|
2679
|
+
async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
|
|
2674
2680
|
);
|
|
2675
2681
|
server.registerTool(
|
|
2676
2682
|
"lexq_history_stats",
|
|
@@ -2728,19 +2734,20 @@ function registerIntegrationTools(server, callApi) {
|
|
|
2728
2734
|
"lexq_integrations_save",
|
|
2729
2735
|
{
|
|
2730
2736
|
title: "Save Integration",
|
|
2731
|
-
description: "Create or update an integration. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
|
|
2737
|
+
description: "Create or update an integration. Provide id to update an existing one; omit id to create new. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
|
|
2732
2738
|
inputSchema: {
|
|
2739
|
+
id: z8.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
|
|
2733
2740
|
type: z8.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
|
|
2734
2741
|
name: z8.string().describe("Integration name"),
|
|
2735
2742
|
baseUrl: z8.string().describe("Base URL of the external service"),
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2743
|
+
credential: z8.string().optional().describe("API key or token for the service"),
|
|
2744
|
+
additionalConfig: z8.string().optional().describe("JSON string of additional config key-value pairs"),
|
|
2745
|
+
isActive: z8.boolean().default(true).describe("Whether the integration is active")
|
|
2739
2746
|
}
|
|
2740
2747
|
},
|
|
2741
|
-
async ({
|
|
2748
|
+
async ({ additionalConfig, ...rest }) => {
|
|
2742
2749
|
const body = { ...rest };
|
|
2743
|
-
if (
|
|
2750
|
+
if (additionalConfig) body.additionalConfig = JSON.parse(additionalConfig);
|
|
2744
2751
|
return callApi("POST", "integrations", { body });
|
|
2745
2752
|
}
|
|
2746
2753
|
);
|
package/dist/mcp/register.js
CHANGED
|
@@ -66,10 +66,10 @@ function registerGroupTools(server, callApi) {
|
|
|
66
66
|
name: z.string().describe("Group name (unique among non-ARCHIVED)"),
|
|
67
67
|
priority: z.number().int().min(0).describe("Execution priority (lower = higher)"),
|
|
68
68
|
description: z.string().optional().describe("Group description"),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
|
|
70
|
+
activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy when mode is EXCLUSIVE or MAX_N"),
|
|
71
|
+
executionLimit: z.number().int().min(1).optional().describe("Max rule executions (required when mode is MAX_N)"),
|
|
72
|
+
activationGroup: z.string().optional().describe("Activation group name")
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
75
|
async (args) => {
|
|
@@ -78,12 +78,10 @@ function registerGroupTools(server, callApi) {
|
|
|
78
78
|
priority: args.priority
|
|
79
79
|
};
|
|
80
80
|
if (args.description !== void 0) body.description = args.description;
|
|
81
|
-
if (args.
|
|
82
|
-
|
|
83
|
-
if (args.
|
|
84
|
-
|
|
85
|
-
if (args.maxSelections !== void 0) body.maxSelections = args.maxSelections;
|
|
86
|
-
if (args.activationGroupId !== void 0) body.activationGroupId = args.activationGroupId;
|
|
81
|
+
if (args.activationMode !== void 0) body.activationMode = args.activationMode;
|
|
82
|
+
if (args.activationStrategy !== void 0) body.activationStrategy = args.activationStrategy;
|
|
83
|
+
if (args.executionLimit !== void 0) body.executionLimit = args.executionLimit;
|
|
84
|
+
if (args.activationGroup !== void 0) body.activationGroup = args.activationGroup;
|
|
87
85
|
return callApi("POST", "policy-groups", { body });
|
|
88
86
|
}
|
|
89
87
|
);
|
|
@@ -91,16 +89,16 @@ function registerGroupTools(server, callApi) {
|
|
|
91
89
|
"lexq_groups_update",
|
|
92
90
|
{
|
|
93
91
|
title: "Update Policy Group",
|
|
94
|
-
description: "Update
|
|
92
|
+
description: "Update a policy group. This is a full replacement \u2014 omitted optional fields will be set to null on the server.",
|
|
95
93
|
inputSchema: {
|
|
96
94
|
groupId: z.string().uuid().describe("Policy group ID"),
|
|
97
95
|
name: z.string().optional().describe("New name"),
|
|
98
96
|
priority: z.number().int().min(0).optional().describe("New priority"),
|
|
99
97
|
description: z.string().optional().describe("New description"),
|
|
100
98
|
status: z.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
activationMode: z.enum(["NONE", "EXCLUSIVE", "MAX_N"]).optional().describe("Conflict resolution mode"),
|
|
100
|
+
activationStrategy: z.enum(["FIRST_MATCH", "HIGHEST_PRIORITY", "MAX_BENEFIT"]).optional().describe("Strategy"),
|
|
101
|
+
executionLimit: z.number().int().min(1).optional().describe("Max rule executions")
|
|
104
102
|
}
|
|
105
103
|
},
|
|
106
104
|
async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
|
|
@@ -279,17 +277,21 @@ function registerRuleTools(server, callApi) {
|
|
|
279
277
|
"lexq_rules_create",
|
|
280
278
|
{
|
|
281
279
|
title: "Create Rule",
|
|
282
|
-
description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
|
|
280
|
+
description: `Create a rule in a DRAFT version. Requires name, priority, condition tree, and actions array.
|
|
281
|
+
|
|
282
|
+
Note: Rules can reference fact keys that are not yet registered in Fact Definitions. The engine allows this for flexibility. However, registering facts via lexq_facts_create is recommended \u2014 it enables type validation, the Console UI autocomplete, and the dry-run requirements analyzer.
|
|
283
|
+
|
|
283
284
|
Condition: { type: "SINGLE", field, operator, value, valueType } or { type: "GROUP", operator: "AND"|"OR", children: [...] }
|
|
284
|
-
Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
|
|
285
|
+
Operators: EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, CONTAINS, IN, NOT_IN
|
|
285
286
|
Value types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER
|
|
286
|
-
|
|
287
|
+
|
|
287
288
|
Actions: [{ type, parameters }]
|
|
288
|
-
|
|
289
|
+
|
|
289
290
|
Action parameter schemas:
|
|
290
291
|
- DISCOUNT: { refVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT) }
|
|
291
292
|
- POINT: { refVar: string, targetVar: string, method: "PERCENTAGE"|"AMOUNT", rate?: number (when PERCENTAGE), value?: number (when AMOUNT), integrationId: uuid }
|
|
292
|
-
- COUPON_ISSUE: { couponId: string, integrationId: uuid }
|
|
293
|
+
- COUPON_ISSUE: { couponId: string, integrationId: uuid }
|
|
294
|
+
- BLOCK: { reason: string }
|
|
293
295
|
- NOTIFICATION: { channel: "SMS"|"EMAIL"|"PUSH"|"KAKAO", targetVar: string, templateId: string, integrationId: uuid }
|
|
294
296
|
- WEBHOOK: { url: string, method: "POST" }
|
|
295
297
|
- SET_FACT: { key: string, value: string|number|boolean }
|
|
@@ -460,7 +462,7 @@ function registerDeployTools(server, callApi) {
|
|
|
460
462
|
inputSchema: {
|
|
461
463
|
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
462
464
|
versionId: z5.string().uuid().describe("Version ID to publish"),
|
|
463
|
-
memo: z5.string().
|
|
465
|
+
memo: z5.string().min(1).describe("Publish Deployment memo (required)")
|
|
464
466
|
}
|
|
465
467
|
},
|
|
466
468
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
|
|
@@ -473,7 +475,7 @@ function registerDeployTools(server, callApi) {
|
|
|
473
475
|
inputSchema: {
|
|
474
476
|
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
475
477
|
versionId: z5.string().uuid().describe("Version ID to deploy"),
|
|
476
|
-
memo: z5.string().
|
|
478
|
+
memo: z5.string().min(1).describe("Live Deployment memo (required)")
|
|
477
479
|
}
|
|
478
480
|
},
|
|
479
481
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
|
|
@@ -557,10 +559,8 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
557
559
|
{
|
|
558
560
|
title: "Dry Run",
|
|
559
561
|
description: `Execute a single dry run against a version. Tests how rules evaluate given input facts without side effects.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
Always dry-run before publishing to validate rule behavior.`,
|
|
562
|
+
Example input: { "facts": { "payment_amount": 100000, "customer_tier": "VIP" } }
|
|
563
|
+
Always dry-run before publishing to validate rule behavior.`,
|
|
564
564
|
inputSchema: {
|
|
565
565
|
versionId: z6.string().uuid().describe("Policy version ID to test against"),
|
|
566
566
|
facts: z6.string().describe('JSON string of facts object, e.g. {"payment_amount":100000}'),
|
|
@@ -609,14 +609,21 @@ Always dry-run before publishing to validate rule behavior.`,
|
|
|
609
609
|
"lexq_simulation_start",
|
|
610
610
|
{
|
|
611
611
|
title: "Start Simulation",
|
|
612
|
-
description: `Start a batch simulation against historical
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
612
|
+
description: `Start a batch simulation against historical or uploaded data.
|
|
613
|
+
|
|
614
|
+
dataset.type: "HISTORICAL" or "UPLOADED"
|
|
615
|
+
dataset.source (when HISTORICAL): "EXECUTION_LOGS"
|
|
616
|
+
dataset.from / dataset.to: date range (yyyy-MM-dd, when HISTORICAL)
|
|
617
|
+
options.maxRecords: number (max 100000, default 10000)
|
|
618
|
+
options.baselinePolicyVersionId: uuid (optional, for comparison)
|
|
619
|
+
options.includeRuleStats: boolean
|
|
620
|
+
|
|
621
|
+
Example body:
|
|
622
|
+
{
|
|
623
|
+
"policyVersionId": "<uuid>",
|
|
624
|
+
"dataset": { "type": "HISTORICAL", "source": "EXECUTION_LOGS", "from": "2025-01-01", "to": "2025-01-31" },
|
|
625
|
+
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true, "maxRecords": 10000 }
|
|
626
|
+
}`,
|
|
620
627
|
inputSchema: {
|
|
621
628
|
body: z6.string().describe("JSON string of SimulationRequest")
|
|
622
629
|
}
|
|
@@ -688,16 +695,15 @@ Example body:
|
|
|
688
695
|
{
|
|
689
696
|
title: "Upload Dataset",
|
|
690
697
|
description: `Upload inline CSV or JSON content as a simulation dataset.
|
|
691
|
-
The content is uploaded to S3 and a path is returned.
|
|
692
|
-
Use this path in simulation start with dataset type UPLOADED.
|
|
693
|
-
|
|
694
|
-
CSV example:
|
|
695
|
-
user_id,payment_amount
|
|
696
|
-
user_001,150000
|
|
697
|
-
user_002,50000
|
|
698
|
-
|
|
699
|
-
JSON example:
|
|
700
|
-
[{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
|
|
698
|
+
The content is uploaded to S3 and a path is returned.
|
|
699
|
+
Use this path in simulation start with dataset type UPLOADED.
|
|
700
|
+
|
|
701
|
+
CSV example:
|
|
702
|
+
user_id,payment_amount
|
|
703
|
+
user_001,150000
|
|
704
|
+
user_002,50000
|
|
705
|
+
|
|
706
|
+
JSON example: [{"user_id":"user_001","payment_amount":150000}, {"user_id":"user_002","payment_amount":50000}]`,
|
|
701
707
|
inputSchema: {
|
|
702
708
|
content: z6.string().describe("CSV or JSON content as string"),
|
|
703
709
|
filename: z6.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
|
|
@@ -760,10 +766,10 @@ function registerHistoryTools(server, callApi) {
|
|
|
760
766
|
title: "Get Execution Detail",
|
|
761
767
|
description: "Get full execution detail including request facts, result traces, and decision traces.",
|
|
762
768
|
inputSchema: {
|
|
763
|
-
|
|
769
|
+
traceId: z7.string().describe("Trace ID from execution history")
|
|
764
770
|
}
|
|
765
771
|
},
|
|
766
|
-
async ({
|
|
772
|
+
async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
|
|
767
773
|
);
|
|
768
774
|
server.registerTool(
|
|
769
775
|
"lexq_history_stats",
|
|
@@ -821,19 +827,20 @@ function registerIntegrationTools(server, callApi) {
|
|
|
821
827
|
"lexq_integrations_save",
|
|
822
828
|
{
|
|
823
829
|
title: "Save Integration",
|
|
824
|
-
description: "Create or update an integration. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
|
|
830
|
+
description: "Create or update an integration. Provide id to update an existing one; omit id to create new. Types: COUPON, POINT, NOTIFICATION, CRM, MESSENGER, WEBHOOK.",
|
|
825
831
|
inputSchema: {
|
|
832
|
+
id: z8.string().uuid().optional().describe("Integration ID (omit to create, provide to update)"),
|
|
826
833
|
type: z8.enum(["COUPON", "POINT", "NOTIFICATION", "CRM", "MESSENGER", "WEBHOOK"]).describe("Integration type"),
|
|
827
834
|
name: z8.string().describe("Integration name"),
|
|
828
835
|
baseUrl: z8.string().describe("Base URL of the external service"),
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
836
|
+
credential: z8.string().optional().describe("API key or token for the service"),
|
|
837
|
+
additionalConfig: z8.string().optional().describe("JSON string of additional config key-value pairs"),
|
|
838
|
+
isActive: z8.boolean().default(true).describe("Whether the integration is active")
|
|
832
839
|
}
|
|
833
840
|
},
|
|
834
|
-
async ({
|
|
841
|
+
async ({ additionalConfig, ...rest }) => {
|
|
835
842
|
const body = { ...rest };
|
|
836
|
-
if (
|
|
843
|
+
if (additionalConfig) body.additionalConfig = JSON.parse(additionalConfig);
|
|
837
844
|
return callApi("POST", "integrations", { body });
|
|
838
845
|
}
|
|
839
846
|
);
|