@spotpatch/runtime 1.14.0 → 1.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2WA6XVA4.js → chunk-DCN6OMLH.js} +13 -3
- package/dist/{chunk-2WA6XVA4.js.map → chunk-DCN6OMLH.js.map} +1 -1
- package/dist/{chunk-KIDHJQRG.js → chunk-PXJKFEUJ.js} +1 -1
- package/dist/chunk-PXJKFEUJ.js.map +1 -0
- package/dist/contextual-ask-panel.cjs +217 -127
- package/dist/contextual-ask-panel.cjs.map +1 -1
- package/dist/contextual-ask-panel.d.cts +2 -0
- package/dist/contextual-ask-panel.d.ts +2 -0
- package/dist/contextual-ask-panel.js +219 -128
- package/dist/contextual-ask-panel.js.map +1 -1
- package/dist/data-flow-panel.cjs +12 -2
- package/dist/data-flow-panel.cjs.map +1 -1
- package/dist/data-flow-panel.d.cts +1 -1
- package/dist/data-flow-panel.d.ts +1 -1
- package/dist/data-flow-panel.js +7 -1
- package/dist/data-flow-panel.js.map +1 -1
- package/dist/{data-flow-runtime-DMmV0d3E.d.cts → data-flow-runtime-CacBbxN0.d.cts} +2 -1
- package/dist/{data-flow-runtime-DMmV0d3E.d.ts → data-flow-runtime-CacBbxN0.d.ts} +2 -1
- package/dist/data-flow.cjs +13 -2
- package/dist/data-flow.cjs.map +1 -1
- package/dist/data-flow.d.cts +1 -1
- package/dist/data-flow.d.ts +1 -1
- package/dist/data-flow.js +3 -1
- package/dist/external-handoff-panel.cjs +22 -6
- package/dist/external-handoff-panel.cjs.map +1 -1
- package/dist/external-handoff-panel.d.cts +5 -2
- package/dist/external-handoff-panel.d.ts +5 -2
- package/dist/external-handoff-panel.js +21 -6
- package/dist/external-handoff-panel.js.map +1 -1
- package/dist/index.cjs +15 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +11 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-KIDHJQRG.js.map +0 -1
|
@@ -48,6 +48,7 @@ interface ContextualAskPanel {
|
|
|
48
48
|
readonly notify: (event: "copied" | "copy-failed" | "converted" | "source-open-failed") => void;
|
|
49
49
|
readonly readConsent: () => boolean;
|
|
50
50
|
readonly readExecutorId: () => string | undefined;
|
|
51
|
+
readonly readModel: () => string | undefined;
|
|
51
52
|
readonly readQuestion: () => string;
|
|
52
53
|
readonly renderAnswer: (result: AskAnswerResult, stale: boolean) => void;
|
|
53
54
|
readonly renderCapability: (capability?: ContextualAskCapability) => void;
|
|
@@ -113,6 +114,7 @@ interface ContextualAskMessages {
|
|
|
113
114
|
readonly suggestionsLabel: string;
|
|
114
115
|
readonly suggestions: readonly string[];
|
|
115
116
|
readonly executorLabel: string;
|
|
117
|
+
readonly modelLabel: string;
|
|
116
118
|
readonly loadingExecutors: string;
|
|
117
119
|
readonly noExecutor: string;
|
|
118
120
|
readonly unavailable: string;
|
|
@@ -48,6 +48,7 @@ interface ContextualAskPanel {
|
|
|
48
48
|
readonly notify: (event: "copied" | "copy-failed" | "converted" | "source-open-failed") => void;
|
|
49
49
|
readonly readConsent: () => boolean;
|
|
50
50
|
readonly readExecutorId: () => string | undefined;
|
|
51
|
+
readonly readModel: () => string | undefined;
|
|
51
52
|
readonly readQuestion: () => string;
|
|
52
53
|
readonly renderAnswer: (result: AskAnswerResult, stale: boolean) => void;
|
|
53
54
|
readonly renderCapability: (capability?: ContextualAskCapability) => void;
|
|
@@ -113,6 +114,7 @@ interface ContextualAskMessages {
|
|
|
113
114
|
readonly suggestionsLabel: string;
|
|
114
115
|
readonly suggestions: readonly string[];
|
|
115
116
|
readonly executorLabel: string;
|
|
117
|
+
readonly modelLabel: string;
|
|
116
118
|
readonly loadingExecutors: string;
|
|
117
119
|
readonly noExecutor: string;
|
|
118
120
|
readonly unavailable: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getContextualAskExtension,
|
|
3
3
|
registerContextualAskExtension
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PXJKFEUJ.js";
|
|
5
5
|
import {
|
|
6
6
|
createButton,
|
|
7
7
|
createMarkedElement
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
ASK_SOURCE_CONFIDENCES,
|
|
30
30
|
CONTEXTUAL_ASK_EXECUTOR_KINDS,
|
|
31
31
|
CONTEXTUAL_ASK_EXECUTOR_STATES,
|
|
32
|
+
CONTEXTUAL_ASK_LIMITS,
|
|
32
33
|
CONTEXTUAL_ASK_SCHEMA_VERSION,
|
|
33
34
|
isErrorCode
|
|
34
35
|
} from "@spotpatch/shared/contextual-ask-browser";
|
|
@@ -77,8 +78,10 @@ function isExecutorCapability(value) {
|
|
|
77
78
|
"providerDataConsentRequired",
|
|
78
79
|
"readOnlyProven"
|
|
79
80
|
],
|
|
80
|
-
["errorCode"]
|
|
81
|
-
) || !isOpaqueId(value.executorId) || !isEnum(value.kind, CONTEXTUAL_ASK_EXECUTOR_KINDS) || !isNonEmptyString(value.label) || !isNonEmptyString(value.requestedModelLabel) || !isNonEmptyString(value.effectiveModelLabel) ||
|
|
81
|
+
["errorCode", "models"]
|
|
82
|
+
) || !isOpaqueId(value.executorId) || !isEnum(value.kind, CONTEXTUAL_ASK_EXECUTOR_KINDS) || !isNonEmptyString(value.label) || !isNonEmptyString(value.requestedModelLabel) || !isNonEmptyString(value.effectiveModelLabel) || value.models !== void 0 && (!Array.isArray(value.models) || value.models.length === 0 || value.models.length > CONTEXTUAL_ASK_LIMITS.maximumModels || !value.models.every(
|
|
83
|
+
(model) => isNonEmptyString(model) && model.length <= CONTEXTUAL_ASK_LIMITS.maximumLabelCharacters
|
|
84
|
+
) || !unique(value.models)) || !isEnum(value.state, CONTEXTUAL_ASK_EXECUTOR_STATES) || typeof value.providerDataConsentRequired !== "boolean" || typeof value.readOnlyProven !== "boolean" || value.errorCode !== void 0 && !isAskDomainError(value.errorCode)) {
|
|
82
85
|
return false;
|
|
83
86
|
}
|
|
84
87
|
return value.state === "ready" ? value.readOnlyProven && value.errorCode === void 0 : value.errorCode !== void 0;
|
|
@@ -552,6 +555,7 @@ function createContextualAskWorkflow(input) {
|
|
|
552
555
|
return;
|
|
553
556
|
}
|
|
554
557
|
const requestRevision = ++revision;
|
|
558
|
+
const model = input.panel.readModel();
|
|
555
559
|
currentQuestion = question;
|
|
556
560
|
busy = true;
|
|
557
561
|
input.onBusyChange(true);
|
|
@@ -564,6 +568,7 @@ function createContextualAskWorkflow(input) {
|
|
|
564
568
|
requestId: input.createId(),
|
|
565
569
|
envelope,
|
|
566
570
|
executorId,
|
|
571
|
+
...model === void 0 ? {} : { model },
|
|
567
572
|
providerDataConsent: true
|
|
568
573
|
});
|
|
569
574
|
if (!isCurrent(requestRevision)) return;
|
|
@@ -758,6 +763,158 @@ function createContextualAskWorkflow(input) {
|
|
|
758
763
|
});
|
|
759
764
|
}
|
|
760
765
|
|
|
766
|
+
// src/ui/ask-picker.ts
|
|
767
|
+
function createAskPicker(document, onViewChange) {
|
|
768
|
+
const root = createMarkedElement(document, "div");
|
|
769
|
+
root.className = "spotpatch-ask-executor-picker";
|
|
770
|
+
const trigger = createButton(document, "", "spotpatch-ask-executor");
|
|
771
|
+
trigger.id = `spotpatch-ask-picker-${Math.random().toString(36).slice(2)}`;
|
|
772
|
+
trigger.setAttribute("role", "combobox");
|
|
773
|
+
trigger.setAttribute("aria-haspopup", "listbox");
|
|
774
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
775
|
+
const text = createMarkedElement(document, "span");
|
|
776
|
+
trigger.append(text);
|
|
777
|
+
const menu = createMarkedElement(document, "div");
|
|
778
|
+
menu.id = `${trigger.id}-menu`;
|
|
779
|
+
menu.className = "spotpatch-ask-executor-menu";
|
|
780
|
+
menu.setAttribute("role", "listbox");
|
|
781
|
+
menu.hidden = true;
|
|
782
|
+
trigger.setAttribute("aria-controls", menu.id);
|
|
783
|
+
const select = createMarkedElement(document, "select");
|
|
784
|
+
select.className = "spotpatch-ask-executor-native";
|
|
785
|
+
select.tabIndex = -1;
|
|
786
|
+
select.setAttribute("aria-hidden", "true");
|
|
787
|
+
root.append(trigger, menu, select);
|
|
788
|
+
function close(focus = false) {
|
|
789
|
+
if (menu.hidden) return;
|
|
790
|
+
menu.hidden = true;
|
|
791
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
792
|
+
trigger.removeAttribute("aria-activedescendant");
|
|
793
|
+
if (focus) trigger.focus({ preventScroll: true });
|
|
794
|
+
onViewChange();
|
|
795
|
+
}
|
|
796
|
+
function activate(index) {
|
|
797
|
+
const options = [...menu.children];
|
|
798
|
+
const active = options[index];
|
|
799
|
+
if (active === void 0) return;
|
|
800
|
+
for (const option of options) option.dataset.active = String(option === active);
|
|
801
|
+
trigger.setAttribute("aria-activedescendant", active.id);
|
|
802
|
+
const itemRect = active.getBoundingClientRect();
|
|
803
|
+
const menuRect = menu.getBoundingClientRect();
|
|
804
|
+
if (itemRect.top < menuRect.top) menu.scrollTop -= menuRect.top - itemRect.top;
|
|
805
|
+
else if (itemRect.bottom > menuRect.bottom)
|
|
806
|
+
menu.scrollTop += itemRect.bottom - menuRect.bottom;
|
|
807
|
+
}
|
|
808
|
+
function open() {
|
|
809
|
+
if (trigger.disabled || !menu.hidden) return;
|
|
810
|
+
menu.hidden = false;
|
|
811
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
812
|
+
activate(Math.max(0, select.selectedIndex));
|
|
813
|
+
onViewChange();
|
|
814
|
+
}
|
|
815
|
+
function sync() {
|
|
816
|
+
text.textContent = select.selectedOptions[0]?.textContent ?? "";
|
|
817
|
+
trigger.title = text.textContent;
|
|
818
|
+
trigger.dataset.empty = String(select.value.length === 0);
|
|
819
|
+
for (const option of [...menu.children]) {
|
|
820
|
+
option.setAttribute(
|
|
821
|
+
"aria-selected",
|
|
822
|
+
String(option.dataset.value === select.value)
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
function choose(value) {
|
|
827
|
+
if (trigger.disabled) return;
|
|
828
|
+
select.value = value;
|
|
829
|
+
sync();
|
|
830
|
+
close(true);
|
|
831
|
+
select.dispatchEvent(new Event("change", { bubbles: true }));
|
|
832
|
+
}
|
|
833
|
+
function rebuild() {
|
|
834
|
+
close();
|
|
835
|
+
menu.replaceChildren();
|
|
836
|
+
for (const [index, option] of [...select.options].entries()) {
|
|
837
|
+
const item = createMarkedElement(document, "div");
|
|
838
|
+
item.id = `${menu.id}-${String(index)}`;
|
|
839
|
+
item.className = "spotpatch-ask-executor-option";
|
|
840
|
+
item.setAttribute("role", "option");
|
|
841
|
+
item.dataset.value = option.value;
|
|
842
|
+
item.textContent = option.textContent;
|
|
843
|
+
item.title = option.textContent;
|
|
844
|
+
item.addEventListener("pointerdown", (event) => {
|
|
845
|
+
event.preventDefault();
|
|
846
|
+
});
|
|
847
|
+
item.addEventListener("click", () => {
|
|
848
|
+
choose(option.value);
|
|
849
|
+
});
|
|
850
|
+
menu.append(item);
|
|
851
|
+
}
|
|
852
|
+
sync();
|
|
853
|
+
}
|
|
854
|
+
trigger.addEventListener("click", () => {
|
|
855
|
+
if (menu.hidden) open();
|
|
856
|
+
else close();
|
|
857
|
+
});
|
|
858
|
+
trigger.addEventListener("keydown", (event) => {
|
|
859
|
+
if (event.key === "Escape" && !menu.hidden) {
|
|
860
|
+
event.preventDefault();
|
|
861
|
+
event.stopPropagation();
|
|
862
|
+
close();
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (event.key === "Tab") {
|
|
866
|
+
close();
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
if (["Enter", " "].includes(event.key) && !menu.hidden) {
|
|
870
|
+
event.preventDefault();
|
|
871
|
+
const active = [...menu.children].find(
|
|
872
|
+
(item) => item.id === trigger.getAttribute("aria-activedescendant")
|
|
873
|
+
);
|
|
874
|
+
if (active?.dataset.value !== void 0) choose(active.dataset.value);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
878
|
+
event.preventDefault();
|
|
879
|
+
if (menu.hidden) {
|
|
880
|
+
open();
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
const options = [...menu.children];
|
|
884
|
+
const index = options.findIndex(
|
|
885
|
+
(item) => item.id === trigger.getAttribute("aria-activedescendant")
|
|
886
|
+
);
|
|
887
|
+
activate(
|
|
888
|
+
event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + options.length) % options.length
|
|
889
|
+
);
|
|
890
|
+
});
|
|
891
|
+
root.addEventListener("focusout", (event) => {
|
|
892
|
+
if (!(event.relatedTarget instanceof Node) || !root.contains(event.relatedTarget))
|
|
893
|
+
close();
|
|
894
|
+
});
|
|
895
|
+
const outside = (event) => {
|
|
896
|
+
if (!event.composedPath().includes(root)) close();
|
|
897
|
+
};
|
|
898
|
+
document.addEventListener("pointerdown", outside);
|
|
899
|
+
select.addEventListener("change", sync);
|
|
900
|
+
return {
|
|
901
|
+
root,
|
|
902
|
+
trigger,
|
|
903
|
+
select,
|
|
904
|
+
rebuild,
|
|
905
|
+
close,
|
|
906
|
+
setDisabled(disabled) {
|
|
907
|
+
select.disabled = disabled;
|
|
908
|
+
trigger.disabled = disabled || select.options.length < 2;
|
|
909
|
+
trigger.dataset.expandable = String(!trigger.disabled);
|
|
910
|
+
if (trigger.disabled) close();
|
|
911
|
+
},
|
|
912
|
+
dispose() {
|
|
913
|
+
document.removeEventListener("pointerdown", outside);
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
761
918
|
// src/ui/contextual-ask-localization.ts
|
|
762
919
|
var EN = Object.freeze({
|
|
763
920
|
mode: Object.freeze({ ask: "Ask", change: "Change", label: "Task mode" }),
|
|
@@ -772,6 +929,7 @@ var EN = Object.freeze({
|
|
|
772
929
|
"Why is it implemented this way?"
|
|
773
930
|
]),
|
|
774
931
|
executorLabel: "Read-only executor",
|
|
932
|
+
modelLabel: "Model",
|
|
775
933
|
loadingExecutors: "Checking available executors\u2026",
|
|
776
934
|
noExecutor: "No verified read-only executor is available.",
|
|
777
935
|
unavailable: "unavailable",
|
|
@@ -841,6 +999,7 @@ var ZH = Object.freeze({
|
|
|
841
999
|
"\u4E3A\u4EC0\u4E48\u8981\u8FD9\u6837\u5B9E\u73B0\uFF1F"
|
|
842
1000
|
]),
|
|
843
1001
|
executorLabel: "\u53EA\u8BFB\u6267\u884C\u5668",
|
|
1002
|
+
modelLabel: "\u6A21\u578B",
|
|
844
1003
|
loadingExecutors: "\u6B63\u5728\u68C0\u67E5\u53EF\u7528\u6267\u884C\u5668\u2026",
|
|
845
1004
|
noExecutor: "\u76EE\u524D\u6CA1\u6709\u901A\u8FC7\u53EA\u8BFB\u9A8C\u8BC1\u7684\u6267\u884C\u5668\u3002",
|
|
846
1005
|
unavailable: "\u4E0D\u53EF\u7528",
|
|
@@ -909,7 +1068,8 @@ function createStyles(document) {
|
|
|
909
1068
|
.spotpatch-ask-mode button { min-height: 34px; border: 0; border-radius: 7px; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; }
|
|
910
1069
|
.spotpatch-ask-mode button[aria-selected="true"] { color: #f7f7ff; background: linear-gradient(135deg, rgb(139 123 255 / 25%), rgb(82 168 255 / 14%)); box-shadow: inset 0 0 0 1px rgb(139 123 255 / 24%); }
|
|
911
1070
|
.spotpatch-ask-panel { display: grid; gap: 14px; }
|
|
912
|
-
.spotpatch-ask-field { display: grid; gap: 7px; }
|
|
1071
|
+
.spotpatch-ask-field { display: grid; gap: 7px; min-width: 0; }
|
|
1072
|
+
.spotpatch-ask-field[hidden] { display: none; }
|
|
913
1073
|
.spotpatch-ask-field > label, .spotpatch-ask-label { color: #c9cad2; font-size: 11px; font-weight: 680; }
|
|
914
1074
|
.spotpatch-ask-question { box-sizing: border-box; width: 100%; min-height: 92px; resize: vertical; border: 1px solid var(--spotpatch-border); border-radius: 10px; padding: 11px 12px; outline: none; color: var(--spotpatch-text); background: var(--spotpatch-bg-input); line-height: 1.55; }
|
|
915
1075
|
.spotpatch-ask-question:focus { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }
|
|
@@ -924,10 +1084,10 @@ function createStyles(document) {
|
|
|
924
1084
|
.spotpatch-ask-executor:focus-visible { border-color: rgb(139 123 255 / 68%); box-shadow: 0 0 0 3px rgb(139 123 255 / 12%); }
|
|
925
1085
|
.spotpatch-ask-executor:disabled { color: var(--spotpatch-text); background: rgb(255 255 255 / 3%); cursor: default; opacity: 1; }
|
|
926
1086
|
.spotpatch-ask-executor[data-empty="true"]:disabled { color: var(--spotpatch-text-muted); }
|
|
927
|
-
.spotpatch-ask-executor-menu { display: grid; gap: 3px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background:
|
|
1087
|
+
.spotpatch-ask-executor-menu { display: grid; gap: 3px; border: 1px solid var(--spotpatch-border); border-radius: 9px; padding: 4px; background: var(--spotpatch-bg-input); max-height: 224px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; box-shadow: 0 10px 28px rgb(0 0 0 / 28%); }
|
|
928
1088
|
.spotpatch-ask-executor-menu[hidden] { display: none; }
|
|
929
|
-
.spotpatch-ask-executor-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; }
|
|
930
|
-
.spotpatch-ask-executor-option
|
|
1089
|
+
.spotpatch-ask-executor-option { box-sizing: border-box; min-height: 34px; border: 0; border-radius: 6px; padding: 7px 9px; color: var(--spotpatch-text-secondary); background: transparent; cursor: pointer; font: inherit; text-align: left; overflow-wrap: anywhere; }
|
|
1090
|
+
.spotpatch-ask-executor-option[data-active="true"], .spotpatch-ask-executor-option:hover { color: #fff; background: rgb(139 123 255 / 13%); outline: none; }
|
|
931
1091
|
.spotpatch-ask-executor-option[aria-selected="true"] { color: #f4f1ff; background: rgb(139 123 255 / 20%); }
|
|
932
1092
|
.spotpatch-ask-executor-native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
933
1093
|
.spotpatch-ask-executor-status { margin: 0; border-left: 2px solid var(--spotpatch-warning); padding-left: 8px; color: #d8b66c; font-size: 10.5px; line-height: 1.45; }
|
|
@@ -1028,33 +1188,21 @@ function createContextualAskPanel(input) {
|
|
|
1028
1188
|
const executorField = createMarkedElement(document, "div");
|
|
1029
1189
|
executorField.className = "spotpatch-ask-field";
|
|
1030
1190
|
const executorLabel = createMarkedElement(document, "label");
|
|
1031
|
-
const executorPicker =
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
const
|
|
1035
|
-
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
const executorText = createMarkedElement(document, "span");
|
|
1042
|
-
executorTrigger.append(executorText);
|
|
1043
|
-
const executorMenu = createMarkedElement(document, "div");
|
|
1044
|
-
executorMenu.id = executorMenuId;
|
|
1045
|
-
executorMenu.className = "spotpatch-ask-executor-menu";
|
|
1046
|
-
executorMenu.setAttribute("role", "listbox");
|
|
1047
|
-
executorMenu.hidden = true;
|
|
1048
|
-
executorSelect.className = "spotpatch-ask-executor-native";
|
|
1049
|
-
executorSelect.tabIndex = -1;
|
|
1050
|
-
executorSelect.setAttribute("aria-hidden", "true");
|
|
1051
|
-
executorLabel.htmlFor = executorId;
|
|
1191
|
+
const executorPicker = createAskPicker(document, input.onViewChange);
|
|
1192
|
+
const executorSelect = executorPicker.select;
|
|
1193
|
+
executorLabel.htmlFor = executorPicker.trigger.id;
|
|
1194
|
+
const modelField = createMarkedElement(document, "div");
|
|
1195
|
+
modelField.className = "spotpatch-ask-field";
|
|
1196
|
+
const modelLabel = createMarkedElement(document, "label");
|
|
1197
|
+
const modelPicker = createAskPicker(document, input.onViewChange);
|
|
1198
|
+
modelLabel.htmlFor = modelPicker.trigger.id;
|
|
1199
|
+
modelField.append(modelLabel, modelPicker.root);
|
|
1200
|
+
let modelExecutorId;
|
|
1052
1201
|
const executorStatus = createMarkedElement(document, "p");
|
|
1053
1202
|
executorStatus.className = "spotpatch-ask-executor-status";
|
|
1054
1203
|
executorStatus.setAttribute("role", "status");
|
|
1055
1204
|
executorStatus.hidden = true;
|
|
1056
|
-
|
|
1057
|
-
executorField.append(executorLabel, executorPicker, executorStatus);
|
|
1205
|
+
executorField.append(executorLabel, executorPicker.root, executorStatus);
|
|
1058
1206
|
const safety = createMarkedElement(document, "div");
|
|
1059
1207
|
safety.className = "spotpatch-ask-safety";
|
|
1060
1208
|
const dataSummary = createMarkedElement(document, "div");
|
|
@@ -1111,7 +1259,16 @@ function createContextualAskPanel(input) {
|
|
|
1111
1259
|
const convertButton = createButton(document, "", "spotpatch-primary");
|
|
1112
1260
|
answerActions.append(copyButton, convertButton);
|
|
1113
1261
|
answer.append(stale, answerTitle, warnings, blocks, sourcesSection, answerActions);
|
|
1114
|
-
askPanel.append(
|
|
1262
|
+
askPanel.append(
|
|
1263
|
+
questionField,
|
|
1264
|
+
executorField,
|
|
1265
|
+
modelField,
|
|
1266
|
+
safety,
|
|
1267
|
+
status,
|
|
1268
|
+
error,
|
|
1269
|
+
actions,
|
|
1270
|
+
answer
|
|
1271
|
+
);
|
|
1115
1272
|
root.append(modeSwitch, origin, askPanel);
|
|
1116
1273
|
function hasReadyExecutor() {
|
|
1117
1274
|
const selected = currentCapability?.executors.find(
|
|
@@ -1124,57 +1281,31 @@ function createContextualAskPanel(input) {
|
|
|
1124
1281
|
(candidate) => candidate.state === "ready" && candidate.readOnlyProven
|
|
1125
1282
|
) === true;
|
|
1126
1283
|
}
|
|
1127
|
-
function
|
|
1128
|
-
|
|
1129
|
-
(
|
|
1130
|
-
).length ?? 0;
|
|
1131
|
-
}
|
|
1132
|
-
function closeExecutorMenu(focusTrigger = false) {
|
|
1133
|
-
if (executorMenu.hidden) return;
|
|
1134
|
-
executorMenu.hidden = true;
|
|
1135
|
-
executorTrigger.setAttribute("aria-expanded", "false");
|
|
1136
|
-
if (focusTrigger) executorTrigger.focus({ preventScroll: true });
|
|
1137
|
-
input.onViewChange();
|
|
1138
|
-
}
|
|
1139
|
-
function openExecutorMenu(focusSelected = false) {
|
|
1140
|
-
if (executorTrigger.disabled || !executorMenu.hidden) return;
|
|
1141
|
-
executorMenu.hidden = false;
|
|
1142
|
-
executorTrigger.setAttribute("aria-expanded", "true");
|
|
1143
|
-
if (focusSelected) {
|
|
1144
|
-
const selected = executorMenu.querySelector(
|
|
1145
|
-
'.spotpatch-ask-executor-option[aria-selected="true"]'
|
|
1146
|
-
);
|
|
1147
|
-
const first = executorMenu.firstElementChild;
|
|
1148
|
-
const focusTarget = selected ?? (first instanceof HTMLElement ? first : null);
|
|
1149
|
-
focusTarget?.focus({ preventScroll: true });
|
|
1150
|
-
}
|
|
1151
|
-
input.onViewChange();
|
|
1152
|
-
}
|
|
1153
|
-
function syncExecutorControl() {
|
|
1154
|
-
const selectedOption = [...executorSelect.options].find(
|
|
1155
|
-
(option) => option.value === executorSelect.value
|
|
1284
|
+
function renderModels() {
|
|
1285
|
+
const executor = currentCapability?.executors.find(
|
|
1286
|
+
(item) => item.executorId === executorSelect.value
|
|
1156
1287
|
);
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
)
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1288
|
+
const previous = modelExecutorId === executor?.executorId ? modelPicker.select.value : void 0;
|
|
1289
|
+
modelExecutorId = executor?.executorId;
|
|
1290
|
+
const models = executor?.models;
|
|
1291
|
+
modelField.hidden = models === void 0;
|
|
1292
|
+
modelPicker.select.replaceChildren();
|
|
1293
|
+
for (const model of models ?? []) {
|
|
1294
|
+
const option = document.createElement("option");
|
|
1295
|
+
option.value = model;
|
|
1296
|
+
option.textContent = model;
|
|
1297
|
+
modelPicker.select.append(option);
|
|
1166
1298
|
}
|
|
1299
|
+
modelPicker.select.value = models?.find((model) => model === previous) ?? models?.find((model) => model === executor?.requestedModelLabel) ?? models?.[0] ?? "";
|
|
1300
|
+
modelPicker.rebuild();
|
|
1167
1301
|
}
|
|
1168
1302
|
function refreshSubmitState() {
|
|
1169
1303
|
submitButton.disabled = busy || questionInput.value.trim().length === 0 || !hasReadyExecutor() || !consentCheckbox.checked || currentPreview.targetCount === 0;
|
|
1170
1304
|
if (!currentPreview.contextReady) submitButton.disabled = true;
|
|
1171
1305
|
questionInput.disabled = busy;
|
|
1172
|
-
const readyCount = readyExecutorCount();
|
|
1173
1306
|
const executorUnavailable = busy || currentCapability === void 0 || !hasAnyReadyExecutor();
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
executorTrigger.dataset.expandable = String(!executorUnavailable && readyCount > 1);
|
|
1177
|
-
if (executorTrigger.disabled) closeExecutorMenu();
|
|
1307
|
+
executorPicker.setDisabled(executorUnavailable);
|
|
1308
|
+
modelPicker.setDisabled(busy || !hasReadyExecutor());
|
|
1178
1309
|
consentCheckbox.disabled = busy || !hasReadyExecutor();
|
|
1179
1310
|
newQuestionButton.hidden = busy || currentResult === void 0;
|
|
1180
1311
|
cancelButton.hidden = !busy;
|
|
@@ -1217,6 +1348,9 @@ function createContextualAskPanel(input) {
|
|
|
1217
1348
|
questionInput.placeholder = messages.questionPlaceholder;
|
|
1218
1349
|
suggestions.setAttribute("aria-label", messages.suggestionsLabel);
|
|
1219
1350
|
executorLabel.textContent = messages.executorLabel;
|
|
1351
|
+
modelLabel.textContent = messages.modelLabel;
|
|
1352
|
+
executorPicker.root.querySelector("[role=listbox]")?.setAttribute("aria-label", messages.executorLabel);
|
|
1353
|
+
modelPicker.root.querySelector("[role=listbox]")?.setAttribute("aria-label", messages.modelLabel);
|
|
1220
1354
|
consentText.textContent = messages.consent;
|
|
1221
1355
|
safetyText.textContent = messages.safety;
|
|
1222
1356
|
submitButton.textContent = messages.submit;
|
|
@@ -1241,8 +1375,7 @@ function createContextualAskPanel(input) {
|
|
|
1241
1375
|
currentCapability = capability;
|
|
1242
1376
|
const previous = executorSelect.value;
|
|
1243
1377
|
executorSelect.replaceChildren();
|
|
1244
|
-
|
|
1245
|
-
closeExecutorMenu();
|
|
1378
|
+
executorPicker.close();
|
|
1246
1379
|
executorStatus.hidden = true;
|
|
1247
1380
|
executorStatus.textContent = "";
|
|
1248
1381
|
if (capability === void 0) {
|
|
@@ -1265,22 +1398,8 @@ function createContextualAskPanel(input) {
|
|
|
1265
1398
|
for (const executor of readyExecutors) {
|
|
1266
1399
|
const option = document.createElement("option");
|
|
1267
1400
|
option.value = executor.executorId;
|
|
1268
|
-
option.textContent = `${executor.label} \xB7 ${executor.effectiveModelLabel}
|
|
1401
|
+
option.textContent = executor.models === void 0 ? `${executor.label} \xB7 ${executor.effectiveModelLabel}` : executor.label;
|
|
1269
1402
|
executorSelect.append(option);
|
|
1270
|
-
const menuOption = createButton(
|
|
1271
|
-
document,
|
|
1272
|
-
option.textContent,
|
|
1273
|
-
"spotpatch-ask-executor-option"
|
|
1274
|
-
);
|
|
1275
|
-
menuOption.dataset.executorId = executor.executorId;
|
|
1276
|
-
menuOption.setAttribute("role", "option");
|
|
1277
|
-
menuOption.addEventListener("click", () => {
|
|
1278
|
-
executorSelect.value = executor.executorId;
|
|
1279
|
-
syncExecutorControl();
|
|
1280
|
-
closeExecutorMenu(true);
|
|
1281
|
-
executorSelect.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1282
|
-
});
|
|
1283
|
-
executorMenu.append(menuOption);
|
|
1284
1403
|
}
|
|
1285
1404
|
if (readyExecutors.length === 0) {
|
|
1286
1405
|
const option = document.createElement("option");
|
|
@@ -1296,7 +1415,8 @@ function createContextualAskPanel(input) {
|
|
|
1296
1415
|
executorStatus.hidden = false;
|
|
1297
1416
|
}
|
|
1298
1417
|
}
|
|
1299
|
-
|
|
1418
|
+
executorPicker.rebuild();
|
|
1419
|
+
renderModels();
|
|
1300
1420
|
refreshSubmitState();
|
|
1301
1421
|
}
|
|
1302
1422
|
function renderJob(snapshot) {
|
|
@@ -1451,42 +1571,11 @@ ${sourceText}`;
|
|
|
1451
1571
|
applyMode();
|
|
1452
1572
|
});
|
|
1453
1573
|
questionInput.addEventListener("input", refreshSubmitState);
|
|
1454
|
-
executorSelect.addEventListener("change",
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
});
|
|
1459
|
-
executorTrigger.addEventListener("keydown", (event) => {
|
|
1460
|
-
if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
|
|
1461
|
-
event.preventDefault();
|
|
1462
|
-
openExecutorMenu(true);
|
|
1463
|
-
});
|
|
1464
|
-
executorMenu.addEventListener("keydown", (event) => {
|
|
1465
|
-
const options = [
|
|
1466
|
-
...executorMenu.querySelectorAll(
|
|
1467
|
-
".spotpatch-ask-executor-option"
|
|
1468
|
-
)
|
|
1469
|
-
];
|
|
1470
|
-
if (event.key === "Escape") {
|
|
1471
|
-
event.preventDefault();
|
|
1472
|
-
closeExecutorMenu(true);
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
1476
|
-
event.preventDefault();
|
|
1477
|
-
const currentIndex = options.indexOf(document.activeElement);
|
|
1478
|
-
const nextIndex = event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : event.key === "ArrowDown" ? (currentIndex + 1 + options.length) % options.length : (currentIndex - 1 + options.length) % options.length;
|
|
1479
|
-
options[nextIndex]?.focus({ preventScroll: true });
|
|
1480
|
-
});
|
|
1481
|
-
executorPicker.addEventListener("focusout", (event) => {
|
|
1482
|
-
if (!(event.relatedTarget instanceof Node) || !executorPicker.contains(event.relatedTarget)) {
|
|
1483
|
-
closeExecutorMenu();
|
|
1484
|
-
}
|
|
1574
|
+
executorSelect.addEventListener("change", () => {
|
|
1575
|
+
renderModels();
|
|
1576
|
+
refreshSubmitState();
|
|
1577
|
+
input.onViewChange();
|
|
1485
1578
|
});
|
|
1486
|
-
const closeExecutorMenuOutside = (event) => {
|
|
1487
|
-
if (!event.composedPath().includes(executorPicker)) closeExecutorMenu();
|
|
1488
|
-
};
|
|
1489
|
-
document.addEventListener("pointerdown", closeExecutorMenuOutside);
|
|
1490
1579
|
consentCheckbox.addEventListener("change", refreshSubmitState);
|
|
1491
1580
|
const unsubscribeLocale = input.subscribeLocale(applyMessages);
|
|
1492
1581
|
applyMessages();
|
|
@@ -1505,7 +1594,8 @@ ${sourceText}`;
|
|
|
1505
1594
|
clear,
|
|
1506
1595
|
dispose: () => {
|
|
1507
1596
|
unsubscribeLocale();
|
|
1508
|
-
|
|
1597
|
+
executorPicker.dispose();
|
|
1598
|
+
modelPicker.dispose();
|
|
1509
1599
|
},
|
|
1510
1600
|
focusQuestion: () => {
|
|
1511
1601
|
questionInput.focus({ preventScroll: true });
|
|
@@ -1517,6 +1607,7 @@ ${sourceText}`;
|
|
|
1517
1607
|
},
|
|
1518
1608
|
readConsent: () => consentCheckbox.checked,
|
|
1519
1609
|
readExecutorId: () => executorSelect.value || void 0,
|
|
1610
|
+
readModel: () => modelPicker.select.value || void 0,
|
|
1520
1611
|
readQuestion: () => questionInput.value.trim(),
|
|
1521
1612
|
renderAnswer,
|
|
1522
1613
|
renderCapability,
|