@exaudeus/workrail 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/di/container.js +7 -0
- package/dist/di/tokens.d.ts +1 -0
- package/dist/di/tokens.js +1 -0
- package/dist/manifest.json +96 -24
- package/dist/mcp/handlers/v2-execution.js +40 -23
- package/dist/mcp/handlers/workflow.js +1 -1
- package/dist/mcp/server.js +8 -0
- package/dist/mcp/tool-descriptions.js +8 -2
- package/dist/mcp/tools.d.ts +3 -3
- package/dist/mcp/tools.js +5 -4
- package/dist/mcp/types.d.ts +4 -0
- package/dist/mcp/v2/tools.js +2 -2
- package/dist/mcp/validation/index.d.ts +7 -0
- package/dist/mcp/validation/index.js +30 -0
- package/dist/mcp/validation/schema-introspection.d.ts +8 -0
- package/dist/mcp/validation/schema-introspection.js +163 -0
- package/dist/mcp/validation/string-similarity.d.ts +10 -0
- package/dist/mcp/validation/string-similarity.js +76 -0
- package/dist/mcp/validation/suggestion-config.d.ts +9 -0
- package/dist/mcp/validation/suggestion-config.js +16 -0
- package/dist/mcp/validation/suggestion-generator.d.ts +6 -0
- package/dist/mcp/validation/suggestion-generator.js +101 -0
- package/dist/mcp/validation/suggestion-types.d.ts +31 -0
- package/dist/mcp/validation/suggestion-types.js +23 -0
- package/dist/v2/durable-core/encoding/base32-lower.d.ts +4 -0
- package/dist/v2/durable-core/encoding/base32-lower.js +30 -0
- package/dist/v2/durable-core/ids/attempt-id-derivation.d.ts +3 -0
- package/dist/v2/durable-core/ids/attempt-id-derivation.js +32 -0
- package/dist/v2/durable-core/tokens/payloads.js +5 -4
- package/dist/v2/infra/local/id-factory/index.d.ts +11 -0
- package/dist/v2/infra/local/id-factory/index.js +32 -0
- package/package.json +1 -1
package/dist/di/container.js
CHANGED
|
@@ -181,6 +181,7 @@ async function registerV2Services() {
|
|
|
181
181
|
const { NodeBase64UrlV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/base64url/index.js')));
|
|
182
182
|
const { NodeRandomEntropyV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/random-entropy/index.js')));
|
|
183
183
|
const { NodeTimeClockV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/time-clock/index.js')));
|
|
184
|
+
const { IdFactoryV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/id-factory/index.js')));
|
|
184
185
|
tsyringe_1.container.register(tokens_js_1.DI.V2.DataDir, {
|
|
185
186
|
useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new LocalDataDirV2(process.env)),
|
|
186
187
|
});
|
|
@@ -205,6 +206,12 @@ async function registerV2Services() {
|
|
|
205
206
|
tsyringe_1.container.register(tokens_js_1.DI.V2.TimeClock, {
|
|
206
207
|
useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new NodeTimeClockV2()),
|
|
207
208
|
});
|
|
209
|
+
tsyringe_1.container.register(tokens_js_1.DI.V2.IdFactory, {
|
|
210
|
+
useFactory: (0, tsyringe_1.instanceCachingFactory)((c) => {
|
|
211
|
+
const entropy = c.resolve(tokens_js_1.DI.V2.RandomEntropy);
|
|
212
|
+
return new IdFactoryV2(entropy);
|
|
213
|
+
}),
|
|
214
|
+
});
|
|
208
215
|
const { LocalKeyringV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/keyring/index.js')));
|
|
209
216
|
const { LocalSessionEventLogStoreV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/session-store/index.js')));
|
|
210
217
|
const { LocalSnapshotStoreV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/snapshot-store/index.js')));
|
package/dist/di/tokens.d.ts
CHANGED
package/dist/di/tokens.js
CHANGED
|
@@ -33,6 +33,7 @@ exports.DI = {
|
|
|
33
33
|
Base64Url: Symbol('V2.Base64Url'),
|
|
34
34
|
RandomEntropy: Symbol('V2.RandomEntropy'),
|
|
35
35
|
TimeClock: Symbol('V2.TimeClock'),
|
|
36
|
+
IdFactory: Symbol('V2.IdFactory'),
|
|
36
37
|
Keyring: Symbol('V2.Keyring'),
|
|
37
38
|
SessionStore: Symbol('V2.SessionStore'),
|
|
38
39
|
SnapshotStore: Symbol('V2.SnapshotStore'),
|
package/dist/manifest.json
CHANGED
|
@@ -254,16 +254,16 @@
|
|
|
254
254
|
"bytes": 565
|
|
255
255
|
},
|
|
256
256
|
"di/container.js": {
|
|
257
|
-
"sha256": "
|
|
258
|
-
"bytes":
|
|
257
|
+
"sha256": "200c41528c64e4e8cf0e04046bfd254cdbe0900c157be2dfd8c302a4a096d193",
|
|
258
|
+
"bytes": 18890
|
|
259
259
|
},
|
|
260
260
|
"di/tokens.d.ts": {
|
|
261
|
-
"sha256": "
|
|
262
|
-
"bytes":
|
|
261
|
+
"sha256": "3b9e46e178107ad65575350da5d99c238e7a4389d3537e67ff516a04df1191fe",
|
|
262
|
+
"bytes": 1882
|
|
263
263
|
},
|
|
264
264
|
"di/tokens.js": {
|
|
265
|
-
"sha256": "
|
|
266
|
-
"bytes":
|
|
265
|
+
"sha256": "aa90a1af7eba9941663beeeb13a25e2f3ba877ba37cb786bac46b468cc840f1b",
|
|
266
|
+
"bytes": 2327
|
|
267
267
|
},
|
|
268
268
|
"domain/execution/error.d.ts": {
|
|
269
269
|
"sha256": "2eac85c42ec399a23724f868641eeadd0d196b4d324ee4caaff82a6b46155bd9",
|
|
@@ -534,8 +534,8 @@
|
|
|
534
534
|
"bytes": 399
|
|
535
535
|
},
|
|
536
536
|
"mcp/handlers/v2-execution.js": {
|
|
537
|
-
"sha256": "
|
|
538
|
-
"bytes":
|
|
537
|
+
"sha256": "4f3f7d9009007a6795e2dfe998165722f660354323f7e856b26f1a7f62a136be",
|
|
538
|
+
"bytes": 53400
|
|
539
539
|
},
|
|
540
540
|
"mcp/handlers/v2-workflow.d.ts": {
|
|
541
541
|
"sha256": "9fbd4d44854e2060c54982b21e72c608970bb2bd107bb15a8388b26c6b492e55",
|
|
@@ -550,8 +550,8 @@
|
|
|
550
550
|
"bytes": 1748
|
|
551
551
|
},
|
|
552
552
|
"mcp/handlers/workflow.js": {
|
|
553
|
-
"sha256": "
|
|
554
|
-
"bytes":
|
|
553
|
+
"sha256": "7ebd383922c6f238c35c376c8a0aa87b0969a80bb4e7c48e704a8480fd974bb4",
|
|
554
|
+
"bytes": 8254
|
|
555
555
|
},
|
|
556
556
|
"mcp/index.d.ts": {
|
|
557
557
|
"sha256": "525b4247cf90ba3af66769462bcfaab5dbf38ee8c49d2a9ceec1e4b38e33511b",
|
|
@@ -574,8 +574,8 @@
|
|
|
574
574
|
"bytes": 168
|
|
575
575
|
},
|
|
576
576
|
"mcp/server.js": {
|
|
577
|
-
"sha256": "
|
|
578
|
-
"bytes":
|
|
577
|
+
"sha256": "f6bc4b1f3416d03add7b715a5bdae7955a877eae8008c0d2f8b8490dd8ae5708",
|
|
578
|
+
"bytes": 14097
|
|
579
579
|
},
|
|
580
580
|
"mcp/tool-description-provider.d.ts": {
|
|
581
581
|
"sha256": "1d46abc3112e11b68e57197e846f5708293ec9b2281fa71a9124ee2aad71e41b",
|
|
@@ -590,8 +590,8 @@
|
|
|
590
590
|
"bytes": 132
|
|
591
591
|
},
|
|
592
592
|
"mcp/tool-descriptions.js": {
|
|
593
|
-
"sha256": "
|
|
594
|
-
"bytes":
|
|
593
|
+
"sha256": "c8150119782dadd286e8430e9377b0b727891c414be2396e314423713939d6eb",
|
|
594
|
+
"bytes": 7980
|
|
595
595
|
},
|
|
596
596
|
"mcp/tool-factory.d.ts": {
|
|
597
597
|
"sha256": "0fe3c6b863b2d7aef0c3d659ff54f3a9ee8a0a3c2005b6565d2f8ad517bc7211",
|
|
@@ -602,16 +602,16 @@
|
|
|
602
602
|
"bytes": 479
|
|
603
603
|
},
|
|
604
604
|
"mcp/tools.d.ts": {
|
|
605
|
-
"sha256": "
|
|
606
|
-
"bytes":
|
|
605
|
+
"sha256": "8474e810cae37197d5968be4c3dfb9751ba2b09fe8a7f39e0e7dcc414af4bdb5",
|
|
606
|
+
"bytes": 5976
|
|
607
607
|
},
|
|
608
608
|
"mcp/tools.js": {
|
|
609
|
-
"sha256": "
|
|
610
|
-
"bytes":
|
|
609
|
+
"sha256": "0af59932b32bad5ebc9cbc925279d325350c91b43085561d0d218035250b641a",
|
|
610
|
+
"bytes": 8020
|
|
611
611
|
},
|
|
612
612
|
"mcp/types.d.ts": {
|
|
613
|
-
"sha256": "
|
|
614
|
-
"bytes":
|
|
613
|
+
"sha256": "3b7d7d7d30d65cd22b47bc9d559820b3f51984476fce11d4f3b6d820e2ce1eb8",
|
|
614
|
+
"bytes": 3683
|
|
615
615
|
},
|
|
616
616
|
"mcp/types.js": {
|
|
617
617
|
"sha256": "0c12576fd0053115ff096fe26b38f77f1e830b7ec4781aaf94564827c4c9e81a",
|
|
@@ -638,8 +638,8 @@
|
|
|
638
638
|
"bytes": 2579
|
|
639
639
|
},
|
|
640
640
|
"mcp/v2/tools.js": {
|
|
641
|
-
"sha256": "
|
|
642
|
-
"bytes":
|
|
641
|
+
"sha256": "4b0d5d1c019d3f747b0f4211a606d1aba4944f9e570ae9fecc6831987a6cc16f",
|
|
642
|
+
"bytes": 2537
|
|
643
643
|
},
|
|
644
644
|
"mcp/validation/bounded-json.d.ts": {
|
|
645
645
|
"sha256": "82203ac6123d5c6989606c3b5405aaea99ab829c8958835f9ae3ba45b8bc8fd5",
|
|
@@ -649,6 +649,54 @@
|
|
|
649
649
|
"sha256": "0134fd92e1b160f1b57230d9f8a471044858af43484206f911619cf7159e3f0d",
|
|
650
650
|
"bytes": 834
|
|
651
651
|
},
|
|
652
|
+
"mcp/validation/index.d.ts": {
|
|
653
|
+
"sha256": "3e3f12357fd8214470d111454e4002338e5eb93329b5a3758664db51e44c12ec",
|
|
654
|
+
"bytes": 944
|
|
655
|
+
},
|
|
656
|
+
"mcp/validation/index.js": {
|
|
657
|
+
"sha256": "dccd3a2dc7e486afd27ee44f77303486f60cc840563821b97ac341f9cad6650c",
|
|
658
|
+
"bytes": 4445
|
|
659
|
+
},
|
|
660
|
+
"mcp/validation/schema-introspection.d.ts": {
|
|
661
|
+
"sha256": "7e0262e76234dd37079156027e95a30987b8949351f3e9ec0fd7b2be093a159d",
|
|
662
|
+
"bytes": 713
|
|
663
|
+
},
|
|
664
|
+
"mcp/validation/schema-introspection.js": {
|
|
665
|
+
"sha256": "850c09a3c01a5f22440ebc34236c393f3b428748210f5277258a9905cb847d71",
|
|
666
|
+
"bytes": 5293
|
|
667
|
+
},
|
|
668
|
+
"mcp/validation/string-similarity.d.ts": {
|
|
669
|
+
"sha256": "4326210a768a526336b54d4ea20a128a939d92f53e8b2a5a33da06b5372d196a",
|
|
670
|
+
"bytes": 671
|
|
671
|
+
},
|
|
672
|
+
"mcp/validation/string-similarity.js": {
|
|
673
|
+
"sha256": "fafdb80673ad56336009e562cd5dccd93486dd94fa78acbb923cdc47ba63becf",
|
|
674
|
+
"bytes": 2627
|
|
675
|
+
},
|
|
676
|
+
"mcp/validation/suggestion-config.d.ts": {
|
|
677
|
+
"sha256": "70b8395db74ec18bb1ef2309dd16516345b75839d2793bf9c5bfbd1e1d1baa0e",
|
|
678
|
+
"bytes": 388
|
|
679
|
+
},
|
|
680
|
+
"mcp/validation/suggestion-config.js": {
|
|
681
|
+
"sha256": "efda43e48812979d0ddae2abe23809b6b5a3e5b955e74ca5a67716933e468db4",
|
|
682
|
+
"bytes": 592
|
|
683
|
+
},
|
|
684
|
+
"mcp/validation/suggestion-generator.d.ts": {
|
|
685
|
+
"sha256": "491d983f4a03516fc0ba09ff40da2c859ec600f29a41093b0359ba549c7882cc",
|
|
686
|
+
"bytes": 450
|
|
687
|
+
},
|
|
688
|
+
"mcp/validation/suggestion-generator.js": {
|
|
689
|
+
"sha256": "e952a4d3cb569222cde1bd01dd9d5be887ee394ba007478bbb446fa177172859",
|
|
690
|
+
"bytes": 4075
|
|
691
|
+
},
|
|
692
|
+
"mcp/validation/suggestion-types.d.ts": {
|
|
693
|
+
"sha256": "b93ae2e42f4b24789dcbe19db31a41af9534ad0dca85635339c2a10db42e298b",
|
|
694
|
+
"bytes": 1333
|
|
695
|
+
},
|
|
696
|
+
"mcp/validation/suggestion-types.js": {
|
|
697
|
+
"sha256": "c7753960a199508a8a59f8030c4240a076857a3e5926efadc01e808f08d7ff3a",
|
|
698
|
+
"bytes": 729
|
|
699
|
+
},
|
|
652
700
|
"mcp/validation/workflow-next-prevalidate.d.ts": {
|
|
653
701
|
"sha256": "179058225dfb17f4be02d6105bbacdaa99f1441cfc25062b38d8283f0bf35b5a",
|
|
654
702
|
"bytes": 254
|
|
@@ -945,6 +993,22 @@
|
|
|
945
993
|
"sha256": "ae16a0df03c3dec30e9ffca0066b6148568966f6660a3c660f82853e077a0cbd",
|
|
946
994
|
"bytes": 817
|
|
947
995
|
},
|
|
996
|
+
"v2/durable-core/encoding/base32-lower.d.ts": {
|
|
997
|
+
"sha256": "849ef1984db20984f1fce7f40b15d3680c888e01411932d30af6fae4d2132a67",
|
|
998
|
+
"bytes": 175
|
|
999
|
+
},
|
|
1000
|
+
"v2/durable-core/encoding/base32-lower.js": {
|
|
1001
|
+
"sha256": "9065da38936496a34c2808388b5fb68d8aaac6bd3f0f05de184abc101e07c419",
|
|
1002
|
+
"bytes": 934
|
|
1003
|
+
},
|
|
1004
|
+
"v2/durable-core/ids/attempt-id-derivation.d.ts": {
|
|
1005
|
+
"sha256": "baee295f114d8d4a74e9fa529e7c72d458a7c7244f50fad9ebbaea06c57dfe92",
|
|
1006
|
+
"bytes": 207
|
|
1007
|
+
},
|
|
1008
|
+
"v2/durable-core/ids/attempt-id-derivation.js": {
|
|
1009
|
+
"sha256": "c13da44f23890d85edfb64a471f4f4817e973a63b41287d79144a3c9c6a5dcea",
|
|
1010
|
+
"bytes": 1309
|
|
1011
|
+
},
|
|
948
1012
|
"v2/durable-core/ids/index.d.ts": {
|
|
949
1013
|
"sha256": "5525efc423ad30635996907f7560f53559e49e33a64411a684370ebd1ae56410",
|
|
950
1014
|
"bytes": 1792
|
|
@@ -1086,8 +1150,8 @@
|
|
|
1086
1150
|
"bytes": 6756
|
|
1087
1151
|
},
|
|
1088
1152
|
"v2/durable-core/tokens/payloads.js": {
|
|
1089
|
-
"sha256": "
|
|
1090
|
-
"bytes":
|
|
1153
|
+
"sha256": "24978999201e0413cb193e1fee2b9977335ecaa9e2170b901358c9119fac6c3a",
|
|
1154
|
+
"bytes": 2479
|
|
1091
1155
|
},
|
|
1092
1156
|
"v2/durable-core/tokens/token-codec.d.ts": {
|
|
1093
1157
|
"sha256": "44bd65c6102b3aa5fcd82d2854f5466263a20c0b9cbd31aa25f169dfeed8e045",
|
|
@@ -1145,6 +1209,14 @@
|
|
|
1145
1209
|
"sha256": "11917c1d29f34efcd7139f5573067ad20a4093a1c5190e6069ccdc25acf53f24",
|
|
1146
1210
|
"bytes": 578
|
|
1147
1211
|
},
|
|
1212
|
+
"v2/infra/local/id-factory/index.d.ts": {
|
|
1213
|
+
"sha256": "ffcbdcce6a9c6a93c2703e0d844f84fef59e6ef8a3f657d50750e885b88e879b",
|
|
1214
|
+
"bytes": 432
|
|
1215
|
+
},
|
|
1216
|
+
"v2/infra/local/id-factory/index.js": {
|
|
1217
|
+
"sha256": "bd7d8cde4fb63b299f11ff51721c9b468c887856d581e95867bbbee6547642e4",
|
|
1218
|
+
"bytes": 1044
|
|
1219
|
+
},
|
|
1148
1220
|
"v2/infra/local/keyring/index.d.ts": {
|
|
1149
1221
|
"sha256": "e8698dab64327f994bf78e1a6c30131062d8418847417610e6b071ce7e873763",
|
|
1150
1222
|
"bytes": 932
|
|
@@ -36,7 +36,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.handleV2StartWorkflow = handleV2StartWorkflow;
|
|
37
37
|
exports.handleV2ContinueWorkflow = handleV2ContinueWorkflow;
|
|
38
38
|
const os = __importStar(require("os"));
|
|
39
|
-
const crypto_1 = require("crypto");
|
|
40
39
|
const types_js_1 = require("../types.js");
|
|
41
40
|
const output_schemas_js_1 = require("../output-schemas.js");
|
|
42
41
|
const snapshot_state_js_1 = require("../../v2/durable-core/projections/snapshot-state.js");
|
|
@@ -45,6 +44,7 @@ const index_js_1 = require("../../v2/durable-core/tokens/index.js");
|
|
|
45
44
|
const index_js_2 = require("../../v2/durable-core/tokens/index.js");
|
|
46
45
|
const workflow_js_1 = require("../../types/workflow.js");
|
|
47
46
|
const index_js_3 = require("../../v2/durable-core/ids/index.js");
|
|
47
|
+
const attempt_id_derivation_js_1 = require("../../v2/durable-core/ids/attempt-id-derivation.js");
|
|
48
48
|
const neverthrow_1 = require("neverthrow");
|
|
49
49
|
const v1_to_v2_shim_js_1 = require("../../v2/read-only/v1-to-v2-shim.js");
|
|
50
50
|
const hashing_js_1 = require("../../v2/durable-core/canonical/hashing.js");
|
|
@@ -238,7 +238,7 @@ function mapInternalErrorToToolError(e) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
function replayFromRecordedAdvance(args) {
|
|
241
|
-
const { recordedEvent, truth, sessionId, runId, nodeId, workflowHash, attemptId, inputStateToken, inputAckToken, pinnedWorkflow, snapshotStore, keyring, hmac, base64url, } = args;
|
|
241
|
+
const { recordedEvent, truth, sessionId, runId, nodeId, workflowHash, attemptId, inputStateToken, inputAckToken, pinnedWorkflow, snapshotStore, keyring, sha256, hmac, base64url, } = args;
|
|
242
242
|
const checkpointTokenRes = signTokenOrErr({
|
|
243
243
|
unsignedPrefix: 'chk.v1.',
|
|
244
244
|
payload: { tokenVersion: 1, tokenKind: 'checkpoint', sessionId, runId, nodeId, attemptId },
|
|
@@ -295,7 +295,7 @@ function replayFromRecordedAdvance(args) {
|
|
|
295
295
|
}
|
|
296
296
|
const pending = (0, snapshot_state_js_1.derivePendingStep)(snap.enginePayload.engineState);
|
|
297
297
|
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(snap.enginePayload.engineState);
|
|
298
|
-
const nextAttemptId = attemptIdForNextNode(attemptId);
|
|
298
|
+
const nextAttemptId = attemptIdForNextNode(attemptId, sha256);
|
|
299
299
|
const nextAckTokenRes = signTokenOrErr({
|
|
300
300
|
unsignedPrefix: 'ack.v1.',
|
|
301
301
|
payload: { tokenVersion: 1, tokenKind: 'ack', sessionId, runId, nodeId: toNodeIdBranded, attemptId: nextAttemptId },
|
|
@@ -338,7 +338,7 @@ function replayFromRecordedAdvance(args) {
|
|
|
338
338
|
});
|
|
339
339
|
}
|
|
340
340
|
function advanceAndRecord(args) {
|
|
341
|
-
const { truth, sessionId, runId, nodeId, attemptId, workflowHash, dedupeKey, inputContext, inputOutput, lock, pinnedWorkflow, snapshotStore, sessionStore } = args;
|
|
341
|
+
const { truth, sessionId, runId, nodeId, attemptId, workflowHash, dedupeKey, inputContext, inputOutput, lock, pinnedWorkflow, snapshotStore, sessionStore, idFactory } = args;
|
|
342
342
|
const hasRun = truth.events.some((e) => e.kind === 'run_started' && e.scope?.runId === String(runId));
|
|
343
343
|
const hasNode = truth.events.some((e) => e.kind === 'node_created' && e.scope?.runId === String(runId) && e.scope?.nodeId === String(nodeId));
|
|
344
344
|
if (!hasRun || !hasNode) {
|
|
@@ -385,11 +385,11 @@ function advanceAndRecord(args) {
|
|
|
385
385
|
enginePayload: { v: 1, engineState: newEngineState },
|
|
386
386
|
};
|
|
387
387
|
return snapshotStore.putExecutionSnapshotV1(snapshotFile).andThen((newSnapshotRef) => {
|
|
388
|
-
const toNodeId =
|
|
388
|
+
const toNodeId = String(idFactory.mintNodeId());
|
|
389
389
|
const nextEventIndex = truth.events.length === 0 ? 0 : truth.events[truth.events.length - 1].eventIndex + 1;
|
|
390
|
-
const evtAdvanceRecorded =
|
|
391
|
-
const evtNodeCreated =
|
|
392
|
-
const evtEdgeCreated =
|
|
390
|
+
const evtAdvanceRecorded = idFactory.mintEventId();
|
|
391
|
+
const evtNodeCreated = idFactory.mintEventId();
|
|
392
|
+
const evtEdgeCreated = idFactory.mintEventId();
|
|
393
393
|
const hasChildren = truth.events.some((e) => e.kind === 'edge_created' && e.data.fromNodeId === String(nodeId));
|
|
394
394
|
const causeKind = hasChildren ? 'non_tip_advance' : 'intentional_fork';
|
|
395
395
|
const outputId = (0, index_js_1.asOutputId)(`out_recap_${String(attemptId)}`);
|
|
@@ -406,7 +406,7 @@ function advanceAndRecord(args) {
|
|
|
406
406
|
]
|
|
407
407
|
: [];
|
|
408
408
|
const normalizedOutputs = (0, outputs_js_1.normalizeOutputsForAppend)(outputsToAppend);
|
|
409
|
-
const outputEventIds = normalizedOutputs.map(() =>
|
|
409
|
+
const outputEventIds = normalizedOutputs.map(() => idFactory.mintEventId());
|
|
410
410
|
const planRes = (0, ack_advance_append_plan_js_1.buildAckAdvanceAppendPlanV1)({
|
|
411
411
|
sessionId: String(sessionId),
|
|
412
412
|
runId: String(runId),
|
|
@@ -534,11 +534,11 @@ function parseAckTokenOrFail(raw, keyring, hmac, base64url) {
|
|
|
534
534
|
}
|
|
535
535
|
return { ok: true, token: parsedRes.value };
|
|
536
536
|
}
|
|
537
|
-
function newAttemptId() {
|
|
538
|
-
return
|
|
537
|
+
function newAttemptId(idFactory) {
|
|
538
|
+
return idFactory.mintAttemptId();
|
|
539
539
|
}
|
|
540
|
-
function attemptIdForNextNode(parentAttemptId) {
|
|
541
|
-
return (0,
|
|
540
|
+
function attemptIdForNextNode(parentAttemptId, sha256) {
|
|
541
|
+
return (0, attempt_id_derivation_js_1.deriveChildAttemptId)(parentAttemptId, sha256);
|
|
542
542
|
}
|
|
543
543
|
function signTokenOrErr(args) {
|
|
544
544
|
const bytes = (0, index_js_2.encodeTokenPayloadV1)(args.payload);
|
|
@@ -630,7 +630,14 @@ function executeStartWorkflow(input, ctx) {
|
|
|
630
630
|
if (!ctx.v2) {
|
|
631
631
|
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 tools disabled', suggestion: 'Enable v2Tools flag' });
|
|
632
632
|
}
|
|
633
|
-
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, crypto, hmac, base64url } = ctx.v2;
|
|
633
|
+
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, crypto, hmac, base64url, idFactory } = ctx.v2;
|
|
634
|
+
if (!idFactory) {
|
|
635
|
+
return (0, neverthrow_1.errAsync)({
|
|
636
|
+
kind: 'precondition_failed',
|
|
637
|
+
message: 'v2 context missing idFactory',
|
|
638
|
+
suggestion: 'Reinitialize v2 tool context (idFactory must be provided when v2Tools are enabled).',
|
|
639
|
+
});
|
|
640
|
+
}
|
|
634
641
|
const ctxCheck = checkContextBudget({ tool: 'start_workflow', context: input.context });
|
|
635
642
|
if (!ctxCheck.ok)
|
|
636
643
|
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: ctxCheck.error });
|
|
@@ -678,9 +685,9 @@ function executeStartWorkflow(input, ctx) {
|
|
|
678
685
|
});
|
|
679
686
|
})
|
|
680
687
|
.andThen(({ workflow, firstStep, workflowHash, pinnedWorkflow }) => {
|
|
681
|
-
const sessionId =
|
|
682
|
-
const runId =
|
|
683
|
-
const nodeId =
|
|
688
|
+
const sessionId = idFactory.mintSessionId();
|
|
689
|
+
const runId = idFactory.mintRunId();
|
|
690
|
+
const nodeId = idFactory.mintNodeId();
|
|
684
691
|
const snapshot = {
|
|
685
692
|
v: 1,
|
|
686
693
|
kind: 'execution_snapshot',
|
|
@@ -697,9 +704,9 @@ function executeStartWorkflow(input, ctx) {
|
|
|
697
704
|
return snapshotStore.putExecutionSnapshotV1(snapshot)
|
|
698
705
|
.mapErr((cause) => ({ kind: 'snapshot_creation_failed', cause }))
|
|
699
706
|
.andThen((snapshotRef) => {
|
|
700
|
-
const evtSessionCreated =
|
|
701
|
-
const evtRunStarted =
|
|
702
|
-
const evtNodeCreated =
|
|
707
|
+
const evtSessionCreated = idFactory.mintEventId();
|
|
708
|
+
const evtRunStarted = idFactory.mintEventId();
|
|
709
|
+
const evtNodeCreated = idFactory.mintEventId();
|
|
703
710
|
return gate.withHealthySessionLock(sessionId, (lock) => {
|
|
704
711
|
const eventsArray = [
|
|
705
712
|
{
|
|
@@ -768,7 +775,7 @@ function executeStartWorkflow(input, ctx) {
|
|
|
768
775
|
nodeId,
|
|
769
776
|
workflowHash,
|
|
770
777
|
};
|
|
771
|
-
const attemptId = newAttemptId();
|
|
778
|
+
const attemptId = newAttemptId(idFactory);
|
|
772
779
|
const ackPayload = {
|
|
773
780
|
tokenVersion: 1,
|
|
774
781
|
tokenKind: 'ack',
|
|
@@ -812,7 +819,14 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
812
819
|
if (!ctx.v2) {
|
|
813
820
|
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 tools disabled', suggestion: 'Enable v2Tools flag' });
|
|
814
821
|
}
|
|
815
|
-
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, crypto, hmac, base64url } = ctx.v2;
|
|
822
|
+
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, sha256, crypto, hmac, base64url, idFactory } = ctx.v2;
|
|
823
|
+
if (!sha256 || !idFactory) {
|
|
824
|
+
return (0, neverthrow_1.errAsync)({
|
|
825
|
+
kind: 'precondition_failed',
|
|
826
|
+
message: 'v2 context missing required dependencies',
|
|
827
|
+
suggestion: 'Reinitialize v2 tool context (sha256 and idFactory must be provided when v2Tools are enabled).',
|
|
828
|
+
});
|
|
829
|
+
}
|
|
816
830
|
const stateRes = parseStateTokenOrFail(input.stateToken, keyring, hmac, base64url);
|
|
817
831
|
if (!stateRes.ok)
|
|
818
832
|
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: stateRes.failure });
|
|
@@ -864,7 +878,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
864
878
|
const engineState = snapshot.enginePayload.engineState;
|
|
865
879
|
const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
|
|
866
880
|
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(engineState);
|
|
867
|
-
const attemptId = newAttemptId();
|
|
881
|
+
const attemptId = newAttemptId(idFactory);
|
|
868
882
|
const ackTokenRes = signTokenOrErr({
|
|
869
883
|
unsignedPrefix: 'ack.v1.',
|
|
870
884
|
payload: { tokenVersion: 1, tokenKind: 'ack', sessionId, runId, nodeId, attemptId },
|
|
@@ -963,6 +977,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
963
977
|
pinnedWorkflow,
|
|
964
978
|
snapshotStore,
|
|
965
979
|
keyring,
|
|
980
|
+
sha256,
|
|
966
981
|
hmac,
|
|
967
982
|
base64url,
|
|
968
983
|
});
|
|
@@ -986,6 +1001,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
986
1001
|
pinnedWorkflow,
|
|
987
1002
|
snapshotStore,
|
|
988
1003
|
sessionStore,
|
|
1004
|
+
idFactory,
|
|
989
1005
|
}).andThen(() => sessionStore
|
|
990
1006
|
.load(sessionId)
|
|
991
1007
|
.map((truthAfter) => ({ kind: 'replay', truth: truthAfter, recordedEvent: null })));
|
|
@@ -1035,6 +1051,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
1035
1051
|
pinnedWorkflow,
|
|
1036
1052
|
snapshotStore,
|
|
1037
1053
|
keyring,
|
|
1054
|
+
sha256,
|
|
1038
1055
|
hmac,
|
|
1039
1056
|
base64url,
|
|
1040
1057
|
});
|
|
@@ -65,7 +65,7 @@ async function handleWorkflowGet(input, ctx) {
|
|
|
65
65
|
try {
|
|
66
66
|
const { createGetWorkflow } = await Promise.resolve().then(() => __importStar(require('../../application/use-cases/get-workflow.js')));
|
|
67
67
|
const getWorkflowUseCase = createGetWorkflow(ctx.workflowService);
|
|
68
|
-
const result = await withTimeout(getWorkflowUseCase(input.
|
|
68
|
+
const result = await withTimeout(getWorkflowUseCase(input.workflowId, input.mode), TIMEOUT_MS, 'workflow_get');
|
|
69
69
|
if (result.isErr()) {
|
|
70
70
|
const mapped = (0, error_mapper_js_1.mapDomainErrorToToolError)(result.error);
|
|
71
71
|
return mapped;
|
package/dist/mcp/server.js
CHANGED
|
@@ -42,6 +42,7 @@ const types_js_1 = require("./types.js");
|
|
|
42
42
|
const tool_factory_js_1 = require("./tool-factory.js");
|
|
43
43
|
const workflow_next_prevalidate_js_1 = require("./validation/workflow-next-prevalidate.js");
|
|
44
44
|
const bounded_json_js_1 = require("./validation/bounded-json.js");
|
|
45
|
+
const index_js_1 = require("./validation/index.js");
|
|
45
46
|
const tools_js_1 = require("./tools.js");
|
|
46
47
|
const tool_registry_js_1 = require("./v2/tool-registry.js");
|
|
47
48
|
const workflow_js_1 = require("./handlers/workflow.js");
|
|
@@ -94,18 +95,22 @@ async function createToolContext() {
|
|
|
94
95
|
console.error('[FeatureFlags] v2 tools disabled due to keyring initialization failure');
|
|
95
96
|
}
|
|
96
97
|
else {
|
|
98
|
+
const sha256 = container_js_1.container.resolve(tokens_js_1.DI.V2.Sha256);
|
|
97
99
|
const crypto = container_js_1.container.resolve(tokens_js_1.DI.V2.Crypto);
|
|
98
100
|
const hmac = container_js_1.container.resolve(tokens_js_1.DI.V2.HmacSha256);
|
|
99
101
|
const base64url = container_js_1.container.resolve(tokens_js_1.DI.V2.Base64Url);
|
|
102
|
+
const idFactory = container_js_1.container.resolve(tokens_js_1.DI.V2.IdFactory);
|
|
100
103
|
v2 = {
|
|
101
104
|
gate,
|
|
102
105
|
sessionStore,
|
|
103
106
|
snapshotStore,
|
|
104
107
|
pinnedStore,
|
|
105
108
|
keyring: keyringResult.value,
|
|
109
|
+
sha256,
|
|
106
110
|
crypto,
|
|
107
111
|
hmac,
|
|
108
112
|
base64url,
|
|
113
|
+
idFactory,
|
|
109
114
|
};
|
|
110
115
|
console.error('[FeatureFlags] v2 tools enabled');
|
|
111
116
|
}
|
|
@@ -133,11 +138,14 @@ function createHandler(schema, handler) {
|
|
|
133
138
|
return async (args, ctx) => {
|
|
134
139
|
const parseResult = schema.safeParse(args);
|
|
135
140
|
if (!parseResult.success) {
|
|
141
|
+
const suggestionResult = (0, index_js_1.generateSuggestions)(args, schema, index_js_1.DEFAULT_SUGGESTION_CONFIG);
|
|
142
|
+
const suggestionDetails = (0, index_js_1.formatSuggestionDetails)(suggestionResult);
|
|
136
143
|
return toMcpResult((0, types_js_1.errNotRetryable)('VALIDATION_ERROR', 'Invalid input', {
|
|
137
144
|
validationErrors: parseResult.error.errors.map(e => ({
|
|
138
145
|
path: e.path.join('.'),
|
|
139
146
|
message: e.message,
|
|
140
147
|
})),
|
|
148
|
+
...suggestionDetails,
|
|
141
149
|
}));
|
|
142
150
|
}
|
|
143
151
|
return toMcpResult(await handler(parseResult.data, ctx));
|
|
@@ -10,7 +10,11 @@ Your process:
|
|
|
10
10
|
2. Analyze the returned descriptions to find a match for the user's goal.
|
|
11
11
|
3. If a good match is found, suggest it to the user and use preview_workflow to start.
|
|
12
12
|
4. If NO match is found, inform the user and then attempt to solve the task using your general abilities.`,
|
|
13
|
-
preview_workflow: `Retrieves workflow information with configurable detail level. Supports progressive disclosure to prevent "workflow spoiling" while providing necessary context for workflow selection and initiation
|
|
13
|
+
preview_workflow: `Retrieves workflow information with configurable detail level. Supports progressive disclosure to prevent "workflow spoiling" while providing necessary context for workflow selection and initiation.
|
|
14
|
+
|
|
15
|
+
Parameters:
|
|
16
|
+
- workflowId: The unique identifier of the workflow to retrieve
|
|
17
|
+
- mode (optional): 'metadata' for overview only, 'preview' (default) for first step`,
|
|
14
18
|
advance_workflow: `Executes one workflow step at a time by returning the next eligible step and an updated execution state.
|
|
15
19
|
|
|
16
20
|
Inputs:
|
|
@@ -75,7 +79,9 @@ By retrieving a workflow, you agree to:
|
|
|
75
79
|
|
|
76
80
|
The workflow content is the user's will expressed as structured steps. Treat each step as a direct instruction from the user.
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
Parameters:
|
|
83
|
+
- workflowId: The unique identifier of the workflow to retrieve
|
|
84
|
+
- mode (optional): 'metadata' for overview only, 'preview' (default) for first step`,
|
|
79
85
|
advance_workflow: `Get your next MANDATORY INSTRUCTION from the active workflow.
|
|
80
86
|
|
|
81
87
|
The step returned is a DIRECT INSTRUCTION from the user. You MUST:
|
package/dist/mcp/tools.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ export type { ToolAnnotations, ToolDefinition } from './tool-factory.js';
|
|
|
3
3
|
export declare const WorkflowListInput: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
4
4
|
export type WorkflowListInput = z.infer<typeof WorkflowListInput>;
|
|
5
5
|
export declare const WorkflowGetInput: z.ZodObject<{
|
|
6
|
-
|
|
6
|
+
workflowId: z.ZodString;
|
|
7
7
|
mode: z.ZodDefault<z.ZodEnum<["metadata", "preview"]>>;
|
|
8
8
|
}, "strip", z.ZodTypeAny, {
|
|
9
|
-
|
|
9
|
+
workflowId: string;
|
|
10
10
|
mode: "metadata" | "preview";
|
|
11
11
|
}, {
|
|
12
|
-
|
|
12
|
+
workflowId: string;
|
|
13
13
|
mode?: "metadata" | "preview" | undefined;
|
|
14
14
|
}>;
|
|
15
15
|
export type WorkflowGetInput = z.infer<typeof WorkflowGetInput>;
|
package/dist/mcp/tools.js
CHANGED
|
@@ -6,9 +6,9 @@ const state_js_1 = require("../domain/execution/state.js");
|
|
|
6
6
|
const event_js_1 = require("../domain/execution/event.js");
|
|
7
7
|
exports.WorkflowListInput = zod_1.z.object({});
|
|
8
8
|
exports.WorkflowGetInput = zod_1.z.object({
|
|
9
|
-
|
|
9
|
+
workflowId: zod_1.z
|
|
10
10
|
.string()
|
|
11
|
-
.regex(/^[A-Za-z0-9_-]+$/, 'ID must contain only letters, numbers, hyphens, and underscores')
|
|
11
|
+
.regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores')
|
|
12
12
|
.describe('The unique identifier of the workflow to retrieve'),
|
|
13
13
|
mode: zod_1.z
|
|
14
14
|
.enum(['metadata', 'preview'])
|
|
@@ -97,6 +97,7 @@ exports.WORKFLOW_TOOL_TITLES = {
|
|
|
97
97
|
exports.CreateSessionInput = zod_1.z.object({
|
|
98
98
|
workflowId: zod_1.z
|
|
99
99
|
.string()
|
|
100
|
+
.regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores')
|
|
100
101
|
.describe('Workflow identifier (e.g., "bug-investigation", "mr-review")'),
|
|
101
102
|
sessionId: zod_1.z
|
|
102
103
|
.string()
|
|
@@ -107,14 +108,14 @@ exports.CreateSessionInput = zod_1.z.object({
|
|
|
107
108
|
.describe('Initial session data. Can include dashboard, phases, etc.'),
|
|
108
109
|
});
|
|
109
110
|
exports.UpdateSessionInput = zod_1.z.object({
|
|
110
|
-
workflowId: zod_1.z.string().describe('Workflow identifier'),
|
|
111
|
+
workflowId: zod_1.z.string().regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores').describe('Workflow identifier'),
|
|
111
112
|
sessionId: zod_1.z.string().describe('Session identifier'),
|
|
112
113
|
updates: zod_1.z
|
|
113
114
|
.record(zod_1.z.unknown())
|
|
114
115
|
.describe('Data to merge into session. Supports nested updates via dot notation.'),
|
|
115
116
|
});
|
|
116
117
|
exports.ReadSessionInput = zod_1.z.object({
|
|
117
|
-
workflowId: zod_1.z.string().describe('Workflow identifier'),
|
|
118
|
+
workflowId: zod_1.z.string().regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores').describe('Workflow identifier'),
|
|
118
119
|
sessionId: zod_1.z.string().describe('Session identifier'),
|
|
119
120
|
path: zod_1.z
|
|
120
121
|
.string()
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -8,9 +8,11 @@ import type { SessionEventLogAppendStorePortV2, SessionEventLogReadonlyStorePort
|
|
|
8
8
|
import type { SnapshotStorePortV2 } from '../v2/ports/snapshot-store.port.js';
|
|
9
9
|
import type { PinnedWorkflowStorePortV2 } from '../v2/ports/pinned-workflow-store.port.js';
|
|
10
10
|
import type { KeyringV1 } from '../v2/ports/keyring.port.js';
|
|
11
|
+
import type { Sha256PortV2 } from '../v2/ports/sha256.port.js';
|
|
11
12
|
import type { CryptoPortV2 } from '../v2/durable-core/canonical/hashing.js';
|
|
12
13
|
import type { HmacSha256PortV2 } from '../v2/ports/hmac-sha256.port.js';
|
|
13
14
|
import type { Base64UrlPortV2 } from '../v2/ports/base64url.port.js';
|
|
15
|
+
import type { IdFactoryV2 } from '../v2/infra/local/id-factory/index.js';
|
|
14
16
|
import type { JsonValue } from './output-schemas.js';
|
|
15
17
|
export interface SessionHealthDetails {
|
|
16
18
|
readonly health: SessionHealthV2;
|
|
@@ -48,9 +50,11 @@ export interface V2Dependencies {
|
|
|
48
50
|
readonly snapshotStore: SnapshotStorePortV2;
|
|
49
51
|
readonly pinnedStore: PinnedWorkflowStorePortV2;
|
|
50
52
|
readonly keyring: KeyringV1;
|
|
53
|
+
readonly sha256: Sha256PortV2;
|
|
51
54
|
readonly crypto: CryptoPortV2;
|
|
52
55
|
readonly hmac: HmacSha256PortV2;
|
|
53
56
|
readonly base64url: Base64UrlPortV2;
|
|
57
|
+
readonly idFactory: IdFactoryV2;
|
|
54
58
|
}
|
|
55
59
|
export interface ToolContext {
|
|
56
60
|
readonly workflowService: WorkflowService;
|
package/dist/mcp/v2/tools.js
CHANGED
|
@@ -4,11 +4,11 @@ exports.V2_TOOL_ANNOTATIONS = exports.V2_TOOL_TITLES = exports.V2ContinueWorkflo
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
exports.V2ListWorkflowsInput = zod_1.z.object({});
|
|
6
6
|
exports.V2InspectWorkflowInput = zod_1.z.object({
|
|
7
|
-
workflowId: zod_1.z.string().min(1).describe('The workflow ID to inspect'),
|
|
7
|
+
workflowId: zod_1.z.string().min(1).regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores').describe('The workflow ID to inspect'),
|
|
8
8
|
mode: zod_1.z.enum(['metadata', 'preview']).default('preview').describe('Detail level'),
|
|
9
9
|
});
|
|
10
10
|
exports.V2StartWorkflowInput = zod_1.z.object({
|
|
11
|
-
workflowId: zod_1.z.string().min(1).describe('The workflow ID to start'),
|
|
11
|
+
workflowId: zod_1.z.string().min(1).regex(/^[A-Za-z0-9_-]+$/, 'Workflow ID must contain only letters, numbers, hyphens, and underscores').describe('The workflow ID to start'),
|
|
12
12
|
context: zod_1.z.record(zod_1.z.unknown()).optional().describe('External context inputs (conditions, parameters). Do not include workflow progress state.'),
|
|
13
13
|
});
|
|
14
14
|
exports.V2ContinueWorkflowInput = zod_1.z.object({
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { Similarity, ValidationSuggestion, UnknownKeySuggestion, MissingRequiredSuggestion, InvalidEnumSuggestion, SuggestionResult, } from './suggestion-types.js';
|
|
2
|
+
export { similarity, EMPTY_SUGGESTION_RESULT, isUnknownKeySuggestion, isMissingRequiredSuggestion, isInvalidEnumSuggestion, } from './suggestion-types.js';
|
|
3
|
+
export type { SuggestionConfig } from './suggestion-config.js';
|
|
4
|
+
export { DEFAULT_SUGGESTION_CONFIG, MINIMAL_SUGGESTION_CONFIG } from './suggestion-config.js';
|
|
5
|
+
export { levenshteinDistance, computeSimilarity, computeSimilarityIgnoreCase, findClosestMatch, findAllMatches, type ClosestMatch, } from './string-similarity.js';
|
|
6
|
+
export { extractExpectedKeys, extractRequiredKeys, findUnknownKeys, findMissingRequiredKeys, generateExampleValue, generateTemplate, extractEnumValues, } from './schema-introspection.js';
|
|
7
|
+
export { generateSuggestions, formatSuggestionDetails, hasSuggestions, } from './suggestion-generator.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasSuggestions = exports.formatSuggestionDetails = exports.generateSuggestions = exports.extractEnumValues = exports.generateTemplate = exports.generateExampleValue = exports.findMissingRequiredKeys = exports.findUnknownKeys = exports.extractRequiredKeys = exports.extractExpectedKeys = exports.findAllMatches = exports.findClosestMatch = exports.computeSimilarityIgnoreCase = exports.computeSimilarity = exports.levenshteinDistance = exports.MINIMAL_SUGGESTION_CONFIG = exports.DEFAULT_SUGGESTION_CONFIG = exports.isInvalidEnumSuggestion = exports.isMissingRequiredSuggestion = exports.isUnknownKeySuggestion = exports.EMPTY_SUGGESTION_RESULT = exports.similarity = void 0;
|
|
4
|
+
var suggestion_types_js_1 = require("./suggestion-types.js");
|
|
5
|
+
Object.defineProperty(exports, "similarity", { enumerable: true, get: function () { return suggestion_types_js_1.similarity; } });
|
|
6
|
+
Object.defineProperty(exports, "EMPTY_SUGGESTION_RESULT", { enumerable: true, get: function () { return suggestion_types_js_1.EMPTY_SUGGESTION_RESULT; } });
|
|
7
|
+
Object.defineProperty(exports, "isUnknownKeySuggestion", { enumerable: true, get: function () { return suggestion_types_js_1.isUnknownKeySuggestion; } });
|
|
8
|
+
Object.defineProperty(exports, "isMissingRequiredSuggestion", { enumerable: true, get: function () { return suggestion_types_js_1.isMissingRequiredSuggestion; } });
|
|
9
|
+
Object.defineProperty(exports, "isInvalidEnumSuggestion", { enumerable: true, get: function () { return suggestion_types_js_1.isInvalidEnumSuggestion; } });
|
|
10
|
+
var suggestion_config_js_1 = require("./suggestion-config.js");
|
|
11
|
+
Object.defineProperty(exports, "DEFAULT_SUGGESTION_CONFIG", { enumerable: true, get: function () { return suggestion_config_js_1.DEFAULT_SUGGESTION_CONFIG; } });
|
|
12
|
+
Object.defineProperty(exports, "MINIMAL_SUGGESTION_CONFIG", { enumerable: true, get: function () { return suggestion_config_js_1.MINIMAL_SUGGESTION_CONFIG; } });
|
|
13
|
+
var string_similarity_js_1 = require("./string-similarity.js");
|
|
14
|
+
Object.defineProperty(exports, "levenshteinDistance", { enumerable: true, get: function () { return string_similarity_js_1.levenshteinDistance; } });
|
|
15
|
+
Object.defineProperty(exports, "computeSimilarity", { enumerable: true, get: function () { return string_similarity_js_1.computeSimilarity; } });
|
|
16
|
+
Object.defineProperty(exports, "computeSimilarityIgnoreCase", { enumerable: true, get: function () { return string_similarity_js_1.computeSimilarityIgnoreCase; } });
|
|
17
|
+
Object.defineProperty(exports, "findClosestMatch", { enumerable: true, get: function () { return string_similarity_js_1.findClosestMatch; } });
|
|
18
|
+
Object.defineProperty(exports, "findAllMatches", { enumerable: true, get: function () { return string_similarity_js_1.findAllMatches; } });
|
|
19
|
+
var schema_introspection_js_1 = require("./schema-introspection.js");
|
|
20
|
+
Object.defineProperty(exports, "extractExpectedKeys", { enumerable: true, get: function () { return schema_introspection_js_1.extractExpectedKeys; } });
|
|
21
|
+
Object.defineProperty(exports, "extractRequiredKeys", { enumerable: true, get: function () { return schema_introspection_js_1.extractRequiredKeys; } });
|
|
22
|
+
Object.defineProperty(exports, "findUnknownKeys", { enumerable: true, get: function () { return schema_introspection_js_1.findUnknownKeys; } });
|
|
23
|
+
Object.defineProperty(exports, "findMissingRequiredKeys", { enumerable: true, get: function () { return schema_introspection_js_1.findMissingRequiredKeys; } });
|
|
24
|
+
Object.defineProperty(exports, "generateExampleValue", { enumerable: true, get: function () { return schema_introspection_js_1.generateExampleValue; } });
|
|
25
|
+
Object.defineProperty(exports, "generateTemplate", { enumerable: true, get: function () { return schema_introspection_js_1.generateTemplate; } });
|
|
26
|
+
Object.defineProperty(exports, "extractEnumValues", { enumerable: true, get: function () { return schema_introspection_js_1.extractEnumValues; } });
|
|
27
|
+
var suggestion_generator_js_1 = require("./suggestion-generator.js");
|
|
28
|
+
Object.defineProperty(exports, "generateSuggestions", { enumerable: true, get: function () { return suggestion_generator_js_1.generateSuggestions; } });
|
|
29
|
+
Object.defineProperty(exports, "formatSuggestionDetails", { enumerable: true, get: function () { return suggestion_generator_js_1.formatSuggestionDetails; } });
|
|
30
|
+
Object.defineProperty(exports, "hasSuggestions", { enumerable: true, get: function () { return suggestion_generator_js_1.hasSuggestions; } });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare function extractExpectedKeys(schema: z.ZodType): readonly string[];
|
|
3
|
+
export declare function extractRequiredKeys(schema: z.ZodType): readonly string[];
|
|
4
|
+
export declare function findUnknownKeys(args: unknown, schema: z.ZodType): readonly string[];
|
|
5
|
+
export declare function findMissingRequiredKeys(args: unknown, schema: z.ZodType): readonly string[];
|
|
6
|
+
export declare function generateExampleValue(schema: z.ZodType, depth?: number, maxDepth?: number): unknown;
|
|
7
|
+
export declare function generateTemplate(schema: z.ZodType, maxDepth?: number): Readonly<Record<string, unknown>> | null;
|
|
8
|
+
export declare function extractEnumValues(schema: z.ZodType, path: string): readonly string[];
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractExpectedKeys = extractExpectedKeys;
|
|
4
|
+
exports.extractRequiredKeys = extractRequiredKeys;
|
|
5
|
+
exports.findUnknownKeys = findUnknownKeys;
|
|
6
|
+
exports.findMissingRequiredKeys = findMissingRequiredKeys;
|
|
7
|
+
exports.generateExampleValue = generateExampleValue;
|
|
8
|
+
exports.generateTemplate = generateTemplate;
|
|
9
|
+
exports.extractEnumValues = extractEnumValues;
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
function extractExpectedKeys(schema) {
|
|
12
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
13
|
+
return Object.keys(schema._def.shape());
|
|
14
|
+
}
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
function extractRequiredKeys(schema) {
|
|
18
|
+
if (!(schema instanceof zod_1.z.ZodObject)) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
const shape = schema._def.shape();
|
|
22
|
+
const required = [];
|
|
23
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
24
|
+
const field = value;
|
|
25
|
+
if (!(field instanceof zod_1.z.ZodOptional) && !(field instanceof zod_1.z.ZodDefault)) {
|
|
26
|
+
required.push(key);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return required;
|
|
30
|
+
}
|
|
31
|
+
function findUnknownKeys(args, schema) {
|
|
32
|
+
if (typeof args !== 'object' || args === null) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const expectedKeys = new Set(extractExpectedKeys(schema));
|
|
36
|
+
const providedKeys = Object.keys(args);
|
|
37
|
+
return providedKeys.filter(key => !expectedKeys.has(key));
|
|
38
|
+
}
|
|
39
|
+
function findMissingRequiredKeys(args, schema) {
|
|
40
|
+
if (typeof args !== 'object' || args === null) {
|
|
41
|
+
return extractRequiredKeys(schema);
|
|
42
|
+
}
|
|
43
|
+
const providedKeys = new Set(Object.keys(args));
|
|
44
|
+
const requiredKeys = extractRequiredKeys(schema);
|
|
45
|
+
return requiredKeys.filter(key => !providedKeys.has(key));
|
|
46
|
+
}
|
|
47
|
+
function generateExampleValue(schema, depth = 0, maxDepth = 3) {
|
|
48
|
+
if (depth > maxDepth) {
|
|
49
|
+
return '...';
|
|
50
|
+
}
|
|
51
|
+
if (schema instanceof zod_1.z.ZodDefault) {
|
|
52
|
+
return schema._def.defaultValue();
|
|
53
|
+
}
|
|
54
|
+
if (schema instanceof zod_1.z.ZodOptional) {
|
|
55
|
+
return generateExampleValue(schema._def.innerType, depth, maxDepth);
|
|
56
|
+
}
|
|
57
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
58
|
+
const shape = schema._def.shape();
|
|
59
|
+
const result = {};
|
|
60
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
61
|
+
const field = value;
|
|
62
|
+
if (field instanceof zod_1.z.ZodOptional)
|
|
63
|
+
continue;
|
|
64
|
+
result[key] = generateExampleValue(field, depth + 1, maxDepth);
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
if (schema instanceof zod_1.z.ZodDiscriminatedUnion) {
|
|
69
|
+
const options = schema._def.options;
|
|
70
|
+
if (options.length > 0) {
|
|
71
|
+
return generateExampleValue(options[0], depth + 1, maxDepth);
|
|
72
|
+
}
|
|
73
|
+
return {};
|
|
74
|
+
}
|
|
75
|
+
if (schema instanceof zod_1.z.ZodString) {
|
|
76
|
+
const description = schema._def.description;
|
|
77
|
+
if (description) {
|
|
78
|
+
return `<${description}>`;
|
|
79
|
+
}
|
|
80
|
+
return '<string>';
|
|
81
|
+
}
|
|
82
|
+
if (schema instanceof zod_1.z.ZodNumber) {
|
|
83
|
+
return '<number>';
|
|
84
|
+
}
|
|
85
|
+
if (schema instanceof zod_1.z.ZodBoolean) {
|
|
86
|
+
return '<boolean>';
|
|
87
|
+
}
|
|
88
|
+
if (schema instanceof zod_1.z.ZodArray) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
if (schema instanceof zod_1.z.ZodEnum) {
|
|
92
|
+
const values = schema._def.values;
|
|
93
|
+
if (values.length > 0) {
|
|
94
|
+
return values[0];
|
|
95
|
+
}
|
|
96
|
+
return '<enum>';
|
|
97
|
+
}
|
|
98
|
+
if (schema instanceof zod_1.z.ZodLiteral) {
|
|
99
|
+
return schema._def.value;
|
|
100
|
+
}
|
|
101
|
+
if (schema instanceof zod_1.z.ZodRecord) {
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
104
|
+
if (schema instanceof zod_1.z.ZodUnknown || schema instanceof zod_1.z.ZodAny) {
|
|
105
|
+
return '<any>';
|
|
106
|
+
}
|
|
107
|
+
if (schema instanceof zod_1.z.ZodEffects) {
|
|
108
|
+
return generateExampleValue(schema._def.schema, depth, maxDepth);
|
|
109
|
+
}
|
|
110
|
+
return '<unknown>';
|
|
111
|
+
}
|
|
112
|
+
function generateTemplate(schema, maxDepth = 3) {
|
|
113
|
+
if (!(schema instanceof zod_1.z.ZodObject)) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const example = generateExampleValue(schema, 0, maxDepth);
|
|
117
|
+
if (typeof example === 'object' && example !== null) {
|
|
118
|
+
return example;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function extractEnumValues(schema, path) {
|
|
123
|
+
const parts = path.split('.');
|
|
124
|
+
let current = schema;
|
|
125
|
+
for (const part of parts) {
|
|
126
|
+
if (current instanceof zod_1.z.ZodObject) {
|
|
127
|
+
const shape = current._def.shape();
|
|
128
|
+
const field = shape[part];
|
|
129
|
+
if (!field)
|
|
130
|
+
return [];
|
|
131
|
+
current = field;
|
|
132
|
+
}
|
|
133
|
+
else if (current instanceof zod_1.z.ZodOptional) {
|
|
134
|
+
current = current._def.innerType;
|
|
135
|
+
if (current instanceof zod_1.z.ZodObject) {
|
|
136
|
+
const shape = current._def.shape();
|
|
137
|
+
const field = shape[part];
|
|
138
|
+
if (!field)
|
|
139
|
+
return [];
|
|
140
|
+
current = field;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (current instanceof zod_1.z.ZodOptional || current instanceof zod_1.z.ZodDefault) {
|
|
151
|
+
current = current._def.innerType;
|
|
152
|
+
}
|
|
153
|
+
if (current instanceof zod_1.z.ZodEnum) {
|
|
154
|
+
return current._def.values;
|
|
155
|
+
}
|
|
156
|
+
if (current instanceof zod_1.z.ZodLiteral) {
|
|
157
|
+
const value = current._def.value;
|
|
158
|
+
if (typeof value === 'string') {
|
|
159
|
+
return [value];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Similarity } from './suggestion-types.js';
|
|
2
|
+
export declare function levenshteinDistance(a: string, b: string): number;
|
|
3
|
+
export declare function computeSimilarity(a: string, b: string): Similarity;
|
|
4
|
+
export declare function computeSimilarityIgnoreCase(a: string, b: string): Similarity;
|
|
5
|
+
export interface ClosestMatch {
|
|
6
|
+
readonly match: string;
|
|
7
|
+
readonly score: Similarity;
|
|
8
|
+
}
|
|
9
|
+
export declare function findClosestMatch(input: string, candidates: readonly string[], threshold: Similarity): ClosestMatch | null;
|
|
10
|
+
export declare function findAllMatches(input: string, candidates: readonly string[], threshold: Similarity, limit: number): readonly ClosestMatch[];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.levenshteinDistance = levenshteinDistance;
|
|
4
|
+
exports.computeSimilarity = computeSimilarity;
|
|
5
|
+
exports.computeSimilarityIgnoreCase = computeSimilarityIgnoreCase;
|
|
6
|
+
exports.findClosestMatch = findClosestMatch;
|
|
7
|
+
exports.findAllMatches = findAllMatches;
|
|
8
|
+
const suggestion_types_js_1 = require("./suggestion-types.js");
|
|
9
|
+
function levenshteinDistance(a, b) {
|
|
10
|
+
if (a.length > b.length) {
|
|
11
|
+
[a, b] = [b, a];
|
|
12
|
+
}
|
|
13
|
+
const m = a.length;
|
|
14
|
+
const n = b.length;
|
|
15
|
+
if (m === 0)
|
|
16
|
+
return n;
|
|
17
|
+
if (n === 0)
|
|
18
|
+
return m;
|
|
19
|
+
let prevRow = new Array(m + 1);
|
|
20
|
+
let currRow = new Array(m + 1);
|
|
21
|
+
for (let i = 0; i <= m; i++) {
|
|
22
|
+
prevRow[i] = i;
|
|
23
|
+
}
|
|
24
|
+
for (let j = 1; j <= n; j++) {
|
|
25
|
+
currRow[0] = j;
|
|
26
|
+
for (let i = 1; i <= m; i++) {
|
|
27
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
28
|
+
currRow[i] = Math.min(prevRow[i] + 1, currRow[i - 1] + 1, prevRow[i - 1] + cost);
|
|
29
|
+
}
|
|
30
|
+
[prevRow, currRow] = [currRow, prevRow];
|
|
31
|
+
}
|
|
32
|
+
return prevRow[m];
|
|
33
|
+
}
|
|
34
|
+
function computeSimilarity(a, b) {
|
|
35
|
+
if (a === b)
|
|
36
|
+
return (0, suggestion_types_js_1.similarity)(1);
|
|
37
|
+
if (a.length === 0 || b.length === 0)
|
|
38
|
+
return (0, suggestion_types_js_1.similarity)(0);
|
|
39
|
+
const distance = levenshteinDistance(a, b);
|
|
40
|
+
const maxLength = Math.max(a.length, b.length);
|
|
41
|
+
return (0, suggestion_types_js_1.similarity)(1 - distance / maxLength);
|
|
42
|
+
}
|
|
43
|
+
function computeSimilarityIgnoreCase(a, b) {
|
|
44
|
+
return computeSimilarity(a.toLowerCase(), b.toLowerCase());
|
|
45
|
+
}
|
|
46
|
+
function findClosestMatch(input, candidates, threshold) {
|
|
47
|
+
if (candidates.length === 0)
|
|
48
|
+
return null;
|
|
49
|
+
let bestMatch = null;
|
|
50
|
+
let bestScore = (0, suggestion_types_js_1.similarity)(0);
|
|
51
|
+
for (const candidate of candidates) {
|
|
52
|
+
const score = computeSimilarityIgnoreCase(input, candidate);
|
|
53
|
+
if (score > bestScore && score >= threshold) {
|
|
54
|
+
bestScore = score;
|
|
55
|
+
bestMatch = candidate;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (bestMatch === null)
|
|
59
|
+
return null;
|
|
60
|
+
return { match: bestMatch, score: bestScore };
|
|
61
|
+
}
|
|
62
|
+
function findAllMatches(input, candidates, threshold, limit) {
|
|
63
|
+
const matches = [];
|
|
64
|
+
for (const candidate of candidates) {
|
|
65
|
+
const score = computeSimilarityIgnoreCase(input, candidate);
|
|
66
|
+
if (score >= threshold) {
|
|
67
|
+
matches.push({ match: candidate, score });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
matches.sort((a, b) => {
|
|
71
|
+
if (b.score !== a.score)
|
|
72
|
+
return b.score - a.score;
|
|
73
|
+
return a.match.localeCompare(b.match);
|
|
74
|
+
});
|
|
75
|
+
return matches.slice(0, limit);
|
|
76
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Similarity } from './suggestion-types.js';
|
|
2
|
+
export interface SuggestionConfig {
|
|
3
|
+
readonly similarityThreshold: Similarity;
|
|
4
|
+
readonly maxSuggestions: number;
|
|
5
|
+
readonly includeTemplate: boolean;
|
|
6
|
+
readonly maxTemplateDepth: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const DEFAULT_SUGGESTION_CONFIG: SuggestionConfig;
|
|
9
|
+
export declare const MINIMAL_SUGGESTION_CONFIG: SuggestionConfig;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MINIMAL_SUGGESTION_CONFIG = exports.DEFAULT_SUGGESTION_CONFIG = void 0;
|
|
4
|
+
const suggestion_types_js_1 = require("./suggestion-types.js");
|
|
5
|
+
exports.DEFAULT_SUGGESTION_CONFIG = {
|
|
6
|
+
similarityThreshold: (0, suggestion_types_js_1.similarity)(0.6),
|
|
7
|
+
maxSuggestions: 3,
|
|
8
|
+
includeTemplate: true,
|
|
9
|
+
maxTemplateDepth: 3,
|
|
10
|
+
};
|
|
11
|
+
exports.MINIMAL_SUGGESTION_CONFIG = {
|
|
12
|
+
similarityThreshold: (0, suggestion_types_js_1.similarity)(0.7),
|
|
13
|
+
maxSuggestions: 1,
|
|
14
|
+
includeTemplate: false,
|
|
15
|
+
maxTemplateDepth: 1,
|
|
16
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { SuggestionConfig } from './suggestion-config.js';
|
|
3
|
+
import type { SuggestionResult } from './suggestion-types.js';
|
|
4
|
+
export declare function generateSuggestions(args: unknown, schema: z.ZodType, config: SuggestionConfig): SuggestionResult;
|
|
5
|
+
export declare function formatSuggestionDetails(result: SuggestionResult): Record<string, unknown>;
|
|
6
|
+
export declare function hasSuggestions(result: SuggestionResult): boolean;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSuggestions = generateSuggestions;
|
|
4
|
+
exports.formatSuggestionDetails = formatSuggestionDetails;
|
|
5
|
+
exports.hasSuggestions = hasSuggestions;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const suggestion_types_js_1 = require("./suggestion-types.js");
|
|
8
|
+
const string_similarity_js_1 = require("./string-similarity.js");
|
|
9
|
+
const schema_introspection_js_1 = require("./schema-introspection.js");
|
|
10
|
+
function generateUnknownKeySuggestions(unknownKeys, expectedKeys, config) {
|
|
11
|
+
const suggestions = [];
|
|
12
|
+
for (const unknownKey of unknownKeys) {
|
|
13
|
+
const match = (0, string_similarity_js_1.findClosestMatch)(unknownKey, expectedKeys, config.similarityThreshold);
|
|
14
|
+
if (match) {
|
|
15
|
+
suggestions.push({
|
|
16
|
+
kind: 'unknown_key',
|
|
17
|
+
provided: unknownKey,
|
|
18
|
+
didYouMean: match.match,
|
|
19
|
+
similarity: match.score,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
suggestions.sort((a, b) => b.similarity - a.similarity);
|
|
24
|
+
return suggestions.slice(0, config.maxSuggestions);
|
|
25
|
+
}
|
|
26
|
+
function generateMissingRequiredSuggestions(missingKeys, schema, config) {
|
|
27
|
+
if (!(schema instanceof zod_1.z.ZodObject)) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const shape = schema._def.shape();
|
|
31
|
+
const suggestions = [];
|
|
32
|
+
for (const key of missingKeys) {
|
|
33
|
+
const field = shape[key];
|
|
34
|
+
if (field) {
|
|
35
|
+
suggestions.push({
|
|
36
|
+
kind: 'missing_required',
|
|
37
|
+
param: key,
|
|
38
|
+
example: (0, schema_introspection_js_1.generateExampleValue)(field, 0, config.maxTemplateDepth),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
suggestions.sort((a, b) => a.param.localeCompare(b.param));
|
|
43
|
+
return suggestions.slice(0, config.maxSuggestions);
|
|
44
|
+
}
|
|
45
|
+
function generateSuggestions(args, schema, config) {
|
|
46
|
+
const suggestions = [];
|
|
47
|
+
const expectedKeys = (0, schema_introspection_js_1.extractExpectedKeys)(schema);
|
|
48
|
+
const unknownKeys = (0, schema_introspection_js_1.findUnknownKeys)(args, schema);
|
|
49
|
+
const unknownKeySuggestions = generateUnknownKeySuggestions(unknownKeys, expectedKeys, config);
|
|
50
|
+
suggestions.push(...unknownKeySuggestions);
|
|
51
|
+
const missingKeys = (0, schema_introspection_js_1.findMissingRequiredKeys)(args, schema);
|
|
52
|
+
const missingRequiredSuggestions = generateMissingRequiredSuggestions(missingKeys, schema, config);
|
|
53
|
+
suggestions.push(...missingRequiredSuggestions);
|
|
54
|
+
if (suggestions.length === 0 && !config.includeTemplate) {
|
|
55
|
+
return suggestion_types_js_1.EMPTY_SUGGESTION_RESULT;
|
|
56
|
+
}
|
|
57
|
+
const correctTemplate = config.includeTemplate
|
|
58
|
+
? (0, schema_introspection_js_1.generateTemplate)(schema, config.maxTemplateDepth)
|
|
59
|
+
: null;
|
|
60
|
+
return {
|
|
61
|
+
suggestions,
|
|
62
|
+
correctTemplate,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function formatSuggestionDetails(result) {
|
|
66
|
+
const details = {};
|
|
67
|
+
if (result.suggestions.length > 0) {
|
|
68
|
+
details.suggestions = result.suggestions.map(s => {
|
|
69
|
+
switch (s.kind) {
|
|
70
|
+
case 'unknown_key':
|
|
71
|
+
return {
|
|
72
|
+
kind: s.kind,
|
|
73
|
+
provided: s.provided,
|
|
74
|
+
didYouMean: s.didYouMean,
|
|
75
|
+
similarity: Math.round(s.similarity * 100) / 100,
|
|
76
|
+
};
|
|
77
|
+
case 'missing_required':
|
|
78
|
+
return {
|
|
79
|
+
kind: s.kind,
|
|
80
|
+
param: s.param,
|
|
81
|
+
example: s.example,
|
|
82
|
+
};
|
|
83
|
+
case 'invalid_enum':
|
|
84
|
+
return {
|
|
85
|
+
kind: s.kind,
|
|
86
|
+
path: s.path,
|
|
87
|
+
provided: s.provided,
|
|
88
|
+
didYouMean: s.didYouMean,
|
|
89
|
+
allowedValues: s.allowedValues,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (result.correctTemplate !== null) {
|
|
95
|
+
details.correctTemplate = result.correctTemplate;
|
|
96
|
+
}
|
|
97
|
+
return details;
|
|
98
|
+
}
|
|
99
|
+
function hasSuggestions(result) {
|
|
100
|
+
return result.suggestions.length > 0 || result.correctTemplate !== null;
|
|
101
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type Similarity = number & {
|
|
2
|
+
readonly __brand: 'Similarity';
|
|
3
|
+
};
|
|
4
|
+
export declare function similarity(n: number): Similarity;
|
|
5
|
+
export interface UnknownKeySuggestion {
|
|
6
|
+
readonly kind: 'unknown_key';
|
|
7
|
+
readonly provided: string;
|
|
8
|
+
readonly didYouMean: string;
|
|
9
|
+
readonly similarity: Similarity;
|
|
10
|
+
}
|
|
11
|
+
export interface MissingRequiredSuggestion {
|
|
12
|
+
readonly kind: 'missing_required';
|
|
13
|
+
readonly param: string;
|
|
14
|
+
readonly example: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface InvalidEnumSuggestion {
|
|
17
|
+
readonly kind: 'invalid_enum';
|
|
18
|
+
readonly path: string;
|
|
19
|
+
readonly provided: string;
|
|
20
|
+
readonly didYouMean: string | null;
|
|
21
|
+
readonly allowedValues: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export type ValidationSuggestion = UnknownKeySuggestion | MissingRequiredSuggestion | InvalidEnumSuggestion;
|
|
24
|
+
export interface SuggestionResult {
|
|
25
|
+
readonly suggestions: readonly ValidationSuggestion[];
|
|
26
|
+
readonly correctTemplate: Readonly<Record<string, unknown>> | null;
|
|
27
|
+
}
|
|
28
|
+
export declare const EMPTY_SUGGESTION_RESULT: SuggestionResult;
|
|
29
|
+
export declare function isUnknownKeySuggestion(s: ValidationSuggestion): s is UnknownKeySuggestion;
|
|
30
|
+
export declare function isMissingRequiredSuggestion(s: ValidationSuggestion): s is MissingRequiredSuggestion;
|
|
31
|
+
export declare function isInvalidEnumSuggestion(s: ValidationSuggestion): s is InvalidEnumSuggestion;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EMPTY_SUGGESTION_RESULT = void 0;
|
|
4
|
+
exports.similarity = similarity;
|
|
5
|
+
exports.isUnknownKeySuggestion = isUnknownKeySuggestion;
|
|
6
|
+
exports.isMissingRequiredSuggestion = isMissingRequiredSuggestion;
|
|
7
|
+
exports.isInvalidEnumSuggestion = isInvalidEnumSuggestion;
|
|
8
|
+
function similarity(n) {
|
|
9
|
+
return Math.max(0, Math.min(1, n));
|
|
10
|
+
}
|
|
11
|
+
exports.EMPTY_SUGGESTION_RESULT = {
|
|
12
|
+
suggestions: [],
|
|
13
|
+
correctTemplate: null,
|
|
14
|
+
};
|
|
15
|
+
function isUnknownKeySuggestion(s) {
|
|
16
|
+
return s.kind === 'unknown_key';
|
|
17
|
+
}
|
|
18
|
+
function isMissingRequiredSuggestion(s) {
|
|
19
|
+
return s.kind === 'missing_required';
|
|
20
|
+
}
|
|
21
|
+
function isInvalidEnumSuggestion(s) {
|
|
22
|
+
return s.kind === 'invalid_enum';
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeBase32LowerNoPad = encodeBase32LowerNoPad;
|
|
4
|
+
const BASE32_LOWER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
|
|
5
|
+
function encodeBase32LowerNoPad(bytes) {
|
|
6
|
+
let out = '';
|
|
7
|
+
let buffer = 0n;
|
|
8
|
+
let bits = 0;
|
|
9
|
+
for (const b of bytes) {
|
|
10
|
+
buffer = (buffer << 8n) | BigInt(b);
|
|
11
|
+
bits += 8;
|
|
12
|
+
while (bits >= 5) {
|
|
13
|
+
const shift = BigInt(bits - 5);
|
|
14
|
+
const index = Number((buffer >> shift) & 31n);
|
|
15
|
+
out += BASE32_LOWER_ALPHABET[index];
|
|
16
|
+
bits -= 5;
|
|
17
|
+
if (bits === 0) {
|
|
18
|
+
buffer = 0n;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
buffer = buffer & ((1n << BigInt(bits)) - 1n);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (bits > 0) {
|
|
26
|
+
const index = Number((buffer << BigInt(5 - bits)) & 31n);
|
|
27
|
+
out += BASE32_LOWER_ALPHABET[index];
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveChildAttemptId = deriveChildAttemptId;
|
|
4
|
+
const index_js_1 = require("./index.js");
|
|
5
|
+
const base32_lower_js_1 = require("../encoding/base32-lower.js");
|
|
6
|
+
const PREFIX = 'wr_attempt_next_v1:';
|
|
7
|
+
function hexToBytes(hex) {
|
|
8
|
+
if (hex.length % 2 !== 0) {
|
|
9
|
+
throw new Error('hex string must have even length');
|
|
10
|
+
}
|
|
11
|
+
const out = new Uint8Array(hex.length / 2);
|
|
12
|
+
for (let i = 0; i < out.length; i++) {
|
|
13
|
+
const byteHex = hex.slice(i * 2, i * 2 + 2);
|
|
14
|
+
const n = Number.parseInt(byteHex, 16);
|
|
15
|
+
if (Number.isNaN(n)) {
|
|
16
|
+
throw new Error(`invalid hex byte: ${byteHex}`);
|
|
17
|
+
}
|
|
18
|
+
out[i] = n;
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
const SHA256_DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
23
|
+
function deriveChildAttemptId(parent, sha256) {
|
|
24
|
+
const bytes = new TextEncoder().encode(`${PREFIX}${String(parent)}`);
|
|
25
|
+
const digest = String(sha256.sha256(bytes));
|
|
26
|
+
if (!SHA256_DIGEST_RE.test(digest)) {
|
|
27
|
+
throw new Error(`expected sha256:<64hex> digest, got: ${digest}`);
|
|
28
|
+
}
|
|
29
|
+
const first16 = hexToBytes(digest.slice('sha256:'.length, 'sha256:'.length + 32));
|
|
30
|
+
const suffix = (0, base32_lower_js_1.encodeBase32LowerNoPad)(first16);
|
|
31
|
+
return (0, index_js_1.asAttemptId)(`attempt_${suffix}`);
|
|
32
|
+
}
|
|
@@ -8,10 +8,11 @@ const index_js_1 = require("../ids/index.js");
|
|
|
8
8
|
const sha256DigestSchema = zod_1.z.string().regex(/^sha256:[0-9a-f]{64}$/, 'Expected sha256:<64 hex chars>');
|
|
9
9
|
const workflowHashSchema = sha256DigestSchema.transform((v) => (0, index_js_1.asWorkflowHash)((0, index_js_1.asSha256Digest)(v)));
|
|
10
10
|
const nonEmpty = zod_1.z.string().min(1);
|
|
11
|
-
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
11
|
+
const delimiterSafeId = nonEmpty.regex(/^[^:\s]+$/, 'Expected a delimiter-safe ID (no ":" or whitespace)');
|
|
12
|
+
exports.AttemptIdSchema = delimiterSafeId.transform(index_js_1.asAttemptId);
|
|
13
|
+
exports.SessionIdSchema = delimiterSafeId.transform(index_js_1.asSessionId);
|
|
14
|
+
exports.RunIdSchema = delimiterSafeId.transform(index_js_1.asRunId);
|
|
15
|
+
exports.NodeIdSchema = delimiterSafeId.transform(index_js_1.asNodeId);
|
|
15
16
|
exports.StateTokenPayloadV1Schema = zod_1.z.object({
|
|
16
17
|
tokenVersion: zod_1.z.literal(1),
|
|
17
18
|
tokenKind: zod_1.z.literal('state'),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RandomEntropyPortV2 } from '../../../ports/random-entropy.port.js';
|
|
2
|
+
import type { AttemptId, NodeId, RunId, SessionId } from '../../../durable-core/ids/index.js';
|
|
3
|
+
export declare class IdFactoryV2 {
|
|
4
|
+
private readonly entropy;
|
|
5
|
+
constructor(entropy: RandomEntropyPortV2);
|
|
6
|
+
mintSessionId(): SessionId;
|
|
7
|
+
mintRunId(): RunId;
|
|
8
|
+
mintNodeId(): NodeId;
|
|
9
|
+
mintAttemptId(): AttemptId;
|
|
10
|
+
mintEventId(): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IdFactoryV2 = void 0;
|
|
4
|
+
const index_js_1 = require("../../../durable-core/ids/index.js");
|
|
5
|
+
const base32_lower_js_1 = require("../../../durable-core/encoding/base32-lower.js");
|
|
6
|
+
const BYTES = 16;
|
|
7
|
+
function mint(prefix, entropy) {
|
|
8
|
+
const bytes = entropy.generateBytes(BYTES);
|
|
9
|
+
const suffix = (0, base32_lower_js_1.encodeBase32LowerNoPad)(bytes);
|
|
10
|
+
return `${prefix}_${suffix}`;
|
|
11
|
+
}
|
|
12
|
+
class IdFactoryV2 {
|
|
13
|
+
constructor(entropy) {
|
|
14
|
+
this.entropy = entropy;
|
|
15
|
+
}
|
|
16
|
+
mintSessionId() {
|
|
17
|
+
return (0, index_js_1.asSessionId)(mint('sess', this.entropy));
|
|
18
|
+
}
|
|
19
|
+
mintRunId() {
|
|
20
|
+
return (0, index_js_1.asRunId)(mint('run', this.entropy));
|
|
21
|
+
}
|
|
22
|
+
mintNodeId() {
|
|
23
|
+
return (0, index_js_1.asNodeId)(mint('node', this.entropy));
|
|
24
|
+
}
|
|
25
|
+
mintAttemptId() {
|
|
26
|
+
return (0, index_js_1.asAttemptId)(mint('attempt', this.entropy));
|
|
27
|
+
}
|
|
28
|
+
mintEventId() {
|
|
29
|
+
return mint('evt', this.entropy);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.IdFactoryV2 = IdFactoryV2;
|