@byokit/openclaw 0.3.6 → 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/dist/output.js ADDED
@@ -0,0 +1,166 @@
1
+ const record = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
2
+ const own = (v, k) => Object.hasOwn(v, k);
3
+ const types = new Set(['null', 'boolean', 'number', 'integer', 'string', 'array', 'object']);
4
+ const bounds = ['minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum'];
5
+ const counts = ['minLength', 'maxLength', 'minItems', 'maxItems', 'minProperties', 'maxProperties'];
6
+ const annotations = ['title', 'description', 'default', 'examples', '$schema'];
7
+ const keywords = new Set(['type', 'properties', 'required', 'additionalProperties', 'items', 'enum', 'const',
8
+ 'anyOf', 'oneOf', 'allOf', 'not', 'uniqueItems', ...bounds, ...counts, ...annotations]);
9
+ function invalid() { throw new Error('refused: invalid or unsupported output schema'); }
10
+ function checkSchema(s, depth = 0) {
11
+ if (depth > 32)
12
+ invalid();
13
+ if (typeof s === 'boolean')
14
+ return;
15
+ if (!record(s) || Object.keys(s).some((k) => !keywords.has(k)))
16
+ invalid();
17
+ if (own(s, 'type')) {
18
+ const ts = Array.isArray(s.type) ? s.type : [s.type];
19
+ if (!ts.length || ts.some((t) => !types.has(t)) || new Set(ts).size !== ts.length)
20
+ invalid();
21
+ }
22
+ for (const k of bounds)
23
+ if (own(s, k) && (typeof s[k] !== 'number' || !Number.isFinite(s[k])))
24
+ invalid();
25
+ for (const k of counts)
26
+ if (own(s, k) && (typeof s[k] !== 'number' || !Number.isSafeInteger(s[k]) || s[k] < 0))
27
+ invalid();
28
+ for (const k of ['title', 'description'])
29
+ if (own(s, k) && typeof s[k] !== 'string')
30
+ invalid();
31
+ if (own(s, '$schema') && s.$schema !== 'http://json-schema.org/draft-07/schema#')
32
+ invalid();
33
+ if (own(s, 'examples') && !Array.isArray(s.examples))
34
+ invalid();
35
+ if (own(s, 'enum') && (!Array.isArray(s.enum) || !s.enum.length))
36
+ invalid();
37
+ if (own(s, 'uniqueItems') && typeof s.uniqueItems !== 'boolean')
38
+ invalid();
39
+ if (own(s, 'required') && (!Array.isArray(s.required) || s.required.some((k) => typeof k !== 'string')
40
+ || new Set(s.required).size !== s.required.length))
41
+ invalid();
42
+ if (own(s, 'properties')) {
43
+ if (!record(s.properties))
44
+ invalid();
45
+ for (const sub of Object.values(s.properties))
46
+ checkSchema(sub, depth + 1);
47
+ }
48
+ for (const k of ['items', 'additionalProperties', 'not'])
49
+ if (own(s, k))
50
+ checkSchema(s[k], depth + 1);
51
+ for (const k of ['anyOf', 'oneOf', 'allOf'])
52
+ if (own(s, k)) {
53
+ if (!Array.isArray(s[k]) || !s[k].length)
54
+ invalid();
55
+ for (const sub of s[k])
56
+ checkSchema(sub, depth + 1);
57
+ }
58
+ }
59
+ // Equality is structural: JSON objects have no key order, including enum/const values and unique array items.
60
+ function equal(a, b) {
61
+ if (a === b)
62
+ return true;
63
+ if (Array.isArray(a) && Array.isArray(b))
64
+ return a.length === b.length && a.every((v, i) => equal(v, b[i]));
65
+ if (record(a) && record(b))
66
+ return Object.keys(a).length === Object.keys(b).length
67
+ && Object.keys(a).every((k) => own(b, k) && equal(a[k], b[k]));
68
+ return false;
69
+ }
70
+ function hasType(v, t) {
71
+ if (t === 'null')
72
+ return v === null;
73
+ if (t === 'array')
74
+ return Array.isArray(v);
75
+ if (t === 'object')
76
+ return record(v);
77
+ if (t === 'integer')
78
+ return typeof v === 'number' && Number.isInteger(v);
79
+ return typeof v === t && (t !== 'number' || Number.isFinite(v));
80
+ }
81
+ function matches(s, v) {
82
+ if (typeof s === 'boolean')
83
+ return s;
84
+ if (s.type !== undefined && !(Array.isArray(s.type) ? s.type : [s.type]).some((t) => hasType(v, t)))
85
+ return false;
86
+ if (own(s, 'const') && !equal(s.const, v))
87
+ return false;
88
+ if (s.enum && !s.enum.some((e) => equal(e, v)))
89
+ return false;
90
+ if (s.allOf && !s.allOf.every((sub) => matches(sub, v)))
91
+ return false;
92
+ if (s.anyOf && !s.anyOf.some((sub) => matches(sub, v)))
93
+ return false;
94
+ if (s.oneOf && s.oneOf.filter((sub) => matches(sub, v)).length !== 1)
95
+ return false;
96
+ if (s.not !== undefined && matches(s.not, v))
97
+ return false;
98
+ if (typeof v === 'number') {
99
+ if (!Number.isFinite(v) || (s.minimum !== undefined && v < s.minimum) || (s.maximum !== undefined && v > s.maximum)
100
+ || (s.exclusiveMinimum !== undefined && v <= s.exclusiveMinimum) || (s.exclusiveMaximum !== undefined && v >= s.exclusiveMaximum))
101
+ return false;
102
+ }
103
+ if (typeof v === 'string') {
104
+ const length = [...v].length;
105
+ if ((s.minLength !== undefined && length < s.minLength) || (s.maxLength !== undefined && length > s.maxLength))
106
+ return false;
107
+ }
108
+ if (Array.isArray(v)) {
109
+ if ((s.minItems !== undefined && v.length < s.minItems) || (s.maxItems !== undefined && v.length > s.maxItems))
110
+ return false;
111
+ if (s.items !== undefined && !v.every((item) => matches(s.items, item)))
112
+ return false;
113
+ if (s.uniqueItems && v.some((item, i) => v.slice(0, i).some((other) => equal(item, other))))
114
+ return false;
115
+ }
116
+ if (record(v)) {
117
+ const keys = Object.keys(v);
118
+ if ((s.minProperties !== undefined && keys.length < s.minProperties) || (s.maxProperties !== undefined && keys.length > s.maxProperties))
119
+ return false;
120
+ if (s.required?.some((k) => !own(v, k)))
121
+ return false;
122
+ for (const k of keys) {
123
+ const sub = s.properties && own(s.properties, k) ? s.properties[k] : s.additionalProperties;
124
+ if (sub !== undefined && !matches(sub, v[k]))
125
+ return false;
126
+ }
127
+ }
128
+ return true;
129
+ }
130
+ /** Snapshot a JSON-only schema before any await; no mutation can change the prompt or its validation. */
131
+ export function outputSchema(value) {
132
+ let json;
133
+ try {
134
+ json = JSON.stringify(value, (_key, v) => {
135
+ if (v === undefined || typeof v === 'function' || typeof v === 'symbol' || typeof v === 'bigint'
136
+ || (typeof v === 'number' && !Number.isFinite(v)))
137
+ invalid();
138
+ return v;
139
+ });
140
+ }
141
+ catch {
142
+ invalid();
143
+ }
144
+ if (!json || json.length > 65_536 || new TextEncoder().encode(json).length > 65_536)
145
+ invalid();
146
+ const schema = JSON.parse(json);
147
+ if (!record(schema))
148
+ invalid(); // the public run contract requires an object at its root
149
+ checkSchema(schema);
150
+ return {
151
+ prompt: `Return only one JSON value matching this JSON Schema, with no markdown or surrounding text.\n${json}`,
152
+ parse: (text) => {
153
+ try {
154
+ const data = JSON.parse(text, (_key, value) => {
155
+ if (typeof value === 'number' && !Number.isFinite(value))
156
+ throw new Error('invalid number');
157
+ return value;
158
+ });
159
+ return matches(schema, data) ? { data } : undefined;
160
+ }
161
+ catch {
162
+ return undefined;
163
+ }
164
+ },
165
+ };
166
+ }