@scuffi/gardener 0.1.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.
Files changed (21) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -0
  3. package/assets/apps/gardener/dist/gardener_runtime/assets/anthropic-messages-CpAYOexF.js +6431 -0
  4. package/assets/apps/gardener/dist/gardener_runtime/assets/deferred-tools-BwNJSp7E.js +31 -0
  5. package/assets/apps/gardener/dist/gardener_runtime/assets/error-body-D8mmocwO.js +6744 -0
  6. package/assets/apps/gardener/dist/gardener_runtime/assets/hash-DAk4mnwB.js +18 -0
  7. package/assets/apps/gardener/dist/gardener_runtime/assets/json-parse-DCA_fvRV.js +1094 -0
  8. package/assets/apps/gardener/dist/gardener_runtime/assets/mimetext.node.es-XQfmuX2L.js +8403 -0
  9. package/assets/apps/gardener/dist/gardener_runtime/assets/openai-completions-Dg9BYhy-.js +907 -0
  10. package/assets/apps/gardener/dist/gardener_runtime/assets/openai-prompt-cache-IAZGhS1U.js +12 -0
  11. package/assets/apps/gardener/dist/gardener_runtime/assets/openai-responses-shared-BptkVdeL.js +560 -0
  12. package/assets/apps/gardener/dist/gardener_runtime/assets/openai-responses-vjbR2NOB.js +240 -0
  13. package/assets/apps/gardener/dist/gardener_runtime/assets/rolldown-runtime-7_rZTKki.js +42 -0
  14. package/assets/apps/gardener/dist/gardener_runtime/assets/simple-options-tFhuCUzS.js +300 -0
  15. package/assets/apps/gardener/dist/gardener_runtime/assets/transform-messages-B41ICucH.js +246 -0
  16. package/assets/apps/gardener/dist/gardener_runtime/index.js +80307 -0
  17. package/assets/apps/gardener/migrations/0001_actions_baseline.sql +116 -0
  18. package/assets/gardener-distribution.json +5 -0
  19. package/dist/cli.js +24719 -0
  20. package/dist/cli.js.map +7 -0
  21. package/package.json +45 -0
