pagegraph 0.12.0 → 0.14.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.
Files changed (160) hide show
  1. package/README.md +325 -66
  2. package/dist/anthropic-messages-TqKpKmfW.js +1067 -0
  3. package/dist/anthropic-messages-TqKpKmfW.js.map +1 -0
  4. package/dist/audit.d.ts +4 -2
  5. package/dist/audit.js +5 -5
  6. package/dist/audit.js.map +1 -1
  7. package/dist/azure-openai-responses-DJjBLwoI.js +231 -0
  8. package/dist/azure-openai-responses-DJjBLwoI.js.map +1 -0
  9. package/dist/build-only/audit.js +1 -1
  10. package/dist/build-only/claims.d.ts +1 -0
  11. package/dist/build-only/claims.js +6 -0
  12. package/dist/build-only/claims.js.map +1 -0
  13. package/dist/build-only/config.js +1 -1
  14. package/dist/build-only/oxlint.d.ts +1 -0
  15. package/dist/build-only/oxlint.js +6 -0
  16. package/dist/build-only/oxlint.js.map +1 -0
  17. package/dist/build-only/tanstack-start.js +1 -1
  18. package/dist/build-only/vite.js +1 -1
  19. package/dist/{checks-uZk5Em9A.js → checks-BS-aDXB_.js} +2 -2
  20. package/dist/checks-BS-aDXB_.js.map +1 -0
  21. package/dist/claims-Bch7Lxlo.d.ts +92 -0
  22. package/dist/claims-Bv7voeEV.js +431 -0
  23. package/dist/claims-Bv7voeEV.js.map +1 -0
  24. package/dist/claims.d.ts +94 -0
  25. package/dist/claims.js +2 -0
  26. package/dist/cli.js +17607 -43387
  27. package/dist/cli.js.map +1 -1
  28. package/dist/cloudflare-workers-ai-system-one-f3ZrvNYZ.js +41 -0
  29. package/dist/cloudflare-workers-ai-system-one-f3ZrvNYZ.js.map +1 -0
  30. package/dist/config.d.ts +9 -29
  31. package/dist/config.js +2 -2
  32. package/dist/config.js.map +1 -1
  33. package/dist/{content-kcEnQdfi.js → content-CHd0X4s6.js} +2 -2
  34. package/dist/{content-kcEnQdfi.js.map → content-CHd0X4s6.js.map} +1 -1
  35. package/dist/{content-B1cPtL8b.d.ts → content-DgNr7apS.d.ts} +4 -5
  36. package/dist/declare-D5o7hwmv.js.map +1 -1
  37. package/dist/diagnostics-Wt5faNDM.js +108 -0
  38. package/dist/diagnostics-Wt5faNDM.js.map +1 -0
  39. package/dist/dist-B6zg_Z3Z.js +4794 -0
  40. package/dist/dist-B6zg_Z3Z.js.map +1 -0
  41. package/dist/document-CztEu3Vd.d.ts +109 -0
  42. package/dist/document-Dvemcv7V.js +379 -0
  43. package/dist/document-Dvemcv7V.js.map +1 -0
  44. package/dist/env-api-keys-C-OA0yM-.js +124 -0
  45. package/dist/env-api-keys-C-OA0yM-.js.map +1 -0
  46. package/dist/error-body-CyiejW4b.js +103 -0
  47. package/dist/error-body-CyiejW4b.js.map +1 -0
  48. package/dist/facts-1OKclPOk.js +115 -0
  49. package/dist/facts-1OKclPOk.js.map +1 -0
  50. package/dist/github-copilot-headers-CEpMOpQF.js +24 -0
  51. package/dist/github-copilot-headers-CEpMOpQF.js.map +1 -0
  52. package/dist/google-generative-ai-BxABKIKO.js +330 -0
  53. package/dist/google-generative-ai-BxABKIKO.js.map +1 -0
  54. package/dist/google-shared-0gpM2jFi.js +19471 -0
  55. package/dist/google-shared-0gpM2jFi.js.map +1 -0
  56. package/dist/google-vertex-D8Eb5cbu.js +376 -0
  57. package/dist/google-vertex-D8Eb5cbu.js.map +1 -0
  58. package/dist/{declare-DVgdEdOL.d.ts → graph-D1PIndsC.d.ts} +117 -6
  59. package/dist/{graph-Bcsourlv.js → graph-DMNOLXLu.js} +23 -13
  60. package/dist/graph-DMNOLXLu.js.map +1 -0
  61. package/dist/hash-Dp7EzZUo.js +18 -0
  62. package/dist/hash-Dp7EzZUo.js.map +1 -0
  63. package/dist/headers-BRNMVpzu.js +19 -0
  64. package/dist/headers-BRNMVpzu.js.map +1 -0
  65. package/dist/index-C5w9ripz.d.ts +204 -0
  66. package/dist/index.d.ts +6 -160
  67. package/dist/index.js +37 -5
  68. package/dist/index.js.map +1 -1
  69. package/dist/inline-BbS93GAT.js +682 -0
  70. package/dist/inline-BbS93GAT.js.map +1 -0
  71. package/dist/json-parse-C10znB7l.js +383 -0
  72. package/dist/json-parse-C10znB7l.js.map +1 -0
  73. package/dist/llms-Dhr_5u2O.js +19 -0
  74. package/dist/llms-Dhr_5u2O.js.map +1 -0
  75. package/dist/markdown-C6dRE9zD.js +168 -0
  76. package/dist/markdown-C6dRE9zD.js.map +1 -0
  77. package/dist/markdown-path-lJB9BAVZ.js +6 -0
  78. package/dist/markdown-path-lJB9BAVZ.js.map +1 -0
  79. package/dist/{message-DT_CjUdt.js → message-CuBjgZ74.js} +2 -2
  80. package/dist/{message-DT_CjUdt.js.map → message-CuBjgZ74.js.map} +1 -1
  81. package/dist/mistral-conversations-CvaqBWjR.js +690 -0
  82. package/dist/mistral-conversations-CvaqBWjR.js.map +1 -0
  83. package/dist/models-DcT5qOEL.js +1203 -0
  84. package/dist/models-DcT5qOEL.js.map +1 -0
  85. package/dist/node-Ccvru9GE.js +26 -0
  86. package/dist/node-Ccvru9GE.js.map +1 -0
  87. package/dist/node-MEosBOF2.js +2403 -0
  88. package/dist/node-MEosBOF2.js.map +1 -0
  89. package/dist/openai-BCBEd2eO.js +17350 -0
  90. package/dist/openai-BCBEd2eO.js.map +1 -0
  91. package/dist/openai-codex-responses-vJqxeeRC.js +1268 -0
  92. package/dist/openai-codex-responses-vJqxeeRC.js.map +1 -0
  93. package/dist/openai-completions-Cb_fRAbI.js +989 -0
  94. package/dist/openai-completions-Cb_fRAbI.js.map +1 -0
  95. package/dist/openai-prompt-cache-Bc6qNWt0.js +10 -0
  96. package/dist/openai-prompt-cache-Bc6qNWt0.js.map +1 -0
  97. package/dist/openai-responses-sDuh82G5.js +268 -0
  98. package/dist/openai-responses-sDuh82G5.js.map +1 -0
  99. package/dist/openai-responses-shared-mhuo1Jov.js +599 -0
  100. package/dist/openai-responses-shared-mhuo1Jov.js.map +1 -0
  101. package/dist/openrouter-images-CRmBkzpX.js +127 -0
  102. package/dist/openrouter-images-CRmBkzpX.js.map +1 -0
  103. package/dist/oxlint.d.ts +58 -0
  104. package/dist/oxlint.js +202 -0
  105. package/dist/oxlint.js.map +1 -0
  106. package/dist/page-heads-BfjWQvau.d.ts +108 -0
  107. package/dist/{page-heads-6y-CARRQ.js → page-heads-BgbaIjj9.js} +3 -3
  108. package/dist/page-heads-BgbaIjj9.js.map +1 -0
  109. package/dist/pi-Bvw6J0gh.js +56795 -0
  110. package/dist/pi-Bvw6J0gh.js.map +1 -0
  111. package/dist/pi-messages-CejiVYvO.js +308 -0
  112. package/dist/pi-messages-CejiVYvO.js.map +1 -0
  113. package/dist/{projections-DeEFe7XT.d.ts → projections-Bk-qOOsR.d.ts} +2 -2
  114. package/dist/provider-env-t38GK5FF.js +39 -0
  115. package/dist/provider-env-t38GK5FF.js.map +1 -0
  116. package/dist/provider-retry-DzKoh1X7.js +80 -0
  117. package/dist/provider-retry-DzKoh1X7.js.map +1 -0
  118. package/dist/react.d.ts +3 -2
  119. package/dist/react.js +2 -1
  120. package/dist/react.js.map +1 -1
  121. package/dist/rolldown-runtime-B-lAHAz2.js +37 -0
  122. package/dist/sanitize-unicode-Ds14l9Om.js +28 -0
  123. package/dist/sanitize-unicode-Ds14l9Om.js.map +1 -0
  124. package/dist/sdk-C9_wiO6w.js +12503 -0
  125. package/dist/sdk-C9_wiO6w.js.map +1 -0
  126. package/dist/state-BuJP_3Lr.js +28102 -0
  127. package/dist/state-BuJP_3Lr.js.map +1 -0
  128. package/dist/system-one-shared-Dl10ZF7Z.js +167 -0
  129. package/dist/system-one-shared-Dl10ZF7Z.js.map +1 -0
  130. package/dist/tanstack-start/index.d.ts +29 -13
  131. package/dist/tanstack-start/index.js +391 -42
  132. package/dist/tanstack-start/index.js.map +1 -1
  133. package/dist/tanstack-start/markdown.d.ts +12 -0
  134. package/dist/tanstack-start/markdown.js +149 -0
  135. package/dist/tanstack-start/markdown.js.map +1 -0
  136. package/dist/tanstack-start/prerender-worker.d.ts +2 -0
  137. package/dist/tanstack-start/prerender-worker.js +7 -0
  138. package/dist/tanstack-start/prerender-worker.js.map +1 -0
  139. package/dist/tanstack-start/react.d.ts +7 -0
  140. package/dist/tanstack-start/react.js +12 -0
  141. package/dist/tanstack-start/react.js.map +1 -0
  142. package/dist/tanstack-start/server.d.ts +9 -3
  143. package/dist/tanstack-start/server.js +26 -2
  144. package/dist/tanstack-start/server.js.map +1 -1
  145. package/dist/transform-messages-BLJ8EfK6.js +468 -0
  146. package/dist/transform-messages-BLJ8EfK6.js.map +1 -0
  147. package/dist/typesafe-system-one-CwEWMV8P.js +25 -0
  148. package/dist/typesafe-system-one-CwEWMV8P.js.map +1 -0
  149. package/dist/{vite-graph-loader-01p1WxEq.js → vite-graph-loader-CsGiYNWE.js} +6 -5
  150. package/dist/vite-graph-loader-CsGiYNWE.js.map +1 -0
  151. package/dist/vite-graph-loader-DZCwejuJ.d.ts +133 -0
  152. package/package.json +47 -10
  153. package/dist/checks-uZk5Em9A.js.map +0 -1
  154. package/dist/graph-Bcsourlv.js.map +0 -1
  155. package/dist/graph-BxCY90vq.d.ts +0 -104
  156. package/dist/graph-CBIY71w6.d.ts +0 -57
  157. package/dist/page-heads-6y-CARRQ.js.map +0 -1
  158. package/dist/page-heads-DNkjMUEN.d.ts +0 -21
  159. package/dist/vite-graph-loader-01p1WxEq.js.map +0 -1
  160. package/dist/vite-graph-loader-Btgjz5RH.d.ts +0 -56
