{"version":3,"file":"structured-output.d.ts","sourceRoot":"","sources":["../../../../src/runs/shared/structured-output.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,eAAO,MAAM,4BAA4B,yCAAyC,CAAC;AACnF,eAAO,MAAM,6BAA6B,0CAA0C,CAAC;AACrF,eAAO,MAAM,oCAAoC,6GAC0D,CAAC;AAE5G,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB;AAsED,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAO/F;AAED,UAAU,kBAAkB;IAC3B,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,KAAK,iBAAiB,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,kBAAkB,CAAC;AAIjE,wBAAsB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAK/G;AAoCD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,SAAiB,GAAG,OAAO,CAAC,MAAM,IAAI,gBAAgB,CAIlH;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,uBAAuB,CASjH;AAED,wBAAsB,6BAA6B,CAClD,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBvE;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9C;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,uBAAuB,GAAG,SAAS,GAAG,IAAI,CAOjG","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { JsonSchemaObject } from \"../../shared/types.ts\";\nimport { PI_CODING_AGENT_PACKAGE_ROOT_ENV } from \"../../shared/utils.ts\";\n\nexport const STRUCTURED_OUTPUT_SCHEMA_ENV = \"PI_SUBAGENT_STRUCTURED_OUTPUT_SCHEMA\";\nexport const STRUCTURED_OUTPUT_CAPTURE_ENV = \"PI_SUBAGENT_STRUCTURED_OUTPUT_CAPTURE\";\nexport const MISSING_STRUCTURED_OUTPUT_CALL_ERROR =\n\t\"Missing structured_output call; this step has outputSchema and must finish by calling structured_output.\";\n\nexport interface StructuredOutputRuntime {\n\tschema: JsonSchemaObject;\n\tschemaPath: string;\n\toutputPath: string;\n}\n\nconst SCHEMA_MAP_KEYWORDS = [\"properties\", \"patternProperties\", \"$defs\", \"definitions\", \"dependentSchemas\"] as const;\nconst SCHEMA_SINGLE_KEYWORDS = [\n\t\"additionalItems\",\n\t\"additionalProperties\",\n\t\"contains\",\n\t\"not\",\n\t\"propertyNames\",\n\t\"if\",\n\t\"then\",\n\t\"else\",\n\t\"unevaluatedItems\",\n\t\"unevaluatedProperties\",\n\t\"contentSchema\",\n] as const;\nconst SCHEMA_ARRAY_KEYWORDS = [\"allOf\", \"anyOf\", \"oneOf\", \"prefixItems\"] as const;\n\nfunction rewriteLocalJsonPointerRefs(schema: unknown, pointerPrefix: string, inheritsWrapperResource = true): unknown {\n\tif (typeof schema === \"boolean\" || !schema || typeof schema !== \"object\" || Array.isArray(schema)) return schema;\n\tconst source = schema as Record<string, unknown>;\n\tconst rewritten: Record<string, unknown> = { ...source };\n\tconst sharesWrapperResource = inheritsWrapperResource && typeof source.$id !== \"string\";\n\tif (sharesWrapperResource) {\n\t\tfor (const keyword of [\"$ref\", \"$dynamicRef\", \"$recursiveRef\"] as const) {\n\t\t\tconst ref = source[keyword];\n\t\t\tif (ref === \"#\") rewritten[keyword] = pointerPrefix;\n\t\t\telse if (typeof ref === \"string\" && ref.startsWith(\"#/\"))\n\t\t\t\trewritten[keyword] = `${pointerPrefix}${ref.slice(1)}`;\n\t\t}\n\t}\n\tfor (const keyword of SCHEMA_MAP_KEYWORDS) {\n\t\tconst entries = source[keyword];\n\t\tif (!entries || typeof entries !== \"object\" || Array.isArray(entries)) continue;\n\t\trewritten[keyword] = Object.fromEntries(\n\t\t\tObject.entries(entries).map(([name, nested]) => [\n\t\t\t\tname,\n\t\t\t\trewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),\n\t\t\t]),\n\t\t);\n\t}\n\tconst items = source.items;\n\tif (Array.isArray(items))\n\t\trewritten.items = items.map((nested) =>\n\t\t\trewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),\n\t\t);\n\telse if (items !== undefined)\n\t\trewritten.items = rewriteLocalJsonPointerRefs(items, pointerPrefix, sharesWrapperResource);\n\tfor (const keyword of SCHEMA_SINGLE_KEYWORDS) {\n\t\tif (source[keyword] !== undefined)\n\t\t\trewritten[keyword] = rewriteLocalJsonPointerRefs(source[keyword], pointerPrefix, sharesWrapperResource);\n\t}\n\tfor (const keyword of SCHEMA_ARRAY_KEYWORDS) {\n\t\tif (Array.isArray(source[keyword]))\n\t\t\trewritten[keyword] = source[keyword].map((nested) =>\n\t\t\t\trewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),\n\t\t\t);\n\t}\n\tconst dependencies = source.dependencies;\n\tif (dependencies && typeof dependencies === \"object\" && !Array.isArray(dependencies)) {\n\t\trewritten.dependencies = Object.fromEntries(\n\t\t\tObject.entries(dependencies).map(([name, nested]) => [\n\t\t\t\tname,\n\t\t\t\tArray.isArray(nested) ? nested : rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),\n\t\t\t]),\n\t\t);\n\t}\n\treturn rewritten;\n}\n\nexport function createStructuredOutputToolParameters(schema: JsonSchemaObject): JsonSchemaObject {\n\treturn {\n\t\ttype: \"object\",\n\t\tproperties: { value: rewriteLocalJsonPointerRefs(schema, \"#/properties/value\") },\n\t\trequired: [\"value\"],\n\t\tadditionalProperties: false,\n\t};\n}\n\ninterface CompiledJsonSchema {\n\tCheck(value: unknown): boolean;\n\tErrors(value: unknown): Iterable<{ instancePath?: string; message?: string }>;\n}\n\ntype CompileJsonSchema = (schema: unknown) => CompiledJsonSchema;\n\nlet cachedCompile: Promise<CompileJsonSchema> | undefined;\n\nexport async function resolveCompileFromPackageRoot(packageRoot: string): Promise<CompileJsonSchema | undefined> {\n\tconst requireFromRoot = createRequire(path.join(packageRoot, \"package.json\"));\n\tconst resolved = requireFromRoot.resolve(\"typebox/compile\");\n\tconst mod = (await import(pathToFileURL(resolved).href)) as { Compile?: unknown };\n\treturn typeof mod.Compile === \"function\" ? (mod.Compile as CompileJsonSchema) : undefined;\n}\n\nasync function importCompile(): Promise<CompileJsonSchema> {\n\tconst failures: string[] = [];\n\ttry {\n\t\tconst mod = (await import(\"typebox/compile\")) as { Compile?: unknown };\n\t\tif (typeof mod.Compile === \"function\") return mod.Compile as CompileJsonSchema;\n\t\tfailures.push(\"typebox/compile did not export a Compile function\");\n\t} catch (error) {\n\t\tfailures.push(`direct import failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tconst packageRoot = process.env[PI_CODING_AGENT_PACKAGE_ROOT_ENV];\n\tif (packageRoot) {\n\t\ttry {\n\t\t\tconst compile = await resolveCompileFromPackageRoot(packageRoot);\n\t\t\tif (compile) return compile;\n\t\t\tfailures.push(\"Pi package root typebox/compile did not export a Compile function\");\n\t\t} catch (error) {\n\t\t\tfailures.push(`Pi package root import failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t} else {\n\t\tfailures.push(`${PI_CODING_AGENT_PACKAGE_ROOT_ENV} is not set`);\n\t}\n\tthrow new Error(`Cannot load typebox/compile for structured output validation (${failures.join(\"; \")})`);\n}\n\nfunction loadCompile(): Promise<CompileJsonSchema> {\n\tif (!cachedCompile) {\n\t\tcachedCompile = importCompile().catch((error) => {\n\t\t\tcachedCompile = undefined;\n\t\t\tthrow error;\n\t\t});\n\t}\n\treturn cachedCompile;\n}\n\nexport function assertJsonSchemaObject(schema: unknown, label = \"outputSchema\"): asserts schema is JsonSchemaObject {\n\tif (!schema || typeof schema !== \"object\" || Array.isArray(schema)) {\n\t\tthrow new Error(`${label} must be a JSON Schema object.`);\n\t}\n}\n\nexport function createStructuredOutputRuntime(schema: JsonSchemaObject, baseDir?: string): StructuredOutputRuntime {\n\tassertJsonSchemaObject(schema);\n\tconst rootDir = baseDir ?? os.tmpdir();\n\tfs.mkdirSync(rootDir, { recursive: true });\n\tconst dir = fs.mkdtempSync(path.join(rootDir, \"pi-subagent-structured-\"));\n\tconst schemaPath = path.join(dir, \"schema.json\");\n\tconst outputPath = path.join(dir, \"output.json\");\n\tfs.writeFileSync(schemaPath, JSON.stringify(schema), { mode: 0o600 });\n\treturn { schema, schemaPath, outputPath };\n}\n\nexport async function validateStructuredOutputValue(\n\tschema: JsonSchemaObject,\n\tvalue: unknown,\n): Promise<{ status: \"valid\" } | { status: \"invalid\"; message: string }> {\n\tconst compile = await loadCompile();\n\tlet validator: CompiledJsonSchema;\n\ttry {\n\t\tvalidator = compile(schema);\n\t} catch (error) {\n\t\treturn {\n\t\t\tstatus: \"invalid\",\n\t\t\tmessage: `invalid outputSchema: ${error instanceof Error ? error.message : String(error)}`,\n\t\t};\n\t}\n\tif (validator.Check(value)) return { status: \"valid\" };\n\tconst errors = [...validator.Errors(value)].slice(0, 8).map((error) => {\n\t\tconst pathText = error.instancePath ? error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\") : \"root\";\n\t\treturn `${pathText}: ${error.message}`;\n\t});\n\treturn { status: \"invalid\", message: errors.join(\"; \") || \"schema validation failed\" };\n}\n\nexport async function readStructuredOutput(\n\truntime: StructuredOutputRuntime,\n): Promise<{ value?: unknown; error?: string }> {\n\tif (!fs.existsSync(runtime.outputPath)) {\n\t\treturn { error: MISSING_STRUCTURED_OUTPUT_CALL_ERROR };\n\t}\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(fs.readFileSync(runtime.outputPath, \"utf-8\"));\n\t} catch (error) {\n\t\treturn { error: `Failed to read structured output: ${error instanceof Error ? error.message : String(error)}` };\n\t}\n\ttry {\n\t\tconst validation = await validateStructuredOutputValue(runtime.schema, value);\n\t\tif (validation.status === \"invalid\")\n\t\t\treturn { error: `Structured output validation failed: ${validation.message}` };\n\t} catch (error) {\n\t\treturn {\n\t\t\terror: `Failed to validate structured output: ${error instanceof Error ? error.message : String(error)}`,\n\t\t};\n\t}\n\treturn { value };\n}\n\nexport function cleanupStructuredOutputRuntime(runtime: StructuredOutputRuntime | undefined): void {\n\tif (!runtime) return;\n\ttry {\n\t\tfs.rmSync(path.dirname(runtime.schemaPath), { recursive: true, force: true });\n\t} catch {\n\t\t// Best-effort temp cleanup.\n\t}\n}\n"]}