@benjamolina/pi-antigravity-guard 0.2.0 → 0.4.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/README.md +38 -7
- package/dist/catalog.d.ts +446 -0
- package/dist/catalog.js +188 -0
- package/dist/context.d.ts +19 -10
- package/dist/context.js +114 -47
- package/dist/provider.js +2 -11
- package/dist/response.d.ts +31 -6
- package/dist/response.js +98 -49
- package/dist/stream.d.ts +21 -4
- package/dist/stream.js +84 -15
- package/dist/tool-context.d.ts +14 -0
- package/dist/tool-context.js +162 -0
- package/dist/tool-contract.d.ts +17 -0
- package/dist/tool-contract.js +65 -0
- package/dist/tool-schema.d.ts +7 -0
- package/dist/tool-schema.js +125 -0
- package/package.json +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export class ToolPreflightError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
declaration;
|
|
4
|
+
path;
|
|
5
|
+
constructor(code, declaration, path) {
|
|
6
|
+
super(`${code}: declaration ${declaration} at ${path}`);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.declaration = declaration;
|
|
9
|
+
this.path = path;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function ownData(value, name, declaration, path) {
|
|
13
|
+
const object = plainObject(value, declaration, path);
|
|
14
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
|
15
|
+
if (!descriptor || !("value" in descriptor))
|
|
16
|
+
return undefined;
|
|
17
|
+
return descriptor.value;
|
|
18
|
+
}
|
|
19
|
+
export function plainObject(value, declaration, path) {
|
|
20
|
+
if (typeof value !== "object" || value === null || Array.isArray(value) || (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) || Object.getOwnPropertySymbols(value).length > 0)
|
|
21
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
22
|
+
for (const name of Object.getOwnPropertyNames(value)) {
|
|
23
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, name);
|
|
24
|
+
if (!descriptor || !("value" in descriptor))
|
|
25
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
export function denseArray(value, declaration, path) {
|
|
30
|
+
if (!Array.isArray(value) || Object.keys(value).length !== value.length)
|
|
31
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
export function canonicalJson(value, declaration, path, ancestors = new Set()) {
|
|
35
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
36
|
+
return value;
|
|
37
|
+
if (typeof value === "number") {
|
|
38
|
+
if (Number.isFinite(value))
|
|
39
|
+
return value;
|
|
40
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
41
|
+
}
|
|
42
|
+
if (typeof value !== "object")
|
|
43
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
44
|
+
if (ancestors.has(value))
|
|
45
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
46
|
+
ancestors.add(value);
|
|
47
|
+
try {
|
|
48
|
+
if (Array.isArray(value))
|
|
49
|
+
return Object.freeze(denseArray(value, declaration, path).map((item, index) => canonicalJson(item, declaration, `${path}[${index}]`, ancestors)));
|
|
50
|
+
const object = plainObject(value, declaration, path);
|
|
51
|
+
const output = {};
|
|
52
|
+
for (const key of Object.keys(object).sort())
|
|
53
|
+
output[key] = canonicalJson(object[key], declaration, `${path}.${key}`, ancestors);
|
|
54
|
+
return Object.freeze(output);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
ancestors.delete(value);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function freeze(value) {
|
|
61
|
+
return Object.freeze(value);
|
|
62
|
+
}
|
|
63
|
+
export function fail(code, declaration, path) {
|
|
64
|
+
throw new ToolPreflightError(code, declaration, path);
|
|
65
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type JsonObject } from "./tool-contract.ts";
|
|
2
|
+
export interface ToolDeclaration {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly description: string;
|
|
5
|
+
readonly parameters: JsonObject;
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeToolDeclarations(value: unknown): readonly ToolDeclaration[];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { canonicalJson, denseArray, fail, freeze, ownData, plainObject } from "./tool-contract.js";
|
|
2
|
+
const TYPES = new Set(["object", "array", "string", "number", "integer", "boolean"]);
|
|
3
|
+
const KEYWORDS = new Set(["type", "description", "nullable", "enum", "const", "properties", "required", "items"]);
|
|
4
|
+
const MAX_SCHEMA_DEPTH = 32;
|
|
5
|
+
const MAX_SCHEMA_NODES = 2048;
|
|
6
|
+
const MAX_SCHEMA_BYTES = 256 * 1024;
|
|
7
|
+
const MAX_TOTAL_SCHEMA_BYTES = 1024 * 1024;
|
|
8
|
+
export function normalizeToolDeclarations(value) {
|
|
9
|
+
const tools = denseArray(value, "tools", "$");
|
|
10
|
+
const names = new Set();
|
|
11
|
+
const declarations = tools.map((tool, index) => normalizeDeclaration(tool, index, names));
|
|
12
|
+
let totalSchemaBytes = 0;
|
|
13
|
+
for (const declaration of declarations) {
|
|
14
|
+
totalSchemaBytes += Buffer.byteLength(JSON.stringify(declaration.parameters), "utf8");
|
|
15
|
+
if (totalSchemaBytes > MAX_TOTAL_SCHEMA_BYTES)
|
|
16
|
+
fail("PI_TOOL_SCHEMA_LIMIT", declaration.name, "$");
|
|
17
|
+
}
|
|
18
|
+
return freeze(declarations);
|
|
19
|
+
}
|
|
20
|
+
function normalizeDeclaration(value, index, names) {
|
|
21
|
+
const path = `$[${index}]`;
|
|
22
|
+
const tool = plainObject(value, `tool-${index}`, path);
|
|
23
|
+
const name = ownData(tool, "name", `tool-${index}`, path);
|
|
24
|
+
if (typeof name !== "string" || !/^[A-Za-z_][A-Za-z0-9_.:-]{0,63}$/.test(name))
|
|
25
|
+
fail("PI_TOOL_DECLARATION_INVALID", `tool-${index}`, `${path}.name`);
|
|
26
|
+
if (names.has(name))
|
|
27
|
+
fail("PI_TOOL_DECLARATION_DUPLICATE", name, `${path}.name`);
|
|
28
|
+
names.add(name);
|
|
29
|
+
const description = ownData(tool, "description", name, path);
|
|
30
|
+
if (typeof description !== "string" || !description.trim())
|
|
31
|
+
fail("PI_TOOL_DECLARATION_INVALID", name, `${path}.description`);
|
|
32
|
+
const constrainedSampling = ownData(tool, "constrainedSampling", name, path);
|
|
33
|
+
if (constrainedSampling !== undefined && constrainedSampling !== false)
|
|
34
|
+
fail("PI_TOOL_CONSTRAINED_SAMPLING_UNSUPPORTED", name, `${path}.constrainedSampling`);
|
|
35
|
+
const parameterRoot = plainObject(ownData(tool, "parameters", name, path), name, "$");
|
|
36
|
+
if (ownData(parameterRoot, "type", name, "$") !== "object")
|
|
37
|
+
fail("PI_TOOL_SCHEMA_INVALID", name, "$.type");
|
|
38
|
+
const parameters = normalizeSchema(parameterRoot, name, "$");
|
|
39
|
+
if (Buffer.byteLength(JSON.stringify(parameters), "utf8") > MAX_SCHEMA_BYTES)
|
|
40
|
+
fail("PI_TOOL_SCHEMA_LIMIT", name, "$");
|
|
41
|
+
return freeze({ name, description, parameters });
|
|
42
|
+
}
|
|
43
|
+
function normalizeSchema(value, declaration, path, state = { ancestors: new Set(), nodes: 0 }, depth = 0) {
|
|
44
|
+
if (depth > MAX_SCHEMA_DEPTH || ++state.nodes > MAX_SCHEMA_NODES)
|
|
45
|
+
fail("PI_TOOL_SCHEMA_LIMIT", declaration, path);
|
|
46
|
+
if (typeof value === "object" && value !== null) {
|
|
47
|
+
if (state.ancestors.has(value))
|
|
48
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
49
|
+
state.ancestors.add(value);
|
|
50
|
+
}
|
|
51
|
+
const schema = plainObject(value, declaration, path);
|
|
52
|
+
for (const key of Object.keys(schema))
|
|
53
|
+
if (!KEYWORDS.has(key))
|
|
54
|
+
fail("PI_TOOL_SCHEMA_UNSUPPORTED", declaration, `${path}.${key}`);
|
|
55
|
+
const type = ownData(schema, "type", declaration, path);
|
|
56
|
+
if (typeof type !== "string" || !TYPES.has(type))
|
|
57
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.type`);
|
|
58
|
+
const output = { type };
|
|
59
|
+
const description = ownData(schema, "description", declaration, path);
|
|
60
|
+
if (description !== undefined) {
|
|
61
|
+
if (typeof description !== "string")
|
|
62
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.description`);
|
|
63
|
+
output.description = description;
|
|
64
|
+
}
|
|
65
|
+
const nullable = ownData(schema, "nullable", declaration, path);
|
|
66
|
+
if (nullable !== undefined) {
|
|
67
|
+
if (typeof nullable !== "boolean")
|
|
68
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.nullable`);
|
|
69
|
+
output.nullable = nullable;
|
|
70
|
+
}
|
|
71
|
+
const enumValue = ownData(schema, "enum", declaration, path);
|
|
72
|
+
const constant = ownData(schema, "const", declaration, path);
|
|
73
|
+
if (enumValue !== undefined && constant !== undefined)
|
|
74
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.const`);
|
|
75
|
+
if (enumValue !== undefined)
|
|
76
|
+
output.enum = normalizeEnum(enumValue, type, nullable === true, declaration, `${path}.enum`);
|
|
77
|
+
if (constant !== undefined)
|
|
78
|
+
output.enum = freeze([validateEnumValue(constant, type, nullable === true, declaration, `${path}.const`)]);
|
|
79
|
+
if (type === "object")
|
|
80
|
+
normalizeObject(schema, output, declaration, path, state, depth);
|
|
81
|
+
else if (type === "array")
|
|
82
|
+
normalizeArray(schema, output, declaration, path, state, depth);
|
|
83
|
+
else if (ownData(schema, "properties", declaration, path) !== undefined || ownData(schema, "required", declaration, path) !== undefined || ownData(schema, "items", declaration, path) !== undefined)
|
|
84
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
85
|
+
return freeze(output);
|
|
86
|
+
}
|
|
87
|
+
function normalizeObject(schema, output, declaration, path, state, depth) {
|
|
88
|
+
if (ownData(schema, "items", declaration, path) !== undefined)
|
|
89
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.items`);
|
|
90
|
+
const properties = plainObject(ownData(schema, "properties", declaration, path), declaration, `${path}.properties`);
|
|
91
|
+
const names = Object.keys(properties).sort();
|
|
92
|
+
if (!names.length)
|
|
93
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.properties`);
|
|
94
|
+
const normalized = {};
|
|
95
|
+
for (const name of names)
|
|
96
|
+
normalized[name] = normalizeSchema(properties[name], declaration, `${path}.properties.${name}`, state, depth + 1);
|
|
97
|
+
output.properties = freeze(normalized);
|
|
98
|
+
const required = ownData(schema, "required", declaration, path);
|
|
99
|
+
if (required !== undefined) {
|
|
100
|
+
const values = denseArray(required, declaration, `${path}.required`);
|
|
101
|
+
if (values.some((name) => typeof name !== "string" || !Object.hasOwn(properties, name)) || new Set(values).size !== values.length)
|
|
102
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, `${path}.required`);
|
|
103
|
+
output.required = freeze([...values].sort());
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function normalizeArray(schema, output, declaration, path, state, depth) {
|
|
107
|
+
if (ownData(schema, "properties", declaration, path) !== undefined || ownData(schema, "required", declaration, path) !== undefined)
|
|
108
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
109
|
+
output.items = normalizeSchema(ownData(schema, "items", declaration, path), declaration, `${path}.items`, state, depth + 1);
|
|
110
|
+
}
|
|
111
|
+
function normalizeEnum(value, type, nullable, declaration, path) {
|
|
112
|
+
const values = denseArray(value, declaration, path);
|
|
113
|
+
if (!values.length)
|
|
114
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
115
|
+
const normalized = values.map((item, index) => validateEnumValue(item, type, nullable, declaration, `${path}[${index}]`));
|
|
116
|
+
if (new Set(normalized.map((item) => JSON.stringify(item))).size !== normalized.length)
|
|
117
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
118
|
+
return freeze(normalized);
|
|
119
|
+
}
|
|
120
|
+
function validateEnumValue(value, type, nullable, declaration, path) {
|
|
121
|
+
const json = canonicalJson(value, declaration, path);
|
|
122
|
+
if (typeof json === "object" || (json === null && !nullable) || (json !== null && (type === "integer" ? typeof json !== "number" || !Number.isInteger(json) : typeof json !== type)))
|
|
123
|
+
fail("PI_TOOL_SCHEMA_INVALID", declaration, path);
|
|
124
|
+
return json;
|
|
125
|
+
}
|