@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.
- package/LICENSE +21 -0
- package/README.md +17 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/anthropic-messages-CpAYOexF.js +6431 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/deferred-tools-BwNJSp7E.js +31 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/error-body-D8mmocwO.js +6744 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/hash-DAk4mnwB.js +18 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/json-parse-DCA_fvRV.js +1094 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/mimetext.node.es-XQfmuX2L.js +8403 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-completions-Dg9BYhy-.js +907 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-prompt-cache-IAZGhS1U.js +12 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-responses-shared-BptkVdeL.js +560 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/openai-responses-vjbR2NOB.js +240 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/rolldown-runtime-7_rZTKki.js +42 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/simple-options-tFhuCUzS.js +300 -0
- package/assets/apps/gardener/dist/gardener_runtime/assets/transform-messages-B41ICucH.js +246 -0
- package/assets/apps/gardener/dist/gardener_runtime/index.js +80307 -0
- package/assets/apps/gardener/migrations/0001_actions_baseline.sql +116 -0
- package/assets/gardener-distribution.json +5 -0
- package/dist/cli.js +24719 -0
- package/dist/cli.js.map +7 -0
- 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
|