prefix-safe-json 0.4.5 → 0.5.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/LICENSE +27 -4
- package/README.md +273 -398
- package/dist/ajv.d.ts +2 -0
- package/dist/ajv.d.ts.map +1 -0
- package/dist/ajv.js +19 -0
- package/dist/ajv.js.map +1 -0
- package/dist/conformance/runner.d.ts +19 -0
- package/dist/conformance/runner.d.ts.map +1 -0
- package/dist/conformance/runner.js +78 -0
- package/dist/conformance/runner.js.map +1 -0
- package/dist/conformance/types.d.ts +115 -0
- package/dist/conformance/types.d.ts.map +1 -0
- package/dist/conformance/types.js +2 -0
- package/dist/conformance/types.js.map +1 -0
- package/dist/conformance.d.ts +3 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +11 -0
- package/dist/conformance.js.map +1 -0
- package/dist/coordinator/coordinator.d.ts +25 -11
- package/dist/coordinator/coordinator.d.ts.map +1 -1
- package/dist/coordinator/coordinator.js +140 -25
- package/dist/coordinator/coordinator.js.map +1 -1
- package/dist/coordinator/types.d.ts +3 -2
- package/dist/coordinator/types.d.ts.map +1 -1
- package/dist/gate/gate.d.ts +2 -2
- package/dist/gate/gate.d.ts.map +1 -1
- package/dist/gate/gate.js +4 -4
- package/dist/gate/gate.js.map +1 -1
- package/dist/guard/provider-guard.js +1 -1
- package/dist/guard/provider-guard.js.map +1 -1
- package/dist/guard/types.d.ts +11 -4
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/standard-schema.d.ts +2 -0
- package/dist/standard-schema.d.ts.map +1 -0
- package/dist/standard-schema.js +11 -0
- package/dist/standard-schema.js.map +1 -0
- package/dist/validation/ajv-validator.d.ts +43 -0
- package/dist/validation/ajv-validator.d.ts.map +1 -0
- package/dist/validation/ajv-validator.js +63 -0
- package/dist/validation/ajv-validator.js.map +1 -0
- package/dist/validation/standard-schema-validator.d.ts +41 -0
- package/dist/validation/standard-schema-validator.d.ts.map +1 -0
- package/dist/validation/standard-schema-validator.js +131 -0
- package/dist/validation/standard-schema-validator.js.map +1 -0
- package/dist/validation/types.d.ts +60 -0
- package/dist/validation/types.d.ts.map +1 -0
- package/dist/validation/types.js +77 -0
- package/dist/validation/types.js.map +1 -0
- package/package.json +13 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @public (Experimental)
|
|
3
|
+
* The result of validating one tool call's arguments. Structurally minimal
|
|
4
|
+
* on purpose: `errors`, when present, are already-formatted human-readable
|
|
5
|
+
* strings, not ecosystem-specific issue objects (Zod issues, Ajv errors,
|
|
6
|
+
* TypeBox errors, ...) - each adapter is responsible for turning its own
|
|
7
|
+
* validator's native error shape into readable text, so nothing downstream
|
|
8
|
+
* needs to know which validation ecosystem produced a given verdict.
|
|
9
|
+
*/
|
|
10
|
+
export type ToolValidationResult = {
|
|
11
|
+
readonly valid: true;
|
|
12
|
+
} | {
|
|
13
|
+
readonly valid: false;
|
|
14
|
+
readonly errors?: readonly string[];
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* @public (Experimental)
|
|
18
|
+
* The validation boundary this package's execution-authority core depends
|
|
19
|
+
* on. It is deliberately not `ajv`, `zod`, `typebox`, `valibot`, or any
|
|
20
|
+
* other specific ecosystem's own type - implement this against whichever
|
|
21
|
+
* validator your project already uses and pass it in; nothing in this
|
|
22
|
+
* package's core needs to know it exists.
|
|
23
|
+
*
|
|
24
|
+
* A validator verdict is one more piece of evidence, never authority on its
|
|
25
|
+
* own: `valid: false` can make a decision `reject`; `valid: true` never by
|
|
26
|
+
* itself makes a decision `execute` - completeness and lifecycle evidence
|
|
27
|
+
* still have to hold too. See `docs/EXECUTION_GATE.md`.
|
|
28
|
+
*
|
|
29
|
+
* Contract:
|
|
30
|
+
* - `validate` runs synchronously and returns a result. It may throw to
|
|
31
|
+
* signal validator misconfiguration (mirroring how a malformed JSON
|
|
32
|
+
* Schema already fails fast at construction rather than mid-stream); the
|
|
33
|
+
* coordinator treats a thrown `validate()` as `valid: false` for that one
|
|
34
|
+
* call rather than letting the exception abort the whole stream - see
|
|
35
|
+
* `docs/VALIDATION.md#a-validator-that-throws`.
|
|
36
|
+
* - `validate` must be deterministic and free of side effects - it is called
|
|
37
|
+
* with the call's already-parsed, already-complete `stableValue`, and its
|
|
38
|
+
* return value must depend only on that input.
|
|
39
|
+
*/
|
|
40
|
+
export interface ToolInputValidator {
|
|
41
|
+
validate(value: unknown): ToolValidationResult;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @internal
|
|
45
|
+
* Builds the coordinator's internal per-tool validator map from the two
|
|
46
|
+
* explicit, separate registration options. There is no structural/duck-type
|
|
47
|
+
* discrimination anywhere in this path - `schemas` entries are always
|
|
48
|
+
* compiled as JSON Schema, `validators` entries are always used as-is, and
|
|
49
|
+
* a tool name present in both is a construction-time error rather than a
|
|
50
|
+
* silently-resolved precedence rule. See `docs/VALIDATION.md`.
|
|
51
|
+
*
|
|
52
|
+
* Collision detection runs *before* any schema is compiled, so a colliding
|
|
53
|
+
* tool name is always reported as a collision - deterministically, even
|
|
54
|
+
* when that same tool's `schemas` entry also happens to be malformed JSON
|
|
55
|
+
* Schema. Without this ordering, whichever check happened to run first
|
|
56
|
+
* would decide which error the caller sees, for reasons unrelated to which
|
|
57
|
+
* problem is actually more fundamental.
|
|
58
|
+
*/
|
|
59
|
+
export declare function buildValidatorMap(schemas: Record<string, object> | undefined, validators: Record<string, ToolInputValidator> | undefined): Map<string, ToolInputValidator>;
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/validation/types.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAAC;CAChD;AA+BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC3C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,SAAS,GACzD,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAmCjC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { buildSharedAjvValidators } from "./ajv-validator.js";
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
* Runtime shape check for a `validators[toolName]` entry. `ToolInputValidator`
|
|
5
|
+
* is a TypeScript interface, not a runtime guarantee - a plain-JavaScript
|
|
6
|
+
* caller (or a `as never`/`as ToolInputValidator` cast) can hand this
|
|
7
|
+
* anything. An explicitly *registered* malformed validator must never be
|
|
8
|
+
* silently equivalent to "no validator registered": `coordinator.ts`'s
|
|
9
|
+
* `if (validator) { ... }` truthiness check would otherwise skip a `null`/
|
|
10
|
+
* `undefined`/`false`/`0`/`""` entry entirely, letting the call execute
|
|
11
|
+
* with zero diagnostic - the same class of fail-open gap already closed for
|
|
12
|
+
* a validator that returns a malformed *result* (see
|
|
13
|
+
* `docs/VALIDATION.md#a-validator-that-returns-a-malformed-result`). This
|
|
14
|
+
* check exists so that gap cannot reopen one level up, at registration time.
|
|
15
|
+
*/
|
|
16
|
+
function isToolInputValidatorShaped(value) {
|
|
17
|
+
return typeof value === "object" && value !== null && typeof value.validate === "function";
|
|
18
|
+
}
|
|
19
|
+
function describeInvalidValidator(value) {
|
|
20
|
+
if (typeof value === "object") {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return Object.prototype.toString.call(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return `${typeof value} ${String(value)}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
* Builds the coordinator's internal per-tool validator map from the two
|
|
33
|
+
* explicit, separate registration options. There is no structural/duck-type
|
|
34
|
+
* discrimination anywhere in this path - `schemas` entries are always
|
|
35
|
+
* compiled as JSON Schema, `validators` entries are always used as-is, and
|
|
36
|
+
* a tool name present in both is a construction-time error rather than a
|
|
37
|
+
* silently-resolved precedence rule. See `docs/VALIDATION.md`.
|
|
38
|
+
*
|
|
39
|
+
* Collision detection runs *before* any schema is compiled, so a colliding
|
|
40
|
+
* tool name is always reported as a collision - deterministically, even
|
|
41
|
+
* when that same tool's `schemas` entry also happens to be malformed JSON
|
|
42
|
+
* Schema. Without this ordering, whichever check happened to run first
|
|
43
|
+
* would decide which error the caller sees, for reasons unrelated to which
|
|
44
|
+
* problem is actually more fundamental.
|
|
45
|
+
*/
|
|
46
|
+
export function buildValidatorMap(schemas, validators) {
|
|
47
|
+
if (schemas && validators) {
|
|
48
|
+
for (const toolName of Object.keys(validators)) {
|
|
49
|
+
if (Object.prototype.hasOwnProperty.call(schemas, toolName)) {
|
|
50
|
+
throw new Error(`prefix-safe-json: tool ${JSON.stringify(toolName)} is registered in both "schemas" and ` +
|
|
51
|
+
`"validators" - a tool's validation must come from exactly one source. Remove one registration.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const map = new Map();
|
|
56
|
+
if (schemas) {
|
|
57
|
+
// One shared Ajv instance for every schema in THIS `schemas` object -
|
|
58
|
+
// pre-0.5 behavior, restored here after 0.5's per-schema
|
|
59
|
+
// createAjvValidator() calls regressed it (a schema could no longer
|
|
60
|
+
// $ref another schema registered in the same construction - see
|
|
61
|
+
// buildSharedAjvValidators's own doc comment for the direct proof).
|
|
62
|
+
for (const [toolName, validator] of buildSharedAjvValidators(schemas)) {
|
|
63
|
+
map.set(toolName, validator);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (validators) {
|
|
67
|
+
for (const [toolName, validator] of Object.entries(validators)) {
|
|
68
|
+
if (!isToolInputValidatorShaped(validator)) {
|
|
69
|
+
throw new Error(`prefix-safe-json: validators[${JSON.stringify(toolName)}] is not a valid ToolInputValidator - ` +
|
|
70
|
+
`expected an object with a "validate" function, received: ${describeInvalidValidator(validator)}`);
|
|
71
|
+
}
|
|
72
|
+
map.set(toolName, validator);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return map;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/validation/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AA2C9D;;;;;;;;;;;;;GAaG;AACH,SAAS,0BAA0B,CAAC,KAAc;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,OAAQ,KAAgC,CAAC,QAAQ,KAAK,UAAU,CAAC;AACzH,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAc;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,OAAO,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAA2C,EAC3C,UAA0D;IAE1D,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;QAC1B,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC5D,MAAM,IAAI,KAAK,CACb,0BAA0B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,uCAAuC;oBACvF,gGAAgG,CACnG,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,EAA8B,CAAC;IAClD,IAAI,OAAO,EAAE,CAAC;QACZ,sEAAsE;QACtE,yDAAyD;QACzD,oEAAoE;QACpE,gEAAgE;QAChE,oEAAoE;QACpE,KAAK,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,wBAAwB,CAAC,OAAO,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,IAAI,UAAU,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,0BAA0B,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3C,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,wCAAwC;oBAC9F,4DAA4D,wBAAwB,CAAC,SAAS,CAAC,EAAE,CACpG,CAAC;YACJ,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prefix-safe-json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Fail-closed execution integrity for streamed LLM tool calls — reject truncated or unconfirmed arguments before side effects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"json",
|
|
@@ -31,6 +31,18 @@
|
|
|
31
31
|
".": {
|
|
32
32
|
"types": "./dist/index.d.ts",
|
|
33
33
|
"import": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./ajv": {
|
|
36
|
+
"types": "./dist/ajv.d.ts",
|
|
37
|
+
"import": "./dist/ajv.js"
|
|
38
|
+
},
|
|
39
|
+
"./standard-schema": {
|
|
40
|
+
"types": "./dist/standard-schema.d.ts",
|
|
41
|
+
"import": "./dist/standard-schema.js"
|
|
42
|
+
},
|
|
43
|
+
"./conformance": {
|
|
44
|
+
"types": "./dist/conformance.d.ts",
|
|
45
|
+
"import": "./dist/conformance.js"
|
|
34
46
|
}
|
|
35
47
|
},
|
|
36
48
|
"files": [
|