@@ -0,0 +1,468 @@
1
+ import { S as getSystemMessageText } from "./models-DcT5qOEL.js";
2
+ //#region node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js
3
+ function loadNodeOs() {
4
+ if (typeof process === "undefined" || !(process.versions?.node || process.versions?.bun)) return null;
5
+ return process.getBuiltinModule?.("node:os") ?? null;
6
+ }
7
+ const nodeOs = loadNodeOs();
8
+ function getPiUserAgent() {
9
+ return nodeOs ? `pi (${nodeOs.platform()} ${nodeOs.release()}; ${nodeOs.arch()})` : "pi (browser)";
10
+ }
11
+ //#endregion
12
+ //#region node_modules/@earendil-works/pi-ai/dist/api/constrained-sampling.js
13
+ var UnsupportedStrictJsonSchemaError = class extends Error {};
14
+ const UNSUPPORTED_STRICT_SCHEMA_KEYS = [
15
+ "$ref",
16
+ "$defs",
17
+ "definitions",
18
+ "allOf",
19
+ "oneOf",
20
+ "patternProperties",
21
+ "dependentSchemas",
22
+ "dependencies",
23
+ "unevaluatedProperties",
24
+ "propertyNames",
25
+ "contains",
26
+ "prefixItems",
27
+ "not",
28
+ "if",
29
+ "then",
30
+ "else"
31
+ ];
32
+ function isJsonSchemaObject(value) {
33
+ return typeof value === "object" && value !== null && !Array.isArray(value);
34
+ }
35
+ function isStructuredSchema(schema) {
36
+ if (!isJsonSchemaObject(schema)) return false;
37
+ const types = typeof schema.type === "string" ? [schema.type] : Array.isArray(schema.type) ? schema.type : [];
38
+ return types.includes("object") || types.includes("array") || schema.properties !== void 0 || schema.items !== void 0;
39
+ }
40
+ function schemaAllowsNull(schema) {
41
+ if (!isJsonSchemaObject(schema)) return false;
42
+ if (schema.type === "null" || Array.isArray(schema.type) && schema.type.includes("null")) return true;
43
+ if (schema.const === null || Array.isArray(schema.enum) && schema.enum.includes(null)) return true;
44
+ return Array.isArray(schema.anyOf) && schema.anyOf.some((variant) => schemaAllowsNull(variant));
45
+ }
46
+ function makeJsonSchemaNodeStrict(schema, isUnsupportedKeyword) {
47
+ if (!isJsonSchemaObject(schema)) throw new UnsupportedStrictJsonSchemaError("boolean schemas are unsupported");
48
+ for (const key of UNSUPPORTED_STRICT_SCHEMA_KEYS) if (schema[key] !== void 0) throw new UnsupportedStrictJsonSchemaError(`${key} schemas are unsupported`);
49
+ if (isUnsupportedKeyword) {
50
+ for (const [key, value] of Object.entries(schema)) if (isUnsupportedKeyword(key, value)) throw new UnsupportedStrictJsonSchemaError(`${key}: ${JSON.stringify(value)} is unsupported`);
51
+ }
52
+ if (schema.anyOf !== void 0) {
53
+ if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) throw new UnsupportedStrictJsonSchemaError("anyOf must contain at least one schema");
54
+ for (const variant of schema.anyOf) {
55
+ if (isStructuredSchema(variant)) throw new UnsupportedStrictJsonSchemaError("object and array unions are unsupported");
56
+ makeJsonSchemaNodeStrict(variant, isUnsupportedKeyword);
57
+ }
58
+ }
59
+ if (schema.items !== void 0) {
60
+ if (Array.isArray(schema.items)) throw new UnsupportedStrictJsonSchemaError("tuple schemas are unsupported");
61
+ makeJsonSchemaNodeStrict(schema.items, isUnsupportedKeyword);
62
+ }
63
+ const isObjectSchema = schema.type === "object";
64
+ if (schema.properties !== void 0 && !isObjectSchema) throw new UnsupportedStrictJsonSchemaError("properties require type object");
65
+ if (!isObjectSchema) return;
66
+ if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) throw new UnsupportedStrictJsonSchemaError("schema-valued or true additionalProperties is unsupported");
67
+ if (schema.properties !== void 0 && !isJsonSchemaObject(schema.properties)) throw new UnsupportedStrictJsonSchemaError("object properties must be a schema map");
68
+ if (schema.required !== void 0 && (!Array.isArray(schema.required) || schema.required.some((key) => typeof key !== "string"))) throw new UnsupportedStrictJsonSchemaError("object required must be a string array");
69
+ const properties = schema.properties ?? {};
70
+ const propertyNames = Object.keys(properties);
71
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
72
+ if ([...required].some((key) => !propertyNames.includes(key))) throw new UnsupportedStrictJsonSchemaError("required contains an unknown property");
73
+ for (const [key, property] of Object.entries(properties)) {
74
+ makeJsonSchemaNodeStrict(property, isUnsupportedKeyword);
75
+ if (!required.has(key) && !schemaAllowsNull(property)) properties[key] = { anyOf: [property, { type: "null" }] };
76
+ }
77
+ schema.required = propertyNames;
78
+ schema.additionalProperties = false;
79
+ }
80
+ /** Convert a tool schema to the strict subset expected by provider constrained sampling. */
81
+ function makeStrictJsonSchema(schema, isUnsupportedKeyword) {
82
+ const cloned = structuredClone(schema);
83
+ if (!isJsonSchemaObject(cloned)) throw new UnsupportedStrictJsonSchemaError("root schema must have type object");
84
+ makeJsonSchemaNodeStrict(cloned, isUnsupportedKeyword);
85
+ if (cloned.type !== "object") throw new UnsupportedStrictJsonSchemaError("root schema must have type object");
86
+ return cloned;
87
+ }
88
+ function getJsonSchemaToolParameters(tool, strict) {
89
+ return strict === true ? makeStrictJsonSchema(tool.parameters) : tool.parameters;
90
+ }
91
+ function getGrammarToolInput(toolName, arguments_, inputProperty) {
92
+ const input = arguments_[inputProperty];
93
+ if (typeof input !== "string") throw new Error(`Grammar tool call "${toolName}" requires argument "${inputProperty}" to be a string.`);
94
+ return input;
95
+ }
96
+ function appendGrammarToolInputJsonDelta(buffer, inputProperty, nextInput, close) {
97
+ if (buffer.closed) {
98
+ if (close && nextInput === buffer.input) return void 0;
99
+ throw new Error(`grammar tool input for property "${inputProperty}" changed after it was closed`);
100
+ }
101
+ if (!nextInput.startsWith(buffer.input)) throw new Error(`grammar tool input for property "${inputProperty}" changed non-monotonically`);
102
+ const inputDelta = nextInput.slice(buffer.input.length);
103
+ if (!close && inputDelta.length === 0) return void 0;
104
+ let delta = "";
105
+ if (!buffer.started) {
106
+ delta += `{${JSON.stringify(inputProperty)}:"`;
107
+ buffer.started = true;
108
+ }
109
+ delta += JSON.stringify(inputDelta).slice(1, -1);
110
+ buffer.input = nextInput;
111
+ if (close) {
112
+ delta += "\"}";
113
+ buffer.closed = true;
114
+ }
115
+ return delta;
116
+ }
117
+ function inferGrammarInputProperty(tool) {
118
+ const schema = tool.parameters;
119
+ if (schema.type !== "object") throw new Error("grammar constrained sampling requires an object parameter schema");
120
+ if (!Array.isArray(schema.required) || schema.required.length !== 1 || typeof schema.required[0] !== "string") throw new Error("grammar constrained sampling requires exactly one required string property");
121
+ const inputProperty = schema.required[0];
122
+ if (!schema.properties?.[inputProperty]) throw new Error(`grammar constrained sampling requires a properties entry for ${inputProperty}`);
123
+ if (schema.properties[inputProperty]?.type !== "string") throw new Error(`grammar constrained sampling property ${inputProperty} must have type string`);
124
+ return inputProperty;
125
+ }
126
+ /**
127
+ * Decide whether a JSON-schema tool is sent in strict mode. `isUnsupportedKeyword` lets a provider
128
+ * reject extra keywords its strict mode does not accept, so "prefer" tools fall back to non-strict.
129
+ */
130
+ function resolveJsonSchemaStrictSampling(tool, supportsStrictMode, isUnsupportedKeyword) {
131
+ const config = tool.constrainedSampling;
132
+ if (!config || config.type !== "json_schema") return void 0;
133
+ if (supportsStrictMode) try {
134
+ makeStrictJsonSchema(tool.parameters, isUnsupportedKeyword);
135
+ return true;
136
+ } catch (error) {
137
+ if (!(error instanceof UnsupportedStrictJsonSchemaError)) throw error;
138
+ if (config.strict !== "require") return void 0;
139
+ throw new Error(`Tool "${tool.name}" requires JSON-schema constrained sampling, but ${error.message}.`);
140
+ }
141
+ if (config.strict === "require") throw new Error(`Tool "${tool.name}" requires JSON-schema constrained sampling, but strict tools are unsupported.`);
142
+ }
143
+ function resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools) {
144
+ const config = tool.constrainedSampling;
145
+ if (!config || config.type !== "grammar") return;
146
+ if (!supportsOpenAIGrammarTools) return;
147
+ const larkDefinition = config.variants.openai_lark;
148
+ const regexDefinition = config.variants.openai_regex;
149
+ const hasLarkDefinition = typeof larkDefinition === "string" && larkDefinition.trim().length > 0;
150
+ const hasRegexDefinition = typeof regexDefinition === "string" && regexDefinition.trim().length > 0;
151
+ if (!hasLarkDefinition && !hasRegexDefinition) throw new Error(`Tool "${tool.name}" cannot use grammar constrained sampling: no supported grammar variant was provided.`);
152
+ try {
153
+ return {
154
+ format: hasLarkDefinition ? "lark" : "regex",
155
+ definition: hasLarkDefinition ? larkDefinition : regexDefinition,
156
+ inputProperty: inferGrammarInputProperty(tool)
157
+ };
158
+ } catch (error) {
159
+ const message = error instanceof Error ? error.message : String(error);
160
+ throw new Error(`Tool "${tool.name}" cannot use grammar constrained sampling: ${message}.`);
161
+ }
162
+ }
163
+ function createGrammarToolInputProperties(tools, supportsOpenAIGrammarTools) {
164
+ const properties = /* @__PURE__ */ new Map();
165
+ for (const tool of tools ?? []) {
166
+ const grammar = resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools);
167
+ if (grammar) properties.set(tool.name, grammar.inputProperty);
168
+ }
169
+ return properties;
170
+ }
171
+ //#endregion
172
+ //#region node_modules/@earendil-works/pi-ai/dist/utils/estimate.js
173
+ const CHARS_PER_TOKEN = 4;
174
+ const ESTIMATED_IMAGE_CHARS = 4800;
175
+ function calculateContextTokens(usage) {
176
+ return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
177
+ }
178
+ function safeJsonStringify(value) {
179
+ try {
180
+ return JSON.stringify(value) ?? "undefined";
181
+ } catch {
182
+ return "[unserializable]";
183
+ }
184
+ }
185
+ function estimateTextAndImageContentChars(content) {
186
+ if (typeof content === "string") return content.length;
187
+ let chars = 0;
188
+ for (const block of content) chars += block.type === "text" ? block.text.length : ESTIMATED_IMAGE_CHARS;
189
+ return chars;
190
+ }
191
+ function estimateTextTokens(text) {
192
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
193
+ }
194
+ function estimateTextAndImageContentTokens(content) {
195
+ return Math.ceil(estimateTextAndImageContentChars(content) / CHARS_PER_TOKEN);
196
+ }
197
+ function estimateMessageTokens(message) {
198
+ let chars = 0;
199
+ if (message.role === "system") return estimateTextTokens(getSystemMessageText(message)) + estimateToolsTokens(message.toolsAdded) + estimateToolsTokens(message.toolsRemoved);
200
+ if (message.role === "user") return estimateTextAndImageContentTokens(message.content);
201
+ if (message.role === "toolResult") return estimateTextAndImageContentTokens(message.content);
202
+ for (const block of message.content) if (block.type === "text") chars += block.text.length;
203
+ else if (block.type === "thinking") chars += block.thinking.length;
204
+ else chars += block.name.length + safeJsonStringify(block.arguments).length;
205
+ return Math.ceil(chars / CHARS_PER_TOKEN);
206
+ }
207
+ function getLastAssistantUsageInfo(messages) {
208
+ let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;
209
+ let usageInfo;
210
+ for (let i = 0; i < messages.length; i++) {
211
+ const message = messages[i];
212
+ if (message.role === "assistant") {
213
+ const assistant = message;
214
+ if (assistant.timestamp >= latestPrefixTimestamp && assistant.stopReason !== "aborted" && assistant.stopReason !== "error" && calculateContextTokens(assistant.usage) > 0) usageInfo = {
215
+ usage: assistant.usage,
216
+ index: i
217
+ };
218
+ }
219
+ latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);
220
+ }
221
+ return usageInfo;
222
+ }
223
+ function estimateContextTokens(context) {
224
+ const messages = "messages" in context ? context.messages : context;
225
+ const usageInfo = getLastAssistantUsageInfo(messages);
226
+ if (usageInfo) {
227
+ const usageTokens = calculateContextTokens(usageInfo.usage);
228
+ let trailingTokens = 0;
229
+ for (let i = usageInfo.index + 1; i < messages.length; i++) trailingTokens += estimateMessageTokens(messages[i]);
230
+ return {
231
+ tokens: usageTokens + trailingTokens,
232
+ usageTokens,
233
+ trailingTokens,
234
+ lastUsageIndex: usageInfo.index
235
+ };
236
+ }
237
+ let tokens = 0;
238
+ for (const message of messages) tokens += estimateMessageTokens(message);
239
+ return {
240
+ tokens,
241
+ usageTokens: 0,
242
+ trailingTokens: tokens,
243
+ lastUsageIndex: null
244
+ };
245
+ }
246
+ function estimateToolsTokens(tools) {
247
+ if (!tools || tools.length === 0) return 0;
248
+ return estimateTextTokens(safeJsonStringify(tools));
249
+ }
250
+ //#endregion
251
+ //#region node_modules/@earendil-works/pi-ai/dist/api/simple-options.js
252
+ const CONTEXT_SAFETY_TOKENS = 4096;
253
+ const MIN_MAX_TOKENS = 1;
254
+ function clampMaxTokensToContext(model, context, maxTokens) {
255
+ if (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);
256
+ const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;
257
+ return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));
258
+ }
259
+ function buildBaseOptions(model, context, options, apiKey) {
260
+ return {
261
+ temperature: options?.temperature,
262
+ samplingParams: options?.samplingParams,
263
+ maxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),
264
+ signal: options?.signal,
265
+ telemetryContext: options?.telemetryContext,
266
+ apiKey: apiKey || options?.apiKey,
267
+ fetch: options?.fetch,
268
+ transport: options?.transport,
269
+ cacheRetention: options?.cacheRetention,
270
+ sessionId: options?.sessionId,
271
+ headers: options?.headers,
272
+ onPayload: options?.onPayload,
273
+ onResponse: options?.onResponse,
274
+ onProviderStreamEvent: options?.onProviderStreamEvent,
275
+ timeoutMs: options?.timeoutMs,
276
+ websocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,
277
+ maxRetries: options?.maxRetries,
278
+ maxRetryDelayMs: options?.maxRetryDelayMs,
279
+ metadata: options?.metadata,
280
+ env: options?.env
281
+ };
282
+ }
283
+ /** Tokens always left for the answer when a thinking budget shares the response ceiling. */
284
+ const MIN_ANSWER_TOKENS = 1024;
285
+ const DEFAULT_THINKING_BUDGETS = {
286
+ minimal: 1024,
287
+ low: 2048,
288
+ medium: 8192,
289
+ high: 16384
290
+ };
291
+ function clampReasoning(effort) {
292
+ return effort === "xhigh" || effort === "max" ? "high" : effort;
293
+ }
294
+ function thinkingBudgetForLevel(reasoningLevel, customBudgets) {
295
+ return {
296
+ ...DEFAULT_THINKING_BUDGETS,
297
+ ...customBudgets
298
+ }[clampReasoning(reasoningLevel)];
299
+ }
300
+ /** Cap a thinking budget so at least MIN_ANSWER_TOKENS remain under a shared response ceiling. */
301
+ function clampThinkingBudgetToAnswerRoom(thinkingBudget, ceiling) {
302
+ return Math.min(thinkingBudget, Math.max(0, ceiling - MIN_ANSWER_TOKENS));
303
+ }
304
+ function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
305
+ let thinkingBudget = thinkingBudgetForLevel(reasoningLevel, customBudgets);
306
+ const maxTokens = baseMaxTokens === void 0 ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
307
+ if (maxTokens <= thinkingBudget) thinkingBudget = clampThinkingBudgetToAnswerRoom(thinkingBudget, maxTokens);
308
+ return {
309
+ maxTokens,
310
+ thinkingBudget
311
+ };
312
+ }
313
+ //#endregion
314
+ //#region node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js
315
+ const NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
316
+ const NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
317
+ function replaceImagesWithPlaceholder(content, placeholder) {
318
+ const result = [];
319
+ let previousWasPlaceholder = false;
320
+ for (const block of content) {
321
+ if (block.type === "image") {
322
+ if (!previousWasPlaceholder) result.push({
323
+ type: "text",
324
+ text: placeholder
325
+ });
326
+ previousWasPlaceholder = true;
327
+ continue;
328
+ }
329
+ result.push(block);
330
+ previousWasPlaceholder = block.text === placeholder;
331
+ }
332
+ return result;
333
+ }
334
+ function downgradeUnsupportedImages(messages, model) {
335
+ if (model.input.includes("image")) return messages;
336
+ return messages.map((msg) => {
337
+ if (msg.role === "user" && Array.isArray(msg.content)) return {
338
+ ...msg,
339
+ content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
340
+ };
341
+ if (msg.role === "toolResult") return {
342
+ ...msg,
343
+ content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
344
+ };
345
+ return msg;
346
+ });
347
+ }
348
+ /**
349
+ * Normalize tool call ID for cross-provider compatibility.
350
+ * OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.
351
+ * Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).
352
+ */
353
+ function transformMessages(messages, model, normalizeToolCallId) {
354
+ const toolCallIdMap = /* @__PURE__ */ new Map();
355
+ const transformed = downgradeUnsupportedImages(messages.map((msg) => msg.content == null ? {
356
+ ...msg,
357
+ content: []
358
+ } : msg), model).map((msg) => {
359
+ if (msg.role === "system" || msg.role === "user") return msg;
360
+ if (msg.role === "toolResult") {
361
+ const normalizedId = toolCallIdMap.get(msg.toolCallId);
362
+ if (normalizedId && normalizedId !== msg.toolCallId) return {
363
+ ...msg,
364
+ toolCallId: normalizedId
365
+ };
366
+ return msg;
367
+ }
368
+ if (msg.role === "assistant") {
369
+ const assistantMsg = msg;
370
+ const isSameModel = assistantMsg.provider === model.provider && assistantMsg.api === model.api && assistantMsg.model === model.id;
371
+ const transformedContent = assistantMsg.content.flatMap((block) => {
372
+ if (block.type === "thinking") {
373
+ if (block.redacted) return isSameModel ? block : [];
374
+ if (isSameModel && block.thinkingSignature) return block;
375
+ if (!block.thinking || block.thinking.trim() === "") return [];
376
+ if (isSameModel) return block;
377
+ return {
378
+ type: "text",
379
+ text: block.thinking
380
+ };
381
+ }
382
+ if (block.type === "text") {
383
+ if (isSameModel) return block;
384
+ return {
385
+ type: "text",
386
+ text: block.text
387
+ };
388
+ }
389
+ if (block.type === "toolCall") {
390
+ const toolCall = block;
391
+ let normalizedToolCall = toolCall;
392
+ if (!isSameModel && toolCall.thoughtSignature) {
393
+ normalizedToolCall = { ...toolCall };
394
+ delete normalizedToolCall.thoughtSignature;
395
+ }
396
+ if (!isSameModel && normalizeToolCallId) {
397
+ const normalizedId = normalizeToolCallId(toolCall.id, model, assistantMsg);
398
+ if (normalizedId !== toolCall.id) {
399
+ toolCallIdMap.set(toolCall.id, normalizedId);
400
+ normalizedToolCall = {
401
+ ...normalizedToolCall,
402
+ id: normalizedId
403
+ };
404
+ }
405
+ }
406
+ return normalizedToolCall;
407
+ }
408
+ return block;
409
+ });
410
+ return {
411
+ ...assistantMsg,
412
+ content: transformedContent
413
+ };
414
+ }
415
+ return msg;
416
+ });
417
+ const result = [];
418
+ let pendingToolCalls = [];
419
+ let existingToolResultIds = /* @__PURE__ */ new Set();
420
+ const heldSystemMessages = [];
421
+ const closePendingToolCalls = () => {
422
+ if (pendingToolCalls.length > 0) {
423
+ for (const tc of pendingToolCalls) if (!existingToolResultIds.has(tc.id)) result.push({
424
+ role: "toolResult",
425
+ toolCallId: tc.id,
426
+ toolName: tc.name,
427
+ content: [{
428
+ type: "text",
429
+ text: "No result provided"
430
+ }],
431
+ isError: true,
432
+ timestamp: Date.now()
433
+ });
434
+ pendingToolCalls = [];
435
+ existingToolResultIds = /* @__PURE__ */ new Set();
436
+ }
437
+ result.push(...heldSystemMessages);
438
+ heldSystemMessages.length = 0;
439
+ };
440
+ for (let i = 0; i < transformed.length; i++) {
441
+ const msg = transformed[i];
442
+ if (msg.role === "assistant") {
443
+ closePendingToolCalls();
444
+ const assistantMsg = msg;
445
+ if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") continue;
446
+ const toolCalls = assistantMsg.content.filter((b) => b.type === "toolCall");
447
+ if (toolCalls.length > 0) {
448
+ pendingToolCalls = toolCalls;
449
+ existingToolResultIds = /* @__PURE__ */ new Set();
450
+ }
451
+ result.push(msg);
452
+ } else if (msg.role === "toolResult") {
453
+ existingToolResultIds.add(msg.toolCallId);
454
+ result.push(msg);
455
+ } else if (msg.role === "system") if (pendingToolCalls.length > 0) heldSystemMessages.push(msg);
456
+ else result.push(msg);
457
+ else if (msg.role === "user") {
458
+ closePendingToolCalls();
459
+ result.push(msg);
460
+ } else result.push(msg);
461
+ }
462
+ closePendingToolCalls();
463
+ return result;
464
+ }
465
+ //#endregion
466
+ export { clampThinkingBudgetToAnswerRoom as a, createGrammarToolInputProperties as c, resolveGrammarConstrainedSampling as d, resolveJsonSchemaStrictSampling as f, clampMaxTokensToContext as i, getGrammarToolInput as l, adjustMaxTokensForThinking as n, thinkingBudgetForLevel as o, getPiUserAgent as p, buildBaseOptions as r, appendGrammarToolInputJsonDelta as s, transformMessages as t, getJsonSchemaToolParameters as u };
467
+
468
+ //# sourceMappingURL=transform-messages-BLJ8EfK6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-messages-BLJ8EfK6.js","names":[],"sources":["../node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js","../node_modules/@earendil-works/pi-ai/dist/api/constrained-sampling.js","../node_modules/@earendil-works/pi-ai/dist/utils/estimate.js","../node_modules/@earendil-works/pi-ai/dist/api/simple-options.js","../node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js"],"sourcesContent":["function loadNodeOs() {\n if (typeof process === \"undefined\" || !(process.versions?.node || process.versions?.bun)) {\n return null;\n }\n return process.getBuiltinModule?.(\"node:os\") ?? null;\n}\n// Keep runtime OS loading browser-safe. A top-level runtime import of node:os breaks browser/Vite builds.\nconst nodeOs = loadNodeOs();\nexport function getPiUserAgent() {\n return nodeOs ? `pi (${nodeOs.platform()} ${nodeOs.release()}; ${nodeOs.arch()})` : \"pi (browser)\";\n}\n//# sourceMappingURL=pi-user-agent.js.map","class UnsupportedStrictJsonSchemaError extends Error {\n}\nconst UNSUPPORTED_STRICT_SCHEMA_KEYS = [\n \"$ref\",\n \"$defs\",\n \"definitions\",\n \"allOf\",\n \"oneOf\",\n \"patternProperties\",\n \"dependentSchemas\",\n \"dependencies\",\n \"unevaluatedProperties\",\n \"propertyNames\",\n \"contains\",\n \"prefixItems\",\n \"not\",\n \"if\",\n \"then\",\n \"else\",\n];\nfunction isJsonSchemaObject(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction isStructuredSchema(schema) {\n if (!isJsonSchemaObject(schema))\n return false;\n const types = typeof schema.type === \"string\" ? [schema.type] : Array.isArray(schema.type) ? schema.type : [];\n return (types.includes(\"object\") ||\n types.includes(\"array\") ||\n schema.properties !== undefined ||\n schema.items !== undefined);\n}\nfunction schemaAllowsNull(schema) {\n if (!isJsonSchemaObject(schema))\n return false;\n if (schema.type === \"null\" || (Array.isArray(schema.type) && schema.type.includes(\"null\")))\n return true;\n if (schema.const === null || (Array.isArray(schema.enum) && schema.enum.includes(null)))\n return true;\n return Array.isArray(schema.anyOf) && schema.anyOf.some((variant) => schemaAllowsNull(variant));\n}\nfunction makeJsonSchemaNodeStrict(schema, isUnsupportedKeyword) {\n if (!isJsonSchemaObject(schema)) {\n throw new UnsupportedStrictJsonSchemaError(\"boolean schemas are unsupported\");\n }\n for (const key of UNSUPPORTED_STRICT_SCHEMA_KEYS) {\n if (schema[key] !== undefined) {\n throw new UnsupportedStrictJsonSchemaError(`${key} schemas are unsupported`);\n }\n }\n if (isUnsupportedKeyword) {\n for (const [key, value] of Object.entries(schema)) {\n if (isUnsupportedKeyword(key, value)) {\n throw new UnsupportedStrictJsonSchemaError(`${key}: ${JSON.stringify(value)} is unsupported`);\n }\n }\n }\n if (schema.anyOf !== undefined) {\n if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) {\n throw new UnsupportedStrictJsonSchemaError(\"anyOf must contain at least one schema\");\n }\n for (const variant of schema.anyOf) {\n if (isStructuredSchema(variant)) {\n throw new UnsupportedStrictJsonSchemaError(\"object and array unions are unsupported\");\n }\n makeJsonSchemaNodeStrict(variant, isUnsupportedKeyword);\n }\n }\n if (schema.items !== undefined) {\n if (Array.isArray(schema.items)) {\n throw new UnsupportedStrictJsonSchemaError(\"tuple schemas are unsupported\");\n }\n makeJsonSchemaNodeStrict(schema.items, isUnsupportedKeyword);\n }\n const isObjectSchema = schema.type === \"object\";\n if (schema.properties !== undefined && !isObjectSchema) {\n throw new UnsupportedStrictJsonSchemaError(\"properties require type object\");\n }\n if (!isObjectSchema)\n return;\n if (schema.additionalProperties !== undefined && schema.additionalProperties !== false) {\n throw new UnsupportedStrictJsonSchemaError(\"schema-valued or true additionalProperties is unsupported\");\n }\n if (schema.properties !== undefined && !isJsonSchemaObject(schema.properties)) {\n throw new UnsupportedStrictJsonSchemaError(\"object properties must be a schema map\");\n }\n if (schema.required !== undefined &&\n (!Array.isArray(schema.required) || schema.required.some((key) => typeof key !== \"string\"))) {\n throw new UnsupportedStrictJsonSchemaError(\"object required must be a string array\");\n }\n const properties = schema.properties ?? {};\n const propertyNames = Object.keys(properties);\n const required = new Set(Array.isArray(schema.required) ? schema.required : []);\n if ([...required].some((key) => !propertyNames.includes(key))) {\n throw new UnsupportedStrictJsonSchemaError(\"required contains an unknown property\");\n }\n for (const [key, property] of Object.entries(properties)) {\n makeJsonSchemaNodeStrict(property, isUnsupportedKeyword);\n if (!required.has(key) && !schemaAllowsNull(property)) {\n properties[key] = { anyOf: [property, { type: \"null\" }] };\n }\n }\n schema.required = propertyNames;\n schema.additionalProperties = false;\n}\n/** Convert a tool schema to the strict subset expected by provider constrained sampling. */\nexport function makeStrictJsonSchema(schema, isUnsupportedKeyword) {\n const cloned = structuredClone(schema);\n if (!isJsonSchemaObject(cloned)) {\n throw new UnsupportedStrictJsonSchemaError(\"root schema must have type object\");\n }\n makeJsonSchemaNodeStrict(cloned, isUnsupportedKeyword);\n if (cloned.type !== \"object\") {\n throw new UnsupportedStrictJsonSchemaError(\"root schema must have type object\");\n }\n return cloned;\n}\nexport function getJsonSchemaToolParameters(tool, strict) {\n return (strict === true ? makeStrictJsonSchema(tool.parameters) : tool.parameters);\n}\nexport function getGrammarToolInput(toolName, arguments_, inputProperty) {\n const input = arguments_[inputProperty];\n if (typeof input !== \"string\") {\n throw new Error(`Grammar tool call \"${toolName}\" requires argument \"${inputProperty}\" to be a string.`);\n }\n return input;\n}\nexport function appendGrammarToolInputJsonDelta(buffer, inputProperty, nextInput, close) {\n if (buffer.closed) {\n if (close && nextInput === buffer.input)\n return undefined;\n throw new Error(`grammar tool input for property \"${inputProperty}\" changed after it was closed`);\n }\n if (!nextInput.startsWith(buffer.input)) {\n throw new Error(`grammar tool input for property \"${inputProperty}\" changed non-monotonically`);\n }\n const inputDelta = nextInput.slice(buffer.input.length);\n if (!close && inputDelta.length === 0)\n return undefined;\n let delta = \"\";\n if (!buffer.started) {\n delta += `{${JSON.stringify(inputProperty)}:\"`;\n buffer.started = true;\n }\n delta += JSON.stringify(inputDelta).slice(1, -1);\n buffer.input = nextInput;\n if (close) {\n delta += '\"}';\n buffer.closed = true;\n }\n return delta;\n}\nfunction inferGrammarInputProperty(tool) {\n const schema = tool.parameters;\n if (schema.type !== \"object\") {\n throw new Error(\"grammar constrained sampling requires an object parameter schema\");\n }\n if (!Array.isArray(schema.required) || schema.required.length !== 1 || typeof schema.required[0] !== \"string\") {\n throw new Error(\"grammar constrained sampling requires exactly one required string property\");\n }\n const inputProperty = schema.required[0];\n if (!schema.properties?.[inputProperty]) {\n throw new Error(`grammar constrained sampling requires a properties entry for ${inputProperty}`);\n }\n if (schema.properties[inputProperty]?.type !== \"string\") {\n throw new Error(`grammar constrained sampling property ${inputProperty} must have type string`);\n }\n return inputProperty;\n}\n/**\n * Decide whether a JSON-schema tool is sent in strict mode. `isUnsupportedKeyword` lets a provider\n * reject extra keywords its strict mode does not accept, so \"prefer\" tools fall back to non-strict.\n */\nexport function resolveJsonSchemaStrictSampling(tool, supportsStrictMode, isUnsupportedKeyword) {\n const config = tool.constrainedSampling;\n if (!config || config.type !== \"json_schema\")\n return undefined;\n if (supportsStrictMode) {\n try {\n makeStrictJsonSchema(tool.parameters, isUnsupportedKeyword);\n return true;\n }\n catch (error) {\n if (!(error instanceof UnsupportedStrictJsonSchemaError))\n throw error;\n if (config.strict !== \"require\")\n return undefined;\n throw new Error(`Tool \"${tool.name}\" requires JSON-schema constrained sampling, but ${error.message}.`);\n }\n }\n if (config.strict === \"require\") {\n throw new Error(`Tool \"${tool.name}\" requires JSON-schema constrained sampling, but strict tools are unsupported.`);\n }\n return undefined;\n}\nexport function resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools) {\n const config = tool.constrainedSampling;\n if (!config || config.type !== \"grammar\") {\n return undefined;\n }\n if (!supportsOpenAIGrammarTools) {\n return undefined;\n }\n const larkDefinition = config.variants.openai_lark;\n const regexDefinition = config.variants.openai_regex;\n const hasLarkDefinition = typeof larkDefinition === \"string\" && larkDefinition.trim().length > 0;\n const hasRegexDefinition = typeof regexDefinition === \"string\" && regexDefinition.trim().length > 0;\n if (!hasLarkDefinition && !hasRegexDefinition) {\n throw new Error(`Tool \"${tool.name}\" cannot use grammar constrained sampling: no supported grammar variant was provided.`);\n }\n try {\n return {\n format: hasLarkDefinition ? \"lark\" : \"regex\",\n definition: hasLarkDefinition ? larkDefinition : regexDefinition,\n inputProperty: inferGrammarInputProperty(tool),\n };\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Tool \"${tool.name}\" cannot use grammar constrained sampling: ${message}.`);\n }\n}\nexport function createGrammarToolInputProperties(tools, supportsOpenAIGrammarTools) {\n const properties = new Map();\n for (const tool of tools ?? []) {\n const grammar = resolveGrammarConstrainedSampling(tool, supportsOpenAIGrammarTools);\n if (grammar) {\n properties.set(tool.name, grammar.inputProperty);\n }\n }\n return properties;\n}\n//# sourceMappingURL=constrained-sampling.js.map","import { getSystemMessageText } from \"./text.js\";\nconst CHARS_PER_TOKEN = 4;\nconst ESTIMATED_IMAGE_CHARS = 4800;\nexport function calculateContextTokens(usage) {\n return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction safeJsonStringify(value) {\n try {\n return JSON.stringify(value) ?? \"undefined\";\n }\n catch {\n return \"[unserializable]\";\n }\n}\nfunction estimateTextAndImageContentChars(content) {\n if (typeof content === \"string\")\n return content.length;\n let chars = 0;\n for (const block of content)\n chars += block.type === \"text\" ? block.text.length : ESTIMATED_IMAGE_CHARS;\n return chars;\n}\nexport function estimateTextTokens(text) {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\nexport function estimateTextAndImageContentTokens(content) {\n return Math.ceil(estimateTextAndImageContentChars(content) / CHARS_PER_TOKEN);\n}\nexport function estimateMessageTokens(message) {\n let chars = 0;\n if (message.role === \"system\") {\n return (estimateTextTokens(getSystemMessageText(message)) +\n estimateToolsTokens(message.toolsAdded) +\n estimateToolsTokens(message.toolsRemoved));\n }\n if (message.role === \"user\")\n return estimateTextAndImageContentTokens(message.content);\n if (message.role === \"toolResult\")\n return estimateTextAndImageContentTokens(message.content);\n for (const block of message.content) {\n if (block.type === \"text\") {\n chars += block.text.length;\n }\n else if (block.type === \"thinking\") {\n chars += block.thinking.length;\n }\n else {\n chars += block.name.length + safeJsonStringify(block.arguments).length;\n }\n }\n return Math.ceil(chars / CHARS_PER_TOKEN);\n}\nfunction getLastAssistantUsageInfo(messages) {\n let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;\n let usageInfo;\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i];\n if (message.role === \"assistant\") {\n const assistant = message;\n // A newer prefix message was inserted after this response (for example, a\n // compaction summary), so its usage cannot describe the current prefix.\n const usageAppliesToPrefix = assistant.timestamp >= latestPrefixTimestamp;\n if (usageAppliesToPrefix &&\n assistant.stopReason !== \"aborted\" &&\n assistant.stopReason !== \"error\" &&\n calculateContextTokens(assistant.usage) > 0) {\n usageInfo = { usage: assistant.usage, index: i };\n }\n }\n latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);\n }\n return usageInfo;\n}\nexport function estimateContextTokens(context) {\n const messages = \"messages\" in context ? context.messages : context;\n const usageInfo = getLastAssistantUsageInfo(messages);\n if (usageInfo) {\n const usageTokens = calculateContextTokens(usageInfo.usage);\n let trailingTokens = 0;\n for (let i = usageInfo.index + 1; i < messages.length; i++) {\n trailingTokens += estimateMessageTokens(messages[i]);\n }\n return { tokens: usageTokens + trailingTokens, usageTokens, trailingTokens, lastUsageIndex: usageInfo.index };\n }\n let tokens = 0;\n for (const message of messages)\n tokens += estimateMessageTokens(message);\n return { tokens, usageTokens: 0, trailingTokens: tokens, lastUsageIndex: null };\n}\nfunction estimateToolsTokens(tools) {\n if (!tools || tools.length === 0)\n return 0;\n return estimateTextTokens(safeJsonStringify(tools));\n}\n//# sourceMappingURL=estimate.js.map","import { estimateContextTokens } from \"../utils/estimate.js\";\nconst CONTEXT_SAFETY_TOKENS = 4096;\nconst MIN_MAX_TOKENS = 1;\nexport function clampMaxTokensToContext(model, context, maxTokens) {\n if (model.contextWindow <= 0)\n return Math.max(MIN_MAX_TOKENS, maxTokens);\n const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n}\nexport function buildBaseOptions(model, context, options, apiKey) {\n return {\n temperature: options?.temperature,\n samplingParams: options?.samplingParams,\n maxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),\n signal: options?.signal,\n telemetryContext: options?.telemetryContext,\n apiKey: apiKey || options?.apiKey,\n fetch: options?.fetch,\n transport: options?.transport,\n cacheRetention: options?.cacheRetention,\n sessionId: options?.sessionId,\n headers: options?.headers,\n onPayload: options?.onPayload,\n onResponse: options?.onResponse,\n onProviderStreamEvent: options?.onProviderStreamEvent,\n timeoutMs: options?.timeoutMs,\n websocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n maxRetries: options?.maxRetries,\n maxRetryDelayMs: options?.maxRetryDelayMs,\n metadata: options?.metadata,\n env: options?.env,\n };\n}\n/** Tokens always left for the answer when a thinking budget shares the response ceiling. */\nexport const MIN_ANSWER_TOKENS = 1024;\nexport const DEFAULT_THINKING_BUDGETS = {\n minimal: 1024,\n low: 2048,\n medium: 8192,\n high: 16384,\n};\nexport function clampReasoning(effort) {\n return effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\nexport function thinkingBudgetForLevel(reasoningLevel, customBudgets) {\n const budgets = { ...DEFAULT_THINKING_BUDGETS, ...customBudgets };\n const level = clampReasoning(reasoningLevel);\n return budgets[level];\n}\n/** Cap a thinking budget so at least MIN_ANSWER_TOKENS remain under a shared response ceiling. */\nexport function clampThinkingBudgetToAnswerRoom(thinkingBudget, ceiling) {\n return Math.min(thinkingBudget, Math.max(0, ceiling - MIN_ANSWER_TOKENS));\n}\nexport function adjustMaxTokensForThinking(\n// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\nbaseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {\n let thinkingBudget = thinkingBudgetForLevel(reasoningLevel, customBudgets);\n const maxTokens = baseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n if (maxTokens <= thinkingBudget) {\n thinkingBudget = clampThinkingBudgetToAnswerRoom(thinkingBudget, maxTokens);\n }\n return { maxTokens, thinkingBudget };\n}\n//# sourceMappingURL=simple-options.js.map","const NON_VISION_USER_IMAGE_PLACEHOLDER = \"(image omitted: model does not support images)\";\nconst NON_VISION_TOOL_IMAGE_PLACEHOLDER = \"(tool image omitted: model does not support images)\";\nfunction replaceImagesWithPlaceholder(content, placeholder) {\n const result = [];\n let previousWasPlaceholder = false;\n for (const block of content) {\n if (block.type === \"image\") {\n if (!previousWasPlaceholder) {\n result.push({ type: \"text\", text: placeholder });\n }\n previousWasPlaceholder = true;\n continue;\n }\n result.push(block);\n previousWasPlaceholder = block.text === placeholder;\n }\n return result;\n}\nfunction downgradeUnsupportedImages(messages, model) {\n if (model.input.includes(\"image\")) {\n return messages;\n }\n return messages.map((msg) => {\n if (msg.role === \"user\" && Array.isArray(msg.content)) {\n return {\n ...msg,\n content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER),\n };\n }\n if (msg.role === \"toolResult\") {\n return {\n ...msg,\n content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER),\n };\n }\n return msg;\n });\n}\n/**\n * Normalize tool call ID for cross-provider compatibility.\n * OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.\n * Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).\n */\nexport function transformMessages(messages, model, normalizeToolCallId) {\n // Build a map of original tool call IDs to normalized IDs\n const toolCallIdMap = new Map();\n // Normalize null/undefined content from untyped callers (custom tools, hand-built\n // histories, old session files) so downstream code can rely on the type contract.\n const normalizedMessages = messages.map((msg) => (msg.content == null ? { ...msg, content: [] } : msg));\n const imageAwareMessages = downgradeUnsupportedImages(normalizedMessages, model);\n // First pass: transform messages (unsupported image downgrade, thinking blocks, tool call ID normalization)\n const transformed = imageAwareMessages.map((msg) => {\n // System and user messages pass through unchanged\n if (msg.role === \"system\" || msg.role === \"user\") {\n return msg;\n }\n // Handle toolResult messages - normalize toolCallId if we have a mapping\n if (msg.role === \"toolResult\") {\n const normalizedId = toolCallIdMap.get(msg.toolCallId);\n if (normalizedId && normalizedId !== msg.toolCallId) {\n return { ...msg, toolCallId: normalizedId };\n }\n return msg;\n }\n // Assistant messages need transformation check\n if (msg.role === \"assistant\") {\n const assistantMsg = msg;\n const isSameModel = assistantMsg.provider === model.provider &&\n assistantMsg.api === model.api &&\n assistantMsg.model === model.id;\n const transformedContent = assistantMsg.content.flatMap((block) => {\n if (block.type === \"thinking\") {\n // Redacted thinking is opaque encrypted content, only valid for the same model.\n // Drop it for cross-model to avoid API errors.\n if (block.redacted) {\n return isSameModel ? block : [];\n }\n // For same model: keep thinking blocks with signatures (needed for replay)\n // even if the thinking text is empty (OpenAI encrypted reasoning)\n if (isSameModel && block.thinkingSignature)\n return block;\n // Skip empty thinking blocks, convert others to plain text\n if (!block.thinking || block.thinking.trim() === \"\")\n return [];\n if (isSameModel)\n return block;\n return {\n type: \"text\",\n text: block.thinking,\n };\n }\n if (block.type === \"text\") {\n if (isSameModel)\n return block;\n return {\n type: \"text\",\n text: block.text,\n };\n }\n if (block.type === \"toolCall\") {\n const toolCall = block;\n let normalizedToolCall = toolCall;\n if (!isSameModel && toolCall.thoughtSignature) {\n normalizedToolCall = { ...toolCall };\n delete normalizedToolCall.thoughtSignature;\n }\n if (!isSameModel && normalizeToolCallId) {\n const normalizedId = normalizeToolCallId(toolCall.id, model, assistantMsg);\n if (normalizedId !== toolCall.id) {\n toolCallIdMap.set(toolCall.id, normalizedId);\n normalizedToolCall = { ...normalizedToolCall, id: normalizedId };\n }\n }\n return normalizedToolCall;\n }\n return block;\n });\n return {\n ...assistantMsg,\n content: transformedContent,\n };\n }\n return msg;\n });\n // Second pass: insert synthetic empty tool results for orphaned tool calls\n // This preserves thinking signatures and satisfies API requirements\n const result = [];\n let pendingToolCalls = [];\n let existingToolResultIds = new Set();\n // System messages are transparent to tool-call accounting: one that lands between a tool\n // call and its results is held back and emitted after the results (synthetic ones\n // included), so it never causes a duplicate result for a call that is answered later.\n const heldSystemMessages = [];\n const closePendingToolCalls = () => {\n if (pendingToolCalls.length > 0) {\n for (const tc of pendingToolCalls) {\n if (!existingToolResultIds.has(tc.id)) {\n result.push({\n role: \"toolResult\",\n toolCallId: tc.id,\n toolName: tc.name,\n content: [{ type: \"text\", text: \"No result provided\" }],\n isError: true,\n timestamp: Date.now(),\n });\n }\n }\n pendingToolCalls = [];\n existingToolResultIds = new Set();\n }\n result.push(...heldSystemMessages);\n heldSystemMessages.length = 0;\n };\n for (let i = 0; i < transformed.length; i++) {\n const msg = transformed[i];\n if (msg.role === \"assistant\") {\n // If we have pending orphaned tool calls from a previous assistant, insert synthetic results now\n closePendingToolCalls();\n // Skip errored/aborted assistant messages entirely.\n // These are incomplete turns that shouldn't be replayed:\n // - May have partial content (reasoning without message, incomplete tool calls)\n // - Replaying them can cause API errors (e.g., OpenAI \"reasoning without following item\")\n // - The model should retry from the last valid state\n const assistantMsg = msg;\n if (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n continue;\n }\n // Track tool calls from this assistant message\n const toolCalls = assistantMsg.content.filter((b) => b.type === \"toolCall\");\n if (toolCalls.length > 0) {\n pendingToolCalls = toolCalls;\n existingToolResultIds = new Set();\n }\n result.push(msg);\n }\n else if (msg.role === \"toolResult\") {\n existingToolResultIds.add(msg.toolCallId);\n result.push(msg);\n }\n else if (msg.role === \"system\") {\n if (pendingToolCalls.length > 0) {\n heldSystemMessages.push(msg);\n }\n else {\n result.push(msg);\n }\n }\n else if (msg.role === \"user\") {\n // A new user turn interrupts tool flow - insert synthetic results for orphaned calls\n closePendingToolCalls();\n result.push(msg);\n }\n else {\n result.push(msg);\n }\n }\n // If the conversation ends with unresolved tool calls, synthesize results now.\n closePendingToolCalls();\n return result;\n}\n//# sourceMappingURL=transform-messages.js.map"],"x_google_ignoreList":[0,1,2,3,4],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { n as isRecord, t as classifySystemOne } from "./system-one-shared-Dl10ZF7Z.js";
2
+ //#region node_modules/@earendil-works/pi-ai/dist/api/typesafe-system-one.js
3
+ /**
4
+ * TypeSafe's native System One protocol. OpenRouter serves the same protocol,
5
+ * so both providers use this API with different base URLs.
6
+ */
7
+ const transport = {
8
+ api: "typesafe-system-one",
9
+ label: "System One API",
10
+ url: (model) => new URL("systemone", `${model.baseUrl.replace(/\/+$/u, "")}/`),
11
+ payload: (model, request) => ({
12
+ model: model.id,
13
+ ...request
14
+ }),
15
+ output: (body) => {
16
+ if (!isRecord(body)) throw new Error("System One API returned an unexpected response");
17
+ return body;
18
+ }
19
+ };
20
+ /** TypeSafe System One classification with public `bool` values mapped to wire-level `noul`. */
21
+ const classify = (model, context, options) => classifySystemOne(transport, model, context, options);
22
+ //#endregion
23
+ export { classify };
24
+
25
+ //# sourceMappingURL=typesafe-system-one-CwEWMV8P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typesafe-system-one-CwEWMV8P.js","names":[],"sources":["../node_modules/@earendil-works/pi-ai/dist/api/typesafe-system-one.js"],"sourcesContent":["import { classifySystemOne, isRecord } from \"./system-one-shared.js\";\n/**\n * TypeSafe's native System One protocol. OpenRouter serves the same protocol,\n * so both providers use this API with different base URLs.\n */\nconst transport = {\n api: \"typesafe-system-one\",\n label: \"System One API\",\n url: (model) => new URL(\"systemone\", `${model.baseUrl.replace(/\\/+$/u, \"\")}/`),\n payload: (model, request) => ({ model: model.id, ...request }),\n output: (body) => {\n if (!isRecord(body))\n throw new Error(\"System One API returned an unexpected response\");\n return body;\n },\n};\n/** TypeSafe System One classification with public `bool` values mapped to wire-level `noul`. */\nexport const classify = (model, context, options) => classifySystemOne(transport, model, context, options);\n//# sourceMappingURL=typesafe-system-one.js.map"],"x_google_ignoreList":[0],"mappings":";;;;;;AAKA,MAAM,YAAY;CACd,KAAK;CACL,OAAO;CACP,MAAM,UAAU,IAAI,IAAI,aAAa,GAAG,MAAM,QAAQ,QAAQ,SAAS,EAAE,EAAE,EAAE;CAC7E,UAAU,OAAO,aAAa;EAAE,OAAO,MAAM;EAAI,GAAG;CAAQ;CAC5D,SAAS,SAAS;EACd,IAAI,CAAC,SAAS,IAAI,GACd,MAAM,IAAI,MAAM,gDAAgD;EACpE,OAAO;CACX;AACJ;;AAEA,MAAa,YAAY,OAAO,SAAS,YAAY,kBAAkB,WAAW,OAAO,SAAS,OAAO"}
@@ -60,10 +60,10 @@ const stubPlugin = (stubs) => {
60
60
  const seedEnv = (env) => {
61
61
  for (const [key, value] of Object.entries(env)) process.env[key] ??= value;
62
62
  };
63
- const inlineConfigFor = (options) => ({
63
+ const inlineConfigFor = (options, environment) => ({
64
64
  configFile: false,
65
65
  root: options.root,
66
- mode: "production",
66
+ mode: environment?.mode ?? "production",
67
67
  logLevel: "error",
68
68
  appType: "custom",
69
69
  clearScreen: false,
@@ -79,10 +79,10 @@ const inlineConfigFor = (options) => ({
79
79
  * Build a {@link SeoGraphLoader} that evaluates `entry` in a headless Vite
80
80
  * server rooted at `root`, and returns what its `exportName` export resolves to.
81
81
  */
82
- const viteGraphLoader = (options) => async (input) => {
82
+ const viteGraphLoader = (options) => async (input, environment) => {
83
83
  const exportName = options.exportName ?? "loadSeoGraph";
84
84
  if (options.env) seedEnv(options.env);
85
- const server = await withCleanStdout(() => createServer(inlineConfigFor(options))).catch((cause) => {
85
+ const server = await withCleanStdout(() => createServer(inlineConfigFor(options, environment))).catch((cause) => {
86
86
  throw new Error(`Could not start the Vite loader: ${messageOf(cause)}`);
87
87
  });
88
88
  return {
@@ -95,10 +95,11 @@ const viteGraphLoader = (options) => async (input) => {
95
95
  await withCleanStdout(() => server.close()).catch(() => {});
96
96
  throw new Error(`Could not build the SEO graph: ${messageOf(cause)}`);
97
97
  }),
98
+ site: options.site,
98
99
  dispose: () => withCleanStdout(() => server.close())
99
100
  };
100
101
  };
101
102
  //#endregion
102
103
  export { withCleanStdout as n, viteGraphLoader as t };
103
104
 
104
- //# sourceMappingURL=vite-graph-loader-01p1WxEq.js.map
105
+ //# sourceMappingURL=vite-graph-loader-CsGiYNWE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-graph-loader-CsGiYNWE.js","names":[],"sources":["../src/config/vite-graph-loader.ts"],"sourcesContent":["/**\n * A graph loader that evaluates the host app's own graph module inside a\n * headless Vite server.\n *\n * The SEO graph is built *by the app*: its module reads the generated route\n * tree and whatever content collections it owns, so it pulls in the app's real\n * module graph — path aliases, virtual modules from content plugins, bare\n * imports that only exist inside a server runtime. A CLI cannot just `import()`\n * that from Node or Bun.\n *\n * So this boots a scoped, in-process Vite server (middleware mode, no HMR, no\n * watcher, no HTTP listener), `ssrLoadModule`s the app's graph module, and calls\n * its exported loader. The graph comes back as a live in-process object — there\n * is no serialization boundary for the commands to cross — and the server is\n * closed by {@link LoadedSeoGraph.dispose}.\n *\n * Everything host-shaped is an option: the app supplies its own {@link\n * ViteGraphLoaderOptions.plugins} (a content plugin, an MDX loader), {@link\n * ViteGraphLoaderOptions.stubs} for bare modules that only resolve inside its\n * server runtime, and {@link ViteGraphLoaderOptions.env} for variables its\n * modules parse at import. This file knows about none of them.\n */\n\nimport { createServer, type InlineConfig, type PluginOption } from \"vite\";\n\nimport type { PagegraphOptions } from \"../tanstack-start/graph\";\nimport type { Facts } from \"../markdown/facts\";\n\nimport type { SeoGraph } from \"../core/graph\";\nimport type { RobotsConfig } from \"../core/projections\";\n\n/** Identity and robots policy produced by the graph's host. */\nexport interface SiteRuntime {\n readonly origin: string;\n readonly indexable: boolean;\n readonly robots: Pick<RobotsConfig, \"disallow\" | \"contentSignal\" | \"directives\">;\n}\n\n/** A graph, plus the release of whatever producing it acquired. */\nexport interface LoadedSeoGraph {\n readonly graph: SeoGraph;\n /** The site's identity and policy belong to the graph-producing host. */\n readonly site: SiteRuntime;\n /** Settings and artifacts from the same resolved app that produced the graph. */\n readonly pagegraph?: { readonly root: string; readonly options: PagegraphOptions; readonly facts: Facts } | undefined;\n /** Called once the command is done with the graph, on success or failure. */\n readonly dispose: () => Promise<void>;\n}\n\n/**\n * Produces the SEO graph for the `pagegraph` CLI. A plain promise on purpose: a\n * config file must be writable without Effect, which the CLI keeps behind its\n * `bin` (an optional peer dependency).\n */\n/** JSON input that can be supplied by config files to an app graph export. */\nexport type GraphLoaderInput = null | boolean | number | string | ReadonlyArray<GraphLoaderInput> | { readonly [key: string]: GraphLoaderInput };\n\n/** Per-invocation evaluation settings, separate from the graph module's JSON input. */\nexport interface GraphLoaderEnvironment {\n readonly command?: \"serve\" | \"build\" | undefined;\n readonly mode?: string | undefined;\n}\n\nexport type SeoGraphLoader<Input extends GraphLoaderInput | void = void> =\n (input: Input, environment?: GraphLoaderEnvironment) => Promise<LoadedSeoGraph>;\n\nexport interface ViteGraphLoaderOptions {\n /** The app's Vite root — the directory its aliases and plugins resolve against. */\n readonly root: string;\n /** Module exporting the graph loader, root-relative (e.g. `/lib/seo/graph.ts`). */\n readonly entry: string;\n /** Site identity and robots policy for this graph. */\n readonly site: SiteRuntime;\n /** Named export on `entry` returning `Promise<SeoGraph>`. Defaults to `loadSeoGraph`. */\n readonly exportName?: string | undefined;\n /** Vite plugins the app's module graph needs — a content/MDX plugin, say. */\n readonly plugins?: ReadonlyArray<PluginOption> | undefined;\n /**\n * Bare or virtual module ids to replace with inert source, so a module that\n * only resolves inside the app's server runtime does not break the load.\n */\n readonly stubs?: Readonly<Record<string, string>> | undefined;\n /**\n * Variables to seed on `process.env` before the app's modules parse it. Vite\n * exposes prefixed values through `import.meta.env`, so this is how a module\n * that demands an env var at import time is satisfied. Existing values win —\n * a real `.env` is never clobbered.\n */\n readonly env?: Readonly<Record<string, string>> | undefined;\n}\n\nconst messageOf = (cause: unknown): string =>\n cause instanceof Error ? cause.message : String(cause);\n\n/**\n * Vite and its plugins write progress to stdout. The CLI reserves stdout for the\n * data plane, so redirect it to stderr for the duration of the load.\n *\n * Both the stream method and `console.log`/`info` are swapped: under Bun,\n * `console.log` writes to fd 1 natively rather than going through\n * `process.stdout.write`, so the stream swap alone would miss a plugin that\n * logs through the console.\n */\nexport const withCleanStdout = async <A>(run: () => Promise<A>): Promise<A> => {\n const originalWrite = process.stdout.write.bind(process.stdout);\n const originalLog = console.log;\n const originalInfo = console.info;\n process.stdout.write = process.stderr.write.bind(process.stderr) as typeof process.stdout.write;\n console.log = (...args: Array<unknown>) => console.error(...args);\n console.info = (...args: Array<unknown>) => console.error(...args);\n try {\n return await run();\n } finally {\n process.stdout.write = originalWrite;\n console.log = originalLog;\n console.info = originalInfo;\n }\n};\n\n/** Turn `{ id: source }` into a Vite plugin that resolves and loads each id. */\nconst stubPlugin = (stubs: Readonly<Record<string, string>>): PluginOption => {\n const virtualIdOf = (id: string) => `\\0seo-cli-stub:${id}`;\n const sourceByVirtualId = new Map(\n Object.entries(stubs).map(([id, source]) => [virtualIdOf(id), source]),\n );\n return {\n name: \"seo:stubs\",\n resolveId: (id) => (id in stubs ? virtualIdOf(id) : null),\n load: (id) => sourceByVirtualId.get(id) ?? null,\n };\n};\n\nconst seedEnv = (env: Readonly<Record<string, string>>): void => {\n for (const [key, value] of Object.entries(env)) {\n // oxlint-disable-next-line node/no-process-env -- CLI boundary: seeds the raw env BEFORE the app's own env module parses it; that module is the consumer here, not an option\n process.env[key] ??= value;\n }\n};\n\nconst inlineConfigFor = (options: ViteGraphLoaderOptions, environment?: GraphLoaderEnvironment): InlineConfig => ({\n configFile: false,\n root: options.root,\n mode: environment?.mode ?? \"production\",\n logLevel: \"error\",\n appType: \"custom\",\n clearScreen: false,\n server: { middlewareMode: true, hmr: false, watch: null },\n resolve: { tsconfigPaths: true },\n plugins: [\n ...(options.stubs === undefined ? [] : [stubPlugin(options.stubs)]),\n ...(options.plugins ?? []),\n ],\n});\n\n/**\n * Build a {@link SeoGraphLoader} that evaluates `entry` in a headless Vite\n * server rooted at `root`, and returns what its `exportName` export resolves to.\n */\nexport const viteGraphLoader =\n <Input extends GraphLoaderInput | void = void>(options: ViteGraphLoaderOptions): SeoGraphLoader<Input> =>\n async (input, environment) => {\n const exportName = options.exportName ?? \"loadSeoGraph\";\n if (options.env) seedEnv(options.env);\n\n const server = await withCleanStdout(() => createServer(inlineConfigFor(options, environment))).catch(\n (cause: unknown) => {\n throw new Error(`Could not start the Vite loader: ${messageOf(cause)}`);\n },\n );\n\n // The server is a resource from here on: a failed load must still close it,\n // and a successful one hands the close to the caller as `dispose`.\n const graph = await withCleanStdout(async () => {\n const module = (await server.ssrLoadModule(options.entry)) as Record<string, unknown>;\n const load = module[exportName];\n if (typeof load !== \"function\") {\n throw new Error(\n `${options.entry} has no \\`${exportName}\\` export (found: ${Object.keys(module).join(\", \") || \"nothing\"}).`,\n );\n }\n return (await load(input)) as SeoGraph;\n }).catch(async (cause: unknown) => {\n // Close on the way out, but never let a close failure bury the real\n // error: the reason the graph did not build is the useful one.\n await withCleanStdout(() => server.close()).catch(() => {});\n throw new Error(`Could not build the SEO graph: ${messageOf(cause)}`);\n });\n\n return { graph, site: options.site, dispose: () => withCleanStdout(() => server.close()) };\n };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2FA,MAAM,aAAa,UACjB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;;;;;;;;;;AAWvD,MAAa,kBAAkB,OAAU,QAAsC;CAC7E,MAAM,gBAAgB,QAAQ,OAAO,MAAM,KAAK,QAAQ,MAAM;CAC9D,MAAM,cAAc,QAAQ;CAC5B,MAAM,eAAe,QAAQ;CAC7B,QAAQ,OAAO,QAAQ,QAAQ,OAAO,MAAM,KAAK,QAAQ,MAAM;CAC/D,QAAQ,OAAO,GAAG,SAAyB,QAAQ,MAAM,GAAG,IAAI;CAChE,QAAQ,QAAQ,GAAG,SAAyB,QAAQ,MAAM,GAAG,IAAI;CACjE,IAAI;EACF,OAAO,MAAM,IAAI;CACnB,UAAU;EACR,QAAQ,OAAO,QAAQ;EACvB,QAAQ,MAAM;EACd,QAAQ,OAAO;CACjB;AACF;;AAGA,MAAM,cAAc,UAA0D;CAC5E,MAAM,eAAe,OAAe,kBAAkB;CACtD,MAAM,oBAAoB,IAAI,IAC5B,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,CAAC,CACvE;CACA,OAAO;EACL,MAAM;EACN,YAAY,OAAQ,MAAM,QAAQ,YAAY,EAAE,IAAI;EACpD,OAAO,OAAO,kBAAkB,IAAI,EAAE,KAAK;CAC7C;AACF;AAEA,MAAM,WAAW,QAAgD;CAC/D,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAE3C,QAAQ,IAAI,SAAS;AAEzB;AAEA,MAAM,mBAAmB,SAAiC,iBAAwD;CAChH,YAAY;CACZ,MAAM,QAAQ;CACd,MAAM,aAAa,QAAQ;CAC3B,UAAU;CACV,SAAS;CACT,aAAa;CACb,QAAQ;EAAE,gBAAgB;EAAM,KAAK;EAAO,OAAO;CAAK;CACxD,SAAS,EAAE,eAAe,KAAK;CAC/B,SAAS,CACP,GAAI,QAAQ,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,WAAW,QAAQ,KAAK,CAAC,GACjE,GAAI,QAAQ,WAAW,CAAC,CAC1B;AACF;;;;;AAMA,MAAa,mBACoC,YAC/C,OAAO,OAAO,gBAAgB;CAC5B,MAAM,aAAa,QAAQ,cAAc;CACzC,IAAI,QAAQ,KAAK,QAAQ,QAAQ,GAAG;CAEpC,MAAM,SAAS,MAAM,sBAAsB,aAAa,gBAAgB,SAAS,WAAW,CAAC,CAAC,CAAC,CAAC,OAC7F,UAAmB;EAClB,MAAM,IAAI,MAAM,oCAAoC,UAAU,KAAK,GAAG;CACxE,CACF;CAoBA,OAAO;EAAE,OAAA,MAhBW,gBAAgB,YAAY;GAC9C,MAAM,SAAU,MAAM,OAAO,cAAc,QAAQ,KAAK;GACxD,MAAM,OAAO,OAAO;GACpB,IAAI,OAAO,SAAS,YAClB,MAAM,IAAI,MACR,GAAG,QAAQ,MAAM,YAAY,WAAW,oBAAoB,OAAO,KAAK,MAAM,CAAC,CAAC,KAAK,IAAI,KAAK,UAAU,GAC1G;GAEF,OAAQ,MAAM,KAAK,KAAK;EAC1B,CAAC,CAAC,CAAC,MAAM,OAAO,UAAmB;GAGjC,MAAM,sBAAsB,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;GAC1D,MAAM,IAAI,MAAM,kCAAkC,UAAU,KAAK,GAAG;EACtE,CAAC;EAEe,MAAM,QAAQ;EAAM,eAAe,sBAAsB,OAAO,MAAM,CAAC;CAAE;AAC3F"}