pi-commandcode-provider 0.4.3 → 0.5.1
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/CHANGELOG.md +28 -0
- package/CONTRIBUTING.md +18 -0
- package/README.md +100 -72
- package/index.ts +84 -91
- package/package.json +15 -6
- package/scripts/pi-authenticated.mjs +49 -0
- package/scripts/pi-isolated.mjs +78 -0
- package/src/converters.ts +64 -85
- package/src/core.ts +107 -31
- package/src/cost.ts +16 -4
- package/src/json-schema.ts +382 -0
- package/src/models.ts +251 -15
- package/src/overflow.ts +120 -0
- package/src/pricing.ts +226 -0
- package/src/runtime.ts +279 -0
- package/src/types.ts +19 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
2
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function stringValue(value: unknown): string | undefined {
|
|
6
|
+
return typeof value === "string" ? value : undefined
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function booleanValue(value: unknown): boolean | undefined {
|
|
10
|
+
return typeof value === "boolean" ? value : undefined
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type JsonSchemaValue = boolean | Record<string, unknown>
|
|
14
|
+
|
|
15
|
+
const JSON_SCHEMA_TYPES = new Set([
|
|
16
|
+
"array",
|
|
17
|
+
"boolean",
|
|
18
|
+
"integer",
|
|
19
|
+
"null",
|
|
20
|
+
"number",
|
|
21
|
+
"object",
|
|
22
|
+
"string",
|
|
23
|
+
])
|
|
24
|
+
|
|
25
|
+
const LEGACY_KINDS = new Set([
|
|
26
|
+
"any",
|
|
27
|
+
"array",
|
|
28
|
+
"boolean",
|
|
29
|
+
"enum",
|
|
30
|
+
"integer",
|
|
31
|
+
"intersect",
|
|
32
|
+
"intersection",
|
|
33
|
+
"literal",
|
|
34
|
+
"never",
|
|
35
|
+
"null",
|
|
36
|
+
"nullable",
|
|
37
|
+
"number",
|
|
38
|
+
"object",
|
|
39
|
+
"optional",
|
|
40
|
+
"string",
|
|
41
|
+
"undefined",
|
|
42
|
+
"union",
|
|
43
|
+
"unknown",
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
const LEGACY_FIELDS = new Set([
|
|
47
|
+
"element",
|
|
48
|
+
"kind",
|
|
49
|
+
"inner",
|
|
50
|
+
"optional",
|
|
51
|
+
"value",
|
|
52
|
+
"values",
|
|
53
|
+
"variants",
|
|
54
|
+
"wrapped",
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
const SCHEMA_MAP_FIELDS = new Set([
|
|
58
|
+
"$defs",
|
|
59
|
+
"definitions",
|
|
60
|
+
"dependentSchemas",
|
|
61
|
+
"patternProperties",
|
|
62
|
+
"properties",
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
const SCHEMA_ARRAY_FIELDS = new Set(["allOf", "anyOf", "oneOf", "prefixItems"])
|
|
66
|
+
|
|
67
|
+
const SCHEMA_VALUE_FIELDS = new Set([
|
|
68
|
+
"additionalItems",
|
|
69
|
+
"additionalProperties",
|
|
70
|
+
"contains",
|
|
71
|
+
"contentSchema",
|
|
72
|
+
"else",
|
|
73
|
+
"if",
|
|
74
|
+
"items",
|
|
75
|
+
"not",
|
|
76
|
+
"propertyNames",
|
|
77
|
+
"then",
|
|
78
|
+
"unevaluatedItems",
|
|
79
|
+
"unevaluatedProperties",
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
const SCHEMA_KEYWORDS = new Set([
|
|
83
|
+
"$anchor",
|
|
84
|
+
"$comment",
|
|
85
|
+
"$defs",
|
|
86
|
+
"$dynamicAnchor",
|
|
87
|
+
"$dynamicRef",
|
|
88
|
+
"$id",
|
|
89
|
+
"$ref",
|
|
90
|
+
"$schema",
|
|
91
|
+
"$vocabulary",
|
|
92
|
+
"additionalItems",
|
|
93
|
+
"additionalProperties",
|
|
94
|
+
"allOf",
|
|
95
|
+
"anyOf",
|
|
96
|
+
"const",
|
|
97
|
+
"contains",
|
|
98
|
+
"contentEncoding",
|
|
99
|
+
"contentMediaType",
|
|
100
|
+
"contentSchema",
|
|
101
|
+
"default",
|
|
102
|
+
"definitions",
|
|
103
|
+
"dependentRequired",
|
|
104
|
+
"dependentSchemas",
|
|
105
|
+
"description",
|
|
106
|
+
"else",
|
|
107
|
+
"enum",
|
|
108
|
+
"examples",
|
|
109
|
+
"exclusiveMaximum",
|
|
110
|
+
"exclusiveMinimum",
|
|
111
|
+
"format",
|
|
112
|
+
"if",
|
|
113
|
+
"items",
|
|
114
|
+
"maxContains",
|
|
115
|
+
"maxItems",
|
|
116
|
+
"maxLength",
|
|
117
|
+
"maxProperties",
|
|
118
|
+
"maximum",
|
|
119
|
+
"minContains",
|
|
120
|
+
"minItems",
|
|
121
|
+
"minLength",
|
|
122
|
+
"minProperties",
|
|
123
|
+
"minimum",
|
|
124
|
+
"multipleOf",
|
|
125
|
+
"not",
|
|
126
|
+
"oneOf",
|
|
127
|
+
"pattern",
|
|
128
|
+
"patternProperties",
|
|
129
|
+
"prefixItems",
|
|
130
|
+
"properties",
|
|
131
|
+
"propertyNames",
|
|
132
|
+
"readOnly",
|
|
133
|
+
"required",
|
|
134
|
+
"title",
|
|
135
|
+
"type",
|
|
136
|
+
"unevaluatedItems",
|
|
137
|
+
"unevaluatedProperties",
|
|
138
|
+
"uniqueItems",
|
|
139
|
+
"writeOnly",
|
|
140
|
+
])
|
|
141
|
+
|
|
142
|
+
function stringArray(value: unknown): string[] | undefined {
|
|
143
|
+
if (!Array.isArray(value)) return undefined
|
|
144
|
+
const values = value.filter((item): item is string => typeof item === "string")
|
|
145
|
+
return values.length === value.length ? values : undefined
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function validSchemaType(value: unknown): boolean {
|
|
149
|
+
if (typeof value === "string") return JSON_SCHEMA_TYPES.has(value)
|
|
150
|
+
if (!Array.isArray(value) || value.length === 0) return false
|
|
151
|
+
return value.every((item) => typeof item === "string" && JSON_SCHEMA_TYPES.has(item))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function legacyKind(schema: Record<string, unknown>): string | undefined {
|
|
155
|
+
const explicitKind = stringValue(schema.kind)?.toLowerCase()
|
|
156
|
+
if (explicitKind && LEGACY_KINDS.has(explicitKind)) return explicitKind
|
|
157
|
+
|
|
158
|
+
const type = stringValue(schema.type)
|
|
159
|
+
const normalized = type?.toLowerCase()
|
|
160
|
+
if (!normalized || !LEGACY_KINDS.has(normalized)) return undefined
|
|
161
|
+
if (!validSchemaType(type) || Object.keys(schema).some((key) => LEGACY_FIELDS.has(key))) {
|
|
162
|
+
return normalized
|
|
163
|
+
}
|
|
164
|
+
return undefined
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function looksLikeJsonSchema(schema: Record<string, unknown>): boolean {
|
|
168
|
+
if (Object.keys(schema).length === 0) return true
|
|
169
|
+
if (schema.type !== undefined && !validSchemaType(schema.type)) return false
|
|
170
|
+
return Object.keys(schema).some((key) => SCHEMA_KEYWORDS.has(key))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function isOptionalSchema(schema: unknown): boolean {
|
|
174
|
+
if (!isRecord(schema)) return false
|
|
175
|
+
if (booleanValue(schema.optional) === true) return true
|
|
176
|
+
|
|
177
|
+
const kind = legacyKind(schema)
|
|
178
|
+
if (kind === "optional") return true
|
|
179
|
+
if (kind !== "union") return false
|
|
180
|
+
|
|
181
|
+
const variants = Array.isArray(schema.variants)
|
|
182
|
+
? schema.variants
|
|
183
|
+
: Array.isArray(schema.anyOf)
|
|
184
|
+
? schema.anyOf
|
|
185
|
+
: []
|
|
186
|
+
return variants.some((variant) => legacyKind(isRecord(variant) ? variant : {}) === "undefined")
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function schemaValue(value: unknown, seen: WeakSet<object>): JsonSchemaValue {
|
|
190
|
+
if (typeof value === "boolean") return value
|
|
191
|
+
if (!isRecord(value)) return {}
|
|
192
|
+
return convertSchema(value, seen)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function setSchemaProperty(target: Record<string, unknown>, key: string, value: unknown): void {
|
|
196
|
+
Object.defineProperty(target, key, {
|
|
197
|
+
configurable: true,
|
|
198
|
+
enumerable: true,
|
|
199
|
+
value,
|
|
200
|
+
writable: true,
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function schemaMap(value: unknown, seen: WeakSet<object>): Record<string, unknown> {
|
|
205
|
+
if (!isRecord(value)) return {}
|
|
206
|
+
const out: Record<string, unknown> = {}
|
|
207
|
+
for (const [key, item] of Object.entries(value)) {
|
|
208
|
+
setSchemaProperty(out, key, schemaValue(item, seen))
|
|
209
|
+
}
|
|
210
|
+
return out
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function schemaArray(value: unknown, seen: WeakSet<object>): unknown[] {
|
|
214
|
+
if (!Array.isArray(value)) return []
|
|
215
|
+
return value.map((item) => schemaValue(item, seen))
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function isSchemaValue(value: unknown): value is JsonSchemaValue {
|
|
219
|
+
return typeof value === "boolean" || isRecord(value)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function copySchemaObject(
|
|
223
|
+
source: Record<string, unknown>,
|
|
224
|
+
seen: WeakSet<object>,
|
|
225
|
+
legacy: boolean,
|
|
226
|
+
forcedType?: string,
|
|
227
|
+
): JsonSchemaValue {
|
|
228
|
+
const out: Record<string, unknown> = {}
|
|
229
|
+
|
|
230
|
+
for (const [key, value] of Object.entries(source)) {
|
|
231
|
+
if (legacy && LEGACY_FIELDS.has(key)) continue
|
|
232
|
+
if (key === "nullable" || (forcedType !== undefined && key === "type")) continue
|
|
233
|
+
|
|
234
|
+
if (key === "required") {
|
|
235
|
+
const required = stringArray(value)
|
|
236
|
+
if (required) out.required = required
|
|
237
|
+
} else if (SCHEMA_MAP_FIELDS.has(key)) {
|
|
238
|
+
out[key] = schemaMap(value, seen)
|
|
239
|
+
} else if (SCHEMA_ARRAY_FIELDS.has(key)) {
|
|
240
|
+
out[key] = schemaArray(value, seen)
|
|
241
|
+
} else if (SCHEMA_VALUE_FIELDS.has(key)) {
|
|
242
|
+
out[key] =
|
|
243
|
+
Array.isArray(value) && key === "items"
|
|
244
|
+
? schemaArray(value, seen)
|
|
245
|
+
: schemaValue(value, seen)
|
|
246
|
+
} else {
|
|
247
|
+
out[key] = value
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (forcedType !== undefined) out.type = forcedType
|
|
252
|
+
if (booleanValue(source.nullable) === true) return makeNullable(out)
|
|
253
|
+
return out
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function makeNullable(schema: Record<string, unknown>): Record<string, unknown> {
|
|
257
|
+
const type = schema.type
|
|
258
|
+
if (typeof type === "string") {
|
|
259
|
+
if (type === "null") return schema
|
|
260
|
+
return { ...schema, type: [type, "null"] }
|
|
261
|
+
}
|
|
262
|
+
if (Array.isArray(type) && !type.includes("null")) {
|
|
263
|
+
return { ...schema, type: [...type, "null"] }
|
|
264
|
+
}
|
|
265
|
+
if (Array.isArray(schema.anyOf)) {
|
|
266
|
+
return { ...schema, anyOf: [...schema.anyOf, { type: "null" }] }
|
|
267
|
+
}
|
|
268
|
+
return { anyOf: [schema, { type: "null" }] }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function legacyVariants(schema: Record<string, unknown>): unknown[] {
|
|
272
|
+
if (Array.isArray(schema.variants)) return schema.variants
|
|
273
|
+
if (Array.isArray(schema.anyOf)) return schema.anyOf
|
|
274
|
+
return []
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function convertLegacySchema(
|
|
278
|
+
source: Record<string, unknown>,
|
|
279
|
+
kind: string,
|
|
280
|
+
seen: WeakSet<object>,
|
|
281
|
+
): JsonSchemaValue {
|
|
282
|
+
if (kind === "optional") return schemaValue(source.wrapped ?? source.inner, seen)
|
|
283
|
+
if (kind === "nullable") {
|
|
284
|
+
const wrapped = schemaValue(source.wrapped ?? source.inner, seen)
|
|
285
|
+
return typeof wrapped === "boolean" ? wrapped : makeNullable(wrapped)
|
|
286
|
+
}
|
|
287
|
+
if (kind === "undefined" || kind === "never" || kind === "any" || kind === "unknown") return {}
|
|
288
|
+
|
|
289
|
+
if (kind === "union" || kind === "intersect" || kind === "intersection") {
|
|
290
|
+
const variants = legacyVariants(source)
|
|
291
|
+
.map((variant) => schemaValue(variant, seen))
|
|
292
|
+
.filter(
|
|
293
|
+
(variant) =>
|
|
294
|
+
isSchemaValue(variant) &&
|
|
295
|
+
(typeof variant === "boolean" || Object.keys(variant).length > 0),
|
|
296
|
+
)
|
|
297
|
+
if (variants.length === 0) return copySchemaObject(source, seen, true)
|
|
298
|
+
if (variants.length === 1) return variants[0] ?? {}
|
|
299
|
+
|
|
300
|
+
const out = copySchemaObject(source, seen, true)
|
|
301
|
+
if (typeof out !== "boolean") out[kind === "union" ? "anyOf" : "allOf"] = variants
|
|
302
|
+
return out
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (kind === "object") {
|
|
306
|
+
const converted = copySchemaObject(source, seen, true, "object")
|
|
307
|
+
if (typeof converted === "boolean") return converted
|
|
308
|
+
const out = converted
|
|
309
|
+
const sourceProperties = isRecord(source.properties) ? source.properties : undefined
|
|
310
|
+
if (!sourceProperties) return out
|
|
311
|
+
|
|
312
|
+
const properties: Record<string, unknown> = {}
|
|
313
|
+
const optional = stringArray(source.optional) ?? []
|
|
314
|
+
for (const [key, value] of Object.entries(sourceProperties)) {
|
|
315
|
+
setSchemaProperty(properties, key, schemaValue(value, seen))
|
|
316
|
+
}
|
|
317
|
+
out.properties = properties
|
|
318
|
+
|
|
319
|
+
const explicitRequired = stringArray(source.required)
|
|
320
|
+
const required =
|
|
321
|
+
explicitRequired ??
|
|
322
|
+
Object.entries(sourceProperties)
|
|
323
|
+
.filter(([key, value]) => !optional.includes(key) && !isOptionalSchema(value))
|
|
324
|
+
.map(([key]) => key)
|
|
325
|
+
if (required.length > 0) out.required = required
|
|
326
|
+
else delete out.required
|
|
327
|
+
return out
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (kind === "array") {
|
|
331
|
+
const converted = copySchemaObject(source, seen, true, "array")
|
|
332
|
+
if (typeof converted === "boolean") return converted
|
|
333
|
+
const out = converted
|
|
334
|
+
if (!("items" in source) && "element" in source) out.items = schemaValue(source.element, seen)
|
|
335
|
+
return out
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (kind === "enum") {
|
|
339
|
+
const converted = copySchemaObject(source, seen, true)
|
|
340
|
+
if (typeof converted === "boolean") return converted
|
|
341
|
+
const out = converted
|
|
342
|
+
if (!("enum" in out) && Array.isArray(source.values)) out.enum = source.values
|
|
343
|
+
return out
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (kind === "literal") {
|
|
347
|
+
const converted = copySchemaObject(source, seen, true)
|
|
348
|
+
if (typeof converted === "boolean") return converted
|
|
349
|
+
const out = converted
|
|
350
|
+
if (!("const" in out) && "value" in source) out.const = source.value
|
|
351
|
+
return out
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const scalarType =
|
|
355
|
+
kind === "string" ||
|
|
356
|
+
kind === "number" ||
|
|
357
|
+
kind === "boolean" ||
|
|
358
|
+
kind === "integer" ||
|
|
359
|
+
kind === "null"
|
|
360
|
+
? kind
|
|
361
|
+
: undefined
|
|
362
|
+
return scalarType ? copySchemaObject(source, seen, true, scalarType) : {}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function convertSchema(source: Record<string, unknown>, seen: WeakSet<object>): JsonSchemaValue {
|
|
366
|
+
if (seen.has(source)) return {}
|
|
367
|
+
seen.add(source)
|
|
368
|
+
try {
|
|
369
|
+
const kind = legacyKind(source)
|
|
370
|
+
if (kind) return convertLegacySchema(source, kind, seen)
|
|
371
|
+
if (!looksLikeJsonSchema(source)) return {}
|
|
372
|
+
return copySchemaObject(source, seen, false)
|
|
373
|
+
} finally {
|
|
374
|
+
seen.delete(source)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
export function toJsonSchema(schema: unknown): unknown {
|
|
379
|
+
if (typeof schema === "boolean") return schema
|
|
380
|
+
if (!isRecord(schema)) return {}
|
|
381
|
+
return convertSchema(schema, new WeakSet<object>())
|
|
382
|
+
}
|