zidane 8.2.1 → 8.2.3
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/dist/acp-cli.js +8 -8
- package/dist/{acp-D7Pr8NGt.js → acp-oYRjlh71.js} +6 -6
- package/dist/{acp-D7Pr8NGt.js.map → acp-oYRjlh71.js.map} +1 -1
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-DecDtKA_.js → agent-CBQglXtH.js} +9 -379
- package/dist/agent-CBQglXtH.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{builtin-artifact-kinds-B_OEgf8b.js → builtin-artifact-kinds-BmorPkgz.js} +36 -9
- package/dist/builtin-artifact-kinds-BmorPkgz.js.map +1 -0
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +6 -6
- package/dist/chat.d.ts +4 -4
- package/dist/chat.js +15 -15
- package/dist/{cli-shared-Dx4vmif6.js → cli-shared-E5m_pI8A.js} +2 -2
- package/dist/{cli-shared-Dx4vmif6.js.map → cli-shared-E5m_pI8A.js.map} +1 -1
- package/dist/{client-core-imHuBWV3.d.ts → client-core-EEEX_u6D.d.ts} +24 -5
- package/dist/{client-core-imHuBWV3.d.ts.map → client-core-EEEX_u6D.d.ts.map} +1 -1
- package/dist/{connection-loop-CdHt3iQi.d.ts → connection-loop-CpgfUmuw.d.ts} +3 -3
- package/dist/{connection-loop-CdHt3iQi.d.ts.map → connection-loop-CpgfUmuw.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/{credentials-Dti61yoi.js → credentials-B9DfBJP9.js} +11 -7
- package/dist/credentials-B9DfBJP9.js.map +1 -0
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-vy3J6JMA.js → dispatcher-Bv9-c6I2.js} +28 -14
- package/dist/dispatcher-Bv9-c6I2.js.map +1 -0
- package/dist/{engine-BN6PjWAW.js → engine-XmoPPB6U.js} +5 -5
- package/dist/{engine-BN6PjWAW.js.map → engine-XmoPPB6U.js.map} +1 -1
- package/dist/{eval-BaJtxLCW.js → eval-CfQlBR81.js} +2 -2
- package/dist/{eval-BaJtxLCW.js.map → eval-CfQlBR81.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-CT4oUkg6.js → executor-BhthPE1q.js} +3 -3
- package/dist/{executor-CT4oUkg6.js.map → executor-BhthPE1q.js.map} +1 -1
- package/dist/{extensions-BKt7lxxv.js → extensions-BgBwogRW.js} +114 -113
- package/dist/extensions-BgBwogRW.js.map +1 -0
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +2 -2
- package/dist/{fold-rules-BYedvsH7.d.ts → fold-rules-DSypi36k.d.ts} +2 -2
- package/dist/{fold-rules-BYedvsH7.d.ts.map → fold-rules-DSypi36k.d.ts.map} +1 -1
- package/dist/google-O6pRnddf.js +881 -0
- package/dist/google-O6pRnddf.js.map +1 -0
- package/dist/{headless-Ebd1ZEzC.js → headless-R4pbpTkm.js} +3 -3
- package/dist/{headless-Ebd1ZEzC.js.map → headless-R4pbpTkm.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/{host-scoped-settings-Cy_zbmB_.js → host-scoped-settings-C-Nmb6vr.js} +2 -2
- package/dist/{host-scoped-settings-Cy_zbmB_.js.map → host-scoped-settings-C-Nmb6vr.js.map} +1 -1
- package/dist/{host-signals-Cx2IAbHh.js → host-signals-BFudPyCT.js} +5 -5
- package/dist/{host-signals-Cx2IAbHh.js.map → host-signals-BFudPyCT.js.map} +1 -1
- package/dist/{index-pc71ADi6.d.ts → index-AqRZ3gEz.d.ts} +71 -4
- package/dist/index-AqRZ3gEz.d.ts.map +1 -0
- package/dist/{index-Bt_G2Z_2.d.ts → index-CDS7YdUC.d.ts} +5 -5
- package/dist/{index-Bt_G2Z_2.d.ts.map → index-CDS7YdUC.d.ts.map} +1 -1
- package/dist/{index-CidMTcxS.d.ts → index-DyQyDLX1.d.ts} +167 -10
- package/dist/index-DyQyDLX1.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +15 -15
- package/dist/ipc/remote.d.ts +5 -5
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +7 -7
- package/dist/{links-DSZ4uQ5w.js → links-rFaWqS2Y.js} +10 -10
- package/dist/{links-DSZ4uQ5w.js.map → links-rFaWqS2Y.js.map} +1 -1
- package/dist/{mcp-allowlist-BQ5MvhHi.js → mcp-allowlist-CLXweyxk.js} +14 -3
- package/dist/mcp-allowlist-CLXweyxk.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/{oauth-BSqXgads.js → oauth-7_48zR7n.js} +226 -40
- package/dist/oauth-7_48zR7n.js.map +1 -0
- package/dist/{openai-dTmPxM6T.js → openai-Rh6u5NXF.js} +121 -2
- package/dist/openai-Rh6u5NXF.js.map +1 -0
- package/dist/{openrouter-CtZbQDa0.js → openrouter-Dg0yaI-o.js} +91 -2
- package/dist/openrouter-Dg0yaI-o.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{presets-EzlHyFSi.js → presets-DXeHsd24.js} +3 -3
- package/dist/{presets-EzlHyFSi.js.map → presets-DXeHsd24.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{prompts-D2lPHLOV.d.ts → prompts-DmY13jvF.d.ts} +2 -1
- package/dist/prompts-DmY13jvF.d.ts.map +1 -0
- package/dist/protocol-BIv1Yuvl.js.map +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/google.js +1 -784
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +1 -101
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +6 -5
- package/dist/{registry-BBaEgTsX.js → registry-eourRLY2.js} +3 -3
- package/dist/{registry-BBaEgTsX.js.map → registry-eourRLY2.js.map} +1 -1
- package/dist/{remote-hosts-bO7wOt44.js → remote-hosts-DY2J07ut.js} +4 -4
- package/dist/{remote-hosts-bO7wOt44.js.map → remote-hosts-DY2J07ut.js.map} +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/{secret-shapes-Cda65uDH.js → secret-shapes-BjW4l6U0.js} +17 -3
- package/dist/secret-shapes-BjW4l6U0.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-factory-BazyVdzj.js → session-factory-CMwIXE-7.js} +5 -5
- package/dist/{session-factory-BazyVdzj.js.map → session-factory-CMwIXE-7.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{settings-keys-zYaer8DY.js → settings-keys-CPdmkTz7.js} +3 -3
- package/dist/{settings-keys-zYaer8DY.js.map → settings-keys-CPdmkTz7.js.map} +1 -1
- package/dist/{shell-path-od9XHRPt.js → shell-path-B8b3EOtK.js} +3 -3
- package/dist/{shell-path-od9XHRPt.js.map → shell-path-B8b3EOtK.js.map} +1 -1
- package/dist/{skills-use-D68a1gyZ.js → skills-use-CssTEaIj.js} +375 -2
- package/dist/skills-use-CssTEaIj.js.map +1 -0
- package/dist/skills.d.ts +1 -1
- package/dist/store-L01W0gGI.js.map +1 -1
- package/dist/{system-freeze-DXvJpveP.js → system-freeze-Um9ZJiPo.js} +24 -9
- package/dist/system-freeze-Um9ZJiPo.js.map +1 -0
- package/dist/{todo-edits-CmqNFvLJ.js → todo-edits-BERpCRPj.js} +3 -3
- package/dist/{todo-edits-CmqNFvLJ.js.map → todo-edits-BERpCRPj.js.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -0
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-9Dpm8F-f.js → tools-pZVFIJ_K.js} +273 -2
- package/dist/tools-pZVFIJ_K.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -4
- package/dist/{transcript-anchors-B3TFJqr_.js → transcript-anchors-jHrg-r-H.js} +10 -10
- package/dist/{transcript-anchors-B3TFJqr_.js.map → transcript-anchors-jHrg-r-H.js.map} +1 -1
- package/dist/{transcript-reconcile-BC2DbTmp.js → transcript-reconcile-CPdrNbbR.js} +19 -2
- package/dist/{transcript-reconcile-BC2DbTmp.js.map → transcript-reconcile-CPdrNbbR.js.map} +1 -1
- package/dist/tui.d.ts +7 -7
- package/dist/tui.js +25 -23
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CIFoOebZ.d.ts → turn-operations-DuGtKuc_.d.ts} +10 -3
- package/dist/turn-operations-DuGtKuc_.d.ts.map +1 -0
- package/dist/{types-iFLlZKd0.d.ts → types-C0PJmBaO.d.ts} +2 -2
- package/dist/{types-iFLlZKd0.d.ts.map → types-C0PJmBaO.d.ts.map} +1 -1
- package/dist/types-JzccL5GE.js +24 -0
- package/dist/types-JzccL5GE.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/dist/{url-BTH-HE9Y.js → url-D8KZ7Edw.js} +2 -2
- package/dist/{url-BTH-HE9Y.js.map → url-D8KZ7Edw.js.map} +1 -1
- package/dist/{version-4T82xRxQ.js → version-bd3DQJkc.js} +2 -2
- package/dist/{version-4T82xRxQ.js.map → version-bd3DQJkc.js.map} +1 -1
- package/dist/wire-DH77Z-rr.js +80 -0
- package/dist/wire-DH77Z-rr.js.map +1 -0
- package/dist/{workspace-exec-stream-By8na6vz.js → workspace-exec-stream-CyfYgqAh.js} +4 -4
- package/dist/{workspace-exec-stream-By8na6vz.js.map → workspace-exec-stream-CyfYgqAh.js.map} +1 -1
- package/dist/{write-file-B4vi3SvQ.js → write-file-QYrcDdl3.js} +3 -3
- package/dist/{write-file-B4vi3SvQ.js.map → write-file-QYrcDdl3.js.map} +1 -1
- package/dist/{ws-CS312Jpx.js → ws-CURQ2igk.js} +5 -5
- package/dist/{ws-CS312Jpx.js.map → ws-CURQ2igk.js.map} +1 -1
- package/dist/{ws-client-wWka-Jku.js → ws-client-BVljYbdb.js} +3 -3
- package/dist/{ws-client-wWka-Jku.js.map → ws-client-BVljYbdb.js.map} +1 -1
- package/dist/xai-CStTwCV2.js +182 -0
- package/dist/xai-CStTwCV2.js.map +1 -0
- package/docs/ARCHITECTURE.md +1 -0
- package/docs/ARTIFACTS.md +1 -1
- package/docs/EXTENSIONS.md +9 -5
- package/package.json +2 -2
- package/dist/agent-DecDtKA_.js.map +0 -1
- package/dist/builtin-artifact-kinds-B_OEgf8b.js.map +0 -1
- package/dist/credentials-Dti61yoi.js.map +0 -1
- package/dist/dispatcher-vy3J6JMA.js.map +0 -1
- package/dist/extensions-BKt7lxxv.js.map +0 -1
- package/dist/index-CidMTcxS.d.ts.map +0 -1
- package/dist/index-pc71ADi6.d.ts.map +0 -1
- package/dist/mcp-allowlist-BQ5MvhHi.js.map +0 -1
- package/dist/oauth-BSqXgads.js.map +0 -1
- package/dist/openai-dTmPxM6T.js.map +0 -1
- package/dist/openrouter-CtZbQDa0.js.map +0 -1
- package/dist/prompts-D2lPHLOV.d.ts.map +0 -1
- package/dist/providers/google.js.map +0 -1
- package/dist/providers/xai.js.map +0 -1
- package/dist/secret-shapes-Cda65uDH.js.map +0 -1
- package/dist/skills-use-D68a1gyZ.js.map +0 -1
- package/dist/system-freeze-DXvJpveP.js.map +0 -1
- package/dist/tools-9Dpm8F-f.js.map +0 -1
- package/dist/turn-operations-CIFoOebZ.d.ts.map +0 -1
|
@@ -6,9 +6,120 @@ import { c as reasoningWireAction, h as SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from
|
|
|
6
6
|
import { a as DecisionUnavailableError, n as DecisionHttpError, o as DecisionUnsupportedError, r as DecisionInvalidResponseError } from "./errors-nt7rnQ71.js";
|
|
7
7
|
import { i as scoreLevelLabel, n as isPromptParts, r as scoreLevelDescription } from "./wire-BsjqYnxu.js";
|
|
8
8
|
import { l as resolveOAuthApiKey, r as extractRuntimeCredentials } from "./oauth-DRrs-65k.js";
|
|
9
|
+
import { a as imageHttpError, i as imageFromBase64, r as imageCount, t as aspectValue } from "./wire-DH77Z-rr.js";
|
|
9
10
|
import { n as stream$1, t as stream } from "./pi-ai-responses-DpHLSriS.js";
|
|
11
|
+
import { Buffer } from "node:buffer";
|
|
10
12
|
import { normalizeContext } from "@earendil-works/pi-ai";
|
|
11
13
|
import { getBuiltinModel } from "@earendil-works/pi-ai/providers/all";
|
|
14
|
+
//#region src/providers/images/openai.ts
|
|
15
|
+
const BASE_URL = "https://api.openai.com/v1";
|
|
16
|
+
/** OpenAI's GPT Image models. */
|
|
17
|
+
const OPENAI_IMAGE_MODELS = [
|
|
18
|
+
{
|
|
19
|
+
id: "gpt-image-2",
|
|
20
|
+
name: "GPT Image 2",
|
|
21
|
+
input: ["text", "image"],
|
|
22
|
+
transparency: true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "gpt-image-1",
|
|
26
|
+
name: "GPT Image 1",
|
|
27
|
+
input: ["text", "image"],
|
|
28
|
+
transparency: true
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "gpt-image-1-mini",
|
|
32
|
+
name: "GPT Image 1 Mini",
|
|
33
|
+
input: ["text", "image"],
|
|
34
|
+
transparency: true
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* The GPT Image size nearest to an aspect ratio. The API takes three sizes:
|
|
39
|
+
* square, landscape 3:2 and portrait 2:3.
|
|
40
|
+
*
|
|
41
|
+
* @param ratio - Requested aspect ratio; absent lets the model choose.
|
|
42
|
+
*/
|
|
43
|
+
function openaiImageSize(ratio) {
|
|
44
|
+
if (!ratio) return "auto";
|
|
45
|
+
const value = aspectValue(ratio);
|
|
46
|
+
if (value > 1.15) return "1536x1024";
|
|
47
|
+
if (value < .87) return "1024x1536";
|
|
48
|
+
return "1024x1024";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* OpenAI image generation as a {@link ProviderImages}. Unavailable while `resolveKey` returns `null`.
|
|
52
|
+
*
|
|
53
|
+
* @param options - Key resolver, headers and test overrides.
|
|
54
|
+
* @param options.resolveKey - Returns the platform key, or `null` when none is available. Called on every request.
|
|
55
|
+
* @param options.headers - Extra request headers.
|
|
56
|
+
* @param options.fetch - Fetch override, for tests.
|
|
57
|
+
*/
|
|
58
|
+
function openaiImages(options) {
|
|
59
|
+
const doFetch = options.fetch ?? fetch;
|
|
60
|
+
return {
|
|
61
|
+
defaultModel: OPENAI_IMAGE_MODELS[0].id,
|
|
62
|
+
models: OPENAI_IMAGE_MODELS,
|
|
63
|
+
availability: () => options.resolveKey() ? { available: true } : {
|
|
64
|
+
available: false,
|
|
65
|
+
reason: "OpenAI image generation needs a platform API key (sk-…). A ChatGPT sign-in does not cover it."
|
|
66
|
+
},
|
|
67
|
+
async generate(request, signal) {
|
|
68
|
+
const key = options.resolveKey();
|
|
69
|
+
if (!key) throw new Error("OpenAI image generation needs a platform API key (sk-…). Add one in the OpenAI provider settings.");
|
|
70
|
+
const fields = {
|
|
71
|
+
model: request.model,
|
|
72
|
+
prompt: request.prompt,
|
|
73
|
+
n: String(imageCount(request.count)),
|
|
74
|
+
size: openaiImageSize(request.aspectRatio),
|
|
75
|
+
output_format: "png",
|
|
76
|
+
...request.transparent ? { background: "transparent" } : {}
|
|
77
|
+
};
|
|
78
|
+
const headers = {
|
|
79
|
+
...options.headers,
|
|
80
|
+
authorization: `Bearer ${key}`
|
|
81
|
+
};
|
|
82
|
+
const references = request.references ?? [];
|
|
83
|
+
let res;
|
|
84
|
+
if (references.length === 0) res = await doFetch(`${BASE_URL}/images/generations`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: {
|
|
87
|
+
...headers,
|
|
88
|
+
"content-type": "application/json"
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
...fields,
|
|
92
|
+
n: Number(fields.n)
|
|
93
|
+
}),
|
|
94
|
+
signal
|
|
95
|
+
});
|
|
96
|
+
else {
|
|
97
|
+
const form = new FormData();
|
|
98
|
+
for (const [name, value] of Object.entries(fields)) form.append(name, value);
|
|
99
|
+
references.forEach((ref, i) => {
|
|
100
|
+
const ext = ref.mediaType.split("/")[1] ?? "png";
|
|
101
|
+
form.append("image[]", new Blob([Buffer.from(ref.data, "base64")], { type: ref.mediaType }), `reference-${i + 1}.${ext}`);
|
|
102
|
+
});
|
|
103
|
+
res = await doFetch(`${BASE_URL}/images/edits`, {
|
|
104
|
+
method: "POST",
|
|
105
|
+
headers,
|
|
106
|
+
body: form,
|
|
107
|
+
signal
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (!res.ok) throw await imageHttpError("OpenAI", res);
|
|
111
|
+
const json = await res.json();
|
|
112
|
+
const images = (json.data ?? []).flatMap((item) => item.b64_json ? [imageFromBase64(item.b64_json)] : []);
|
|
113
|
+
if (images.length === 0) throw new Error("OpenAI returned no image.");
|
|
114
|
+
const revised = json.data?.find((item) => item.revised_prompt)?.revised_prompt;
|
|
115
|
+
return {
|
|
116
|
+
images,
|
|
117
|
+
model: request.model,
|
|
118
|
+
...revised ? { text: `Revised prompt: ${revised}` } : {}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
12
123
|
/** Decision models OpenAI is known to serve. The first is the default. */
|
|
13
124
|
const OPENAI_DECISION_MODELS = ["gpt-6-luna"];
|
|
14
125
|
/** USD per 1M input tokens; decisions bill input only. */
|
|
@@ -691,6 +802,14 @@ function openai(params) {
|
|
|
691
802
|
]),
|
|
692
803
|
...params?.extraHeaders ? { headers: params.extraHeaders } : {}
|
|
693
804
|
}),
|
|
805
|
+
images: openaiImages({
|
|
806
|
+
resolveKey: () => pickOpenAIPlatformKey([
|
|
807
|
+
params?.apiKey,
|
|
808
|
+
process.env.OPENAI_API_KEY,
|
|
809
|
+
process.env.OPENAI_CODEX_API_KEY
|
|
810
|
+
]),
|
|
811
|
+
...params?.extraHeaders ? { headers: params.extraHeaders } : {}
|
|
812
|
+
}),
|
|
694
813
|
async countTokens(payload, signal) {
|
|
695
814
|
const standardKey = pickStandardOpenAIKey(params);
|
|
696
815
|
if (!standardKey) return null;
|
|
@@ -833,6 +952,6 @@ function openai(params) {
|
|
|
833
952
|
};
|
|
834
953
|
}
|
|
835
954
|
//#endregion
|
|
836
|
-
export { OPENAI_DECISION_MODELS as a, toPiMessages as i, mapCodexStopReason as n, openai as r, classifyOpenAIError as t };
|
|
955
|
+
export { OPENAI_DECISION_MODELS as a, toPiMessages as i, mapCodexStopReason as n, OPENAI_IMAGE_MODELS as o, openai as r, classifyOpenAIError as t };
|
|
837
956
|
|
|
838
|
-
//# sourceMappingURL=openai-
|
|
957
|
+
//# sourceMappingURL=openai-Rh6u5NXF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-Rh6u5NXF.js","names":["getModel","catalogLookup","streamOpenAIResponses","streamOpenAICodexResponses","stream"],"sources":["../src/providers/images/openai.ts","../src/providers/openai-decisions.ts","../src/providers/openai.ts"],"sourcesContent":["/**\n * OpenAI image generation on the platform API: `POST /v1/images/generations`,\n * or `POST /v1/images/edits` (multipart) when the request carries reference\n * images. Needs a platform key (`sk-…`); a Codex OAuth token is not valid on\n * this API, so the adapter reports itself unavailable without one.\n */\n\nimport type { ImageAspectRatio, ImageModelInfo, ProviderImages } from './types'\nimport type { ImageFetch } from './wire'\nimport { Buffer } from 'node:buffer'\nimport { aspectValue, imageCount, imageFromBase64, imageHttpError } from './wire'\n\nconst BASE_URL = 'https://api.openai.com/v1'\n\n/** OpenAI's GPT Image models. */\nexport const OPENAI_IMAGE_MODELS: readonly ImageModelInfo[] = [\n { id: 'gpt-image-2', name: 'GPT Image 2', input: ['text', 'image'], transparency: true },\n { id: 'gpt-image-1', name: 'GPT Image 1', input: ['text', 'image'], transparency: true },\n { id: 'gpt-image-1-mini', name: 'GPT Image 1 Mini', input: ['text', 'image'], transparency: true },\n]\n\n/**\n * The GPT Image size nearest to an aspect ratio. The API takes three sizes:\n * square, landscape 3:2 and portrait 2:3.\n *\n * @param ratio - Requested aspect ratio; absent lets the model choose.\n */\nexport function openaiImageSize(ratio: ImageAspectRatio | undefined): string {\n if (!ratio)\n return 'auto'\n const value = aspectValue(ratio)\n if (value > 1.15)\n return '1536x1024'\n if (value < 0.87)\n return '1024x1536'\n return '1024x1024'\n}\n\ninterface ImagesResponse {\n data?: Array<{ b64_json?: string, revised_prompt?: string }>\n}\n\n/**\n * OpenAI image generation as a {@link ProviderImages}. Unavailable while `resolveKey` returns `null`.\n *\n * @param options - Key resolver, headers and test overrides.\n * @param options.resolveKey - Returns the platform key, or `null` when none is available. Called on every request.\n * @param options.headers - Extra request headers.\n * @param options.fetch - Fetch override, for tests.\n */\nexport function openaiImages(options: { resolveKey: () => string | null, headers?: Record<string, string>, fetch?: ImageFetch }): ProviderImages {\n const doFetch = options.fetch ?? fetch\n return {\n defaultModel: OPENAI_IMAGE_MODELS[0]!.id,\n models: OPENAI_IMAGE_MODELS,\n availability: () => options.resolveKey()\n ? { available: true }\n : { available: false, reason: 'OpenAI image generation needs a platform API key (sk-…). A ChatGPT sign-in does not cover it.' },\n async generate(request, signal) {\n const key = options.resolveKey()\n if (!key)\n throw new Error('OpenAI image generation needs a platform API key (sk-…). Add one in the OpenAI provider settings.')\n const fields: Record<string, string> = {\n model: request.model,\n prompt: request.prompt,\n n: String(imageCount(request.count)),\n size: openaiImageSize(request.aspectRatio),\n output_format: 'png',\n ...(request.transparent ? { background: 'transparent' } : {}),\n }\n const headers = { ...options.headers, authorization: `Bearer ${key}` }\n const references = request.references ?? []\n let res: Response\n if (references.length === 0) {\n res = await doFetch(`${BASE_URL}/images/generations`, {\n method: 'POST',\n headers: { ...headers, 'content-type': 'application/json' },\n body: JSON.stringify({ ...fields, n: Number(fields.n) }),\n signal,\n })\n }\n else {\n const form = new FormData()\n for (const [name, value] of Object.entries(fields))\n form.append(name, value)\n references.forEach((ref, i) => {\n const ext = ref.mediaType.split('/')[1] ?? 'png'\n form.append('image[]', new Blob([Buffer.from(ref.data, 'base64')], { type: ref.mediaType }), `reference-${i + 1}.${ext}`)\n })\n res = await doFetch(`${BASE_URL}/images/edits`, { method: 'POST', headers, body: form, signal })\n }\n if (!res.ok)\n throw await imageHttpError('OpenAI', res)\n const json = await res.json() as ImagesResponse\n const images = (json.data ?? []).flatMap(item => item.b64_json ? [imageFromBase64(item.b64_json)] : [])\n if (images.length === 0)\n throw new Error('OpenAI returned no image.')\n const revised = json.data?.find(item => item.revised_prompt)?.revised_prompt\n return { images, model: request.model, ...(revised ? { text: `Revised prompt: ${revised}` } : {}) }\n },\n }\n}\n","/**\n * OpenAI Decisions (`POST https://api.openai.com/v1/decisions`).\n *\n * Needs a standard platform API key (`sk-…`): Codex OAuth tokens are not\n * valid bearers for `api.openai.com`, so without one the capability reports\n * itself unavailable and no request is sent.\n *\n * Wire shape vs canonical:\n * - `input` is a string or one user message of `input_text` / `input_image`\n * (inline base64 data URLs) parts; JSON input is sent as pretty-printed text.\n * - questions are an array with a `name`; choices are `[{ value, description }]`,\n * score levels `[{ label, description }]`; predicates take no criteria, so\n * they are folded into the instructions.\n * - answers come back as an array; probabilities as arrays of `{ value, probability }`.\n */\n\nimport type { ProviderDecisionAvailability, ProviderDecisionRequest, ProviderDecisionResponse, ProviderDecisions } from '.'\nimport type { DecisionAnswer, DecisionInput, DecisionQuestion } from '../decisions/types'\nimport { DecisionHttpError, DecisionInvalidResponseError, DecisionUnavailableError, DecisionUnsupportedError } from '../decisions/errors'\nimport { isPromptParts, scoreLevelDescription, scoreLevelLabel } from '../decisions/wire'\n\n/** Endpoint of OpenAI Decisions. */\nexport const OPENAI_DECISIONS_URL = 'https://api.openai.com/v1/decisions'\n/** Decision models OpenAI is known to serve. The first is the default. */\nexport const OPENAI_DECISION_MODELS = ['gpt-6-luna'] as const\n\n/** USD per 1M input tokens; decisions bill input only. */\nconst INPUT_PRICE_PER_MTOK: Readonly<Record<string, number>> = {\n 'gpt-6-luna': 0.10,\n}\n\n/** Reason reported when no platform API key is available. */\nexport const OPENAI_DECISIONS_KEY_REQUIRED = 'OpenAI decisions require a platform API key (sk-…); Codex OAuth tokens are not accepted'\n\nfunction toWireInput(input: DecisionInput): unknown {\n if (typeof input === 'string')\n return input\n if (!isPromptParts(input))\n return JSON.stringify(input, null, 2)\n const content = input.map((part) => {\n if (part.type === 'text')\n return { type: 'input_text', text: part.text }\n if (part.type === 'image')\n return { type: 'input_image', image_url: `data:${part.mediaType};base64,${part.data}` }\n if (part.type === 'document' && part.encoding === 'text')\n return { type: 'input_text', text: part.data }\n throw new DecisionUnsupportedError(`OpenAI decisions accept text and images only (got a ${part.type} part)`)\n })\n return [{ role: 'user', content }]\n}\n\nfunction toWireQuestion(name: string, q: DecisionQuestion): Record<string, unknown> {\n switch (q.type) {\n case 'predicate':\n return {\n type: 'predicate',\n name,\n instructions: q.criteria ? `${q.instructions}\\n\\nTrue when: ${q.criteria.true}\\nFalse when: ${q.criteria.false}` : q.instructions,\n }\n case 'choice':\n return {\n type: 'choice',\n name,\n instructions: q.instructions,\n choices: Object.entries(q.choices).map(([value, description]) => ({ value, ...(description ? { description } : {}) })),\n }\n case 'score':\n return {\n type: 'score',\n name,\n instructions: q.instructions,\n levels: q.levels.map((level) => {\n const description = scoreLevelDescription(level)\n return { label: scoreLevelLabel(level), ...(description ? { description } : {}) }\n }),\n }\n }\n}\n\nfunction num(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined\n}\n\nfunction probabilityEntries(v: unknown): Array<{ value: unknown, label: unknown, probability: number }> | undefined {\n if (!Array.isArray(v))\n return undefined\n const out: Array<{ value: unknown, label: unknown, probability: number }> = []\n for (const e of v) {\n const p = e && typeof e === 'object' ? num((e as { probability?: unknown }).probability) : undefined\n if (p !== undefined)\n out.push({ value: (e as { value?: unknown }).value, label: (e as { label?: unknown }).label, probability: p })\n }\n return out\n}\n\nfunction fromWireAnswer(raw: Record<string, unknown>, question: DecisionQuestion | undefined): DecisionAnswer {\n const confidence = num(raw.confidence)\n switch (raw.type) {\n case 'predicate':\n return { type: 'predicate', probability: num(raw.probability) ?? Number.NaN }\n case 'choice': {\n const entries = probabilityEntries(raw.probabilities)\n const probabilities = entries ? Object.fromEntries(entries.map(e => [String(e.value), e.probability])) : undefined\n return {\n type: 'choice',\n choice: String(raw.choice),\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'score': {\n const entries = probabilityEntries(raw.probabilities)\n const labels = question?.type === 'score' ? question.levels.map(scoreLevelLabel) : undefined\n const levels = labels?.length ?? entries?.length ?? 0\n // Levels go out by label; an entry may come back keyed by index or by label.\n const levelIndex = (e: { value: unknown, label: unknown }): number => {\n if (typeof e.value === 'number')\n return e.value\n for (const key of [e.label, e.value]) {\n const i = typeof key === 'string' && labels ? labels.indexOf(key) : -1\n if (i >= 0)\n return i\n }\n return Number(e.value)\n }\n const probabilities = entries\n ? Array.from({ length: levels }, (_, i) => entries.find(e => levelIndex(e) === i)?.probability ?? 0)\n : undefined\n return {\n type: 'score',\n score: num(raw.score) ?? Number.NaN,\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'refusal': {\n const message = typeof raw.refusal === 'string' ? raw.refusal : typeof raw.message === 'string' ? raw.message : undefined\n return { type: 'refusal', ...(message ? { message } : {}) }\n }\n default:\n throw new DecisionInvalidResponseError(`answer has unknown type \"${String(raw.type)}\"`)\n }\n}\n\nasync function errorMessage(res: Response): Promise<string> {\n const text = await res.text().catch(() => '')\n try {\n const json = JSON.parse(text) as { error?: { message?: unknown } }\n if (typeof json.error?.message === 'string')\n return json.error.message\n }\n catch {}\n return text.slice(0, 500) || `HTTP ${res.status}`\n}\n\n/** A standard platform key usable on api.openai.com, or `null`. */\nexport function pickOpenAIPlatformKey(candidates: ReadonlyArray<string | undefined>): string | null {\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * The native Decisions endpoint of OpenAI as a {@link ProviderDecisions}.\n * Unavailable while `resolveKey` returns `null`. Cost is estimated from input tokens only.\n *\n * @param options - Key resolver, headers and test overrides.\n * @param options.resolveKey - Returns the platform key, or `null` when none is available. Called on every request.\n * @param options.headers - Extra request headers.\n * @param options.url - Endpoint override, for tests.\n * @param options.fetch - Fetch override, for tests.\n */\nexport function openaiDecisions(options: {\n /** Resolved at call time so env/credential changes are picked up. */\n resolveKey: () => string | null\n headers?: Record<string, string>\n url?: string\n fetch?: typeof fetch\n}): ProviderDecisions {\n const doFetch = options.fetch ?? fetch\n return {\n defaultModel: OPENAI_DECISION_MODELS[0],\n models: OPENAI_DECISION_MODELS,\n availability: (): ProviderDecisionAvailability => options.resolveKey()\n ? { available: true }\n : { available: false, reason: OPENAI_DECISIONS_KEY_REQUIRED },\n async decide(request: ProviderDecisionRequest, signal: AbortSignal): Promise<ProviderDecisionResponse> {\n const key = options.resolveKey()\n if (!key)\n throw new DecisionUnavailableError(OPENAI_DECISIONS_KEY_REQUIRED)\n const body = {\n model: request.model,\n input: toWireInput(request.input),\n questions: Object.entries(request.questions).map(([name, q]) => toWireQuestion(name, q)),\n }\n const res = await doFetch(options.url ?? OPENAI_DECISIONS_URL, {\n method: 'POST',\n headers: { ...options.headers, 'authorization': `Bearer ${key}`, 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal,\n })\n if (!res.ok)\n throw new DecisionHttpError(res.status, await errorMessage(res))\n let json: Record<string, unknown>\n try {\n json = await res.json() as Record<string, unknown>\n }\n catch {\n throw new DecisionInvalidResponseError('response is not JSON')\n }\n if (!Array.isArray(json.answers))\n throw new DecisionInvalidResponseError('response has no answers array')\n const names = Object.keys(request.questions)\n const answers: Record<string, DecisionAnswer> = {}\n json.answers.forEach((raw: unknown, i: number) => {\n if (!raw || typeof raw !== 'object')\n throw new DecisionInvalidResponseError(`answer ${i} is not an object`)\n const a = raw as Record<string, unknown>\n // Names are echoed back; fall back to position for an answer without one.\n const name = typeof a.name === 'string' ? a.name : names[i]\n if (name)\n answers[name] = fromWireAnswer(a, request.questions[name])\n })\n const model = typeof json.model === 'string' ? json.model : request.model\n const usage = (json.usage ?? {}) as Record<string, unknown>\n const input = num(usage.input_tokens) ?? num(usage.prompt_tokens) ?? 0\n const output = num(usage.output_tokens) ?? num(usage.completion_tokens) ?? 0\n const price = INPUT_PRICE_PER_MTOK[request.model] ?? INPUT_PRICE_PER_MTOK[model]\n return {\n answers,\n usage: { input, output, ...(price !== undefined ? { cost: (input * price) / 1_000_000 } : {}) },\n model,\n ...(typeof json.id === 'string' ? { id: json.id } : {}),\n }\n },\n }\n}\n","import type {\n AssistantMessage as PiAssistantMessage,\n Context as PiContext,\n JsonObject as PiJsonObject,\n Message as PiMessage,\n Model as PiModel,\n Tool as PiTool,\n Usage as PiUsage,\n} from '@earendil-works/pi-ai'\nimport type { Provider, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, ToolResultDocumentContent, TurnFinishReason, TurnUsage } from '../types'\nimport type { ModelCatalog } from './model-catalog'\nimport type { OAuthParams } from './oauth'\nimport { normalizeContext } from '@earendil-works/pi-ai'\nimport { stream as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses'\nimport { stream as streamOpenAIResponses } from '@earendil-works/pi-ai/api/openai-responses'\nimport { getBuiltinModel as getModel } from '@earendil-works/pi-ai/providers/all'\nimport { announcedResetMs, classifyErrorPrelude, classifyProviderLimit, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError, providerLimitReason } from '../errors'\nimport { unsupportedMediaError } from '../prompt'\nimport { reasoningWireAction, SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { systemNotesAsText } from '../system-notes'\nimport { renderSystemForWire } from '../system-prompt'\nimport { assertResolvedMediaBlock, documentBlockMarker } from '../types'\nimport { fillEstimatedCost } from './cost'\nimport { openaiImages } from './images/openai'\n// `lookupModel` is aliased: that name is already the pi-ai registry getter below.\nimport { aliasCatalogProviders, lookupModel as catalogLookup, mergeCatalogEntry } from './model-catalog'\nimport { extractRuntimeCredentials, resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\nimport { openaiDecisions, pickOpenAIPlatformKey } from './openai-decisions'\nimport { sanitizeToolSpecs } from './schema-sanitize'\nimport { createToolNameBoundary } from './tool-name-boundary'\n\nconst PROVIDER_ID = 'openai-codex'\n/**\n * pi-ai registry id for the standard platform API (`api.openai.com`).\n * The provider auto-detects the backend per stream from the credential\n * shape: a Codex OAuth JWT (`eyJ…`) streams via the ChatGPT Codex backend,\n * a platform API key (`sk-…`) via the standard Responses API. Same model\n * ids, same event contract — only the wire endpoint and billing differ.\n */\nconst PLATFORM_PROVIDER_ID = 'openai'\nconst DEFAULT_MODEL = 'gpt-6-astra'\n\n// Metadata aliases for model ids OpenAI publishes as shorthand (e.g. `gpt-5.6`\n// → the Sol flagship). Used ONLY to resolve extra-model metadata (cost,\n// context window, output ceiling); the requested id is preserved on the wire,\n// which OpenAI accepts. Mirrors `openaiDescriptor.modelAliases` in the chat\n// layer (`src/chat/providers.ts`) — the provider layer can't import that\n// descriptor without a layering cycle. Keep the two in sync.\nconst MODEL_ALIASES: Readonly<Record<string, string>> = {\n 'gpt-5.6': 'gpt-5.6-sol',\n}\n\ntype CodexModel = PiModel<'openai-codex-responses'>\ntype PlatformModel = PiModel<'openai-responses'>\n\n/** Options for {@link openai}: an API key or ChatGPT OAuth credentials, plus model and request settings. */\nexport interface OpenAIParams extends OAuthParams {\n /** ChatGPT account id sent with runtime OAuth credentials. Normally derived from the access token. */\n accountId?: string\n /**\n * Model used when a request does not set one.\n * @default 'gpt-6-astra'\n */\n defaultModel?: string\n /** Transport for the Codex backend: `sse`, `websocket` or `auto`. Ignored for platform API keys. */\n transport?: 'sse' | 'websocket' | 'auto'\n /**\n * Extra HTTP headers merged into every request (the streaming Responses call\n * and the token-count endpoint). Use for routing/attribution headers a proxy\n * in front of the OpenAI Codex endpoint consumes. Merged with provider\n * defaults; pi-ai lets these override defaults, so avoid `authorization` /\n * `content-type` unless you intend to replace them.\n */\n extraHeaders?: Record<string, string>\n}\n\n// pi-ai's `getModel` is typed for `KnownProvider` × `keyof models[P]`;\n// we look up by free-form `modelId` (the registry holds string ids at\n// runtime) and let pi-ai's miss-throw fall through via the wider lookup.\nconst lookupModel = getModel as (provider: string, modelId: string) => CodexModel | undefined\n\nfunction resolveModel(\n modelId: string,\n providerId: string = PROVIDER_ID,\n catalog?: ModelCatalog,\n): CodexModel {\n // A catalog entry overlays whatever the registry resolves below (including\n // the alias and default-model paths), so an override fixes metadata without\n // having to restate the whole model record.\n const entry = catalogLookup(providerId, modelId, catalog)\n const model = lookupModel(providerId, modelId)\n if (model)\n return mergeCatalogEntry(model, entry)\n\n // Shorthand aliases (`gpt-5.6` → `gpt-5.6-sol`): use the canonical\n // registry entry's metadata (cost, context window, output ceiling) while\n // keeping the requested id on the wire — OpenAI accepts the shorthand,\n // and pi-ai's usage accounting must bill at the real rates rather than\n // the default-model fallback's.\n const aliasId = MODEL_ALIASES[modelId]\n const aliased = aliasId ? lookupModel(providerId, aliasId) : undefined\n if (aliased)\n return mergeCatalogEntry({ ...aliased, id: modelId }, entry)\n\n // Registry miss with a catalog entry: the entry is all we know, so build the\n // record from the default model's shape and let the entry override. Without\n // one this stays the \"unknown id, default metadata\" fallback.\n const fallback = lookupModel(providerId, DEFAULT_MODEL)\n if (!fallback)\n throw new Error(`OpenAI model registry (${providerId}) is missing the default model: ${DEFAULT_MODEL}`)\n\n return mergeCatalogEntry({ ...fallback, id: modelId, name: modelId }, entry)\n}\n\nfunction emptyUsage(): PiUsage {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n }\n}\n\nfunction formatTools(tools: ToolSpec[]): PiTool[] {\n // Codex's Responses API runs the same schema validator as the OpenAI\n // Chat Completions endpoint — apply the same sanitisation pass so MCP\n // tools with non-standard root shapes don't 400 here either.\n const sanitized = sanitizeToolSpecs(tools, { profile: 'openai' })\n // `?? ''`: strict validators (and anthropic/openai-format gateways) treat\n // `description` as a required string; MCP tools routinely omit it.\n return sanitized.map(t => ({\n name: t.name,\n description: t.description ?? '',\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction piToolResultMessage(\n result: Extract<SessionContentBlock, { type: 'tool_result' }>,\n toolName = '',\n): PiMessage {\n // pi-ai's ToolResultMessage natively accepts (TextContent | ImageContent)[].\n // Map zidane's canonical union directly — no flattening needed.\n const content = typeof result.output === 'string'\n ? [{ type: 'text' as const, text: result.output }]\n : result.output.map((block) => {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n }\n if (block.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (block.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }\n return { type: 'text' as const, text: block.text }\n })\n\n return {\n role: 'toolResult',\n toolCallId: result.callId,\n toolName,\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n }\n}\n\nfunction piUserMessage(\n content: SessionContentBlock[],\n): PiMessage | null {\n for (const b of content) {\n if (b.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (b.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n }\n\n const textBlocks = content.filter(b => b.type === 'text')\n const imageBlocks = content.filter(b => b.type === 'image')\n const documentBlocks = content.filter(b => b.type === 'document')\n\n if (imageBlocks.length === 0 && textBlocks.length === 0 && documentBlocks.length === 0)\n return null\n\n if (imageBlocks.length === 0 && documentBlocks.length === 0 && textBlocks.length === 1)\n return { role: 'user', content: textBlocks[0].text, timestamp: Date.now() }\n\n return {\n role: 'user',\n content: [\n ...imageBlocks.map((img) => {\n assertResolvedMediaBlock(img, 'OpenAI wire messages')\n return { type: 'image' as const, data: img.data, mimeType: img.mediaType }\n }),\n // NOTE: OpenAI's API natively accepts PDFs (Responses `input_file` /\n // Chat Completions `file`), but pi-ai's message content union is\n // text|image only — it has no file content type — so documents degrade to\n // a marker here. To forward PDFs to OpenAI, route via:\n // openaiCompat({ name: 'openai', apiKey, baseURL: 'https://api.openai.com/v1',\n // capabilities: { documents: true } })\n // which emits the `{type:'file'}` Chat Completions part directly. (That\n // path accepts application/pdf only; spreadsheets/.docx need the\n // Responses API, which would require an input_file content type in pi-ai.)\n ...documentBlocks.map((block) => {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }),\n ...textBlocks.map(block => ({ type: 'text' as const, text: block.text })),\n ],\n timestamp: Date.now(),\n }\n}\n\nfunction piAssistantMessage(\n content: SessionContentBlock[],\n modelId: string,\n): PiAssistantMessage {\n const piContent: PiAssistantMessage['content'] = []\n for (const block of content) {\n if (block.type === 'text') {\n piContent.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n // Shared cross-provider policy (`reasoningWireAction`): drop blocks\n // minted by Anthropic (their HMAC is not valid `encrypted_content`),\n // strip the signature from untagged legacy blocks (no signature-400\n // recovery exists on this path), forward openai-tagged ones intact.\n const action = reasoningWireAction(block, 'openai')\n if (action === 'drop')\n continue\n piContent.push({\n type: 'thinking',\n thinking: block.text,\n ...(action === 'keep' && block.signature !== undefined ? { thinkingSignature: block.signature } : {}),\n })\n }\n else if (block.type === 'tool_call') {\n // `input` is parsed wire JSON; pi-ai types it as `JsonObject`.\n piContent.push({ type: 'toolCall', id: block.id, name: block.name, arguments: block.input as PiJsonObject })\n }\n // `redacted_thinking` (Anthropic-only) and `provider_reasoning` (provider-\n // bound reasoning state) are intentionally dropped — Codex Responses\n // doesn't accept them.\n }\n\n return {\n role: 'assistant',\n content: piContent,\n api: 'openai-codex-responses',\n provider: PROVIDER_ID,\n model: modelId,\n usage: emptyUsage(),\n stopReason: 'stop',\n timestamp: Date.now(),\n }\n}\n\n/**\n * Converts session messages to pi-ai messages for the Responses wire, pairing tool calls with their results.\n *\n * @param messages - Session messages to convert.\n * @param modelId - Model id stamped on converted assistant messages.\n */\nexport function toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\n // System notes have no native slot on this wire: send them as `<system-reminder>` text.\n messages = systemNotesAsText(messages)\n const out: PiMessage[] = []\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n const toolCalls = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_call' }> => b.type === 'tool_call')\n\n if (msg.role === 'assistant' && toolCalls.length > 0) {\n const next = messages[i + 1]\n const nextToolResults = next?.role === 'user'\n ? next.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n : []\n const resultById = new Map(nextToolResults.map(result => [result.callId, result]))\n\n let assistantContent: SessionContentBlock[] = []\n for (const block of msg.content) {\n assistantContent.push(block)\n if (block.type !== 'tool_call')\n continue\n\n out.push(piAssistantMessage(assistantContent, modelId))\n assistantContent = []\n\n const result = resultById.get(block.id)\n if (result) {\n out.push(piToolResultMessage(result, block.name))\n }\n else {\n out.push(piToolResultMessage({\n type: 'tool_result',\n callId: block.id,\n output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,\n isError: true,\n }, block.name))\n }\n }\n if (assistantContent.length > 0)\n out.push(piAssistantMessage(assistantContent, modelId))\n\n if (next?.role === 'user') {\n const remainingUserContent = next.content.filter((block) => {\n if (block.type !== 'tool_result')\n return true\n // Orphan/duplicate tool results should already be removed by the\n // canonical repair pass. If one reaches this adapter, do not send it\n // as an unpaired provider message.\n return false\n })\n const userMessage = piUserMessage(remainingUserContent)\n if (userMessage)\n out.push(userMessage)\n i++\n }\n continue\n }\n\n const toolResults = msg.content.filter(b => b.type === 'tool_result')\n if (toolResults.length > 0) {\n const userMsg = msg.role === 'user'\n ? piUserMessage(msg.content.filter(b => b.type !== 'tool_result'))\n : null\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n if (msg.role === 'user') {\n const userMsg = piUserMessage(msg.content)\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n out.push(piAssistantMessage(msg.content, modelId))\n }\n\n return out\n}\n\n/**\n * Map pi-ai's `StopReason` to the zidane `TurnFinishReason` union — the same\n * native-stop-reason fidelity anthropic's `mapStopReason` / openai-compat's\n * `mapOAIFinishReason` provide. `length` (max-token truncation) maps to\n * `'length'`, not to a clean `stop`. `hasToolCalls` is the fallback for\n * messages whose stop reason is missing or doesn't carry the tool-call signal.\n *\n * @param stopReason - pi-ai stop reason, when present.\n * @param hasToolCalls - Whether the turn contains tool calls.\n */\nexport function mapCodexStopReason(stopReason: string | undefined, hasToolCalls: boolean): TurnFinishReason {\n switch (stopReason) {\n case 'toolUse':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'error':\n return 'error'\n case 'stop':\n return hasToolCalls ? 'tool-calls' : 'stop'\n case 'aborted':\n return 'other'\n default:\n return hasToolCalls ? 'tool-calls' : 'stop'\n }\n}\n\nfunction fromPiAssistantMessage(message: PiAssistantMessage): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const block of message.content) {\n if (block.type === 'text') {\n content.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n const out: Extract<SessionContentBlock, { type: 'thinking' }> = {\n type: 'thinking',\n text: block.thinking,\n }\n if (typeof block.thinkingSignature === 'string') {\n out.signature = block.thinkingSignature\n out.signatureProducer = 'openai'\n }\n content.push(out)\n }\n else if (block.type === 'toolCall') {\n content.push({ type: 'tool_call', id: block.id, name: block.name, input: block.arguments })\n }\n }\n\n return { role: 'assistant', content }\n}\n\nfunction extractToolCalls(message: PiAssistantMessage) {\n return message.content\n .filter(block => block.type === 'toolCall')\n .map(block => ({\n id: block.id,\n name: block.name,\n input: block.arguments as Record<string, unknown>,\n }))\n}\n\nfunction extractText(message: PiAssistantMessage): string {\n return message.content\n .filter((block): block is Extract<PiAssistantMessage['content'][number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n}\n\nfunction toTurnUsage(usage: PiUsage, finishReason: TurnFinishReason | undefined, modelId: string, catalog?: ModelCatalog): Promise<TurnUsage> {\n return fillEstimatedCost({\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead || undefined,\n cacheCreation: usage.cacheWrite || undefined,\n cost: usage.cost.total || undefined,\n ...(finishReason ? { finishReason } : {}),\n modelId,\n }, 'openai', undefined, catalog)\n}\n\n/**\n * Transient pi-ai error patterns worth a loop-level retry. pi-ai's Codex stream\n * retries pre-stream 429 / 5xx only when `maxRetries` is set (default 0, see\n * `openai-codex-responses.js`), and this provider does not set it. So the\n * loop-level retry, with its longer backoff, is the retry layer for capacity\n * events, plus mid-stream emissions (pi-ai surfaces those as plain `Error`s\n * with no status).\n *\n * Mirrors pi-ai's own `isRetryableError` regex so both layers recognize the\n * same failure modes.\n */\nconst TRANSIENT_OPENAI_MESSAGE_RE = /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused|gateway.?time.?out|temporarily.?unavailable/i\n\n/** Numeric HTTP status codes pi-ai sometimes attaches when bubbling structured errors. */\nfunction isRetryableStatusCode(err: object): boolean {\n const status = (err as { status?: unknown }).status\n if (typeof status !== 'number')\n return false\n return isRetryableHttpStatus(status)\n}\n\n/**\n * Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s\n * (wrapping `event.error.errorMessage`) or via stream event types.\n *\n * The retryable hint is set on a transient failure — pattern-matched against\n * `message` since pi-ai strips structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`\n * to disable the loop-level retry.\n *\n * @param err - Error thrown by pi-ai or the HTTP layer.\n */\nexport function classifyOpenAIError(err: unknown): ClassifiedError | null {\n const prelude = classifyErrorPrelude(err)\n if (prelude === 'not-object')\n return null\n if (prelude === 'aborted')\n return { kind: 'aborted' }\n\n const anyErr = err as { name?: string, message?: string, code?: string, type?: string }\n\n const message = anyErr.message ?? ''\n const code = anyErr.code ?? anyErr.type\n\n if (code === 'context_length_exceeded' || matchesContextExceeded(message)) {\n return {\n kind: 'context_exceeded',\n providerCode: code ?? 'context_length_exceeded',\n message,\n }\n }\n\n if (matchesToolPairingError(message)) {\n return {\n kind: 'tool_pairing_corruption',\n providerCode: code ?? 'invalid_request_error',\n message,\n }\n }\n\n // pi-ai wraps API errors in generic `Error` — treat as provider_error when we have a message.\n if (message.length > 0) {\n const retryable = isRetryableStatusCode(anyErr) || TRANSIENT_OPENAI_MESSAGE_RE.test(message)\n const status = (anyErr as { status?: unknown }).status\n const reason = providerLimitReason({ status: typeof status === 'number' ? status : undefined, code, message })\n if (reason) {\n // Codex OAuth runs on the user's ChatGPT plan, and pi-ai's message says so.\n const retryAfterMs = announcedResetMs(message)\n return classifyProviderLimit(\n { reason, provider: /ChatGPT/.test(message) ? 'ChatGPT' : 'OpenAI', ...(retryAfterMs !== undefined ? { retryAfterMs } : {}) },\n { providerCode: code, retryable },\n )\n }\n return {\n kind: 'provider_error',\n providerCode: code,\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n }\n\n return null\n}\n\n/**\n * OpenAI's org-verification rejection for `reasoning.summary` — e.g.\n * \"Your organization must be verified to generate reasoning summaries\".\n * Matched loosely on the two load-bearing words so minor copy changes\n * don't defeat the platform-branch fallback.\n */\nfunction isReasoningSummaryVerificationError(err: unknown): boolean {\n if (!(err instanceof Error))\n return false\n return /reasoning summar/i.test(err.message) && /verif/i.test(err.message)\n}\n\n/**\n * A standard OpenAI API key usable against `api.openai.com` (for the exact\n * token-count endpoint), or `null` when only a Codex-OAuth credential is\n * available. Codex OAuth access tokens are JWTs (`eyJ…`) and are NOT valid\n * bearers for the standard API; a real key looks like `sk-…` (but not the\n * Anthropic `sk-ant-…` form). Checks `params.apiKey` then `OPENAI_API_KEY`.\n */\nfunction pickStandardOpenAIKey(params?: OpenAIParams): string | null {\n const candidates = [params?.apiKey, process.env.OPENAI_API_KEY]\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * Convert canonical {@link SessionMessage}s to OpenAI Responses-API `input`\n * items for the token-count endpoint. Only the text-bearing shape is needed\n * here (the count path sends a tiny dummy message); images/tool-results are\n * down-converted to text so the count never throws on an exotic block.\n */\nfunction toResponsesInput(messages: SessionMessage[]): unknown[] {\n return systemNotesAsText(messages).map((msg) => {\n const text = msg.content\n .map(b => (b.type === 'text' ? b.text : ''))\n .filter(Boolean)\n .join('\\n')\n const part = msg.role === 'assistant' ? 'output_text' : 'input_text'\n return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: [{ type: part, text }] }\n })\n}\n\n/** Convert pi-ai `PiTool` specs to Responses-API function tools. */\nfunction toResponsesTools(tools: unknown[]): unknown[] {\n return tools.map((t) => {\n const tool = t as { name?: string, description?: string, parameters?: unknown }\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n }\n })\n}\n\nfunction applyPayloadOverrides(payload: unknown, options: StreamOptions, toWireToolName: (name: string) => string = name => name): unknown {\n const body = payload as Record<string, unknown>\n\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n body.tool_choice = { type: 'function', name: toWireToolName(options.toolChoice.name) }\n else if (options.toolChoice.type === 'required')\n body.tool_choice = 'required'\n else\n body.tool_choice = 'auto'\n }\n\n return body\n}\n\n/**\n * Creates the OpenAI provider on the Responses API.\n * Picks the backend per request from the credential: a Codex OAuth token streams through the ChatGPT Codex backend, a platform API key (`sk-…`) through the standard Responses API.\n * A run reads `params.apiKey`, then `OPENAI_CODEX_API_KEY`, then the stored OAuth credentials. `OPENAI_API_KEY` is read only by the exact token count (`countTokens`) and by the decisions helper, together with `params.apiKey` and `OPENAI_CODEX_API_KEY`.\n *\n * @param params - API key or OAuth credentials, account id, default model, transport and extra headers.\n *\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { openai } from 'zidane/providers/openai'\n *\n * const agent = createAgent({\n * provider: openai({ apiKey: process.env.OPENAI_API_KEY }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function openai(params?: OpenAIParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n const baseCredentials = extractRuntimeCredentials(params)\n let runtimeCredentials = baseCredentials\n ? { ...baseCredentials, ...(params?.accountId ? { accountId: params.accountId } : {}) }\n : undefined\n\n return {\n name: 'openai',\n meta: {\n defaultModel,\n isOAuth: true,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n // pi-ai's Codex Responses wire has no audio/video input content type.\n audio: false,\n video: false,\n },\n },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAIError,\n // Decisions live on the standard platform API, so only a platform key\n // works: explicit `apiKey`, `OPENAI_API_KEY`, or a platform key stored\n // under the Codex env slot (the chat host's API-key login writes there).\n decisions: openaiDecisions({\n resolveKey: () => pickOpenAIPlatformKey([params?.apiKey, process.env.OPENAI_API_KEY, process.env.OPENAI_CODEX_API_KEY]),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n }),\n // The Images API is on the platform API too: same key rule as decisions.\n images: openaiImages({\n resolveKey: () => pickOpenAIPlatformKey([params?.apiKey, process.env.OPENAI_API_KEY, process.env.OPENAI_CODEX_API_KEY]),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n }),\n\n async countTokens(payload, signal): Promise<number | null> {\n // The exact count endpoint (`POST /v1/responses/input_tokens`) lives on\n // the standard OpenAI API and needs a standard `OPENAI_API_KEY` bearer.\n // This provider authenticates via Codex OAuth against the Codex backend,\n // whose token is NOT valid for that endpoint — so we only attempt the\n // count when a standard key is present (env or params.apiKey that isn't\n // an OAuth/JWT token). Otherwise return null → heuristic fallback.\n const standardKey = pickStandardOpenAIKey(params)\n if (!standardKey)\n return null\n try {\n const tools = payload.tools as PiTool[]\n const nameBoundary = createToolNameBoundary(payload.messages, tools.map(tool => tool.name))\n const res = await fetch('https://api.openai.com/v1/responses/input_tokens', {\n method: 'POST',\n headers: {\n ...params?.extraHeaders,\n 'authorization': `Bearer ${standardKey}`,\n 'content-type': 'application/json',\n },\n // The Responses `input_tokens` endpoint takes the same shape as\n // `responses.create`: `instructions` (system), `input` (Responses\n // input items — NOT pi-ai messages), and function-shaped `tools`.\n body: JSON.stringify({\n model: payload.model || defaultModel,\n instructions: renderSystemForWire(payload.system),\n input: toResponsesInput(nameBoundary.messages),\n tools: toResponsesTools(tools.map(tool => ({ ...tool, name: nameBoundary.toWire(tool.name) }))),\n }),\n ...(signal ? { signal } : {}),\n })\n if (!res.ok)\n return null\n const json = (await res.json()) as { input_tokens?: unknown }\n return typeof json.input_tokens === 'number' ? json.input_tokens : null\n }\n catch {\n return null\n }\n },\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'openai',\n providerId: PROVIDER_ID,\n params: runtimeCredentials ? { ...params, ...runtimeCredentials } : params,\n envKey: 'OPENAI_CODEX_API_KEY',\n extraCredentialKeys: ['accountId'],\n missingError: 'No OpenAI Codex OAuth token found. Run `bun run auth --openai` first.',\n refreshError: reason => `OpenAI Codex OAuth token refresh failed. Run \\`bun run auth --openai\\` again. ${reason}`,\n },\n {\n ...callbacks,\n async onOAuthRefresh(ctx) {\n if (ctx.source === 'params') {\n runtimeCredentials = {\n access: ctx.credentials.access,\n refresh: ctx.credentials.refresh,\n expires: ctx.credentials.expires,\n ...(typeof ctx.credentials.accountId === 'string' ? { accountId: ctx.credentials.accountId } : {}),\n }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n // Backend auto-detection by credential shape. A Codex OAuth access\n // token is a JWT whose claims carry the `chatgpt_account_id` the Codex\n // backend requires per request; a standard `sk-…` platform key can\n // NEVER stream there (pi-ai fails with an opaque \"Failed to extract\n // accountId from token\") — but it's a first-class credential for the\n // standard Responses API, so route it there instead. Scoped to the\n // unambiguous `sk-` shape: exotic bearers (test harnesses, relays)\n // keep flowing to the Codex path untouched.\n const usePlatformApi = apiKey.startsWith('sk-')\n const model = resolveModel(modelId, usePlatformApi ? PLATFORM_PROVIDER_ID : PROVIDER_ID, options.modelCatalog)\n const tools = options.tools as PiTool[]\n const nameBoundary = createToolNameBoundary(options.messages, tools.map(tool => tool.name))\n // Codex's Responses API has no `cache_control` analogue, but the\n // system-prompt boundary marker is structural metadata that should\n // never reach the model. Strip it via `renderSystemForWire`; the\n // doctrine + env are collapsed into a single byte stream the model\n // sees as one logical prompt.\n // pi-ai's stream entry points take a `TranscriptContext`: the prompt\n // and tools folded into a leading system message. `normalizeContext` is\n // the only producer of that branded type.\n const rawContext: PiContext = {\n systemPrompt: renderSystemForWire(options.system),\n messages: toPiMessages(nameBoundary.messages, modelId),\n tools: tools.map(tool => ({ ...tool, name: nameBoundary.toWire(tool.name) })),\n }\n const context = normalizeContext(rawContext)\n // OpenAI's `reasoning_effort` accepts minimal/low/medium/high/xhigh, and\n // the GPT-5.6 line adds a native `max` tier. Clamp `max` to `xhigh` on\n // older models only; `'adaptive'` degrades to no reasoning rather than\n // forwarding an unknown value the API would reject.\n const supportsMaxEffort = modelId.startsWith('gpt-5.6')\n const reasoningLevel\n = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking === 'max' && !supportsMaxEffort ? 'xhigh' : options.thinking\n : undefined\n // Options are shared verbatim across both backends — the platform\n // Responses API and the Codex bridge take the same reasoning / service\n // tier knobs; only the websocket `transport` toggle is Codex-specific.\n const makeStream = (reasoningSummary: 'auto' | undefined) => {\n const streamOptions = {\n apiKey,\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n signal: options.signal,\n reasoningEffort: reasoningLevel,\n reasoningSummary,\n ...(options.modelOptions?.fast ? { serviceTier: 'priority' as const } : {}),\n // pi-ai sends it as `prompt_cache_key` (and session headers on the\n // platform API, websocket reuse on Codex). Unset = no key.\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n // pi-ai types the payload as `unknown`; both backends send the\n // Responses-API body shape `applyPayloadOverrides` expects.\n onPayload: (payload: unknown) => applyPayloadOverrides(payload as Record<string, unknown>, options, nameBoundary.toWire),\n }\n return usePlatformApi\n ? streamOpenAIResponses(model as unknown as PlatformModel, context, streamOptions)\n : streamOpenAICodexResponses(model, context, { ...streamOptions, transport: params?.transport })\n }\n let stream = makeStream(reasoningLevel ? 'auto' : undefined)\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n\n const consume = async (s: ReturnType<typeof makeStream>) => {\n for await (const event of s) {\n if (event.type === 'text_delta') {\n text += event.delta\n callbacks.onText(event.delta)\n }\n else if (event.type === 'thinking_delta') {\n thinking += event.delta\n callbacks.onThinking?.(event.delta)\n }\n else if (event.type === 'thinking_end') {\n const delta = event.content.startsWith(thinking)\n ? event.content.slice(thinking.length)\n : (thinking ? '' : event.content)\n if (delta) {\n thinking += delta\n callbacks.onThinking?.(delta)\n }\n }\n else if (event.type === 'toolcall_start' || event.type === 'toolcall_delta') {\n // Liveness only: a tool-only turn streams nothing else for the stall watchdog to see.\n callbacks.onToolCallDelta?.()\n }\n else if (event.type === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n throw new Error(event.error.errorMessage || (usePlatformApi ? 'OpenAI API error' : 'OpenAI Codex API error'))\n }\n }\n }\n\n try {\n await consume(stream)\n }\n catch (err) {\n // The platform Responses API rejects reasoning summaries for\n // organizations that haven't completed verification (the Codex\n // backend has no such gate). That 400 fails request validation, so\n // nothing has streamed yet — retry once without the summary rather\n // than bricking every reasoning-enabled stream for those orgs.\n const nothingStreamed = text.length === 0 && thinking.length === 0 && finalMessage === undefined\n if (usePlatformApi && reasoningLevel && nothingStreamed && isReasoningSummaryVerificationError(err)) {\n stream = makeStream(undefined)\n await consume(stream)\n }\n else {\n throw err\n }\n }\n\n finalMessage ??= await stream.result()\n text ||= extractText(finalMessage)\n\n const toolCalls = extractToolCalls(finalMessage)\n .map(call => ({ ...call, name: nameBoundary.fromWire(call.name) }))\n const assistantTurn = fromPiAssistantMessage(finalMessage)\n assistantTurn.content = assistantTurn.content.map(block =>\n block.type === 'tool_call' ? { ...block, name: nameBoundary.fromWire(block.name) } : block,\n )\n const finishReason = mapCodexStopReason(finalMessage.stopReason, toolCalls.length > 0)\n // Metadata resolves under `openai-codex` (or `openai` on the platform\n // path) while cost estimation runs under `openai` — accept a catalog\n // entry keyed either way so one entry fixes both.\n const usage = await toTurnUsage(finalMessage.usage, finishReason, modelId, aliasCatalogProviders(\n options.modelCatalog,\n [usePlatformApi ? PLATFORM_PROVIDER_ID : PROVIDER_ID, PLATFORM_PROVIDER_ID],\n ))\n\n return {\n assistantMessage: assistantTurn,\n text,\n toolCalls,\n done: toolCalls.length === 0,\n usage,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,MAAM,WAAW;;AAGjB,MAAa,sBAAiD;CAC5D;EAAE,IAAI;EAAe,MAAM;EAAe,OAAO,CAAC,QAAQ,OAAO;EAAG,cAAc;CAAK;CACvF;EAAE,IAAI;EAAe,MAAM;EAAe,OAAO,CAAC,QAAQ,OAAO;EAAG,cAAc;CAAK;CACvF;EAAE,IAAI;EAAoB,MAAM;EAAoB,OAAO,CAAC,QAAQ,OAAO;EAAG,cAAc;CAAK;AACnG;;;;;;;AAQA,SAAgB,gBAAgB,OAA6C;CAC3E,IAAI,CAAC,OACH,OAAO;CACT,MAAM,QAAQ,YAAY,KAAK;CAC/B,IAAI,QAAQ,MACV,OAAO;CACT,IAAI,QAAQ,KACV,OAAO;CACT,OAAO;AACT;;;;;;;;;AAcA,SAAgB,aAAa,SAAoH;CAC/I,MAAM,UAAU,QAAQ,SAAS;CACjC,OAAO;EACL,cAAc,oBAAoB,EAAE,CAAE;EACtC,QAAQ;EACR,oBAAoB,QAAQ,WAAW,IACnC,EAAE,WAAW,KAAK,IAClB;GAAE,WAAW;GAAO,QAAQ;EAAgG;EAChI,MAAM,SAAS,SAAS,QAAQ;GAC9B,MAAM,MAAM,QAAQ,WAAW;GAC/B,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,mGAAmG;GACrH,MAAM,SAAiC;IACrC,OAAO,QAAQ;IACf,QAAQ,QAAQ;IAChB,GAAG,OAAO,WAAW,QAAQ,KAAK,CAAC;IACnC,MAAM,gBAAgB,QAAQ,WAAW;IACzC,eAAe;IACf,GAAI,QAAQ,cAAc,EAAE,YAAY,cAAc,IAAI,CAAC;GAC7D;GACA,MAAM,UAAU;IAAE,GAAG,QAAQ;IAAS,eAAe,UAAU;GAAM;GACrE,MAAM,aAAa,QAAQ,cAAc,CAAC;GAC1C,IAAI;GACJ,IAAI,WAAW,WAAW,GACxB,MAAM,MAAM,QAAQ,GAAG,SAAS,sBAAsB;IACpD,QAAQ;IACR,SAAS;KAAE,GAAG;KAAS,gBAAgB;IAAmB;IAC1D,MAAM,KAAK,UAAU;KAAE,GAAG;KAAQ,GAAG,OAAO,OAAO,CAAC;IAAE,CAAC;IACvD;GACF,CAAC;QAEE;IACH,MAAM,OAAO,IAAI,SAAS;IAC1B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAC/C,KAAK,OAAO,MAAM,KAAK;IACzB,WAAW,SAAS,KAAK,MAAM;KAC7B,MAAM,MAAM,IAAI,UAAU,MAAM,GAAG,CAAC,CAAC,MAAM;KAC3C,KAAK,OAAO,WAAW,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,UAAU,CAAC,GAAG,aAAa,IAAI,EAAE,GAAG,KAAK;IAC1H,CAAC;IACD,MAAM,MAAM,QAAQ,GAAG,SAAS,gBAAgB;KAAE,QAAQ;KAAQ;KAAS,MAAM;KAAM;IAAO,CAAC;GACjG;GACA,IAAI,CAAC,IAAI,IACP,MAAM,MAAM,eAAe,UAAU,GAAG;GAC1C,MAAM,OAAO,MAAM,IAAI,KAAK;GAC5B,MAAM,UAAU,KAAK,QAAQ,CAAC,EAAA,CAAG,SAAQ,SAAQ,KAAK,WAAW,CAAC,gBAAgB,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC;GACtG,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,MAAM,2BAA2B;GAC7C,MAAM,UAAU,KAAK,MAAM,MAAK,SAAQ,KAAK,cAAc,CAAC,EAAE;GAC9D,OAAO;IAAE;IAAQ,OAAO,QAAQ;IAAO,GAAI,UAAU,EAAE,MAAM,mBAAmB,UAAU,IAAI,CAAC;GAAG;EACpG;CACF;AACF;;AC7EA,MAAa,yBAAyB,CAAC,YAAY;;AAGnD,MAAM,uBAAyD,EAC7D,cAAc,GAChB;;AAGA,MAAa,gCAAgC;AAE7C,SAAS,YAAY,OAA+B;CAClD,IAAI,OAAO,UAAU,UACnB,OAAO;CACT,IAAI,CAAC,cAAc,KAAK,GACtB,OAAO,KAAK,UAAU,OAAO,MAAM,CAAC;CAUtC,OAAO,CAAC;EAAE,MAAM;EAAQ,SATR,MAAM,KAAK,SAAS;GAClC,IAAI,KAAK,SAAS,QAChB,OAAO;IAAE,MAAM;IAAc,MAAM,KAAK;GAAK;GAC/C,IAAI,KAAK,SAAS,SAChB,OAAO;IAAE,MAAM;IAAe,WAAW,QAAQ,KAAK,UAAU,UAAU,KAAK;GAAO;GACxF,IAAI,KAAK,SAAS,cAAc,KAAK,aAAa,QAChD,OAAO;IAAE,MAAM;IAAc,MAAM,KAAK;GAAK;GAC/C,MAAM,IAAI,yBAAyB,uDAAuD,KAAK,KAAK,OAAO;EAC7G,CAC8B;CAAE,CAAC;AACnC;AAEA,SAAS,eAAe,MAAc,GAA8C;CAClF,QAAQ,EAAE,MAAV;EACE,KAAK,aACH,OAAO;GACL,MAAM;GACN;GACA,cAAc,EAAE,WAAW,GAAG,EAAE,aAAa,iBAAiB,EAAE,SAAS,KAAK,gBAAgB,EAAE,SAAS,UAAU,EAAE;EACvH;EACF,KAAK,UACH,OAAO;GACL,MAAM;GACN;GACA,cAAc,EAAE;GAChB,SAAS,OAAO,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB;IAAE;IAAO,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;GAAG,EAAE;EACvH;EACF,KAAK,SACH,OAAO;GACL,MAAM;GACN;GACA,cAAc,EAAE;GAChB,QAAQ,EAAE,OAAO,KAAK,UAAU;IAC9B,MAAM,cAAc,sBAAsB,KAAK;IAC/C,OAAO;KAAE,OAAO,gBAAgB,KAAK;KAAG,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;IAAG;GAClF,CAAC;EACH;CACJ;AACF;AAEA,SAAS,IAAI,GAAgC;CAC3C,OAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,IAAI,IAAI,KAAA;AAC3D;AAEA,SAAS,mBAAmB,GAAwF;CAClH,IAAI,CAAC,MAAM,QAAQ,CAAC,GAClB,OAAO,KAAA;CACT,MAAM,MAAsE,CAAC;CAC7E,KAAK,MAAM,KAAK,GAAG;EACjB,MAAM,IAAI,KAAK,OAAO,MAAM,WAAW,IAAK,EAAgC,WAAW,IAAI,KAAA;EAC3F,IAAI,MAAM,KAAA,GACR,IAAI,KAAK;GAAE,OAAQ,EAA0B;GAAO,OAAQ,EAA0B;GAAO,aAAa;EAAE,CAAC;CACjH;CACA,OAAO;AACT;AAEA,SAAS,eAAe,KAA8B,UAAwD;CAC5G,MAAM,aAAa,IAAI,IAAI,UAAU;CACrC,QAAQ,IAAI,MAAZ;EACE,KAAK,aACH,OAAO;GAAE,MAAM;GAAa,aAAa,IAAI,IAAI,WAAW,KAAK;EAAW;EAC9E,KAAK,UAAU;GACb,MAAM,UAAU,mBAAmB,IAAI,aAAa;GACpD,MAAM,gBAAgB,UAAU,OAAO,YAAY,QAAQ,KAAI,MAAK,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,WAAW,CAAC,CAAC,IAAI,KAAA;GACzG,OAAO;IACL,MAAM;IACN,QAAQ,OAAO,IAAI,MAAM;IACzB,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;IACzC,GAAI,eAAe,KAAA,IAAY,EAAE,WAAW,IAAI,CAAC;GACnD;EACF;EACA,KAAK,SAAS;GACZ,MAAM,UAAU,mBAAmB,IAAI,aAAa;GACpD,MAAM,SAAS,UAAU,SAAS,UAAU,SAAS,OAAO,IAAI,eAAe,IAAI,KAAA;GACnF,MAAM,SAAS,QAAQ,UAAU,SAAS,UAAU;GAEpD,MAAM,cAAc,MAAkD;IACpE,IAAI,OAAO,EAAE,UAAU,UACrB,OAAO,EAAE;IACX,KAAK,MAAM,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,GAAG;KACpC,MAAM,IAAI,OAAO,QAAQ,YAAY,SAAS,OAAO,QAAQ,GAAG,IAAI;KACpE,IAAI,KAAK,GACP,OAAO;IACX;IACA,OAAO,OAAO,EAAE,KAAK;GACvB;GACA,MAAM,gBAAgB,UAClB,MAAM,KAAK,EAAE,QAAQ,OAAO,IAAI,GAAG,MAAM,QAAQ,MAAK,MAAK,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,IACjG,KAAA;GACJ,OAAO;IACL,MAAM;IACN,OAAO,IAAI,IAAI,KAAK,KAAK;IACzB,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;IACzC,GAAI,eAAe,KAAA,IAAY,EAAE,WAAW,IAAI,CAAC;GACnD;EACF;EACA,KAAK,WAAW;GACd,MAAM,UAAU,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,KAAA;GAChH,OAAO;IAAE,MAAM;IAAW,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;GAAG;EAC5D;EACA,SACE,MAAM,IAAI,6BAA6B,4BAA4B,OAAO,IAAI,IAAI,EAAE,EAAE;CAC1F;AACF;AAEA,eAAe,aAAa,KAAgC;CAC1D,MAAM,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,EAAE;CAC5C,IAAI;EACF,MAAM,OAAO,KAAK,MAAM,IAAI;EAC5B,IAAI,OAAO,KAAK,OAAO,YAAY,UACjC,OAAO,KAAK,MAAM;CACtB,QACM,CAAC;CACP,OAAO,KAAK,MAAM,GAAG,GAAG,KAAK,QAAQ,IAAI;AAC3C;;AAGA,SAAgB,sBAAsB,YAA8D;CAClG,KAAK,MAAM,OAAO,YAChB,IAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,KAAK,KAAK,CAAC,IAAI,WAAW,SAAS,GAC/E,OAAO;CAEX,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,gBAAgB,SAMV;CACpB,MAAM,UAAU,QAAQ,SAAS;CACjC,OAAO;EACL,cAAc,uBAAuB;EACrC,QAAQ;EACR,oBAAkD,QAAQ,WAAW,IACjE,EAAE,WAAW,KAAK,IAClB;GAAE,WAAW;GAAO,QAAQ;EAA8B;EAC9D,MAAM,OAAO,SAAkC,QAAwD;GACrG,MAAM,MAAM,QAAQ,WAAW;GAC/B,IAAI,CAAC,KACH,MAAM,IAAI,yBAAyB,6BAA6B;GAClE,MAAM,OAAO;IACX,OAAO,QAAQ;IACf,OAAO,YAAY,QAAQ,KAAK;IAChC,WAAW,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,MAAM,OAAO,eAAe,MAAM,CAAC,CAAC;GACzF;GACA,MAAM,MAAM,MAAM,QAAQ,QAAQ,OAAA,uCAA6B;IAC7D,QAAQ;IACR,SAAS;KAAE,GAAG,QAAQ;KAAS,iBAAiB,UAAU;KAAO,gBAAgB;IAAmB;IACpG,MAAM,KAAK,UAAU,IAAI;IACzB;GACF,CAAC;GACD,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,kBAAkB,IAAI,QAAQ,MAAM,aAAa,GAAG,CAAC;GACjE,IAAI;GACJ,IAAI;IACF,OAAO,MAAM,IAAI,KAAK;GACxB,QACM;IACJ,MAAM,IAAI,6BAA6B,sBAAsB;GAC/D;GACA,IAAI,CAAC,MAAM,QAAQ,KAAK,OAAO,GAC7B,MAAM,IAAI,6BAA6B,+BAA+B;GACxE,MAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS;GAC3C,MAAM,UAA0C,CAAC;GACjD,KAAK,QAAQ,SAAS,KAAc,MAAc;IAChD,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,MAAM,IAAI,6BAA6B,UAAU,EAAE,kBAAkB;IACvE,MAAM,IAAI;IAEV,MAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,MAAM;IACzD,IAAI,MACF,QAAQ,QAAQ,eAAe,GAAG,QAAQ,UAAU,KAAK;GAC7D,CAAC;GACD,MAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ;GACpE,MAAM,QAAS,KAAK,SAAS,CAAC;GAC9B,MAAM,QAAQ,IAAI,MAAM,YAAY,KAAK,IAAI,MAAM,aAAa,KAAK;GACrE,MAAM,SAAS,IAAI,MAAM,aAAa,KAAK,IAAI,MAAM,iBAAiB,KAAK;GAC3E,MAAM,QAAQ,qBAAqB,QAAQ,UAAU,qBAAqB;GAC1E,OAAO;IACL;IACA,OAAO;KAAE;KAAO;KAAQ,GAAI,UAAU,KAAA,IAAY,EAAE,MAAO,QAAQ,QAAS,IAAU,IAAI,CAAC;IAAG;IAC9F;IACA,GAAI,OAAO,KAAK,OAAO,WAAW,EAAE,IAAI,KAAK,GAAG,IAAI,CAAC;GACvD;EACF;CACF;AACF;;;ACxMA,MAAM,cAAc;;;;;;;;AAQpB,MAAM,uBAAuB;AAC7B,MAAM,gBAAgB;AAQtB,MAAM,gBAAkD,EACtD,WAAW,cACb;AA6BA,MAAM,cAAcA;AAEpB,SAAS,aACP,SACA,aAAqB,aACrB,SACY;CAIZ,MAAM,QAAQC,cAAc,YAAY,SAAS,OAAO;CACxD,MAAM,QAAQ,YAAY,YAAY,OAAO;CAC7C,IAAI,OACF,OAAO,kBAAkB,OAAO,KAAK;CAOvC,MAAM,UAAU,cAAc;CAC9B,MAAM,UAAU,UAAU,YAAY,YAAY,OAAO,IAAI,KAAA;CAC7D,IAAI,SACF,OAAO,kBAAkB;EAAE,GAAG;EAAS,IAAI;CAAQ,GAAG,KAAK;CAK7D,MAAM,WAAW,YAAY,YAAY,aAAa;CACtD,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,0BAA0B,WAAW,kCAAkC,eAAe;CAExG,OAAO,kBAAkB;EAAE,GAAG;EAAU,IAAI;EAAS,MAAM;CAAQ,GAAG,KAAK;AAC7E;AAEA,SAAS,aAAsB;CAC7B,OAAO;EACL,OAAO;EACP,QAAQ;EACR,WAAW;EACX,YAAY;EACZ,aAAa;EACb,MAAM;GAAE,OAAO;GAAG,QAAQ;GAAG,WAAW;GAAG,YAAY;GAAG,OAAO;EAAE;CACrE;AACF;AAEA,SAAS,YAAY,OAA6B;CAOhD,OAHkB,kBAAkB,OAAO,EAAE,SAAS,SAAS,CAGhD,CAAC,CAAC,KAAI,OAAM;EACzB,MAAM,EAAE;EACR,aAAa,EAAE,eAAe;EAC9B,YAAY,EAAE;CAChB,EAAE;AACJ;AAEA,SAAS,eAAe,KAAwC;CAC9D,OAAO,oBAAoB,KAAK,kBAAkB;AACpD;AAEA,SAAS,oBACP,QACA,WAAW,IACA;CAGX,MAAM,UAAU,OAAO,OAAO,WAAW,WACrC,CAAC;EAAE,MAAM;EAAiB,MAAM,OAAO;CAAO,CAAC,IAC/C,OAAO,OAAO,KAAK,UAAU;EAC3B,IAAI,MAAM,SAAS,SAAS;GAC1B,yBAAyB,OAAO,sBAAsB;GACtD,OAAO;IAAE,MAAM;IAAkB,MAAM,MAAM;IAAM,UAAU,MAAM;GAAU;EAC/E;EACA,IAAI,MAAM,SAAS,SACjB,MAAM,sBAAsB,SAAS,QAAQ;EAC/C,IAAI,MAAM,SAAS,SACjB,MAAM,sBAAsB,SAAS,QAAQ;EAC/C,IAAI,MAAM,SAAS,YAAY;GAC7B,yBAAyB,OAAO,sBAAsB;GACtD,OAAO;IAAE,MAAM;IAAiB,MAAM,eAAe,KAAK;GAAE;EAC9D;EACA,OAAO;GAAE,MAAM;GAAiB,MAAM,MAAM;EAAK;CACnD,CAAC;CAEL,OAAO;EACL,MAAM;EACN,YAAY,OAAO;EACnB;EACA;EACA,SAAS,OAAO,WAAW;EAC3B,WAAW,KAAK,IAAI;CACtB;AACF;AAEA,SAAS,cACP,SACkB;CAClB,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,EAAE,SAAS,SACb,MAAM,sBAAsB,SAAS,QAAQ;EAC/C,IAAI,EAAE,SAAS,SACb,MAAM,sBAAsB,SAAS,QAAQ;CACjD;CAEA,MAAM,aAAa,QAAQ,QAAO,MAAK,EAAE,SAAS,MAAM;CACxD,MAAM,cAAc,QAAQ,QAAO,MAAK,EAAE,SAAS,OAAO;CAC1D,MAAM,iBAAiB,QAAQ,QAAO,MAAK,EAAE,SAAS,UAAU;CAEhE,IAAI,YAAY,WAAW,KAAK,WAAW,WAAW,KAAK,eAAe,WAAW,GACnF,OAAO;CAET,IAAI,YAAY,WAAW,KAAK,eAAe,WAAW,KAAK,WAAW,WAAW,GACnF,OAAO;EAAE,MAAM;EAAQ,SAAS,WAAW,EAAE,CAAC;EAAM,WAAW,KAAK,IAAI;CAAE;CAE5E,OAAO;EACL,MAAM;EACN,SAAS;GACP,GAAG,YAAY,KAAK,QAAQ;IAC1B,yBAAyB,KAAK,sBAAsB;IACpD,OAAO;KAAE,MAAM;KAAkB,MAAM,IAAI;KAAM,UAAU,IAAI;IAAU;GAC3E,CAAC;GAUD,GAAG,eAAe,KAAK,UAAU;IAC/B,yBAAyB,OAAO,sBAAsB;IACtD,OAAO;KAAE,MAAM;KAAiB,MAAM,eAAe,KAAK;IAAE;GAC9D,CAAC;GACD,GAAG,WAAW,KAAI,WAAU;IAAE,MAAM;IAAiB,MAAM,MAAM;GAAK,EAAE;EAC1E;EACA,WAAW,KAAK,IAAI;CACtB;AACF;AAEA,SAAS,mBACP,SACA,SACoB;CACpB,MAAM,YAA2C,CAAC;CAClD,KAAK,MAAM,SAAS,SAClB,IAAI,MAAM,SAAS,QACjB,UAAU,KAAK;EAAE,MAAM;EAAQ,MAAM,MAAM;CAAK,CAAC;MAE9C,IAAI,MAAM,SAAS,YAAY;EAKlC,MAAM,SAAS,oBAAoB,OAAO,QAAQ;EAClD,IAAI,WAAW,QACb;EACF,UAAU,KAAK;GACb,MAAM;GACN,UAAU,MAAM;GAChB,GAAI,WAAW,UAAU,MAAM,cAAc,KAAA,IAAY,EAAE,mBAAmB,MAAM,UAAU,IAAI,CAAC;EACrG,CAAC;CACH,OACK,IAAI,MAAM,SAAS,aAEtB,UAAU,KAAK;EAAE,MAAM;EAAY,IAAI,MAAM;EAAI,MAAM,MAAM;EAAM,WAAW,MAAM;CAAsB,CAAC;CAO/G,OAAO;EACL,MAAM;EACN,SAAS;EACT,KAAK;EACL,UAAU;EACV,OAAO;EACP,OAAO,WAAW;EAClB,YAAY;EACZ,WAAW,KAAK,IAAI;CACtB;AACF;;;;;;;AAQA,SAAgB,aAAa,UAA4B,SAA8B;CAErF,WAAW,kBAAkB,QAAQ;CACrC,MAAM,MAAmB,CAAC;CAE1B,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,MAAM,SAAS;EACrB,MAAM,YAAY,IAAI,QAAQ,QAAQ,MAAgE,EAAE,SAAS,WAAW;EAE5H,IAAI,IAAI,SAAS,eAAe,UAAU,SAAS,GAAG;GACpD,MAAM,OAAO,SAAS,IAAI;GAC1B,MAAM,kBAAkB,MAAM,SAAS,SACnC,KAAK,QAAQ,QAAQ,MAAkE,EAAE,SAAS,aAAa,IAC/G,CAAC;GACL,MAAM,aAAa,IAAI,IAAI,gBAAgB,KAAI,WAAU,CAAC,OAAO,QAAQ,MAAM,CAAC,CAAC;GAEjF,IAAI,mBAA0C,CAAC;GAC/C,KAAK,MAAM,SAAS,IAAI,SAAS;IAC/B,iBAAiB,KAAK,KAAK;IAC3B,IAAI,MAAM,SAAS,aACjB;IAEF,IAAI,KAAK,mBAAmB,kBAAkB,OAAO,CAAC;IACtD,mBAAmB,CAAC;IAEpB,MAAM,SAAS,WAAW,IAAI,MAAM,EAAE;IACtC,IAAI,QACF,IAAI,KAAK,oBAAoB,QAAQ,MAAM,IAAI,CAAC;SAGhD,IAAI,KAAK,oBAAoB;KAC3B,MAAM;KACN,QAAQ,MAAM;KACd,QAAQ;KACR,SAAS;IACX,GAAG,MAAM,IAAI,CAAC;GAElB;GACA,IAAI,iBAAiB,SAAS,GAC5B,IAAI,KAAK,mBAAmB,kBAAkB,OAAO,CAAC;GAExD,IAAI,MAAM,SAAS,QAAQ;IASzB,MAAM,cAAc,cARS,KAAK,QAAQ,QAAQ,UAAU;KAC1D,IAAI,MAAM,SAAS,eACjB,OAAO;KAIT,OAAO;IACT,CACqD,CAAC;IACtD,IAAI,aACF,IAAI,KAAK,WAAW;IACtB;GACF;GACA;EACF;EAGA,IADoB,IAAI,QAAQ,QAAO,MAAK,EAAE,SAAS,aACzC,CAAC,CAAC,SAAS,GAAG;GAC1B,MAAM,UAAU,IAAI,SAAS,SACzB,cAAc,IAAI,QAAQ,QAAO,MAAK,EAAE,SAAS,aAAa,CAAC,IAC/D;GACJ,IAAI,SACF,IAAI,KAAK,OAAO;GAClB;EACF;EAEA,IAAI,IAAI,SAAS,QAAQ;GACvB,MAAM,UAAU,cAAc,IAAI,OAAO;GACzC,IAAI,SACF,IAAI,KAAK,OAAO;GAClB;EACF;EAEA,IAAI,KAAK,mBAAmB,IAAI,SAAS,OAAO,CAAC;CACnD;CAEA,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,mBAAmB,YAAgC,cAAyC;CAC1G,QAAQ,YAAR;EACE,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK,QACH,OAAO,eAAe,eAAe;EACvC,KAAK,WACH,OAAO;EACT,SACE,OAAO,eAAe,eAAe;CACzC;AACF;AAEA,SAAS,uBAAuB,SAA6C;CAC3E,MAAM,UAAiC,CAAC;CAExC,KAAK,MAAM,SAAS,QAAQ,SAC1B,IAAI,MAAM,SAAS,QACjB,QAAQ,KAAK;EAAE,MAAM;EAAQ,MAAM,MAAM;CAAK,CAAC;MAE5C,IAAI,MAAM,SAAS,YAAY;EAClC,MAAM,MAA0D;GAC9D,MAAM;GACN,MAAM,MAAM;EACd;EACA,IAAI,OAAO,MAAM,sBAAsB,UAAU;GAC/C,IAAI,YAAY,MAAM;GACtB,IAAI,oBAAoB;EAC1B;EACA,QAAQ,KAAK,GAAG;CAClB,OACK,IAAI,MAAM,SAAS,YACtB,QAAQ,KAAK;EAAE,MAAM;EAAa,IAAI,MAAM;EAAI,MAAM,MAAM;EAAM,OAAO,MAAM;CAAU,CAAC;CAI9F,OAAO;EAAE,MAAM;EAAa;CAAQ;AACtC;AAEA,SAAS,iBAAiB,SAA6B;CACrD,OAAO,QAAQ,QACZ,QAAO,UAAS,MAAM,SAAS,UAAU,CAAC,CAC1C,KAAI,WAAU;EACb,IAAI,MAAM;EACV,MAAM,MAAM;EACZ,OAAO,MAAM;CACf,EAAE;AACN;AAEA,SAAS,YAAY,SAAqC;CACxD,OAAO,QAAQ,QACZ,QAAQ,UAAqF,MAAM,SAAS,MAAM,CAAC,CACnH,KAAI,UAAS,MAAM,IAAI,CAAC,CACxB,KAAK,EAAE;AACZ;AAEA,SAAS,YAAY,OAAgB,cAA4C,SAAiB,SAA4C;CAC5I,OAAO,kBAAkB;EACvB,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,WAAW,MAAM,aAAa,KAAA;EAC9B,eAAe,MAAM,cAAc,KAAA;EACnC,MAAM,MAAM,KAAK,SAAS,KAAA;EAC1B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;EACvC;CACF,GAAG,UAAU,KAAA,GAAW,OAAO;AACjC;;;;;;;;;;;;AAaA,MAAM,8BAA8B;;AAGpC,SAAS,sBAAsB,KAAsB;CACnD,MAAM,SAAU,IAA6B;CAC7C,IAAI,OAAO,WAAW,UACpB,OAAO;CACT,OAAO,sBAAsB,MAAM;AACrC;;;;;;;;;;;AAYA,SAAgB,oBAAoB,KAAsC;CACxE,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,YAAY,cACd,OAAO;CACT,IAAI,YAAY,WACd,OAAO,EAAE,MAAM,UAAU;CAE3B,MAAM,SAAS;CAEf,MAAM,UAAU,OAAO,WAAW;CAClC,MAAM,OAAO,OAAO,QAAQ,OAAO;CAEnC,IAAI,SAAS,6BAA6B,uBAAuB,OAAO,GACtE,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB;CACF;CAGF,IAAI,wBAAwB,OAAO,GACjC,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB;CACF;CAIF,IAAI,QAAQ,SAAS,GAAG;EACtB,MAAM,YAAY,sBAAsB,MAAM,KAAK,4BAA4B,KAAK,OAAO;EAC3F,MAAM,SAAU,OAAgC;EAChD,MAAM,SAAS,oBAAoB;GAAE,QAAQ,OAAO,WAAW,WAAW,SAAS,KAAA;GAAW;GAAM;EAAQ,CAAC;EAC7G,IAAI,QAAQ;GAEV,MAAM,eAAe,iBAAiB,OAAO;GAC7C,OAAO,sBACL;IAAE;IAAQ,UAAU,UAAU,KAAK,OAAO,IAAI,YAAY;IAAU,GAAI,iBAAiB,KAAA,IAAY,EAAE,aAAa,IAAI,CAAC;GAAG,GAC5H;IAAE,cAAc;IAAM;GAAU,CAClC;EACF;EACA,OAAO;GACL,MAAM;GACN,cAAc;GACd;GACA,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;EACzC;CACF;CAEA,OAAO;AACT;;;;;;;AAQA,SAAS,oCAAoC,KAAuB;CAClE,IAAI,EAAE,eAAe,QACnB,OAAO;CACT,OAAO,oBAAoB,KAAK,IAAI,OAAO,KAAK,SAAS,KAAK,IAAI,OAAO;AAC3E;;;;;;;;AASA,SAAS,sBAAsB,QAAsC;CACnE,MAAM,aAAa,CAAC,QAAQ,QAAQ,QAAQ,IAAI,cAAc;CAC9D,KAAK,MAAM,OAAO,YAChB,IAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,KAAK,KAAK,CAAC,IAAI,WAAW,SAAS,GAC/E,OAAO;CAEX,OAAO;AACT;;;;;;;AAQA,SAAS,iBAAiB,UAAuC;CAC/D,OAAO,kBAAkB,QAAQ,CAAC,CAAC,KAAK,QAAQ;EAC9C,MAAM,OAAO,IAAI,QACd,KAAI,MAAM,EAAE,SAAS,SAAS,EAAE,OAAO,EAAG,CAAC,CAC3C,OAAO,OAAO,CAAC,CACf,KAAK,IAAI;EACZ,MAAM,OAAO,IAAI,SAAS,cAAc,gBAAgB;EACxD,OAAO;GAAE,MAAM,IAAI,SAAS,cAAc,cAAc;GAAQ,SAAS,CAAC;IAAE,MAAM;IAAM;GAAK,CAAC;EAAE;CAClG,CAAC;AACH;;AAGA,SAAS,iBAAiB,OAA6B;CACrD,OAAO,MAAM,KAAK,MAAM;EACtB,MAAM,OAAO;EACb,OAAO;GACL,MAAM;GACN,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,YAAY,KAAK;EACnB;CACF,CAAC;AACH;AAEA,SAAS,sBAAsB,SAAkB,SAAwB,kBAA2C,SAAQ,MAAe;CACzI,MAAM,OAAO;CAEb,IAAI,QAAQ,YAAY;EACtB,IAAI,QAAQ,WAAW,SAAS,UAAU,QAAQ,WAAW,MAC3D,KAAK,cAAc;GAAE,MAAM;GAAY,MAAM,eAAe,QAAQ,WAAW,IAAI;EAAE;OAClF,IAAI,QAAQ,WAAW,SAAS,YACnC,KAAK,cAAc;OAEnB,KAAK,cAAc;CACvB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,OAAO,QAAiC;CACtD,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,kBAAkB,0BAA0B,MAAM;CACxD,IAAI,qBAAqB,kBACrB;EAAE,GAAG;EAAiB,GAAI,QAAQ,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;CAAG,IACpF,KAAA;CAEJ,OAAO;EACL,MAAM;EACN,MAAM;GACJ;GACA,SAAS;GACT,cAAc;IACZ,QAAQ;IACR,mBAAmB;IAEnB,OAAO;IACP,OAAO;GACT;EACF;EACA;EACA;EACA;EACA;EACA,eAAe;EAIf,WAAW,gBAAgB;GACzB,kBAAkB,sBAAsB;IAAC,QAAQ;IAAQ,QAAQ,IAAI;IAAgB,QAAQ,IAAI;GAAoB,CAAC;GACtH,GAAI,QAAQ,eAAe,EAAE,SAAS,OAAO,aAAa,IAAI,CAAC;EACjE,CAAC;EAED,QAAQ,aAAa;GACnB,kBAAkB,sBAAsB;IAAC,QAAQ;IAAQ,QAAQ,IAAI;IAAgB,QAAQ,IAAI;GAAoB,CAAC;GACtH,GAAI,QAAQ,eAAe,EAAE,SAAS,OAAO,aAAa,IAAI,CAAC;EACjE,CAAC;EAED,MAAM,YAAY,SAAS,QAAgC;GAOzD,MAAM,cAAc,sBAAsB,MAAM;GAChD,IAAI,CAAC,aACH,OAAO;GACT,IAAI;IACF,MAAM,QAAQ,QAAQ;IACtB,MAAM,eAAe,uBAAuB,QAAQ,UAAU,MAAM,KAAI,SAAQ,KAAK,IAAI,CAAC;IAC1F,MAAM,MAAM,MAAM,MAAM,oDAAoD;KAC1E,QAAQ;KACR,SAAS;MACP,GAAG,QAAQ;MACX,iBAAiB,UAAU;MAC3B,gBAAgB;KAClB;KAIA,MAAM,KAAK,UAAU;MACnB,OAAO,QAAQ,SAAS;MACxB,cAAc,oBAAoB,QAAQ,MAAM;MAChD,OAAO,iBAAiB,aAAa,QAAQ;MAC7C,OAAO,iBAAiB,MAAM,KAAI,UAAS;OAAE,GAAG;OAAM,MAAM,aAAa,OAAO,KAAK,IAAI;MAAE,EAAE,CAAC;KAChG,CAAC;KACD,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,IAAI,IACP,OAAO;IACT,MAAM,OAAQ,MAAM,IAAI,KAAK;IAC7B,OAAO,OAAO,KAAK,iBAAiB,WAAW,KAAK,eAAe;GACrE,QACM;IACJ,OAAO;GACT;EACF;EAEA,MAAM,OAAO,SAAwB,WAAiD;GACpF,MAAM,UAAU,QAAQ,SAAS;GACjC,MAAM,SAAS,MAAM,mBACnB;IACE,UAAU;IACV,YAAY;IACZ,QAAQ,qBAAqB;KAAE,GAAG;KAAQ,GAAG;IAAmB,IAAI;IACpE,QAAQ;IACR,qBAAqB,CAAC,WAAW;IACjC,cAAc;IACd,eAAc,WAAU,iFAAiF;GAC3G,GACA;IACE,GAAG;IACH,MAAM,eAAe,KAAK;KACxB,IAAI,IAAI,WAAW,UACjB,qBAAqB;MACnB,QAAQ,IAAI,YAAY;MACxB,SAAS,IAAI,YAAY;MACzB,SAAS,IAAI,YAAY;MACzB,GAAI,OAAO,IAAI,YAAY,cAAc,WAAW,EAAE,WAAW,IAAI,YAAY,UAAU,IAAI,CAAC;KAClG;KAEF,MAAM,UAAU,iBAAiB,GAAG;IACtC;GACF,CACF;GASA,MAAM,iBAAiB,OAAO,WAAW,KAAK;GAC9C,MAAM,QAAQ,aAAa,SAAS,iBAAiB,uBAAuB,aAAa,QAAQ,YAAY;GAC7G,MAAM,QAAQ,QAAQ;GACtB,MAAM,eAAe,uBAAuB,QAAQ,UAAU,MAAM,KAAI,SAAQ,KAAK,IAAI,CAAC;GAS1F,MAAM,aAAwB;IAC5B,cAAc,oBAAoB,QAAQ,MAAM;IAChD,UAAU,aAAa,aAAa,UAAU,OAAO;IACrD,OAAO,MAAM,KAAI,UAAS;KAAE,GAAG;KAAM,MAAM,aAAa,OAAO,KAAK,IAAI;IAAE,EAAE;GAC9E;GACA,MAAM,UAAU,iBAAiB,UAAU;GAK3C,MAAM,oBAAoB,QAAQ,WAAW,SAAS;GACtD,MAAM,iBACF,QAAQ,YAAY,QAAQ,aAAa,SAAS,QAAQ,aAAa,aACrE,QAAQ,aAAa,SAAS,CAAC,oBAAoB,UAAU,QAAQ,WACrE,KAAA;GAIN,MAAM,cAAc,qBAAyC;IAC3D,MAAM,gBAAgB;KACpB;KACA,GAAI,QAAQ,cAAc,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;KAC1E,QAAQ,QAAQ;KAChB,iBAAiB;KACjB;KACA,GAAI,QAAQ,cAAc,OAAO,EAAE,aAAa,WAAoB,IAAI,CAAC;KAGzE,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;KAC5D,GAAI,QAAQ,eAAe,EAAE,SAAS,OAAO,aAAa,IAAI,CAAC;KAG/D,YAAY,YAAqB,sBAAsB,SAAoC,SAAS,aAAa,MAAM;IACzH;IACA,OAAO,iBACHC,OAAsB,OAAmC,SAAS,aAAa,IAC/EC,SAA2B,OAAO,SAAS;KAAE,GAAG;KAAe,WAAW,QAAQ;IAAU,CAAC;GACnG;GACA,IAAIC,WAAS,WAAW,iBAAiB,SAAS,KAAA,CAAS;GAE3D,IAAI;GACJ,IAAI,OAAO;GACX,IAAI,WAAW;GAEf,MAAM,UAAU,OAAO,MAAqC;IAC1D,WAAW,MAAM,SAAS,GACxB,IAAI,MAAM,SAAS,cAAc;KAC/B,QAAQ,MAAM;KACd,UAAU,OAAO,MAAM,KAAK;IAC9B,OACK,IAAI,MAAM,SAAS,kBAAkB;KACxC,YAAY,MAAM;KAClB,UAAU,aAAa,MAAM,KAAK;IACpC,OACK,IAAI,MAAM,SAAS,gBAAgB;KACtC,MAAM,QAAQ,MAAM,QAAQ,WAAW,QAAQ,IAC3C,MAAM,QAAQ,MAAM,SAAS,MAAM,IAClC,WAAW,KAAK,MAAM;KAC3B,IAAI,OAAO;MACT,YAAY;MACZ,UAAU,aAAa,KAAK;KAC9B;IACF,OACK,IAAI,MAAM,SAAS,oBAAoB,MAAM,SAAS,kBAEzD,UAAU,kBAAkB;SAEzB,IAAI,MAAM,SAAS,QACtB,eAAe,MAAM;SAElB,IAAI,MAAM,SAAS,SACtB,MAAM,IAAI,MAAM,MAAM,MAAM,iBAAiB,iBAAiB,qBAAqB,yBAAyB;GAGlH;GAEA,IAAI;IACF,MAAM,QAAQA,QAAM;GACtB,SACO,KAAK;IAMV,MAAM,kBAAkB,KAAK,WAAW,KAAK,SAAS,WAAW,KAAK,iBAAiB,KAAA;IACvF,IAAI,kBAAkB,kBAAkB,mBAAmB,oCAAoC,GAAG,GAAG;KACnG,WAAS,WAAW,KAAA,CAAS;KAC7B,MAAM,QAAQA,QAAM;IACtB,OAEE,MAAM;GAEV;GAEA,iBAAiB,MAAMA,SAAO,OAAO;GACrC,SAAS,YAAY,YAAY;GAEjC,MAAM,YAAY,iBAAiB,YAAY,CAAC,CAC7C,KAAI,UAAS;IAAE,GAAG;IAAM,MAAM,aAAa,SAAS,KAAK,IAAI;GAAE,EAAE;GACpE,MAAM,gBAAgB,uBAAuB,YAAY;GACzD,cAAc,UAAU,cAAc,QAAQ,KAAI,UAChD,MAAM,SAAS,cAAc;IAAE,GAAG;IAAO,MAAM,aAAa,SAAS,MAAM,IAAI;GAAE,IAAI,KACvF;GACA,MAAM,eAAe,mBAAmB,aAAa,YAAY,UAAU,SAAS,CAAC;GAIrF,MAAM,QAAQ,MAAM,YAAY,aAAa,OAAO,cAAc,SAAS,sBACzE,QAAQ,cACR,CAAC,iBAAiB,uBAAuB,aAAa,oBAAoB,CAC5E,CAAC;GAED,OAAO;IACL,kBAAkB;IAClB;IACA;IACA,MAAM,UAAU,WAAW;IAC3B;GACF;EACF;CACF;AACF"}
|
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
import { f as openaiCompat } from "./openai-compat-5HkREis_.js";
|
|
2
2
|
import { n as DecisionHttpError, o as DecisionUnsupportedError, r as DecisionInvalidResponseError } from "./errors-nt7rnQ71.js";
|
|
3
3
|
import { i as scoreLevelLabel, n as isPromptParts, r as scoreLevelDescription } from "./wire-BsjqYnxu.js";
|
|
4
|
+
import { o as repeatRequest, r as imageCount } from "./wire-DH77Z-rr.js";
|
|
5
|
+
import { getBuiltinImageModels } from "@earendil-works/pi-ai/providers/all";
|
|
6
|
+
//#region src/providers/images/openrouter.ts
|
|
7
|
+
/** Image model used when a request names none. */
|
|
8
|
+
const OPENROUTER_DEFAULT_IMAGE_MODEL = "google/gemini-3.1-flash-image";
|
|
9
|
+
function catalog() {
|
|
10
|
+
try {
|
|
11
|
+
return getBuiltinImageModels("openrouter");
|
|
12
|
+
} catch {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** OpenRouter's image models, from pi-ai's bundled catalog. */
|
|
17
|
+
function openrouterImageModels() {
|
|
18
|
+
return catalog().map((model) => ({
|
|
19
|
+
id: model.id,
|
|
20
|
+
name: model.name,
|
|
21
|
+
input: model.input.includes("image") ? ["text", "image"] : ["text"]
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* OpenRouter image generation as a {@link ProviderImages}. Always available:
|
|
26
|
+
* the key is checked by the server, not locally.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Key, headers and test overrides.
|
|
29
|
+
* @param options.apiKey - OpenRouter API key.
|
|
30
|
+
* @param options.headers - Request headers, such as attribution headers.
|
|
31
|
+
* @param options.fetch - Fetch override, for tests.
|
|
32
|
+
*/
|
|
33
|
+
function openrouterImages(options) {
|
|
34
|
+
const models = openrouterImageModels();
|
|
35
|
+
return {
|
|
36
|
+
defaultModel: OPENROUTER_DEFAULT_IMAGE_MODEL,
|
|
37
|
+
models,
|
|
38
|
+
availability: () => ({ available: true }),
|
|
39
|
+
async generate(request, signal) {
|
|
40
|
+
const model = catalog().find((m) => m.id === request.model);
|
|
41
|
+
if (!model) throw new Error(`OpenRouter has no image model "${request.model}".`);
|
|
42
|
+
const { generateImages } = await import("@earendil-works/pi-ai/api/openrouter-images");
|
|
43
|
+
const once = async () => {
|
|
44
|
+
let costUsd;
|
|
45
|
+
const doFetch = options.fetch ?? fetch;
|
|
46
|
+
const result = await generateImages(model, { input: [{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: request.prompt
|
|
49
|
+
}, ...(request.references ?? []).map((ref) => ({
|
|
50
|
+
type: "image",
|
|
51
|
+
mimeType: ref.mediaType,
|
|
52
|
+
data: ref.data
|
|
53
|
+
}))] }, {
|
|
54
|
+
apiKey: options.apiKey,
|
|
55
|
+
signal,
|
|
56
|
+
maxRetries: 2,
|
|
57
|
+
...options.headers ? { headers: options.headers } : {},
|
|
58
|
+
onPayload: (payload) => request.aspectRatio ? {
|
|
59
|
+
...payload,
|
|
60
|
+
image_config: { aspect_ratio: request.aspectRatio }
|
|
61
|
+
} : void 0,
|
|
62
|
+
fetch: (async (input, init) => {
|
|
63
|
+
const res = await doFetch(input, init);
|
|
64
|
+
if (res.ok) {
|
|
65
|
+
const body = await res.clone().json().catch(() => void 0);
|
|
66
|
+
if (typeof body?.usage?.cost === "number") costUsd = body.usage.cost;
|
|
67
|
+
}
|
|
68
|
+
return res;
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
if (result.stopReason !== "stop") throw new Error(`OpenRouter image request failed: ${result.errorMessage ?? result.stopReason}`);
|
|
72
|
+
const images = result.output.flatMap((part) => part.type === "image" ? [{
|
|
73
|
+
mediaType: part.mimeType,
|
|
74
|
+
data: part.data
|
|
75
|
+
}] : []);
|
|
76
|
+
const text = result.output.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n").trim();
|
|
77
|
+
if (images.length === 0) throw new Error(`OpenRouter returned no image${text ? `: ${text}` : "."}`);
|
|
78
|
+
return {
|
|
79
|
+
images,
|
|
80
|
+
model: result.model,
|
|
81
|
+
...text ? { text } : {},
|
|
82
|
+
...costUsd !== void 0 ? { costUsd } : {}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
return repeatRequest(imageCount(request.count), once);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
4
89
|
/** Decision models OpenRouter is known to serve. The first is the default. */
|
|
5
90
|
const OPENROUTER_DECISION_MODELS = ["typesafe/jev-1.13"];
|
|
6
91
|
function toState(input) {
|
|
@@ -220,6 +305,10 @@ function openrouter(params) {
|
|
|
220
305
|
apiKey,
|
|
221
306
|
headers: ATTRIBUTION_HEADERS
|
|
222
307
|
}),
|
|
308
|
+
images: openrouterImages({
|
|
309
|
+
apiKey,
|
|
310
|
+
headers: ATTRIBUTION_HEADERS
|
|
311
|
+
}),
|
|
223
312
|
async stream(options, callbacks) {
|
|
224
313
|
return await base.stream({
|
|
225
314
|
...options,
|
|
@@ -229,6 +318,6 @@ function openrouter(params) {
|
|
|
229
318
|
};
|
|
230
319
|
}
|
|
231
320
|
//#endregion
|
|
232
|
-
export { OPENROUTER_DECISION_MODELS as i, normalizeOpenRouterModelId as n, openrouter as r, OPENROUTER_DEFAULT_MODEL as t };
|
|
321
|
+
export { openrouterImageModels as a, OPENROUTER_DECISION_MODELS as i, normalizeOpenRouterModelId as n, openrouter as r, OPENROUTER_DEFAULT_MODEL as t };
|
|
233
322
|
|
|
234
|
-
//# sourceMappingURL=openrouter-
|
|
323
|
+
//# sourceMappingURL=openrouter-Dg0yaI-o.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter-Dg0yaI-o.js","names":[],"sources":["../src/providers/images/openrouter.ts","../src/providers/openrouter-decisions.ts","../src/providers/openrouter.ts"],"sourcesContent":["/**\n * OpenRouter image generation, through pi-ai's `openrouter-images` API\n * (chat completions with `modalities: ['image']`). The model list is pi-ai's\n * bundled OpenRouter image catalog. OpenRouter reports the cost of each\n * request in `usage.cost`; pi-ai prices from its catalog, which lists $0 for\n * every image model, so the adapter reads the cost from the response body.\n */\n\nimport type { ImageModel } from '@earendil-works/pi-ai'\nimport type { ImageModelInfo, ProviderImageResponse, ProviderImages } from './types'\nimport type { ImageFetch } from './wire'\nimport { getBuiltinImageModels } from '@earendil-works/pi-ai/providers/all'\nimport { imageCount, repeatRequest } from './wire'\n\n/** Image model used when a request names none. */\nexport const OPENROUTER_DEFAULT_IMAGE_MODEL = 'google/gemini-3.1-flash-image'\n\nfunction catalog(): readonly ImageModel<string>[] {\n try {\n return getBuiltinImageModels('openrouter') as readonly ImageModel<string>[]\n }\n catch {\n return []\n }\n}\n\n/** OpenRouter's image models, from pi-ai's bundled catalog. */\nexport function openrouterImageModels(): readonly ImageModelInfo[] {\n return catalog().map(model => ({\n id: model.id,\n name: model.name,\n input: model.input.includes('image') ? ['text', 'image'] : ['text'],\n }))\n}\n\n/**\n * OpenRouter image generation as a {@link ProviderImages}. Always available:\n * the key is checked by the server, not locally.\n *\n * @param options - Key, headers and test overrides.\n * @param options.apiKey - OpenRouter API key.\n * @param options.headers - Request headers, such as attribution headers.\n * @param options.fetch - Fetch override, for tests.\n */\nexport function openrouterImages(options: { apiKey: string, headers?: Record<string, string>, fetch?: ImageFetch }): ProviderImages {\n const models = openrouterImageModels()\n return {\n defaultModel: OPENROUTER_DEFAULT_IMAGE_MODEL,\n models,\n availability: () => ({ available: true }),\n async generate(request, signal) {\n const model = catalog().find(m => m.id === request.model)\n if (!model)\n throw new Error(`OpenRouter has no image model \"${request.model}\".`)\n const { generateImages } = await import('@earendil-works/pi-ai/api/openrouter-images')\n const once = async (): Promise<ProviderImageResponse> => {\n let costUsd: number | undefined\n const doFetch = options.fetch ?? fetch\n const result = await generateImages(model, {\n input: [\n { type: 'text', text: request.prompt },\n ...(request.references ?? []).map(ref => ({ type: 'image' as const, mimeType: ref.mediaType, data: ref.data })),\n ],\n }, {\n apiKey: options.apiKey,\n signal,\n maxRetries: 2,\n ...(options.headers ? { headers: options.headers } : {}),\n onPayload: payload => request.aspectRatio\n ? { ...(payload as Record<string, unknown>), image_config: { aspect_ratio: request.aspectRatio } }\n : undefined,\n // Reads `usage.cost` off a copy of the body; pi-ai reads the original.\n fetch: (async (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {\n const res = await doFetch(input, init)\n if (res.ok) {\n const body = await res.clone().json().catch(() => undefined) as { usage?: { cost?: unknown } } | undefined\n if (typeof body?.usage?.cost === 'number')\n costUsd = body.usage.cost\n }\n return res\n }) as typeof fetch,\n })\n if (result.stopReason !== 'stop')\n throw new Error(`OpenRouter image request failed: ${result.errorMessage ?? result.stopReason}`)\n const images = result.output.flatMap(part => part.type === 'image' ? [{ mediaType: part.mimeType, data: part.data }] : [])\n const text = result.output.flatMap(part => part.type === 'text' ? [part.text] : []).join('\\n').trim()\n if (images.length === 0)\n throw new Error(`OpenRouter returned no image${text ? `: ${text}` : '.'}`)\n return { images, model: result.model, ...(text ? { text } : {}), ...(costUsd !== undefined ? { costUsd } : {}) }\n }\n return repeatRequest(imageCount(request.count), once)\n },\n }\n}\n","/**\n * OpenRouter Decisions (`POST https://openrouter.ai/api/alpha/decisions`).\n *\n * Wire shape vs canonical:\n * - `state` carries the input (string or JSON); prompt parts are text-only here.\n * - questions are keyed by name; `predicate` is `noul` with `criteria: { true, false }`,\n * choices are a `criteria` map, score levels a `criteria` array.\n * - answers come back keyed by name; probabilities are maps (score: by level index).\n */\n\nimport type { ProviderDecisionRequest, ProviderDecisionResponse, ProviderDecisions } from '.'\nimport type { DecisionAnswer, DecisionInput, DecisionQuestion } from '../decisions/types'\nimport { DecisionHttpError, DecisionInvalidResponseError, DecisionUnsupportedError } from '../decisions/errors'\nimport { isPromptParts, scoreLevelDescription, scoreLevelLabel } from '../decisions/wire'\n\n/** Endpoint of OpenRouter Decisions. */\nexport const OPENROUTER_DECISIONS_URL = 'https://openrouter.ai/api/alpha/decisions'\n/** Decision models OpenRouter is known to serve. The first is the default. */\nexport const OPENROUTER_DECISION_MODELS = ['typesafe/jev-1.13'] as const\n\nfunction toState(input: DecisionInput): unknown {\n if (!isPromptParts(input))\n return input\n const texts: string[] = []\n for (const part of input) {\n if (part.type === 'text')\n texts.push(part.text)\n else if (part.type === 'document' && part.encoding === 'text')\n texts.push(part.data)\n else\n throw new DecisionUnsupportedError(`OpenRouter decisions accept text and JSON input only (got a ${part.type} part)`)\n }\n return texts.join('\\n\\n')\n}\n\nfunction toWireQuestion(q: DecisionQuestion): Record<string, unknown> {\n switch (q.type) {\n case 'predicate':\n return { type: 'noul', instructions: q.instructions, ...(q.criteria ? { criteria: { true: q.criteria.true, false: q.criteria.false } } : {}) }\n case 'choice':\n return { type: 'choice', instructions: q.instructions, criteria: { ...q.choices } }\n case 'score':\n return {\n type: 'score',\n instructions: q.instructions,\n criteria: q.levels.map((level) => {\n const description = scoreLevelDescription(level)\n return description ? `${scoreLevelLabel(level)}: ${description}` : scoreLevelLabel(level)\n }),\n }\n }\n}\n\nfunction num(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined\n}\n\nfunction numberMap(v: unknown): Record<string, number> | undefined {\n if (!v || typeof v !== 'object' || Array.isArray(v))\n return undefined\n const out: Record<string, number> = {}\n for (const [k, p] of Object.entries(v)) {\n const n = num(p)\n if (n !== undefined)\n out[k] = n\n }\n return out\n}\n\nfunction fromWireAnswer(name: string, raw: unknown, question: DecisionQuestion | undefined): DecisionAnswer {\n if (!raw || typeof raw !== 'object')\n throw new DecisionInvalidResponseError(`answer \"${name}\" is not an object`)\n const a = raw as Record<string, unknown>\n const confidence = num(a.confidence)\n switch (a.type) {\n case 'noul':\n return { type: 'predicate', probability: num(a.noul) ?? Number.NaN }\n case 'choice': {\n const probabilities = numberMap(a.probabilities)\n return {\n type: 'choice',\n choice: String(a.choice),\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'score': {\n const map = numberMap(a.probabilities)\n const levels = question?.type === 'score' ? question.levels.length : map ? Object.keys(map).length : 0\n const probabilities = map ? Array.from({ length: levels }, (_, i) => map[String(i)] ?? 0) : undefined\n return {\n type: 'score',\n score: num(a.score) ?? Number.NaN,\n ...(probabilities ? { probabilities } : {}),\n ...(confidence !== undefined ? { confidence } : {}),\n }\n }\n case 'refusal':\n return { type: 'refusal', ...(typeof a.message === 'string' ? { message: a.message } : {}) }\n default:\n throw new DecisionInvalidResponseError(`answer \"${name}\" has unknown type \"${String(a.type)}\"`)\n }\n}\n\nasync function errorMessage(res: Response): Promise<string> {\n const text = await res.text().catch(() => '')\n try {\n const json = JSON.parse(text) as { error?: { message?: unknown } }\n if (typeof json.error?.message === 'string')\n return json.error.message\n }\n catch {}\n return text.slice(0, 500) || `HTTP ${res.status}`\n}\n\n/**\n * The native Decisions endpoint of OpenRouter as a {@link ProviderDecisions}.\n * Always available: the key is checked by the server, not locally.\n *\n * @param options - Key, headers and test overrides.\n * @param options.apiKey - OpenRouter API key, sent as a bearer token.\n * @param options.headers - Request headers, such as attribution headers.\n * @param options.url - Endpoint override, for tests.\n * @param options.fetch - Fetch override, for tests.\n */\nexport function openrouterDecisions(options: {\n apiKey: string\n headers: Record<string, string>\n url?: string\n fetch?: typeof fetch\n}): ProviderDecisions {\n const doFetch = options.fetch ?? fetch\n return {\n defaultModel: OPENROUTER_DECISION_MODELS[0],\n models: OPENROUTER_DECISION_MODELS,\n availability: () => ({ available: true }),\n async decide(request: ProviderDecisionRequest, signal: AbortSignal): Promise<ProviderDecisionResponse> {\n const body = {\n model: request.model,\n state: toState(request.input),\n questions: Object.fromEntries(Object.entries(request.questions).map(([name, q]) => [name, toWireQuestion(q)])),\n }\n const res = await doFetch(options.url ?? OPENROUTER_DECISIONS_URL, {\n method: 'POST',\n headers: { ...options.headers, 'authorization': `Bearer ${options.apiKey}`, 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal,\n })\n if (!res.ok)\n throw new DecisionHttpError(res.status, await errorMessage(res))\n let json: Record<string, unknown>\n try {\n json = await res.json() as Record<string, unknown>\n }\n catch {\n throw new DecisionInvalidResponseError('response is not JSON')\n }\n const rawAnswers = json.answers\n if (!rawAnswers || typeof rawAnswers !== 'object' || Array.isArray(rawAnswers))\n throw new DecisionInvalidResponseError('response has no answers object')\n const answers: Record<string, DecisionAnswer> = {}\n for (const [name, raw] of Object.entries(rawAnswers))\n answers[name] = fromWireAnswer(name, raw, request.questions[name])\n const usage = (json.usage ?? {}) as Record<string, unknown>\n const cost = num(usage.cost)\n return {\n answers,\n usage: { input: num(usage.input_tokens) ?? 0, output: num(usage.output_tokens) ?? 0, ...(cost !== undefined ? { cost } : {}) },\n model: typeof json.model === 'string' ? json.model : request.model,\n ...(typeof json.id === 'string' ? { id: json.id } : {}),\n }\n },\n }\n}\n","import type { Provider, ProviderCapabilities } from '.'\nimport type { PromptCacheKeyOption } from './prompt-cache-key'\nimport { openrouterImages } from './images/openrouter'\nimport { openaiCompat } from './openai-compat'\nimport { openrouterDecisions } from './openrouter-decisions'\n\nconst BASE_URL = 'https://openrouter.ai/api/v1'\n/** Model the OpenRouter provider uses when none is configured. */\nexport const OPENROUTER_DEFAULT_MODEL = 'anthropic/claude-opus-5.5'\n\n// Hyphenated slugs (`-4-6`, `-5-1`) that persisted sessions may carry, mapped to\n// the dotted slugs OpenRouter serves (`.4.6`, `.5.1`). Normalized on the wire so\n// an old persisted id keeps streaming. Keep in sync with\n// `openrouterDescriptor.modelAliases` (chat layer) which mirrors this for\n// metadata lookups — the provider layer can't import the chat descriptor\n// without a layering cycle.\nconst MODEL_ALIASES: Readonly<Record<string, string>> = {\n 'anthropic/claude-sonnet-4-6': 'anthropic/claude-sonnet-4.6',\n 'anthropic/claude-fable-5-1': 'anthropic/claude-fable-5.1',\n}\n\n/** Options for {@link openrouter}. */\nexport interface OpenRouterParams {\n /** API key. Falls back to the `OPENROUTER_API_KEY` environment variable. */\n apiKey?: string\n /**\n * Model used when a request does not set one.\n * @default 'anthropic/claude-opus-5.5'\n */\n defaultModel?: string\n /**\n * Provider capability flags. OpenRouter itself is a router — whether vision,\n * native image-in-tool-result, or document/PDF input are supported depends on\n * the downstream model. Default: `{ vision: true, imageInToolResult: false,\n * documents: true }` — matches the default `anthropic/claude-opus-5.5` model\n * (vision + PDF capable; OpenRouter forwards the OpenAI `file` content part to\n * Anthropic/OpenAI/Gemini routes).\n *\n * Override when routing to a known-text-only model (e.g. `meta-llama/llama-3-8b-instruct`),\n * setting the relevant flags to `false`.\n */\n capabilities?: ProviderCapabilities\n /**\n * PDF-parsing engine for OpenRouter's `file-parser` plugin. Applied only when\n * a request carries a forwarded PDF/`file` part. Default `'pdf-text'` (free\n * text-only extraction, safe on any downstream model). Set `'native'` to use\n * the downstream model's own file support, or `'mistral-ocr'` for\n * scanned/image PDFs. See {@link OpenAICompatParams.pdfEngine}.\n */\n pdfEngine?: 'native' | 'pdf-text' | 'mistral-ocr'\n /**\n * Prompt-cache affinity key, sent as `prompt_cache_key`. Off by default.\n *\n * OpenRouter reads this field as its sticky-routing key, so enabling it pins a\n * session's turns to the provider endpoint that already holds its cache —\n * complementing the automatic stickiness it applies after a cached request.\n * `'session'` keys on the agent's session id. See `./prompt-cache-key.ts`.\n */\n promptCacheKey?: PromptCacheKeyOption\n /**\n * Additionally send the affinity key as this HTTP header, for gateways in\n * front of OpenRouter that route on a header rather than a body field.\n */\n promptCacheKeyHeader?: string\n}\n\nfunction getApiKey(params?: OpenRouterParams): string {\n // Resolution order aligned with other providers — explicit params win, env\n // is the fallback. See cerebras.ts for the rationale.\n if (typeof params?.apiKey === 'string' && params.apiKey.length > 0)\n return params.apiKey\n\n if (process.env.OPENROUTER_API_KEY)\n return process.env.OPENROUTER_API_KEY\n\n throw new Error('No OpenRouter API key found. Pass `apiKey` or set OPENROUTER_API_KEY in your environment.')\n}\n\nconst ATTRIBUTION_HEADERS: Readonly<Record<string, string>> = {\n 'HTTP-Referer': 'https://github.com/Tahul/zidane',\n 'X-Title': 'zidane',\n}\n\n/**\n * Maps legacy OpenRouter model ids to their current slugs and returns other ids unchanged.\n *\n * @param modelId - Model id as stored or requested.\n */\nexport function normalizeOpenRouterModelId(modelId: string): string {\n return MODEL_ALIASES[modelId] ?? modelId\n}\n\n/**\n * OpenRouter provider.\n *\n * Thin wrapper around {@link openaiCompat} with OpenRouter-specific defaults\n * (base URL, default model) and required attribution headers.\n *\n * @param params - API key, default model, capabilities, PDF engine and prompt-cache key settings.\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { openrouter } from 'zidane/providers/openrouter'\n *\n * const agent = createAgent({\n * provider: openrouter({ apiKey: process.env.OPENROUTER_API_KEY }),\n * })\n * await agent.run({ prompt: 'Say hello.' })\n * ```\n */\nexport function openrouter(params?: OpenRouterParams): Provider {\n const apiKey = getApiKey(params)\n const base = openaiCompat({\n name: 'openrouter',\n label: 'OpenRouter',\n apiKey,\n baseURL: BASE_URL,\n defaultModel: normalizeOpenRouterModelId(params?.defaultModel || OPENROUTER_DEFAULT_MODEL),\n extraHeaders: ATTRIBUTION_HEADERS,\n capabilities: params?.capabilities ?? { vision: true, imageInToolResult: false, documents: true },\n // Make PDF parsing deterministic. OpenRouter routes to many models, so the\n // default must work on ANY of them: `'pdf-text'` (free, text-only\n // extraction) never 400s regardless of the downstream model's file support.\n // `'native'` would route to the model's own file handling (richer — page\n // images — for gpt-4o / Gemini / Claude) but 400s on text-only models, so\n // it's opt-in via `pdfEngine: 'native'` (or `'mistral-ocr'` for scans).\n pdfEngine: params?.pdfEngine ?? 'pdf-text',\n ...(params?.promptCacheKey !== undefined ? { promptCacheKey: params.promptCacheKey } : {}),\n ...(params?.promptCacheKeyHeader !== undefined ? { promptCacheKeyHeader: params.promptCacheKeyHeader } : {}),\n // OpenRouter honors `cache_control` markers for Anthropic + Gemini routes and\n // silently ignores them for routes that cache automatically. Safe to turn on\n // by default — the caller can still flip `behavior.cache = false` to opt out\n // without needing to re-instantiate the provider.\n cacheBreakpoints: true,\n // OpenRouter speaks the normalized `reasoning` request field and round-trips\n // structured `reasoning_details` on assistant messages. Captured into\n // `provider_reasoning` blocks and echoed back to preserve extended-reasoning\n // state across turns on the same upstream route.\n supportsReasoning: true,\n })\n\n return {\n ...base,\n decisions: openrouterDecisions({ apiKey, headers: ATTRIBUTION_HEADERS }),\n images: openrouterImages({ apiKey, headers: ATTRIBUTION_HEADERS }),\n async stream(options, callbacks) {\n return await base.stream({\n ...options,\n model: normalizeOpenRouterModelId(options.model),\n }, callbacks)\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fa as Agent, ai as HeadlessResult, ei as FormattedHeadlessResult, ii as HeadlessOutputFormat, ri as HeadlessEvent, ti as FormattedHeadlessTurnEvent } from "../index-DyQyDLX1.js";
|
|
2
2
|
//#region src/output/stream-json.d.ts
|
|
3
3
|
/** Line shape: `zidane` event envelopes or raw `provider` messages. */
|
|
4
4
|
type StreamJsonOutputFormat = HeadlessOutputFormat;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fa as Agent, Sa as Preset, nx as AgentHooks } from "../index-DyQyDLX1.js";
|
|
2
2
|
//#region src/output/terminal.d.ts
|
|
3
3
|
/** Options for {@link setupTerminalOutput}. */
|
|
4
4
|
interface TerminalOutputOptions {
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Ad as
|
|
1
|
+
import { Ad as PluginManifest, Cd as loadAgentPlugin, Dd as PluginAuthor, Ed as LoadedPlugin, Fd as parseSchemaId, Md as SUPPORTED_AGENT_PLUGINS_VERSIONS, Nd as agentPluginsSchemaId, Od as PluginComponentStatus, Pd as isSupportedAgentPluginsVersion, Sd as defaultPluginDataRoot, Td as LoadAgentPluginOptions, _d as expandPluginVars, bd as validatePluginManifest, gd as PLUGIN_MCP_FILE, hd as PLUGIN_SKILLS_DIR, jd as PluginSchemaKind, kd as PluginDiagnostic, vd as ManifestValidation, wd as AgentPluginsVersion, xd as PLUGIN_MANIFEST_FILE, yd as parsePluginManifest } from "./index-DyQyDLX1.js";
|
|
2
2
|
export { type AgentPluginsVersion, type LoadAgentPluginOptions, type LoadedPlugin, type ManifestValidation, PLUGIN_MANIFEST_FILE, PLUGIN_MCP_FILE, PLUGIN_SKILLS_DIR, type PluginAuthor, type PluginComponentStatus, type PluginDiagnostic, type PluginManifest, type PluginSchemaKind, SUPPORTED_AGENT_PLUGINS_VERSIONS, agentPluginsSchemaId, defaultPluginDataRoot, expandPluginVars, isSupportedAgentPluginsVersion, loadAgentPlugin, parsePluginManifest, parseSchemaId, validatePluginManifest };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as definePreset } from "./compose-Db9ZMbyD.js";
|
|
2
2
|
import { a as shell, n as waitTask, r as shellKill } from "./wait-task-BZiNOAcc.js";
|
|
3
|
-
import {
|
|
4
|
-
import { p as createArtifactDetectHook, t as BUILTIN_ARTIFACT_DETECTORS } from "./builtin-artifact-kinds-
|
|
3
|
+
import { c as edit, d as recordArtifact, f as createSpawnTool, n as readFile, o as multiEdit, s as listFiles, t as writeFile } from "./write-file-QYrcDdl3.js";
|
|
4
|
+
import { p as createArtifactDetectHook, t as BUILTIN_ARTIFACT_DETECTORS } from "./builtin-artifact-kinds-BmorPkgz.js";
|
|
5
5
|
//#region src/presets/artifacts.ts
|
|
6
6
|
/**
|
|
7
7
|
* Built-in artifact detection — records pull requests, branches, commits
|
|
@@ -62,4 +62,4 @@ var basic_default = definePreset({
|
|
|
62
62
|
//#endregion
|
|
63
63
|
export { basic_default as n, artifacts_default as r, basicTools as t };
|
|
64
64
|
|
|
65
|
-
//# sourceMappingURL=presets-
|
|
65
|
+
//# sourceMappingURL=presets-DXeHsd24.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets-
|
|
1
|
+
{"version":3,"file":"presets-DXeHsd24.js","names":[],"sources":["../src/presets/artifacts.ts","../src/presets/basic.ts"],"sourcesContent":["import type { AgentHooks } from '../agent'\nimport { definePreset } from '.'\nimport { createArtifactDetectHook } from '../extensions/artifact-detect'\nimport { BUILTIN_ARTIFACT_DETECTORS } from '../extensions/builtin-artifact-kinds'\nimport { recordArtifact } from '../tools/record-artifact'\n\n/**\n * Built-in artifact detection — records pull requests, branches, commits\n * a session produces — never files automatically (see `session/artifacts.ts`).\n *\n * Opt-in by composition, not baked into `basic`: SDK consumers who never\n * spread this preset see zero behavior change, while the TUI / daemon\n * hosts compose it under the profile preset so every chat session gets\n * detection. Extension-registered kinds ride the extension registry's\n * hooks instead; both paths share `createArtifactDetectHook`.\n *\n * Also contributes the `record_artifact` tool — the explicit path for\n * outputs detection can't see (background-shell PRs, deployments, issues).\n */\nconst detectHooks = BUILTIN_ARTIFACT_DETECTORS\n .map(kind => createArtifactDetectHook(kind, {\n warn: (message, fields) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/artifacts] ${message} ${JSON.stringify(fields)}\\n`)\n },\n }))\n .filter((hook): hook is NonNullable<AgentHooks['tool:transform']> => hook !== undefined)\n\n/** Preset that detects pull requests, commits and branches in tool results (files are recorded by the loop, not by detection) and adds the `record_artifact` tool for outputs detection cannot see. Detection runs as `tool:transform` hooks, including those bubbled up from subagents. */\nexport default definePreset({\n tools: { [recordArtifact.spec.name]: recordArtifact },\n hooks: {\n 'tool:transform': detectHooks,\n // Subagents are built from the parent's preset WITHOUT hooks, so their\n // tool results only reach us as the same-ref `child:tool:transform`\n // bubble. Detecting there writes into the child's own metadata bag, and\n // the child's loop lifts it into the shared session under its runId.\n 'child:tool:transform': detectHooks,\n },\n})\n","import { definePreset } from '.'\n// Leaf modules, not the '../tools' barrel: the barrel reaches this file back\n// through spawn → agent → extensions → presets, and `basicTools` reads the\n// tools at load time.\nimport { edit } from '../tools/edit'\nimport { listFiles } from '../tools/list-files'\nimport { multiEdit } from '../tools/multi-edit'\nimport { readFile } from '../tools/read-file'\nimport { shell } from '../tools/shell'\nimport { shellKill } from '../tools/shell-kill'\nimport { createSpawnTool } from '../tools/spawn'\nimport { waitTask } from '../tools/wait-task'\nimport { writeFile } from '../tools/write-file'\n\n/**\n * Core tools available in every basic preset (without spawn).\n *\n * `edit` and `multi_edit` ship in the basic set because surgical edits are the\n * default modality for production agents — `write_file` is for full overwrites.\n * `glob` and `grep` are exported but opt-in: not every agent needs codebase\n * search, and shipping them by default would force `tool:gate` work onto\n * consumers that prefer the model to use `shell` + classic Unix tools.\n */\nexport const basicTools = { shell, shellKill, waitTask, readFile, writeFile, listFiles, edit, multiEdit }\n\n/** Default preset with the shell, file, edit and `spawn` tools and a general-purpose system prompt. The `spawn` tool is created fresh on every access, so each agent gets its own subagent state. */\nexport default definePreset({\n name: 'basic',\n system: 'You are a helpful assistant with access to shell, file reading, file writing, surgical and multi-edit tools, directory listing, and sub-agent spawning. Prefer `edit` / `multi_edit` for in-place changes and `write_file` for full file overwrites. Use them to accomplish tasks in the project directory.',\n // `tools` is a getter so each access (every `{ ...basic }` spread into\n // `createAgent`) mints a FRESH spawn tool. `createSpawnTool()` carries\n // per-instance state (running children, concurrency counter, child-stats\n // accumulator); a module-level singleton instance would be shared by every\n // agent in the process, breaking concurrent rollouts.\n //\n // `persist: true` shares the parent's session with every child agent — child\n // turns land in `session.turns` tagged with their own `runId`, and the run\n // itself is recorded in `session.runs` with `parentRunId` + `depth`. That's\n // what lets a reloaded TUI session reconstruct the full subagent tree (see\n // `eventsFromTurns` in `src/chat/store.ts`). Hosts that want children in-memory\n // only can construct their own preset with `createSpawnTool()`.\n get tools() {\n return { ...basicTools, spawn: createSpawnTool({ persist: true }) }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,MAAM,cAAc,2BACjB,KAAI,SAAQ,yBAAyB,MAAM,EAC1C,OAAO,SAAS,WAAW;CACzB,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,sBAAsB,QAAQ,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;AACpF,EACF,CAAC,CAAC,CAAC,CACF,QAAQ,SAA4D,SAAS,KAAA,CAAS;;AAGzF,IAAA,oBAAe,aAAa;CAC1B,OAAO,GAAG,eAAe,KAAK,OAAO,eAAe;CACpD,OAAO;EACL,kBAAkB;EAKlB,wBAAwB;CAC1B;AACF,CAAC;;;;;;;;;;;;AChBD,MAAa,aAAa;CAAE;CAAO;CAAW;CAAU;CAAU;CAAW;CAAW;CAAM;AAAU;;AAGxG,IAAA,gBAAe,aAAa;CAC1B,MAAM;CACN,QAAQ;CAaR,IAAI,QAAQ;EACV,OAAO;GAAE,GAAG;GAAY,OAAO,gBAAgB,EAAE,SAAS,KAAK,CAAC;EAAE;CACpE;AACF,CAAC"}
|
package/dist/presets.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ca as composePresets, Sa as Preset, n as basicTools, t as _default$1, tx as AgentHookMap, wa as definePreset, xa as _default } from "./index-DyQyDLX1.js";
|
|
2
2
|
export { type AgentHookMap, Preset, _default as artifacts, _default$1 as basic, basicTools, composePresets, definePreset };
|
package/dist/presets.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as definePreset, t as composePresets } from "./compose-Db9ZMbyD.js";
|
|
2
|
-
import { n as basic_default, r as artifacts_default, t as basicTools } from "./presets-
|
|
2
|
+
import { n as basic_default, r as artifacts_default, t as basicTools } from "./presets-DXeHsd24.js";
|
|
3
3
|
export { artifacts_default as artifacts, basic_default as basic, basicTools, composePresets, definePreset };
|
|
@@ -41,6 +41,7 @@ declare const toolPrompts: {
|
|
|
41
41
|
readonly record_artifact: string;
|
|
42
42
|
readonly read_chat_turns: string;
|
|
43
43
|
readonly read_parent_session: string;
|
|
44
|
+
readonly generate_image: string;
|
|
44
45
|
readonly model_search: string;
|
|
45
46
|
readonly skills_use: string;
|
|
46
47
|
readonly skills_read: string;
|
|
@@ -115,4 +116,4 @@ declare const toolPrompts: {
|
|
|
115
116
|
type ToolPrompts = typeof toolPrompts;
|
|
116
117
|
//#endregion
|
|
117
118
|
export { toolPrompts as n, ToolPrompts as t };
|
|
118
|
-
//# sourceMappingURL=prompts-
|
|
119
|
+
//# sourceMappingURL=prompts-DmY13jvF.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts-DmY13jvF.d.ts","names":[],"sources":["../src/tools/prompts.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6Ba;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsIiB,cAAA;;;WAKL,YAAA;;;;;;;;KAmBb,qBAAqB"}
|