@tangle-network/agent-app 0.45.32 → 0.45.34
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/{DesignCanvas-RSWQCXM3.js → DesignCanvas-EODMDQMT.js} +2 -2
- package/dist/{DesignCanvasEditor-XZMGIST7.js → DesignCanvasEditor-DRRZ6ZD3.js} +4 -4
- package/dist/{InvitationsPanel-CJ7DR4F7.js → InvitationsPanel-BATXZHY4.js} +2 -2
- package/dist/{MembersPanel-BB4OD2KB.js → MembersPanel-XNLF3SA4.js} +2 -2
- package/dist/agent-session-controls-1q1XR3j8.d.ts +257 -0
- package/dist/assistant/index.d.ts +1 -1
- package/dist/assistant/index.js +11 -10
- package/dist/assistant/index.js.map +1 -1
- package/dist/chat-react/index.d.ts +1 -1
- package/dist/chat-react/index.js +1 -1
- package/dist/{chunk-YIQHOAHN.js → chunk-3UBAO3N5.js} +3 -3
- package/dist/{chunk-YIQHOAHN.js.map → chunk-3UBAO3N5.js.map} +1 -1
- package/dist/{chunk-PURHUAOR.js → chunk-556RB3XI.js} +5 -5
- package/dist/chunk-556RB3XI.js.map +1 -0
- package/dist/{chunk-HZ4WCA37.js → chunk-5MZXWPFN.js} +9 -9
- package/dist/chunk-5MZXWPFN.js.map +1 -0
- package/dist/{chunk-FNM7JYME.js → chunk-5N434BGF.js} +17 -17
- package/dist/chunk-5N434BGF.js.map +1 -0
- package/dist/{chunk-5SXS3YAB.js → chunk-7MV23XBW.js} +2 -2
- package/dist/chunk-7MV23XBW.js.map +1 -0
- package/dist/{chunk-IFYJDX3J.js → chunk-AIHKKLKY.js} +47 -46
- package/dist/chunk-AIHKKLKY.js.map +1 -0
- package/dist/{chunk-S564OFTL.js → chunk-F4XLTVQ3.js} +3 -3
- package/dist/{chunk-S564OFTL.js.map → chunk-F4XLTVQ3.js.map} +1 -1
- package/dist/{chunk-LSQR6HM6.js → chunk-IN6LNZ7O.js} +35 -34
- package/dist/chunk-IN6LNZ7O.js.map +1 -0
- package/dist/chunk-MIZMWCKW.js +904 -0
- package/dist/chunk-MIZMWCKW.js.map +1 -0
- package/dist/{chunk-QGOU3VXH.js → chunk-UXRJAUJL.js} +3 -3
- package/dist/design-canvas-react/index.js +8 -8
- package/dist/design-canvas-react/index.js.map +1 -1
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/studio-react/index.js +27 -27
- package/dist/studio-react/index.js.map +1 -1
- package/dist/teams-react/index.js +2 -2
- package/dist/teams-react/lazy.js +2 -2
- package/dist/theme/index.js +1 -1
- package/dist/theme/tailwind-preset.d.ts +5 -1
- package/dist/theme/tailwind-preset.js +11 -2
- package/dist/theme/tailwind-preset.js.map +1 -1
- package/dist/theme/tokens.css +126 -79
- package/dist/web-react/async/index.js +1 -1
- package/dist/web-react/index.d.ts +31 -91
- package/dist/web-react/index.js +13 -3
- package/dist/work-product-react/index.js +3 -3
- package/dist/work-product-react/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/agent-session-controls-BwImzYKC.d.ts +0 -129
- package/dist/chunk-5SXS3YAB.js.map +0 -1
- package/dist/chunk-FNM7JYME.js.map +0 -1
- package/dist/chunk-HZ4WCA37.js.map +0 -1
- package/dist/chunk-IFYJDX3J.js.map +0 -1
- package/dist/chunk-L7FHRORY.js +0 -763
- package/dist/chunk-L7FHRORY.js.map +0 -1
- package/dist/chunk-LSQR6HM6.js.map +0 -1
- package/dist/chunk-PURHUAOR.js.map +0 -1
- /package/dist/{DesignCanvas-RSWQCXM3.js.map → DesignCanvas-EODMDQMT.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-XZMGIST7.js.map → DesignCanvasEditor-DRRZ6ZD3.js.map} +0 -0
- /package/dist/{InvitationsPanel-CJ7DR4F7.js.map → InvitationsPanel-BATXZHY4.js.map} +0 -0
- /package/dist/{MembersPanel-BB4OD2KB.js.map → MembersPanel-XNLF3SA4.js.map} +0 -0
- /package/dist/{chunk-QGOU3VXH.js.map → chunk-UXRJAUJL.js.map} +0 -0
package/dist/chunk-L7FHRORY.js
DELETED
|
@@ -1,763 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ATTACHMENT_ACCEPT,
|
|
3
|
-
ATTACHMENT_MAX_COUNT,
|
|
4
|
-
MAX_ATTACHMENT_TOTAL_BYTES,
|
|
5
|
-
MAX_BINARY_ATTACHMENT_BYTES,
|
|
6
|
-
MAX_TEXT_ATTACHMENT_BYTES,
|
|
7
|
-
attachmentSizeErrorMessage,
|
|
8
|
-
attachmentTotalSizeErrorMessage,
|
|
9
|
-
checkAttachmentType,
|
|
10
|
-
sanitizeAttachmentFileName,
|
|
11
|
-
sniffBinary
|
|
12
|
-
} from "./chunk-CCVG2TL6.js";
|
|
13
|
-
import {
|
|
14
|
-
snapHarnessToModel,
|
|
15
|
-
snapModelToHarness
|
|
16
|
-
} from "./chunk-TH7L265V.js";
|
|
17
|
-
|
|
18
|
-
// src/web-react/provider-logo.tsx
|
|
19
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
-
var LOGOS = {
|
|
21
|
-
anthropic: { viewBox: "0 0 24 24", fill: "#D97757", paths: ["M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"] },
|
|
22
|
-
google: { viewBox: "0 0 24 24", fill: "#8E75B2", paths: ["M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81"] },
|
|
23
|
-
deepseek: { viewBox: "0 0 24 24", fill: "#4D6BFE", paths: ["M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45"] },
|
|
24
|
-
mistral: { viewBox: "0 0 24 24", fill: "#FA520F", paths: ["M17.143 3.429v3.428h-3.429v3.429h-3.428V6.857H6.857V3.43H3.43v13.714H0v3.428h10.286v-3.428H6.857v-3.429h3.429v3.429h3.429v-3.429h3.428v3.429h-3.428v3.428H24v-3.428h-3.43V3.429z"] },
|
|
25
|
-
xai: { viewBox: "0 0 24 24", fill: "#000000", paths: ["M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"] },
|
|
26
|
-
nvidia: { viewBox: "0 0 24 24", fill: "#76B900", paths: ["M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z"] },
|
|
27
|
-
meta: { viewBox: "0 0 24 24", fill: "#0467DF", paths: ["M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z"] },
|
|
28
|
-
moonshotai: { viewBox: "0 0 24 24", fill: "#16191E", paths: ["m1.053 16.91 9.538 2.55a21 20.981 0 0 0 .06 2.031l5.956 1.592a12 11.99 0 0 1-15.554-6.172m-1.02-5.79 11.352 3.035a21 20.981 0 0 0-.469 2.01l10.817 2.89a12 11.99 0 0 1-1.845 2.004L.658 15.918a12 11.99 0 0 1-.625-4.796m1.593-5.146L13.573 9.17a21 20.981 0 0 0-1.01 1.874l11.297 3.02a21 20.981 0 0 1-.67 2.362l-11.55-3.087L.125 10.26a12 11.99 0 0 1 1.499-4.285ZM6.067 1.58l11.285 3.016a21 20.981 0 0 0-1.688 1.719l7.824 2.091a21 20.981 0 0 1 .513 2.664L2.107 5.218a12 11.99 0 0 1 3.96-3.638M21.68 4.866 7.222 1.003A12 11.99 0 0 1 21.68 4.866"] },
|
|
29
|
-
openai: { viewBox: "0 0 256 260", fill: "#10A37F", paths: ["M239.184 106.203a64.72 64.72 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.72 64.72 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.67 64.67 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.77 64.77 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483m-97.56 136.338a48.4 48.4 0 0 1-31.105-11.255l1.535-.87l51.67-29.825a8.6 8.6 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601M37.158 197.93a48.35 48.35 0 0 1-5.781-32.589l1.534.921l51.722 29.826a8.34 8.34 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803M23.549 85.38a48.5 48.5 0 0 1 25.58-21.333v61.39a8.29 8.29 0 0 0 4.195 7.316l62.874 36.272l-21.845 12.636a.82.82 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405zm179.466 41.695l-63.08-36.63L161.73 77.86a.82.82 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.54 8.54 0 0 0-4.4-7.213m21.742-32.69l-1.535-.922l-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.72.72 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391zM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87l-51.67 29.825a8.6 8.6 0 0 0-4.246 7.367zm11.868-25.58L128.067 97.3l28.188 16.218v32.434l-28.086 16.218l-28.188-16.218z"] }
|
|
30
|
-
};
|
|
31
|
-
var ALIASES = {
|
|
32
|
-
moonshot: "moonshotai",
|
|
33
|
-
deepseek_ai: "deepseek",
|
|
34
|
-
"x-ai": "xai",
|
|
35
|
-
"meta-llama": "meta"
|
|
36
|
-
};
|
|
37
|
-
var MONOGRAM = {
|
|
38
|
-
cohere: { bg: "#fae8ff", fg: "#c026d3" },
|
|
39
|
-
groq: { bg: "#fce7f3", fg: "#db2777" },
|
|
40
|
-
cerebras: { bg: "#ccfbf1", fg: "#0d9488" },
|
|
41
|
-
zai: { bg: "#ede9fe", fg: "#7c3aed" },
|
|
42
|
-
"z-ai": { bg: "#ede9fe", fg: "#7c3aed" },
|
|
43
|
-
tuner: { bg: "#dbeafe", fg: "#2563eb" }
|
|
44
|
-
};
|
|
45
|
-
function ProviderLogo({ provider, size = 16 }) {
|
|
46
|
-
const key = ALIASES[provider ?? ""] ?? provider ?? "";
|
|
47
|
-
const logo = LOGOS[key];
|
|
48
|
-
if (logo) {
|
|
49
|
-
return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: logo.viewBox, role: "img", "aria-label": key, children: logo.paths.map((d, i) => /* @__PURE__ */ jsx("path", { d, fill: logo.fill }, i)) });
|
|
50
|
-
}
|
|
51
|
-
const mono = MONOGRAM[key] ?? { bg: "#f3f4f6", fg: "#6b7280" };
|
|
52
|
-
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 16 16", role: "img", "aria-label": key || "model", children: [
|
|
53
|
-
/* @__PURE__ */ jsx("rect", { width: "16", height: "16", rx: "4", fill: mono.bg }),
|
|
54
|
-
/* @__PURE__ */ jsx("text", { x: "8", y: "11.6", textAnchor: "middle", fill: mono.fg, fontSize: "9", fontWeight: "700", fontFamily: "system-ui, sans-serif", children: (key || "?").charAt(0).toUpperCase() })
|
|
55
|
-
] });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// src/web-react/controls.tsx
|
|
59
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
60
|
-
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
61
|
-
function ChevronDown({ className }) {
|
|
62
|
-
return /* @__PURE__ */ jsx2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" }) });
|
|
63
|
-
}
|
|
64
|
-
function SearchGlyph({ className }) {
|
|
65
|
-
return /* @__PURE__ */ jsxs2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
66
|
-
/* @__PURE__ */ jsx2("circle", { cx: "11", cy: "11", r: "8" }),
|
|
67
|
-
/* @__PURE__ */ jsx2("path", { d: "m21 21-4.3-4.3" })
|
|
68
|
-
] });
|
|
69
|
-
}
|
|
70
|
-
function SparkleGlyph({ className }) {
|
|
71
|
-
return /* @__PURE__ */ jsx2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1" }) });
|
|
72
|
-
}
|
|
73
|
-
function usePopover(open, setOpen) {
|
|
74
|
-
const containerRef = useRef(null);
|
|
75
|
-
const triggerRef = useRef(null);
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (!open) return;
|
|
78
|
-
function onMouseDown(e) {
|
|
79
|
-
if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
|
|
80
|
-
}
|
|
81
|
-
function onKeyDown(e) {
|
|
82
|
-
if (e.key === "Escape") {
|
|
83
|
-
setOpen(false);
|
|
84
|
-
triggerRef.current?.focus();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
document.addEventListener("mousedown", onMouseDown);
|
|
88
|
-
document.addEventListener("keydown", onKeyDown);
|
|
89
|
-
return () => {
|
|
90
|
-
document.removeEventListener("mousedown", onMouseDown);
|
|
91
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
92
|
-
};
|
|
93
|
-
}, [open, setOpen]);
|
|
94
|
-
return {
|
|
95
|
-
containerRef,
|
|
96
|
-
triggerRef,
|
|
97
|
-
triggerProps: {
|
|
98
|
-
ref: triggerRef,
|
|
99
|
-
"aria-haspopup": true,
|
|
100
|
-
"aria-expanded": open
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
var POPOVER_OPTION_FOCUS = "focus-visible:[outline-offset:-2px]";
|
|
105
|
-
function usePending() {
|
|
106
|
-
const [pending, setPending] = useState(false);
|
|
107
|
-
const inFlight = useRef(false);
|
|
108
|
-
const mounted = useRef(true);
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
mounted.current = true;
|
|
111
|
-
return () => {
|
|
112
|
-
mounted.current = false;
|
|
113
|
-
};
|
|
114
|
-
}, []);
|
|
115
|
-
const run = (action) => {
|
|
116
|
-
if (inFlight.current) return;
|
|
117
|
-
let result;
|
|
118
|
-
try {
|
|
119
|
-
result = action();
|
|
120
|
-
} catch {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
if (!(result instanceof Promise)) return;
|
|
124
|
-
inFlight.current = true;
|
|
125
|
-
setPending(true);
|
|
126
|
-
void result.finally(() => {
|
|
127
|
-
inFlight.current = false;
|
|
128
|
-
if (mounted.current) setPending(false);
|
|
129
|
-
});
|
|
130
|
-
};
|
|
131
|
-
return { pending, run };
|
|
132
|
-
}
|
|
133
|
-
function formatPrice(p) {
|
|
134
|
-
if (!p) return void 0;
|
|
135
|
-
const n = Number(p);
|
|
136
|
-
if (isNaN(n) || n === 0) return void 0;
|
|
137
|
-
const perM = n * 1e6;
|
|
138
|
-
return perM >= 1 ? `$${perM.toFixed(0)}/M` : `$${perM.toFixed(2)}/M`;
|
|
139
|
-
}
|
|
140
|
-
function formatContext(len) {
|
|
141
|
-
if (!len) return void 0;
|
|
142
|
-
if (len >= 1e6) return `${(len / 1e6).toFixed(1)}M ctx`;
|
|
143
|
-
if (len >= 1e3) return `${Math.round(len / 1e3)}K ctx`;
|
|
144
|
-
return `${len} ctx`;
|
|
145
|
-
}
|
|
146
|
-
function SectionHeader({ children }) {
|
|
147
|
-
return /* @__PURE__ */ jsx2("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children });
|
|
148
|
-
}
|
|
149
|
-
function ModelRow({
|
|
150
|
-
model,
|
|
151
|
-
selected,
|
|
152
|
-
onSelect,
|
|
153
|
-
renderProviderBadge
|
|
154
|
-
}) {
|
|
155
|
-
const price = formatPrice(model.pricing?.prompt);
|
|
156
|
-
const ctx = formatContext(model.contextLength);
|
|
157
|
-
return /* @__PURE__ */ jsxs2(
|
|
158
|
-
"button",
|
|
159
|
-
{
|
|
160
|
-
type: "button",
|
|
161
|
-
onClick: onSelect,
|
|
162
|
-
className: `flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${selected ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
|
|
163
|
-
children: [
|
|
164
|
-
renderProviderBadge ? renderProviderBadge(model.provider) : /* @__PURE__ */ jsx2(ProviderLogo, { provider: model.provider, size: 16 }),
|
|
165
|
-
/* @__PURE__ */ jsx2("span", { className: "truncate", children: model.name }),
|
|
166
|
-
!model.supportsTools && /* @__PURE__ */ jsx2("span", { className: "shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground", children: "no tools" }),
|
|
167
|
-
/* @__PURE__ */ jsxs2("span", { className: "ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground", children: [
|
|
168
|
-
ctx && /* @__PURE__ */ jsx2("span", { children: ctx }),
|
|
169
|
-
price && /* @__PURE__ */ jsx2("span", { children: price })
|
|
170
|
-
] })
|
|
171
|
-
]
|
|
172
|
-
}
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = "Recommended", priorityGroup }) {
|
|
176
|
-
const [open, setOpen] = useState(false);
|
|
177
|
-
const [query, setQuery] = useState("");
|
|
178
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
179
|
-
const inputRef = useRef(null);
|
|
180
|
-
const popoverRef = useRef(null);
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
if (open) inputRef.current?.focus();
|
|
183
|
-
}, [open]);
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
if (!open) return;
|
|
186
|
-
const el = popoverRef.current;
|
|
187
|
-
if (!el) return;
|
|
188
|
-
const overflowRight = el.getBoundingClientRect().right - (window.innerWidth - 16);
|
|
189
|
-
el.style.transform = overflowRight > 0 ? `translateX(-${Math.ceil(overflowRight)}px)` : "";
|
|
190
|
-
}, [open]);
|
|
191
|
-
const selected = models.find((m) => m.id === value);
|
|
192
|
-
const filtered = useMemo(() => {
|
|
193
|
-
const q = query.trim().toLowerCase();
|
|
194
|
-
if (!q) return null;
|
|
195
|
-
return models.filter(
|
|
196
|
-
(m) => m.id.toLowerCase().includes(q) || m.name.toLowerCase().includes(q) || (m.description?.toLowerCase() ?? "").includes(q) || m.provider.toLowerCase().includes(q)
|
|
197
|
-
);
|
|
198
|
-
}, [models, query]);
|
|
199
|
-
const sections = useMemo(() => {
|
|
200
|
-
const isPriority = priorityGroup ? (m) => priorityGroup.match(m) : () => false;
|
|
201
|
-
const priority = priorityGroup ? models.filter(isPriority) : [];
|
|
202
|
-
const recommended = models.filter((m) => m.featured && !isPriority(m));
|
|
203
|
-
const byProvider = [];
|
|
204
|
-
for (const m of models) {
|
|
205
|
-
if (m.featured || isPriority(m)) continue;
|
|
206
|
-
const last = byProvider[byProvider.length - 1];
|
|
207
|
-
if (last && last.provider === m.provider) last.items.push(m);
|
|
208
|
-
else byProvider.push({ provider: m.provider, items: [m] });
|
|
209
|
-
}
|
|
210
|
-
return { priority, recommended, byProvider };
|
|
211
|
-
}, [models, priorityGroup]);
|
|
212
|
-
const select = (id) => {
|
|
213
|
-
onChange(id);
|
|
214
|
-
setOpen(false);
|
|
215
|
-
setQuery("");
|
|
216
|
-
};
|
|
217
|
-
return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
218
|
-
/* @__PURE__ */ jsxs2(
|
|
219
|
-
"button",
|
|
220
|
-
{
|
|
221
|
-
type: "button",
|
|
222
|
-
...triggerProps,
|
|
223
|
-
onClick: () => setOpen(!open),
|
|
224
|
-
className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30",
|
|
225
|
-
children: [
|
|
226
|
-
selected ? renderProviderBadge ? renderProviderBadge(selected.provider) : /* @__PURE__ */ jsx2(ProviderLogo, { provider: selected.provider, size: 16 }) : /* @__PURE__ */ jsx2(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
227
|
-
/* @__PURE__ */ jsx2("span", { className: "max-w-[160px] truncate", children: selected?.name ?? value }),
|
|
228
|
-
/* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
229
|
-
]
|
|
230
|
-
}
|
|
231
|
-
),
|
|
232
|
-
open && /* @__PURE__ */ jsxs2("div", { ref: popoverRef, className: "absolute bottom-full left-0 z-50 mb-2 w-[420px] max-w-[calc(100vw-2rem)] overflow-hidden rounded-xl border border-border bg-card shadow-lg", children: [
|
|
233
|
-
/* @__PURE__ */ jsx2("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2", children: [
|
|
234
|
-
/* @__PURE__ */ jsx2(SearchGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
235
|
-
/* @__PURE__ */ jsx2(
|
|
236
|
-
"input",
|
|
237
|
-
{
|
|
238
|
-
ref: inputRef,
|
|
239
|
-
type: "text",
|
|
240
|
-
value: query,
|
|
241
|
-
onChange: (e) => setQuery(e.target.value),
|
|
242
|
-
placeholder: "Search models...",
|
|
243
|
-
className: "flex-1 bg-transparent text-sm placeholder:text-muted-foreground"
|
|
244
|
-
}
|
|
245
|
-
)
|
|
246
|
-
] }) }),
|
|
247
|
-
/* @__PURE__ */ jsxs2("div", { className: "max-h-[400px] overflow-y-auto p-1 pb-2", children: [
|
|
248
|
-
loading && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading models..." }),
|
|
249
|
-
!loading && filtered && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
250
|
-
filtered.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models match your search" }),
|
|
251
|
-
filtered.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
252
|
-
] }),
|
|
253
|
-
!loading && !filtered && models.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No models available" }),
|
|
254
|
-
!loading && !filtered && models.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
255
|
-
priorityGroup && sections.priority.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
256
|
-
/* @__PURE__ */ jsx2(SectionHeader, { children: priorityGroup.label }),
|
|
257
|
-
sections.priority.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
258
|
-
] }),
|
|
259
|
-
sections.recommended.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
260
|
-
/* @__PURE__ */ jsx2(SectionHeader, { children: recommendedLabel }),
|
|
261
|
-
sections.recommended.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
262
|
-
] }),
|
|
263
|
-
sections.byProvider.map((g) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
264
|
-
/* @__PURE__ */ jsx2(SectionHeader, { children: g.provider }),
|
|
265
|
-
g.items.map((m) => /* @__PURE__ */ jsx2(ModelRow, { model: m, selected: m.id === value, onSelect: () => select(m.id), renderProviderBadge }, m.id))
|
|
266
|
-
] }, g.provider))
|
|
267
|
-
] })
|
|
268
|
-
] })
|
|
269
|
-
] })
|
|
270
|
-
] });
|
|
271
|
-
}
|
|
272
|
-
var DEFAULT_EFFORT_LEVELS = [
|
|
273
|
-
{ id: "off", label: "Off" },
|
|
274
|
-
{ id: "low", label: "Quick" },
|
|
275
|
-
{ id: "medium", label: "Standard" },
|
|
276
|
-
{ id: "high", label: "Extended" }
|
|
277
|
-
];
|
|
278
|
-
function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label = "Thinking" }) {
|
|
279
|
-
const [open, setOpen] = useState(false);
|
|
280
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
281
|
-
const selected = levels.find((l) => l.id === value) ?? levels[2] ?? levels[0];
|
|
282
|
-
return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
283
|
-
/* @__PURE__ */ jsxs2(
|
|
284
|
-
"button",
|
|
285
|
-
{
|
|
286
|
-
type: "button",
|
|
287
|
-
...triggerProps,
|
|
288
|
-
onClick: () => setOpen(!open),
|
|
289
|
-
title: label ? `${label} \u2014 how hard the agent reasons before answering` : "Reasoning effort",
|
|
290
|
-
className: "inline-flex min-h-[36px] items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30",
|
|
291
|
-
children: [
|
|
292
|
-
/* @__PURE__ */ jsx2(SparkleGlyph, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
293
|
-
/* @__PURE__ */ jsxs2("span", { children: [
|
|
294
|
-
label ? /* @__PURE__ */ jsxs2("span", { className: "text-muted-foreground", children: [
|
|
295
|
-
label,
|
|
296
|
-
": "
|
|
297
|
-
] }) : null,
|
|
298
|
-
selected?.label
|
|
299
|
-
] }),
|
|
300
|
-
/* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
301
|
-
]
|
|
302
|
-
}
|
|
303
|
-
),
|
|
304
|
-
open && /* @__PURE__ */ jsx2("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 w-40 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg", children: levels.map((l) => /* @__PURE__ */ jsx2(
|
|
305
|
-
"button",
|
|
306
|
-
{
|
|
307
|
-
type: "button",
|
|
308
|
-
role: "menuitemradio",
|
|
309
|
-
"aria-checked": l.id === value,
|
|
310
|
-
onClick: () => {
|
|
311
|
-
onChange(l.id);
|
|
312
|
-
setOpen(false);
|
|
313
|
-
},
|
|
314
|
-
className: `flex min-h-[40px] w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${l.id === value ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
|
|
315
|
-
children: l.label
|
|
316
|
-
},
|
|
317
|
-
l.id
|
|
318
|
-
)) })
|
|
319
|
-
] });
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// src/web-react/use-composer-attachments.ts
|
|
323
|
-
import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
324
|
-
function newId() {
|
|
325
|
-
const cryptoObject = globalThis.crypto;
|
|
326
|
-
if (typeof cryptoObject?.randomUUID === "function") return cryptoObject.randomUUID();
|
|
327
|
-
return `att-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
328
|
-
}
|
|
329
|
-
function dedupeName(name, taken) {
|
|
330
|
-
if (!taken.has(name)) return name;
|
|
331
|
-
const dot = name.lastIndexOf(".");
|
|
332
|
-
const base = dot > 0 ? name.slice(0, dot) : name;
|
|
333
|
-
const ext = dot > 0 ? name.slice(dot) : "";
|
|
334
|
-
let n = 2;
|
|
335
|
-
let candidate = `${base}-${n}${ext}`;
|
|
336
|
-
while (taken.has(candidate)) {
|
|
337
|
-
n += 1;
|
|
338
|
-
candidate = `${base}-${n}${ext}`;
|
|
339
|
-
}
|
|
340
|
-
return candidate;
|
|
341
|
-
}
|
|
342
|
-
function kindForMime(mime) {
|
|
343
|
-
return mime.startsWith("image/") ? "image" : "file";
|
|
344
|
-
}
|
|
345
|
-
function isAcceptedFileType(file, accept) {
|
|
346
|
-
const patterns = accept.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
347
|
-
if (patterns.length === 0) return true;
|
|
348
|
-
const name = file.name.toLowerCase();
|
|
349
|
-
const type = (file.type || "").toLowerCase();
|
|
350
|
-
return patterns.some((pattern) => {
|
|
351
|
-
const lower = pattern.toLowerCase();
|
|
352
|
-
if (lower.startsWith(".")) return name.endsWith(lower);
|
|
353
|
-
if (lower.endsWith("/*")) return type.startsWith(lower.slice(0, -1));
|
|
354
|
-
return type === lower;
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
async function parseUploadError(res) {
|
|
358
|
-
const detail = await res.json().catch(() => null);
|
|
359
|
-
if (detail && typeof detail === "object" && "error" in detail) {
|
|
360
|
-
const error = detail.error;
|
|
361
|
-
if (typeof error === "string" && error) return error;
|
|
362
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
363
|
-
const message = error.message;
|
|
364
|
-
if (typeof message === "string" && message) return message;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return `Upload failed (${res.status})`;
|
|
368
|
-
}
|
|
369
|
-
var NO_UPLOAD_TARGET_MESSAGE = "No upload destination configured (pass uploadUrl or buildUploadRequest)";
|
|
370
|
-
function useComposerAttachments(options) {
|
|
371
|
-
const optionsRef = useRef2(options);
|
|
372
|
-
optionsRef.current = options;
|
|
373
|
-
const [staged, setStagedState] = useState2([]);
|
|
374
|
-
const stagedRef = useRef2([]);
|
|
375
|
-
const controllersRef = useRef2(/* @__PURE__ */ new Map());
|
|
376
|
-
const setStaged = useCallback(
|
|
377
|
-
(updater) => {
|
|
378
|
-
const next = typeof updater === "function" ? updater(stagedRef.current) : updater;
|
|
379
|
-
stagedRef.current = next;
|
|
380
|
-
setStagedState(next);
|
|
381
|
-
},
|
|
382
|
-
[]
|
|
383
|
-
);
|
|
384
|
-
const upload = useCallback(
|
|
385
|
-
async (id, file, name) => {
|
|
386
|
-
const opts = optionsRef.current;
|
|
387
|
-
setStaged(
|
|
388
|
-
(prev) => prev.map((s) => s.id === id ? { ...s, status: "uploading", errorMessage: void 0 } : s)
|
|
389
|
-
);
|
|
390
|
-
const controller = new AbortController();
|
|
391
|
-
controllersRef.current.set(id, controller);
|
|
392
|
-
const form = new FormData();
|
|
393
|
-
form.append("file", file, name);
|
|
394
|
-
const request = opts.buildUploadRequest ? opts.buildUploadRequest({ file, name, form }) : opts.uploadUrl ? { url: opts.uploadUrl } : null;
|
|
395
|
-
if (!request) {
|
|
396
|
-
setStaged(
|
|
397
|
-
(prev) => prev.map(
|
|
398
|
-
(s) => s.id === id ? { ...s, status: "error", errorMessage: NO_UPLOAD_TARGET_MESSAGE } : s
|
|
399
|
-
)
|
|
400
|
-
);
|
|
401
|
-
opts.onError?.(NO_UPLOAD_TARGET_MESSAGE);
|
|
402
|
-
controllersRef.current.delete(id);
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
try {
|
|
406
|
-
const res = await fetch(request.url, {
|
|
407
|
-
method: "POST",
|
|
408
|
-
credentials: "same-origin",
|
|
409
|
-
...request.init,
|
|
410
|
-
body: form,
|
|
411
|
-
signal: controller.signal
|
|
412
|
-
});
|
|
413
|
-
if (!res.ok) {
|
|
414
|
-
const message = await parseUploadError(res);
|
|
415
|
-
setStaged(
|
|
416
|
-
(prev) => prev.map((s) => s.id === id ? { ...s, status: "error", errorMessage: message } : s)
|
|
417
|
-
);
|
|
418
|
-
opts.onError?.(message);
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
const data = await res.json();
|
|
422
|
-
const uploaded = data.files?.[0];
|
|
423
|
-
if (!uploaded) {
|
|
424
|
-
const message = "Upload returned no file";
|
|
425
|
-
setStaged(
|
|
426
|
-
(prev) => prev.map((s) => s.id === id ? { ...s, status: "error", errorMessage: message } : s)
|
|
427
|
-
);
|
|
428
|
-
opts.onError?.(message);
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
setStaged(
|
|
432
|
-
(prev) => prev.map((s) => s.id === id ? { ...s, status: "ready", reference: uploaded } : s)
|
|
433
|
-
);
|
|
434
|
-
} catch (err) {
|
|
435
|
-
if (err.name === "AbortError") return;
|
|
436
|
-
const message = err instanceof Error && err.message ? err.message : "Upload failed \u2014 check your connection";
|
|
437
|
-
setStaged(
|
|
438
|
-
(prev) => prev.map((s) => s.id === id ? { ...s, status: "error", errorMessage: message } : s)
|
|
439
|
-
);
|
|
440
|
-
opts.onError?.(message);
|
|
441
|
-
} finally {
|
|
442
|
-
controllersRef.current.delete(id);
|
|
443
|
-
}
|
|
444
|
-
},
|
|
445
|
-
[setStaged]
|
|
446
|
-
);
|
|
447
|
-
const addFiles = useCallback(
|
|
448
|
-
async (files) => {
|
|
449
|
-
const opts = optionsRef.current;
|
|
450
|
-
const enabled2 = opts.enabled ?? true;
|
|
451
|
-
if (!enabled2) {
|
|
452
|
-
opts.onReject?.("Attachments are disabled");
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
const accept = opts.accept ?? ATTACHMENT_ACCEPT;
|
|
456
|
-
const maxCount = opts.limits?.maxCount ?? ATTACHMENT_MAX_COUNT;
|
|
457
|
-
const maxBinaryBytes = opts.limits?.maxBinaryBytes ?? MAX_BINARY_ATTACHMENT_BYTES;
|
|
458
|
-
const maxTextBytes = opts.limits?.maxTextBytes ?? MAX_TEXT_ATTACHMENT_BYTES;
|
|
459
|
-
const maxTotalBytes = opts.limits?.maxTotalBytes ?? MAX_ATTACHMENT_TOTAL_BYTES;
|
|
460
|
-
const allowedKinds = opts.allowedKinds ?? ["image", "file"];
|
|
461
|
-
const list = Array.isArray(files) ? files : Array.from(files);
|
|
462
|
-
const currentCount = stagedRef.current.length;
|
|
463
|
-
const countAccepted = [];
|
|
464
|
-
for (const file of list) {
|
|
465
|
-
if (!isAcceptedFileType(file, accept)) {
|
|
466
|
-
opts.onReject?.(`"${file.name}" is not an accepted file type (${accept}).`, file);
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
if (currentCount + countAccepted.length >= maxCount) {
|
|
470
|
-
opts.onReject?.(`"${file.name}" was not added \u2014 the ${maxCount}-file limit is already reached.`, file);
|
|
471
|
-
continue;
|
|
472
|
-
}
|
|
473
|
-
countAccepted.push(file);
|
|
474
|
-
}
|
|
475
|
-
const sizeAccepted = [];
|
|
476
|
-
for (const file of countAccepted) {
|
|
477
|
-
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
478
|
-
const sniff = sniffBinary(bytes);
|
|
479
|
-
const typeCheck = checkAttachmentType(file.name, sniff);
|
|
480
|
-
if (!typeCheck.succeeded) {
|
|
481
|
-
opts.onReject?.(typeCheck.message, file);
|
|
482
|
-
continue;
|
|
483
|
-
}
|
|
484
|
-
const limit = sniff.binary ? maxBinaryBytes : maxTextBytes;
|
|
485
|
-
if (file.size > limit) {
|
|
486
|
-
opts.onReject?.(attachmentSizeErrorMessage(file.name, file.size, limit), file);
|
|
487
|
-
continue;
|
|
488
|
-
}
|
|
489
|
-
const mediaType = sniff.mime ?? file.type ?? "";
|
|
490
|
-
const kind = kindForMime(mediaType);
|
|
491
|
-
if (!allowedKinds.includes(kind)) {
|
|
492
|
-
opts.onReject?.(`"${file.name}" is a ${kind} attachment, which isn't accepted here`, file);
|
|
493
|
-
continue;
|
|
494
|
-
}
|
|
495
|
-
sizeAccepted.push(file);
|
|
496
|
-
}
|
|
497
|
-
const accepted = [];
|
|
498
|
-
let totalBytes = stagedRef.current.reduce((total, s) => total + s.size, 0);
|
|
499
|
-
for (const file of sizeAccepted) {
|
|
500
|
-
const nextTotalBytes = totalBytes + file.size;
|
|
501
|
-
if (nextTotalBytes > maxTotalBytes) {
|
|
502
|
-
opts.onReject?.(attachmentTotalSizeErrorMessage(nextTotalBytes, maxTotalBytes), file);
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
accepted.push(file);
|
|
506
|
-
totalBytes = nextTotalBytes;
|
|
507
|
-
}
|
|
508
|
-
if (accepted.length === 0) return;
|
|
509
|
-
const taken = new Set(stagedRef.current.map((s) => s.name));
|
|
510
|
-
const entries = accepted.map((file) => {
|
|
511
|
-
const name = dedupeName(sanitizeAttachmentFileName(file.name), taken);
|
|
512
|
-
taken.add(name);
|
|
513
|
-
return {
|
|
514
|
-
id: newId(),
|
|
515
|
-
file,
|
|
516
|
-
name,
|
|
517
|
-
size: file.size,
|
|
518
|
-
status: "pending",
|
|
519
|
-
previewUrl: file.type.startsWith("image/") ? URL.createObjectURL(file) : void 0
|
|
520
|
-
};
|
|
521
|
-
});
|
|
522
|
-
setStaged((prev) => [...prev, ...entries]);
|
|
523
|
-
for (const entry of entries) void upload(entry.id, entry.file, entry.name);
|
|
524
|
-
},
|
|
525
|
-
[setStaged, upload]
|
|
526
|
-
);
|
|
527
|
-
const retry = useCallback(
|
|
528
|
-
(id) => {
|
|
529
|
-
const entry = stagedRef.current.find((s) => s.id === id);
|
|
530
|
-
if (!entry) return;
|
|
531
|
-
void upload(entry.id, entry.file, entry.name);
|
|
532
|
-
},
|
|
533
|
-
[upload]
|
|
534
|
-
);
|
|
535
|
-
const removeAttachment = useCallback(
|
|
536
|
-
(id) => {
|
|
537
|
-
controllersRef.current.get(id)?.abort();
|
|
538
|
-
controllersRef.current.delete(id);
|
|
539
|
-
const entry = stagedRef.current.find((s) => s.id === id);
|
|
540
|
-
if (entry?.previewUrl) URL.revokeObjectURL(entry.previewUrl);
|
|
541
|
-
setStaged((prev) => prev.filter((s) => s.id !== id));
|
|
542
|
-
},
|
|
543
|
-
[setStaged]
|
|
544
|
-
);
|
|
545
|
-
const clear = useCallback(() => {
|
|
546
|
-
for (const controller of controllersRef.current.values()) controller.abort();
|
|
547
|
-
controllersRef.current.clear();
|
|
548
|
-
for (const entry of stagedRef.current) {
|
|
549
|
-
if (entry.previewUrl) URL.revokeObjectURL(entry.previewUrl);
|
|
550
|
-
}
|
|
551
|
-
setStaged([]);
|
|
552
|
-
}, [setStaged]);
|
|
553
|
-
useEffect2(
|
|
554
|
-
() => () => {
|
|
555
|
-
for (const controller of controllersRef.current.values()) controller.abort();
|
|
556
|
-
controllersRef.current.clear();
|
|
557
|
-
for (const entry of stagedRef.current) {
|
|
558
|
-
if (entry.previewUrl) URL.revokeObjectURL(entry.previewUrl);
|
|
559
|
-
}
|
|
560
|
-
},
|
|
561
|
-
[]
|
|
562
|
-
);
|
|
563
|
-
const composerFiles = useMemo2(
|
|
564
|
-
() => staged.map((s) => ({
|
|
565
|
-
id: s.id,
|
|
566
|
-
name: s.name,
|
|
567
|
-
size: s.size,
|
|
568
|
-
kind: "file",
|
|
569
|
-
status: s.status
|
|
570
|
-
})),
|
|
571
|
-
[staged]
|
|
572
|
-
);
|
|
573
|
-
const references = useMemo2(
|
|
574
|
-
() => staged.filter((s) => s.status === "ready" && !!s.reference).map((s) => s.reference),
|
|
575
|
-
[staged]
|
|
576
|
-
);
|
|
577
|
-
const hasPending = useMemo2(
|
|
578
|
-
() => staged.some((s) => s.status === "pending" || s.status === "uploading"),
|
|
579
|
-
[staged]
|
|
580
|
-
);
|
|
581
|
-
const hasError = useMemo2(() => staged.some((s) => s.status === "error"), [staged]);
|
|
582
|
-
const enabled = options.enabled ?? true;
|
|
583
|
-
const blockReason = !enabled ? "Attachments are disabled" : hasPending ? "Attachments are still uploading" : hasError ? "Remove failed attachments to send" : null;
|
|
584
|
-
return {
|
|
585
|
-
composerFiles,
|
|
586
|
-
references,
|
|
587
|
-
addFiles,
|
|
588
|
-
retry,
|
|
589
|
-
removeAttachment,
|
|
590
|
-
clear,
|
|
591
|
-
hasPending,
|
|
592
|
-
hasError,
|
|
593
|
-
blockReason
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// src/web-react/agent-session-controls.tsx
|
|
598
|
-
import { useMemo as useMemo3, useState as useState3 } from "react";
|
|
599
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
600
|
-
var HARNESS_LABELS = {
|
|
601
|
-
opencode: "OpenCode (any model)",
|
|
602
|
-
"claude-code": "Claude Code (Anthropic)",
|
|
603
|
-
codex: "Codex (OpenAI)",
|
|
604
|
-
"kimi-code": "Kimi (Moonshot)",
|
|
605
|
-
amp: "Amp",
|
|
606
|
-
"factory-droids": "Factory Droids",
|
|
607
|
-
cursor: "Cursor",
|
|
608
|
-
hermes: "Hermes",
|
|
609
|
-
forge: "Forge",
|
|
610
|
-
pi: "Pi",
|
|
611
|
-
openclaw: "OpenClaw",
|
|
612
|
-
acp: "ACP",
|
|
613
|
-
"cli-base": "CLI"
|
|
614
|
-
};
|
|
615
|
-
function harnessLabel(h) {
|
|
616
|
-
return HARNESS_LABELS[h] ?? h;
|
|
617
|
-
}
|
|
618
|
-
function ChevronDown2({ className }) {
|
|
619
|
-
return /* @__PURE__ */ jsx3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" }) });
|
|
620
|
-
}
|
|
621
|
-
function GearGlyph({ className }) {
|
|
622
|
-
return /* @__PURE__ */ jsxs3("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
623
|
-
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "3" }),
|
|
624
|
-
/* @__PURE__ */ jsx3("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
625
|
-
] });
|
|
626
|
-
}
|
|
627
|
-
var FOCUS_RING = "";
|
|
628
|
-
function HarnessPicker({
|
|
629
|
-
value,
|
|
630
|
-
onChange,
|
|
631
|
-
available
|
|
632
|
-
}) {
|
|
633
|
-
const [open, setOpen] = useState3(false);
|
|
634
|
-
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
635
|
-
const options = available ?? Object.keys(HARNESS_LABELS);
|
|
636
|
-
return /* @__PURE__ */ jsxs3("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
637
|
-
/* @__PURE__ */ jsxs3(
|
|
638
|
-
"button",
|
|
639
|
-
{
|
|
640
|
-
type: "button",
|
|
641
|
-
...triggerProps,
|
|
642
|
-
onClick: () => setOpen(!open),
|
|
643
|
-
title: "Agent backend",
|
|
644
|
-
className: `inline-flex w-full items-center justify-between gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30 ${FOCUS_RING}`,
|
|
645
|
-
children: [
|
|
646
|
-
/* @__PURE__ */ jsx3("span", { className: "truncate", children: harnessLabel(value) }),
|
|
647
|
-
/* @__PURE__ */ jsx3(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
648
|
-
]
|
|
649
|
-
}
|
|
650
|
-
),
|
|
651
|
-
open && /* @__PURE__ */ jsx3("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 max-h-64 w-full min-w-[220px] overflow-y-auto rounded-xl border border-border bg-card p-1 shadow-lg", children: options.map((h) => /* @__PURE__ */ jsx3(
|
|
652
|
-
"button",
|
|
653
|
-
{
|
|
654
|
-
type: "button",
|
|
655
|
-
role: "menuitemradio",
|
|
656
|
-
"aria-checked": h === value,
|
|
657
|
-
onClick: () => {
|
|
658
|
-
onChange(h);
|
|
659
|
-
setOpen(false);
|
|
660
|
-
},
|
|
661
|
-
className: `flex w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${FOCUS_RING} ${h === value ? "bg-primary/10 font-medium" : "hover:bg-accent/30"}`,
|
|
662
|
-
children: harnessLabel(h)
|
|
663
|
-
},
|
|
664
|
-
h
|
|
665
|
-
)) })
|
|
666
|
-
] });
|
|
667
|
-
}
|
|
668
|
-
function useCoherentHandlers(props) {
|
|
669
|
-
const { model, models, harness, onModelChange, onHarnessChange } = props;
|
|
670
|
-
const canonicalIds = useMemo3(() => models.map((m) => m.id), [models]);
|
|
671
|
-
const onModel = (next) => {
|
|
672
|
-
onModelChange(next);
|
|
673
|
-
const nextHarness = snapHarnessToModel(harness, next);
|
|
674
|
-
if (nextHarness !== harness) onHarnessChange(nextHarness);
|
|
675
|
-
};
|
|
676
|
-
const onHarness = (next) => {
|
|
677
|
-
onHarnessChange(next);
|
|
678
|
-
const snapped = snapModelToHarness(next, model, canonicalIds);
|
|
679
|
-
if (snapped !== model) onModelChange(snapped);
|
|
680
|
-
};
|
|
681
|
-
return { onModel, onHarness };
|
|
682
|
-
}
|
|
683
|
-
function AgentSessionControls(props) {
|
|
684
|
-
const {
|
|
685
|
-
models,
|
|
686
|
-
modelsLoading,
|
|
687
|
-
model,
|
|
688
|
-
harness,
|
|
689
|
-
availableHarnesses,
|
|
690
|
-
effort,
|
|
691
|
-
onEffortChange,
|
|
692
|
-
layout = "inline",
|
|
693
|
-
showHarness = true,
|
|
694
|
-
renderProviderBadge,
|
|
695
|
-
className
|
|
696
|
-
} = props;
|
|
697
|
-
const { onModel, onHarness } = useCoherentHandlers(props);
|
|
698
|
-
const [open, setOpen] = useState3(false);
|
|
699
|
-
const { containerRef: popoverRef, triggerProps } = usePopover(open, setOpen);
|
|
700
|
-
const selectedModel = models.find((m) => m.id === model);
|
|
701
|
-
const showEffort = selectedModel?.supportsReasoning ?? true;
|
|
702
|
-
const modelPicker = /* @__PURE__ */ jsx3(
|
|
703
|
-
ModelPicker,
|
|
704
|
-
{
|
|
705
|
-
value: model,
|
|
706
|
-
onChange: onModel,
|
|
707
|
-
models,
|
|
708
|
-
loading: modelsLoading,
|
|
709
|
-
renderProviderBadge
|
|
710
|
-
}
|
|
711
|
-
);
|
|
712
|
-
if (layout === "inline") {
|
|
713
|
-
return /* @__PURE__ */ jsxs3("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
714
|
-
modelPicker,
|
|
715
|
-
showHarness && /* @__PURE__ */ jsx3(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
716
|
-
showEffort && /* @__PURE__ */ jsx3(EffortPicker, { value: effort, onChange: onEffortChange })
|
|
717
|
-
] });
|
|
718
|
-
}
|
|
719
|
-
const hasAdvanced = showHarness || showEffort;
|
|
720
|
-
return /* @__PURE__ */ jsxs3("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
721
|
-
modelPicker,
|
|
722
|
-
hasAdvanced && /* @__PURE__ */ jsxs3("div", { ref: popoverRef, className: "relative inline-flex", children: [
|
|
723
|
-
/* @__PURE__ */ jsx3(
|
|
724
|
-
"button",
|
|
725
|
-
{
|
|
726
|
-
type: "button",
|
|
727
|
-
...triggerProps,
|
|
728
|
-
onClick: () => setOpen(!open),
|
|
729
|
-
title: "Model settings \u2014 pick the agent backend and how hard it thinks",
|
|
730
|
-
className: `flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[state=open]:bg-muted ${FOCUS_RING}`,
|
|
731
|
-
"data-state": open ? "open" : "closed",
|
|
732
|
-
children: /* @__PURE__ */ jsx3(GearGlyph, { className: "h-4 w-4" })
|
|
733
|
-
}
|
|
734
|
-
),
|
|
735
|
-
open && /* @__PURE__ */ jsxs3("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-72 space-y-3 rounded-xl border border-border bg-card p-3 shadow-lg", children: [
|
|
736
|
-
showHarness && /* @__PURE__ */ jsxs3("div", { className: "space-y-1.5", children: [
|
|
737
|
-
/* @__PURE__ */ jsx3("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
|
|
738
|
-
/* @__PURE__ */ jsx3(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
739
|
-
/* @__PURE__ */ jsx3("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
|
|
740
|
-
] }),
|
|
741
|
-
showEffort && /* @__PURE__ */ jsxs3("div", { className: "space-y-1.5", children: [
|
|
742
|
-
/* @__PURE__ */ jsx3("p", { className: "text-xs font-medium text-foreground", children: "Thinking" }),
|
|
743
|
-
/* @__PURE__ */ jsx3(EffortPicker, { value: effort, onChange: onEffortChange, label: "" }),
|
|
744
|
-
/* @__PURE__ */ jsx3("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
|
|
745
|
-
] })
|
|
746
|
-
] })
|
|
747
|
-
] })
|
|
748
|
-
] });
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
export {
|
|
752
|
-
ProviderLogo,
|
|
753
|
-
ChevronDown,
|
|
754
|
-
usePopover,
|
|
755
|
-
POPOVER_OPTION_FOCUS,
|
|
756
|
-
usePending,
|
|
757
|
-
ModelPicker,
|
|
758
|
-
DEFAULT_EFFORT_LEVELS,
|
|
759
|
-
EffortPicker,
|
|
760
|
-
useComposerAttachments,
|
|
761
|
-
AgentSessionControls
|
|
762
|
-
};
|
|
763
|
-
//# sourceMappingURL=chunk-L7FHRORY.js.map
|