@@ -0,0 +1,240 @@
1
+ import { c as AssistantMessageEventStream, i as clampThinkingLevel } from "./json-parse-DCA_fvRV.js";
2
+ import { a as hasCopilotVisionInput, c as getProviderEnvValue, i as buildCopilotDynamicHeaders, n as buildBaseOptions, o as retryProviderRequest, s as headersToRecord } from "./simple-options-tFhuCUzS.js";
3
+ import { t as splitDeferredTools } from "./deferred-tools-BwNJSp7E.js";
4
+ import { r as createGrammarToolInputProperties } from "./transform-messages-B41ICucH.js";
5
+ import { n as normalizeProviderError, r as OpenAI, t as formatProviderError } from "./error-body-D8mmocwO.js";
6
+ import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache-IAZGhS1U.js";
7
+ import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared-BptkVdeL.js";
8
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js
9
+ var OPENAI_TOOL_CALL_PROVIDERS = /* @__PURE__ */ new Set([
10
+ "openai",
11
+ "openai-codex",
12
+ "opencode"
13
+ ]);
14
+ var OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;
15
+ function hasHeader(headers, name) {
16
+ if (!headers) return false;
17
+ const expected = name.toLowerCase();
18
+ for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;
19
+ return false;
20
+ }
21
+ function getClientApiKey(provider, apiKey, headers) {
22
+ if (apiKey) return apiKey;
23
+ if (hasHeader(headers, "authorization") || hasHeader(headers, "cf-aig-authorization")) return "unused";
24
+ throw new Error(`No API key for provider: ${provider}`);
25
+ }
26
+ function detectSessionAffinityFormat(model) {
27
+ return model.provider === "openrouter" || model.baseUrl.includes("openrouter.ai") ? "openrouter" : "openai";
28
+ }
29
+ /**
30
+ * Resolve cache retention preference.
31
+ * Defaults to "short" and uses PI_CACHE_RETENTION for backward compatibility.
32
+ */
33
+ function resolveCacheRetention(cacheRetention, env) {
34
+ if (cacheRetention) return cacheRetention;
35
+ if (getProviderEnvValue("PI_CACHE_RETENTION", env) === "long") return "long";
36
+ return "short";
37
+ }
38
+ function getCompat(model) {
39
+ return {
40
+ supportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,
41
+ sessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),
42
+ supportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,
43
+ supportsStrictMode: model.compat?.supportsStrictMode ?? false,
44
+ supportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,
45
+ supportsToolSearch: model.compat?.supportsToolSearch ?? false,
46
+ supportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false
47
+ };
48
+ }
49
+ function getPromptCacheRetention(compat, cacheRetention) {
50
+ return cacheRetention === "long" && compat.supportsLongCacheRetention ? "24h" : void 0;
51
+ }
52
+ function formatOpenAIResponsesError(error) {
53
+ return formatProviderError(normalizeProviderError(error), "OpenAI API error");
54
+ }
55
+ /**
56
+ * Generate function for OpenAI Responses API
57
+ */
58
+ var stream = (model, context, options) => {
59
+ const stream = new AssistantMessageEventStream();
60
+ (async () => {
61
+ const output = {
62
+ role: "assistant",
63
+ content: [],
64
+ api: model.api,
65
+ provider: model.provider,
66
+ model: model.id,
67
+ usage: {
68
+ input: 0,
69
+ output: 0,
70
+ cacheRead: 0,
71
+ cacheWrite: 0,
72
+ totalTokens: 0,
73
+ cost: {
74
+ input: 0,
75
+ output: 0,
76
+ cacheRead: 0,
77
+ cacheWrite: 0,
78
+ total: 0
79
+ }
80
+ },
81
+ stopReason: "pending",
82
+ timestamp: Date.now()
83
+ };
84
+ try {
85
+ const apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);
86
+ const cacheSessionId = resolveCacheRetention(options?.cacheRetention, options?.env) === "none" ? void 0 : options?.sessionId;
87
+ const compat = getCompat(model);
88
+ const grammarToolInputProperties = createGrammarToolInputProperties(context.tools, compat.supportsOpenAIGrammarTools);
89
+ const client = createClient(model, context, apiKey, options?.headers, options?.fetch, cacheSessionId);
90
+ let params = buildParams(model, context, options, compat, grammarToolInputProperties);
91
+ const nextParams = await options?.onPayload?.(params, model);
92
+ if (nextParams !== void 0) params = nextParams;
93
+ const requestOptions = {
94
+ ...options?.signal ? { signal: options.signal } : {},
95
+ ...options?.timeoutMs !== void 0 ? { timeout: options.timeoutMs } : {},
96
+ maxRetries: 0
97
+ };
98
+ const { data: openaiStream, response } = await retryProviderRequest(() => client.responses.create(params, requestOptions).withResponse(), {
99
+ maxRetries: options?.maxRetries,
100
+ maxRetryDelayMs: options?.maxRetryDelayMs,
101
+ signal: options?.signal
102
+ });
103
+ await options?.onResponse?.({
104
+ status: response.status,
105
+ headers: headersToRecord(response.headers)
106
+ }, model);
107
+ stream.push({
108
+ type: "start",
109
+ partial: output
110
+ });
111
+ await processResponsesStream(openaiStream, output, stream, model, {
112
+ serviceTier: options?.serviceTier,
113
+ grammarToolInputProperties,
114
+ applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model)
115
+ });
116
+ if (options?.signal?.aborted) throw new Error("Request was aborted");
117
+ if (output.stopReason === "pending") throw new Error("OpenAI Responses stream ended without a stop reason");
118
+ if (output.stopReason === "aborted" || output.stopReason === "error") throw new Error("An unknown error occurred");
119
+ stream.push({
120
+ type: "done",
121
+ reason: output.stopReason,
122
+ message: output
123
+ });
124
+ stream.end();
125
+ } catch (error) {
126
+ for (const block of output.content) {
127
+ delete block.index;
128
+ delete block.partialJson;
129
+ delete block.customInput;
130
+ }
131
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
132
+ output.errorMessage = formatOpenAIResponsesError(error);
133
+ stream.push({
134
+ type: "error",
135
+ reason: output.stopReason,
136
+ error: output
137
+ });
138
+ stream.end();
139
+ }
140
+ })();
141
+ return stream;
142
+ };
143
+ var streamSimple = (model, context, options) => {
144
+ getClientApiKey(model.provider, options?.apiKey, options?.headers);
145
+ const base = buildBaseOptions(model, context, options, options?.apiKey);
146
+ const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;
147
+ const reasoningEffort = clampedReasoning === "off" ? void 0 : clampedReasoning;
148
+ return stream(model, context, {
149
+ ...base,
150
+ reasoningEffort
151
+ });
152
+ };
153
+ function createClient(model, context, apiKey, optionsHeaders, fetch, sessionId) {
154
+ const compat = getCompat(model);
155
+ const headers = { ...model.headers };
156
+ if (model.provider === "github-copilot") {
157
+ const hasImages = hasCopilotVisionInput(context.messages);
158
+ const copilotHeaders = buildCopilotDynamicHeaders({
159
+ messages: context.messages,
160
+ hasImages
161
+ });
162
+ Object.assign(headers, copilotHeaders);
163
+ }
164
+ if (sessionId) {
165
+ if (compat.sessionAffinityFormat === "openrouter") headers["x-session-id"] = sessionId;
166
+ else {
167
+ if (compat.sessionAffinityFormat === "openai") headers.session_id = sessionId;
168
+ headers["x-client-request-id"] = sessionId;
169
+ }
170
+ }
171
+ if (optionsHeaders) Object.assign(headers, optionsHeaders);
172
+ return new OpenAI({
173
+ apiKey,
174
+ baseURL: model.baseUrl,
175
+ dangerouslyAllowBrowser: true,
176
+ fetch,
177
+ defaultHeaders: headers
178
+ });
179
+ }
180
+ function buildParams(model, context, options, compat = getCompat(model), grammarToolInputProperties = createGrammarToolInputProperties(context.tools, compat.supportsOpenAIGrammarTools)) {
181
+ const toolPlacement = splitDeferredTools(context, compat.supportsToolSearch);
182
+ const messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {
183
+ grammarToolInputProperties,
184
+ deferredTools: toolPlacement.deferred,
185
+ toolOptions: {
186
+ supportsStrictMode: compat.supportsStrictMode,
187
+ supportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools
188
+ }
189
+ });
190
+ const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
191
+ const disableImplicitPromptCache = cacheRetention === "none" && compat.supportsExplicitPromptCacheMode;
192
+ const params = {
193
+ model: model.id,
194
+ input: messages,
195
+ stream: true,
196
+ prompt_cache_key: cacheRetention === "none" ? void 0 : clampOpenAIPromptCacheKey(options?.sessionId),
197
+ prompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),
198
+ prompt_cache_options: disableImplicitPromptCache ? { mode: "explicit" } : void 0,
199
+ store: false
200
+ };
201
+ if (options?.maxTokens) params.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);
202
+ if (options?.temperature !== void 0) params.temperature = options?.temperature;
203
+ if (options?.serviceTier !== void 0) params.service_tier = options.serviceTier;
204
+ if (toolPlacement.immediate.length > 0) params.tools = convertResponsesTools(toolPlacement.immediate, {
205
+ supportsStrictMode: compat.supportsStrictMode,
206
+ supportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools
207
+ });
208
+ if (options?.toolChoice !== void 0) params.tool_choice = options.toolChoice;
209
+ if (model.reasoning) {
210
+ if (options?.reasoningEffort || options?.reasoningSummary) {
211
+ params.reasoning = {
212
+ effort: options?.reasoningEffort ? model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort : "medium",
213
+ summary: options?.reasoningSummary || "auto"
214
+ };
215
+ params.include = ["reasoning.encrypted_content"];
216
+ } else if (model.provider !== "github-copilot" && model.thinkingLevelMap?.off !== null) params.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
217
+ if (model.provider === "xai") params.include = ["reasoning.encrypted_content"];
218
+ }
219
+ return params;
220
+ }
221
+ function getServiceTierCostMultiplier(model, serviceTier) {
222
+ switch (serviceTier) {
223
+ case "flex": return .5;
224
+ case "priority": return model.id === "gpt-5.5" ? 2.5 : 2;
225
+ default: return 1;
226
+ }
227
+ }
228
+ function applyServiceTierPricing(usage, serviceTier, model) {
229
+ const multiplier = getServiceTierCostMultiplier(model, serviceTier);
230
+ if (multiplier === 1) return;
231
+ usage.cost.input *= multiplier;
232
+ usage.cost.output *= multiplier;
233
+ usage.cost.cacheRead *= multiplier;
234
+ usage.cost.cacheWrite *= multiplier;
235
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
236
+ }
237
+ //#endregion
238
+ export { stream, streamSimple };
239
+
240
+ //# sourceMappingURL=openai-responses-vjbR2NOB.js.map
@@ -0,0 +1,42 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esmMin = (fn, res, err) => () => {
9
+ if (err) throw err[0];
10
+ try {
11
+ return fn && (res = fn(fn = 0)), res;
12
+ } catch (e) {
13
+ throw err = [e], e;
14
+ }
15
+ };
16
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
17
+ var __exportAll = (all, no_symbols) => {
18
+ let target = {};
19
+ for (var name in all) __defProp(target, name, {
20
+ get: all[name],
21
+ enumerable: true
22
+ });
23
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
24
+ return target;
25
+ };
26
+ var __copyProps = (to, from, except, desc) => {
27
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
28
+ key = keys[i];
29
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
30
+ get: ((k) => from[k]).bind(null, key),
31
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
32
+ });
33
+ }
34
+ return to;
35
+ };
36
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
37
+ value: mod,
38
+ enumerable: true
39
+ }) : target, mod));
40
+ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
41
+ //#endregion
42
+ export { __toESM as a, __toCommonJS as i, __esmMin as n, __exportAll as r, __commonJSMin as t };
@@ -0,0 +1,300 @@
1
+ import { t as __commonJSMin } from "./rolldown-runtime-7_rZTKki.js";
2
+ import * as m from "node:fs";
3
+ //#region builtin:esm-external-require-node:fs
4
+ var require_builtin_esm_external_require_node_fs = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5
+ module.exports = m.default;
6
+ }));
7
+ //#endregion
8
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/provider-env.js
9
+ var procEnvCache = null;
10
+ /**
11
+ * Fallback for https://github.com/oven-sh/bun/issues/27802.
12
+ * Bun compiled binaries can expose an empty process.env inside Linux sandboxes
13
+ * even though /proc/self/environ contains the environment.
14
+ *
15
+ * This intentionally duplicates restoreSandboxEnv() in
16
+ * packages/coding-agent/src/bun/restore-sandbox-env.ts. The ai package can be
17
+ * used directly, without going through that entrypoint, so provider env lookup
18
+ * must not depend on process.env having been patched.
19
+ */
20
+ function getBunSandboxEnvValue(name) {
21
+ if (typeof process === "undefined" || !process.versions?.bun || Object.keys(process.env).length > 0) return;
22
+ if (procEnvCache === null) {
23
+ procEnvCache = /* @__PURE__ */ new Map();
24
+ try {
25
+ const { readFileSync } = require_builtin_esm_external_require_node_fs();
26
+ const data = readFileSync("/proc/self/environ", "utf-8");
27
+ for (const entry of data.split("\0")) {
28
+ const idx = entry.indexOf("=");
29
+ if (idx > 0) procEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));
30
+ }
31
+ } catch {}
32
+ }
33
+ return procEnvCache.get(name);
34
+ }
35
+ /**
36
+ * Resolve a provider env value from scoped overrides, normal process.env, then
37
+ * the duplicated Bun sandbox fallback for direct pi-ai consumers.
38
+ */
39
+ function getProviderEnvValue(name, env) {
40
+ return env?.[name] || (typeof process !== "undefined" ? process.env[name] : void 0) || getBunSandboxEnvValue(name) || void 0;
41
+ }
42
+ //#endregion
43
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/headers.js
44
+ function headersToRecord(headers) {
45
+ const result = {};
46
+ for (const [key, value] of headers.entries()) result[key] = value;
47
+ return result;
48
+ }
49
+ //#endregion
50
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/provider-retry.js
51
+ var DEFAULT_MAX_RETRY_DELAY_MS = 6e4;
52
+ function isProviderError(error) {
53
+ if (!(error instanceof Error) || !("status" in error) || !("headers" in error)) return false;
54
+ return (error.status === void 0 || typeof error.status === "number") && (error.headers === void 0 || error.headers instanceof Headers);
55
+ }
56
+ /** Mirrors the pinned OpenAI/Anthropic SDK retry policy; review when either SDK is upgraded. */
57
+ function isRetryableProviderError(error) {
58
+ const shouldRetry = error.headers?.get("x-should-retry");
59
+ if (shouldRetry === "true") return true;
60
+ if (shouldRetry === "false") return false;
61
+ if (error.status === void 0) return true;
62
+ return error.status === 408 || error.status === 409 || error.status === 429 || typeof error.status === "number" && error.status >= 500;
63
+ }
64
+ function validateServerRetryDelayMs(delayMs, maxRetryDelayMs, providerErrorMessage) {
65
+ const maxDelayMs = maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;
66
+ if (maxDelayMs > 0 && delayMs > maxDelayMs) throw new Error(`Server requested ${Math.ceil(delayMs / 1e3)}s retry delay (max: ${Math.ceil(maxDelayMs / 1e3)}s). ${providerErrorMessage}`);
67
+ return delayMs;
68
+ }
69
+ function getRetryDelayMs(error, retryIndex, maxRetryDelayMs) {
70
+ const retryAfterMs = error.headers?.get("retry-after-ms");
71
+ if (retryAfterMs) {
72
+ const value = Number.parseFloat(retryAfterMs);
73
+ if (!Number.isNaN(value)) return validateServerRetryDelayMs(value, maxRetryDelayMs, error.message);
74
+ }
75
+ const retryAfter = error.headers?.get("retry-after");
76
+ if (retryAfter) {
77
+ const seconds = Number.parseFloat(retryAfter);
78
+ return validateServerRetryDelayMs(Number.isNaN(seconds) ? Date.parse(retryAfter) - Date.now() : seconds * 1e3, maxRetryDelayMs, error.message);
79
+ }
80
+ return Math.min(.5 * 2 ** retryIndex, 8) * 1e3 * (1 - Math.random() * .25);
81
+ }
82
+ function createAbortError() {
83
+ const error = /* @__PURE__ */ new Error("Request aborted");
84
+ error.name = "AbortError";
85
+ return error;
86
+ }
87
+ function abortableSleep(ms, signal) {
88
+ return new Promise((resolve, reject) => {
89
+ if (signal?.aborted) {
90
+ reject(createAbortError());
91
+ return;
92
+ }
93
+ const onAbort = () => {
94
+ clearTimeout(timeout);
95
+ reject(createAbortError());
96
+ };
97
+ const timeout = setTimeout(() => {
98
+ signal?.removeEventListener("abort", onAbort);
99
+ resolve();
100
+ }, Math.max(0, ms));
101
+ signal?.addEventListener("abort", onAbort, { once: true });
102
+ });
103
+ }
104
+ /**
105
+ * Reproduce the retry behavior used by the OpenAI and Anthropic SDKs while making
106
+ * their backoff sleep interruptible. Their built-in retry timers ignore the
107
+ * request AbortSignal, so callers must invoke the SDK with `maxRetries: 0` and
108
+ * wrap the request with this helper. Provider-requested delays above
109
+ * `maxRetryDelayMs` fail immediately (60 seconds by default); set it to zero to
110
+ * disable the limit.
111
+ */
112
+ async function retryProviderRequest(request, options = {}) {
113
+ const maxRetries = options.maxRetries ?? 0;
114
+ let retriesRemaining = maxRetries;
115
+ for (;;) try {
116
+ return await request();
117
+ } catch (error) {
118
+ if (options.signal?.aborted) throw createAbortError();
119
+ if (retriesRemaining <= 0 || !isProviderError(error) || !isRetryableProviderError(error)) throw error;
120
+ const retryIndex = maxRetries - retriesRemaining;
121
+ retriesRemaining--;
122
+ await abortableSleep(getRetryDelayMs(error, retryIndex, options.maxRetryDelayMs), options.signal);
123
+ }
124
+ }
125
+ //#endregion
126
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/api/github-copilot-headers.js
127
+ function inferCopilotInitiator(messages) {
128
+ const last = messages[messages.length - 1];
129
+ return last && last.role !== "user" ? "agent" : "user";
130
+ }
131
+ function hasCopilotVisionInput(messages) {
132
+ return messages.some((msg) => {
133
+ if (msg.role === "user" && Array.isArray(msg.content)) return msg.content.some((c) => c.type === "image");
134
+ if (msg.role === "toolResult" && Array.isArray(msg.content)) return msg.content.some((c) => c.type === "image");
135
+ return false;
136
+ });
137
+ }
138
+ function buildCopilotDynamicHeaders(params) {
139
+ const headers = {
140
+ "X-Initiator": inferCopilotInitiator(params.messages),
141
+ "Openai-Intent": "conversation-edits"
142
+ };
143
+ if (params.hasImages) headers["Copilot-Vision-Request"] = "true";
144
+ return headers;
145
+ }
146
+ //#endregion
147
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js
148
+ var CHARS_PER_TOKEN = 4;
149
+ var ESTIMATED_IMAGE_CHARS = 4800;
150
+ function calculateContextTokens(usage) {
151
+ return usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
152
+ }
153
+ function safeJsonStringify(value) {
154
+ try {
155
+ return JSON.stringify(value) ?? "undefined";
156
+ } catch {
157
+ return "[unserializable]";
158
+ }
159
+ }
160
+ function estimateTextAndImageContentChars(content) {
161
+ if (typeof content === "string") return content.length;
162
+ let chars = 0;
163
+ for (const block of content) chars += block.type === "text" ? block.text.length : ESTIMATED_IMAGE_CHARS;
164
+ return chars;
165
+ }
166
+ function estimateTextTokens(text) {
167
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
168
+ }
169
+ function estimateTextAndImageContentTokens(content) {
170
+ return Math.ceil(estimateTextAndImageContentChars(content) / CHARS_PER_TOKEN);
171
+ }
172
+ function estimateMessageTokens(message) {
173
+ let chars = 0;
174
+ if (message.role === "user") return estimateTextAndImageContentTokens(message.content);
175
+ if (message.role === "toolResult") return estimateTextAndImageContentTokens(message.content);
176
+ for (const block of message.content) if (block.type === "text") chars += block.text.length;
177
+ else if (block.type === "thinking") chars += block.thinking.length;
178
+ else chars += block.name.length + safeJsonStringify(block.arguments).length;
179
+ return Math.ceil(chars / CHARS_PER_TOKEN);
180
+ }
181
+ function getLastAssistantUsageInfo(messages) {
182
+ let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;
183
+ let usageInfo;
184
+ for (let i = 0; i < messages.length; i++) {
185
+ const message = messages[i];
186
+ if (message.role === "assistant") {
187
+ const assistant = message;
188
+ if (assistant.timestamp >= latestPrefixTimestamp && assistant.stopReason !== "aborted" && assistant.stopReason !== "error" && calculateContextTokens(assistant.usage) > 0) usageInfo = {
189
+ usage: assistant.usage,
190
+ index: i
191
+ };
192
+ }
193
+ latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);
194
+ }
195
+ return usageInfo;
196
+ }
197
+ function estimateMessages(messages) {
198
+ const usageInfo = getLastAssistantUsageInfo(messages);
199
+ if (usageInfo) {
200
+ const usageTokens = calculateContextTokens(usageInfo.usage);
201
+ let trailingTokens = 0;
202
+ for (let i = usageInfo.index + 1; i < messages.length; i++) trailingTokens += estimateMessageTokens(messages[i]);
203
+ return {
204
+ tokens: usageTokens + trailingTokens,
205
+ usageTokens,
206
+ trailingTokens,
207
+ lastUsageIndex: usageInfo.index
208
+ };
209
+ }
210
+ let tokens = 0;
211
+ for (const message of messages) tokens += estimateMessageTokens(message);
212
+ return {
213
+ tokens,
214
+ usageTokens: 0,
215
+ trailingTokens: tokens,
216
+ lastUsageIndex: null
217
+ };
218
+ }
219
+ function estimateToolsTokens(tools) {
220
+ if (!tools || tools.length === 0) return 0;
221
+ return estimateTextTokens(safeJsonStringify(tools));
222
+ }
223
+ function isMessageArray(value) {
224
+ return Array.isArray(value);
225
+ }
226
+ function estimateContextTokens(context) {
227
+ if (isMessageArray(context)) return estimateMessages(context);
228
+ const estimate = estimateMessages(context.messages);
229
+ if (estimate.lastUsageIndex !== null) {
230
+ const addedNames = new Set(context.messages.slice(estimate.lastUsageIndex + 1).filter((message) => message.role === "toolResult").flatMap((message) => message.addedToolNames ?? []));
231
+ const addedToolTokens = estimateToolsTokens(context.tools?.filter((tool) => addedNames.has(tool.name)));
232
+ return {
233
+ tokens: estimate.tokens + addedToolTokens,
234
+ usageTokens: estimate.usageTokens,
235
+ trailingTokens: estimate.trailingTokens + addedToolTokens,
236
+ lastUsageIndex: estimate.lastUsageIndex
237
+ };
238
+ }
239
+ const prefixTokens = (context.systemPrompt ? estimateTextTokens(context.systemPrompt) : 0) + estimateToolsTokens(context.tools);
240
+ return {
241
+ tokens: estimate.tokens + prefixTokens,
242
+ usageTokens: estimate.usageTokens,
243
+ trailingTokens: estimate.trailingTokens + prefixTokens,
244
+ lastUsageIndex: estimate.lastUsageIndex
245
+ };
246
+ }
247
+ //#endregion
248
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.83.0_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1_c038161535a4cc121d37390bb491fb78/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js
249
+ var CONTEXT_SAFETY_TOKENS = 4096;
250
+ var MIN_MAX_TOKENS = 1;
251
+ function clampMaxTokensToContext(model, context, maxTokens) {
252
+ if (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);
253
+ const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;
254
+ return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));
255
+ }
256
+ function buildBaseOptions(model, context, options, apiKey) {
257
+ return {
258
+ temperature: options?.temperature,
259
+ maxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),
260
+ signal: options?.signal,
261
+ apiKey: apiKey || options?.apiKey,
262
+ fetch: options?.fetch,
263
+ transport: options?.transport,
264
+ cacheRetention: options?.cacheRetention,
265
+ sessionId: options?.sessionId,
266
+ headers: options?.headers,
267
+ onPayload: options?.onPayload,
268
+ onResponse: options?.onResponse,
269
+ timeoutMs: options?.timeoutMs,
270
+ websocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,
271
+ maxRetries: options?.maxRetries,
272
+ maxRetryDelayMs: options?.maxRetryDelayMs,
273
+ metadata: options?.metadata,
274
+ env: options?.env
275
+ };
276
+ }
277
+ function clampReasoning(effort) {
278
+ return effort === "xhigh" || effort === "max" ? "high" : effort;
279
+ }
280
+ function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
281
+ const budgets = {
282
+ minimal: 1024,
283
+ low: 2048,
284
+ medium: 8192,
285
+ high: 16384,
286
+ ...customBudgets
287
+ };
288
+ const minOutputTokens = 1024;
289
+ let thinkingBudget = budgets[clampReasoning(reasoningLevel)];
290
+ const maxTokens = baseMaxTokens === void 0 ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
291
+ if (maxTokens <= thinkingBudget) thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
292
+ return {
293
+ maxTokens,
294
+ thinkingBudget
295
+ };
296
+ }
297
+ //#endregion
298
+ export { hasCopilotVisionInput as a, getProviderEnvValue as c, buildCopilotDynamicHeaders as i, buildBaseOptions as n, retryProviderRequest as o, clampMaxTokensToContext as r, headersToRecord as s, adjustMaxTokensForThinking as t };
299
+
300
+ //# sourceMappingURL=simple-options-tFhuCUzS.js.map