@helpai/elements 0.19.1 → 0.19.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/configurator.mjs +3 -3
- package/elements-web-component.esm.js +21 -21
- package/elements-web-component.esm.js.map +3 -3
- package/elements.cjs.js +21 -21
- package/elements.cjs.js.map +3 -3
- package/elements.esm.js +22 -22
- package/elements.esm.js.map +3 -3
- package/elements.js +21 -21
- package/elements.js.map +3 -3
- package/index.mjs +68 -30
- package/package.json +1 -1
- package/schema.json +10 -10
- package/schema.mjs +3 -3
- package/web-component.mjs +68 -30
package/index.mjs
CHANGED
|
@@ -128,7 +128,7 @@ var STRINGS_EN = {
|
|
|
128
128
|
formChooseAtMost: "Choose at most {max}",
|
|
129
129
|
formOther: "Other",
|
|
130
130
|
formOtherPlaceholder: "Type your answer\u2026",
|
|
131
|
-
inputRequired: "
|
|
131
|
+
inputRequired: "I need a bit more info",
|
|
132
132
|
inputSubmit: "Submit",
|
|
133
133
|
inputSkip: "Skip",
|
|
134
134
|
inputSubmitted: "Answer submitted",
|
|
@@ -238,7 +238,7 @@ var STRINGS_FR = {
|
|
|
238
238
|
formChooseAtMost: "Choisissez au plus {max}",
|
|
239
239
|
formOther: "Autre",
|
|
240
240
|
formOtherPlaceholder: "Saisissez votre r\xE9ponse\u2026",
|
|
241
|
-
inputRequired: "
|
|
241
|
+
inputRequired: "J'ai besoin de quelques pr\xE9cisions",
|
|
242
242
|
inputSubmit: "Envoyer",
|
|
243
243
|
inputSkip: "Ignorer",
|
|
244
244
|
inputSubmitted: "R\xE9ponse envoy\xE9e",
|
|
@@ -462,7 +462,7 @@ var DEFAULT_ATTACHMENTS = {
|
|
|
462
462
|
maxCount: 10,
|
|
463
463
|
accept: "*/*"
|
|
464
464
|
};
|
|
465
|
-
var DEFAULT_WELCOME = { animation: "
|
|
465
|
+
var DEFAULT_WELCOME = { animation: "instant", speed: 60 };
|
|
466
466
|
var DEFAULT_FEATURES = {
|
|
467
467
|
files: true,
|
|
468
468
|
voice: "local",
|
|
@@ -1985,9 +1985,10 @@ function partFromReactive(p33) {
|
|
|
1985
1985
|
import { signal as signal2 } from "@preact/signals";
|
|
1986
1986
|
|
|
1987
1987
|
// src/stream/constants.ts
|
|
1988
|
-
var ASK_USER_INPUT_TOOL = "tool:ask-user-input";
|
|
1989
1988
|
function isAskUserInputTool(toolName) {
|
|
1990
|
-
|
|
1989
|
+
if (!toolName) return false;
|
|
1990
|
+
const name = toolName.startsWith("tool:") ? toolName.slice(5) : toolName;
|
|
1991
|
+
return name === "ask-user-input" || name === "ask_user_input" || name === "request-user-input" || name === "request_user_input";
|
|
1991
1992
|
}
|
|
1992
1993
|
var TRIGGER = {
|
|
1993
1994
|
submitMessage: "submit-message",
|
|
@@ -4363,6 +4364,9 @@ function hardenLink(a) {
|
|
|
4363
4364
|
import { useComputed as useComputed2, useSignal } from "@preact/signals";
|
|
4364
4365
|
import { Fragment, jsx as jsx13, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
4365
4366
|
var p12 = BRAND.cssPrefix;
|
|
4367
|
+
function displayToolName(toolName) {
|
|
4368
|
+
return (toolName.startsWith("tool:") ? toolName.slice(5) : toolName).replace(/[-_]+/g, " ");
|
|
4369
|
+
}
|
|
4366
4370
|
function ToolApproval({ part, strings, active, onDecision }) {
|
|
4367
4371
|
const approval = useComputed2(() => part.approvalSig.value);
|
|
4368
4372
|
const input = useComputed2(() => part.inputSig.value);
|
|
@@ -4372,7 +4376,7 @@ function ToolApproval({ part, strings, active, onDecision }) {
|
|
|
4372
4376
|
const ap = approval.value;
|
|
4373
4377
|
return /* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-approval ${p12}-tool-decided`, "data-testid": TID.toolDecision, children: [
|
|
4374
4378
|
/* @__PURE__ */ jsx13("span", { class: `${p12}-tool-decided-label`, "data-approved": ap?.approved ? "true" : "false", children: ap?.approved ? strings.approved : strings.rejected }),
|
|
4375
|
-
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: part.toolName }),
|
|
4379
|
+
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: displayToolName(part.toolName) }),
|
|
4376
4380
|
ap?.reason ? /* @__PURE__ */ jsx13("span", { class: `${p12}-tool-decided-value`, children: ap.reason }) : null
|
|
4377
4381
|
] });
|
|
4378
4382
|
}
|
|
@@ -4380,7 +4384,7 @@ function ToolApproval({ part, strings, active, onDecision }) {
|
|
|
4380
4384
|
return /* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-approval`, "data-testid": TID.toolApproval, children: [
|
|
4381
4385
|
/* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-head`, children: [
|
|
4382
4386
|
/* @__PURE__ */ jsx13("span", { class: `${p12}-tool-badge`, children: strings.approvalRequired }),
|
|
4383
|
-
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: part.toolName })
|
|
4387
|
+
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: displayToolName(part.toolName) })
|
|
4384
4388
|
] }),
|
|
4385
4389
|
args ? /* @__PURE__ */ jsx13("pre", { class: `${p12}-tool-args`, children: args }) : null,
|
|
4386
4390
|
active ? /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
@@ -4490,10 +4494,17 @@ function num(v) {
|
|
|
4490
4494
|
// src/ui/tool-ask-input.tsx
|
|
4491
4495
|
import { jsx as jsx14, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
4492
4496
|
var p13 = BRAND.cssPrefix;
|
|
4493
|
-
function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
4497
|
+
function ToolAskInput({ part, strings, active, onSubmit, onDecision }) {
|
|
4494
4498
|
const state = useComputed3(() => part.stateSig.value);
|
|
4499
|
+
const approval = useComputed3(() => part.approvalSig.value);
|
|
4495
4500
|
const request = useComputed3(() => parseAskUserInput(part.inputSig.value));
|
|
4496
|
-
const decided = state.value === "output" || state.value === "error";
|
|
4501
|
+
const decided = state.value === "output" || state.value === "error" || approval.value?.approved !== void 0;
|
|
4502
|
+
const viaApproval = approval.value !== void 0;
|
|
4503
|
+
const resolve = (answer, accepted) => {
|
|
4504
|
+
if (viaApproval) onDecision(part.toolCallId, accepted, answer);
|
|
4505
|
+
else if (request.value.responseType === "confirmation") onSubmit(part.toolCallId, { confirmed: accepted });
|
|
4506
|
+
else onSubmit(part.toolCallId, accepted ? { answer } : {});
|
|
4507
|
+
};
|
|
4497
4508
|
if (decided) {
|
|
4498
4509
|
return /* @__PURE__ */ jsx14(DecidedSummary, { part, strings });
|
|
4499
4510
|
}
|
|
@@ -4515,7 +4526,7 @@ function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
|
4515
4526
|
{
|
|
4516
4527
|
type: "button",
|
|
4517
4528
|
class: `${p13}-form-skip`,
|
|
4518
|
-
onClick: () =>
|
|
4529
|
+
onClick: () => resolve(void 0, false),
|
|
4519
4530
|
"data-testid": TID.toolInputSkip,
|
|
4520
4531
|
children: strings.reject
|
|
4521
4532
|
}
|
|
@@ -4525,7 +4536,7 @@ function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
|
4525
4536
|
{
|
|
4526
4537
|
type: "button",
|
|
4527
4538
|
class: `${p13}-form-submit`,
|
|
4528
|
-
onClick: () =>
|
|
4539
|
+
onClick: () => resolve(void 0, true),
|
|
4529
4540
|
"data-testid": TID.toolInputSubmit,
|
|
4530
4541
|
children: strings.approve
|
|
4531
4542
|
}
|
|
@@ -4536,9 +4547,9 @@ function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
|
4536
4547
|
fields: askInputToFields(req),
|
|
4537
4548
|
strings,
|
|
4538
4549
|
submitLabel: strings.inputSubmit,
|
|
4539
|
-
onSubmit: (values) =>
|
|
4550
|
+
onSubmit: (values) => resolve(values.answer ?? Object.values(values).join(", "), true),
|
|
4540
4551
|
skipLabel: req.required === false ? strings.inputSkip : void 0,
|
|
4541
|
-
onSkip: req.required === false ? () =>
|
|
4552
|
+
onSkip: req.required === false ? () => resolve(void 0, false) : void 0,
|
|
4542
4553
|
submitTestId: TID.toolInputSubmit,
|
|
4543
4554
|
skipTestId: TID.toolInputSkip
|
|
4544
4555
|
}
|
|
@@ -4553,10 +4564,12 @@ function Header({ strings, title }) {
|
|
|
4553
4564
|
}
|
|
4554
4565
|
function DecidedSummary({ part, strings }) {
|
|
4555
4566
|
const output = useComputed3(() => part.outputSig.value);
|
|
4556
|
-
const
|
|
4567
|
+
const approval = useComputed3(() => part.approvalSig.value);
|
|
4568
|
+
const answer = approval.value?.approved !== void 0 ? approval.value.reason ?? "" : summarizeOutput(output.value);
|
|
4569
|
+
const skipped = approval.value?.approved === false;
|
|
4557
4570
|
return /* @__PURE__ */ jsxs11("div", { class: `${p13}-tool-ask-input ${p13}-tool-decided`, "data-testid": TID.toolDecision, children: [
|
|
4558
|
-
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-label`, children: strings.inputSubmitted }),
|
|
4559
|
-
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-value`, children:
|
|
4571
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-label`, children: skipped ? strings.inputSkip : strings.inputSubmitted }),
|
|
4572
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-value`, children: skipped ? "" : answer || strings.inputSubmitted })
|
|
4560
4573
|
] });
|
|
4561
4574
|
}
|
|
4562
4575
|
function summarizeOutput(output) {
|
|
@@ -4686,12 +4699,21 @@ function ToolPartView({
|
|
|
4686
4699
|
const state = useComputed4(() => part.stateSig.value);
|
|
4687
4700
|
const hasApproval = useComputed4(() => part.approvalSig.value !== void 0);
|
|
4688
4701
|
if (tool?.humanInLoop) {
|
|
4702
|
+
if (isAskUserInputTool(part.toolName) || state.value === "awaiting-input") {
|
|
4703
|
+
return /* @__PURE__ */ jsx16(
|
|
4704
|
+
ToolAskInput,
|
|
4705
|
+
{
|
|
4706
|
+
part,
|
|
4707
|
+
strings,
|
|
4708
|
+
active: interactive,
|
|
4709
|
+
onSubmit: tool.onResult,
|
|
4710
|
+
onDecision: tool.onDecision
|
|
4711
|
+
}
|
|
4712
|
+
);
|
|
4713
|
+
}
|
|
4689
4714
|
if (hasApproval.value || state.value === "awaiting-approval") {
|
|
4690
4715
|
return /* @__PURE__ */ jsx16(ToolApproval, { part, strings, active: interactive, onDecision: tool.onDecision });
|
|
4691
4716
|
}
|
|
4692
|
-
if (isAskUserInputTool(part.toolName) || state.value === "awaiting-input") {
|
|
4693
|
-
return /* @__PURE__ */ jsx16(ToolAskInput, { part, strings, active: interactive, onSubmit: tool.onResult });
|
|
4694
|
-
}
|
|
4695
4717
|
}
|
|
4696
4718
|
return showToolCalls ? /* @__PURE__ */ jsx16(ToolChip, { part, strings }) : null;
|
|
4697
4719
|
}
|
|
@@ -4754,19 +4776,23 @@ function MessageList({
|
|
|
4754
4776
|
const [showJump, setShowJump] = useState6(false);
|
|
4755
4777
|
const [scrolling, setScrolling] = useState6(false);
|
|
4756
4778
|
const hasHydratedRef = useRef5(false);
|
|
4779
|
+
const detachedRef = useRef5(false);
|
|
4780
|
+
const autoPinAtRef = useRef5(0);
|
|
4781
|
+
const pinBottom = (el) => {
|
|
4782
|
+
autoPinAtRef.current = performance.now();
|
|
4783
|
+
el.scrollTop = el.scrollHeight;
|
|
4784
|
+
};
|
|
4757
4785
|
const firstMessageId = messages.value[0]?.id;
|
|
4758
4786
|
useLayoutEffect(() => {
|
|
4759
4787
|
const el = ref.current;
|
|
4760
4788
|
if (!el) return;
|
|
4761
4789
|
if (messages.value.length === 0) return;
|
|
4762
4790
|
hasHydratedRef.current = true;
|
|
4763
|
-
const
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
pinBottom();
|
|
4767
|
-
const resizeObs = new ResizeObserver(pinBottom);
|
|
4791
|
+
const pinNow = () => pinBottom(el);
|
|
4792
|
+
pinNow();
|
|
4793
|
+
const resizeObs = new ResizeObserver(pinNow);
|
|
4768
4794
|
resizeObs.observe(el);
|
|
4769
|
-
const mutationObs = new MutationObserver(
|
|
4795
|
+
const mutationObs = new MutationObserver(pinNow);
|
|
4770
4796
|
mutationObs.observe(el, { childList: true, subtree: true, characterData: true });
|
|
4771
4797
|
const timerId = setTimeout(() => {
|
|
4772
4798
|
resizeObs.disconnect();
|
|
@@ -4782,8 +4808,14 @@ function MessageList({
|
|
|
4782
4808
|
const el = ref.current;
|
|
4783
4809
|
if (!el) return;
|
|
4784
4810
|
if (!hasHydratedRef.current) return;
|
|
4811
|
+
if (messages.value.at(-1)?.role === "user") {
|
|
4812
|
+
detachedRef.current = false;
|
|
4813
|
+
pinBottom(el);
|
|
4814
|
+
return;
|
|
4815
|
+
}
|
|
4816
|
+
if (detachedRef.current) return;
|
|
4785
4817
|
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4786
|
-
if (distanceFromBottom < STICK_THRESHOLD) el
|
|
4818
|
+
if (distanceFromBottom < STICK_THRESHOLD) pinBottom(el);
|
|
4787
4819
|
}, [messages.value.length]);
|
|
4788
4820
|
useEffect8(() => {
|
|
4789
4821
|
const el = ref.current;
|
|
@@ -4791,8 +4823,9 @@ function MessageList({
|
|
|
4791
4823
|
const last = messages.value.at(-1);
|
|
4792
4824
|
if (!last) return;
|
|
4793
4825
|
const pinIfNear = () => {
|
|
4826
|
+
if (detachedRef.current) return;
|
|
4794
4827
|
const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4795
|
-
if (distance < STICK_THRESHOLD * 2) el
|
|
4828
|
+
if (distance < STICK_THRESHOLD * 2) pinBottom(el);
|
|
4796
4829
|
};
|
|
4797
4830
|
if (last.status !== "streaming") {
|
|
4798
4831
|
const rafId = requestAnimationFrame(pinIfNear);
|
|
@@ -4806,8 +4839,8 @@ function MessageList({
|
|
|
4806
4839
|
const activeFormId = form?.form.id;
|
|
4807
4840
|
useLayoutEffect(() => {
|
|
4808
4841
|
const el = ref.current;
|
|
4809
|
-
if (!el || !activeFormId) return;
|
|
4810
|
-
el
|
|
4842
|
+
if (!el || !activeFormId || detachedRef.current) return;
|
|
4843
|
+
pinBottom(el);
|
|
4811
4844
|
}, [activeFormId]);
|
|
4812
4845
|
useEffect8(() => {
|
|
4813
4846
|
const el = ref.current;
|
|
@@ -4816,6 +4849,9 @@ function MessageList({
|
|
|
4816
4849
|
let idleTimer;
|
|
4817
4850
|
const onScroll = () => {
|
|
4818
4851
|
syncJump();
|
|
4852
|
+
if (performance.now() - autoPinAtRef.current > 150) {
|
|
4853
|
+
detachedRef.current = el.scrollHeight - el.scrollTop - el.clientHeight > 8;
|
|
4854
|
+
}
|
|
4819
4855
|
setScrolling(true);
|
|
4820
4856
|
clearTimeout(idleTimer);
|
|
4821
4857
|
idleTimer = setTimeout(() => setScrolling(false), DIVIDER_IDLE_MS);
|
|
@@ -4829,7 +4865,9 @@ function MessageList({
|
|
|
4829
4865
|
}, []);
|
|
4830
4866
|
const jumpToBottom = () => {
|
|
4831
4867
|
const el = ref.current;
|
|
4832
|
-
if (el)
|
|
4868
|
+
if (!el) return;
|
|
4869
|
+
detachedRef.current = false;
|
|
4870
|
+
pinBottom(el);
|
|
4833
4871
|
};
|
|
4834
4872
|
const rows = [];
|
|
4835
4873
|
let prevDay = "";
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -911,7 +911,7 @@
|
|
|
911
911
|
"type": "object",
|
|
912
912
|
"properties": {
|
|
913
913
|
"animation": {
|
|
914
|
-
"default": "
|
|
914
|
+
"default": "instant",
|
|
915
915
|
"description": "How welcome messages render — `typewriter` types each message in character-by-character; `instant` shows them whole.",
|
|
916
916
|
"type": "string",
|
|
917
917
|
"enum": [
|
|
@@ -932,14 +932,14 @@
|
|
|
932
932
|
"speed"
|
|
933
933
|
],
|
|
934
934
|
"additionalProperties": {},
|
|
935
|
-
"description": "How welcome messages render — typewriter effect with adjustable cps speed.",
|
|
935
|
+
"description": "How welcome messages render — instant by default; opt into a typewriter effect with adjustable cps speed.",
|
|
936
936
|
"examples": [
|
|
937
937
|
{
|
|
938
|
-
"animation": "
|
|
939
|
-
"speed": 60
|
|
938
|
+
"animation": "instant"
|
|
940
939
|
},
|
|
941
940
|
{
|
|
942
|
-
"animation": "
|
|
941
|
+
"animation": "typewriter",
|
|
942
|
+
"speed": 60
|
|
943
943
|
}
|
|
944
944
|
]
|
|
945
945
|
},
|
|
@@ -2665,7 +2665,7 @@
|
|
|
2665
2665
|
"type": "object",
|
|
2666
2666
|
"properties": {
|
|
2667
2667
|
"animation": {
|
|
2668
|
-
"default": "
|
|
2668
|
+
"default": "instant",
|
|
2669
2669
|
"description": "How welcome messages render — `typewriter` types each message in character-by-character; `instant` shows them whole.",
|
|
2670
2670
|
"type": "string",
|
|
2671
2671
|
"enum": [
|
|
@@ -2686,14 +2686,14 @@
|
|
|
2686
2686
|
"speed"
|
|
2687
2687
|
],
|
|
2688
2688
|
"additionalProperties": {},
|
|
2689
|
-
"description": "How welcome messages render — typewriter effect with adjustable cps speed.",
|
|
2689
|
+
"description": "How welcome messages render — instant by default; opt into a typewriter effect with adjustable cps speed.",
|
|
2690
2690
|
"examples": [
|
|
2691
2691
|
{
|
|
2692
|
-
"animation": "
|
|
2693
|
-
"speed": 60
|
|
2692
|
+
"animation": "instant"
|
|
2694
2693
|
},
|
|
2695
2694
|
{
|
|
2696
|
-
"animation": "
|
|
2695
|
+
"animation": "typewriter",
|
|
2696
|
+
"speed": 60
|
|
2697
2697
|
}
|
|
2698
2698
|
]
|
|
2699
2699
|
},
|
package/schema.mjs
CHANGED
|
@@ -345,12 +345,12 @@ var composerOptionsSchema = z10.object({
|
|
|
345
345
|
import { z as z11 } from "zod";
|
|
346
346
|
var welcomeAnimationSchema = z11.enum(["typewriter", "instant"]);
|
|
347
347
|
var welcomeOptionsSchema = z11.object({
|
|
348
|
-
animation: welcomeAnimationSchema.default("
|
|
348
|
+
animation: welcomeAnimationSchema.default("instant").describe(
|
|
349
349
|
"How welcome messages render \u2014 `typewriter` types each message in character-by-character; `instant` shows them whole."
|
|
350
350
|
),
|
|
351
351
|
speed: z11.number().int().min(1).max(2e3).default(60).describe("Typewriter speed in characters per second. Only meaningful when `animation = typewriter`.")
|
|
352
|
-
}).loose().describe("How welcome messages render \u2014 typewriter effect with adjustable cps speed.").meta({
|
|
353
|
-
examples: [{ animation: "
|
|
352
|
+
}).loose().describe("How welcome messages render \u2014 instant by default; opt into a typewriter effect with adjustable cps speed.").meta({
|
|
353
|
+
examples: [{ animation: "instant" }, { animation: "typewriter", speed: 60 }]
|
|
354
354
|
});
|
|
355
355
|
|
|
356
356
|
// src/schema/widget/footer.ts
|
package/web-component.mjs
CHANGED
|
@@ -128,7 +128,7 @@ var STRINGS_EN = {
|
|
|
128
128
|
formChooseAtMost: "Choose at most {max}",
|
|
129
129
|
formOther: "Other",
|
|
130
130
|
formOtherPlaceholder: "Type your answer\u2026",
|
|
131
|
-
inputRequired: "
|
|
131
|
+
inputRequired: "I need a bit more info",
|
|
132
132
|
inputSubmit: "Submit",
|
|
133
133
|
inputSkip: "Skip",
|
|
134
134
|
inputSubmitted: "Answer submitted",
|
|
@@ -238,7 +238,7 @@ var STRINGS_FR = {
|
|
|
238
238
|
formChooseAtMost: "Choisissez au plus {max}",
|
|
239
239
|
formOther: "Autre",
|
|
240
240
|
formOtherPlaceholder: "Saisissez votre r\xE9ponse\u2026",
|
|
241
|
-
inputRequired: "
|
|
241
|
+
inputRequired: "J'ai besoin de quelques pr\xE9cisions",
|
|
242
242
|
inputSubmit: "Envoyer",
|
|
243
243
|
inputSkip: "Ignorer",
|
|
244
244
|
inputSubmitted: "R\xE9ponse envoy\xE9e",
|
|
@@ -447,7 +447,7 @@ var DEFAULT_ATTACHMENTS = {
|
|
|
447
447
|
maxCount: 10,
|
|
448
448
|
accept: "*/*"
|
|
449
449
|
};
|
|
450
|
-
var DEFAULT_WELCOME = { animation: "
|
|
450
|
+
var DEFAULT_WELCOME = { animation: "instant", speed: 60 };
|
|
451
451
|
var DEFAULT_FEATURES = {
|
|
452
452
|
files: true,
|
|
453
453
|
voice: "local",
|
|
@@ -2040,9 +2040,10 @@ function partFromReactive(p33) {
|
|
|
2040
2040
|
import { signal as signal2 } from "@preact/signals";
|
|
2041
2041
|
|
|
2042
2042
|
// src/stream/constants.ts
|
|
2043
|
-
var ASK_USER_INPUT_TOOL = "tool:ask-user-input";
|
|
2044
2043
|
function isAskUserInputTool(toolName) {
|
|
2045
|
-
|
|
2044
|
+
if (!toolName) return false;
|
|
2045
|
+
const name = toolName.startsWith("tool:") ? toolName.slice(5) : toolName;
|
|
2046
|
+
return name === "ask-user-input" || name === "ask_user_input" || name === "request-user-input" || name === "request_user_input";
|
|
2046
2047
|
}
|
|
2047
2048
|
var TRIGGER = {
|
|
2048
2049
|
submitMessage: "submit-message",
|
|
@@ -4418,6 +4419,9 @@ function hardenLink(a) {
|
|
|
4418
4419
|
import { useComputed as useComputed2, useSignal } from "@preact/signals";
|
|
4419
4420
|
import { Fragment, jsx as jsx13, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
4420
4421
|
var p12 = BRAND.cssPrefix;
|
|
4422
|
+
function displayToolName(toolName) {
|
|
4423
|
+
return (toolName.startsWith("tool:") ? toolName.slice(5) : toolName).replace(/[-_]+/g, " ");
|
|
4424
|
+
}
|
|
4421
4425
|
function ToolApproval({ part, strings, active, onDecision }) {
|
|
4422
4426
|
const approval = useComputed2(() => part.approvalSig.value);
|
|
4423
4427
|
const input = useComputed2(() => part.inputSig.value);
|
|
@@ -4427,7 +4431,7 @@ function ToolApproval({ part, strings, active, onDecision }) {
|
|
|
4427
4431
|
const ap = approval.value;
|
|
4428
4432
|
return /* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-approval ${p12}-tool-decided`, "data-testid": TID.toolDecision, children: [
|
|
4429
4433
|
/* @__PURE__ */ jsx13("span", { class: `${p12}-tool-decided-label`, "data-approved": ap?.approved ? "true" : "false", children: ap?.approved ? strings.approved : strings.rejected }),
|
|
4430
|
-
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: part.toolName }),
|
|
4434
|
+
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: displayToolName(part.toolName) }),
|
|
4431
4435
|
ap?.reason ? /* @__PURE__ */ jsx13("span", { class: `${p12}-tool-decided-value`, children: ap.reason }) : null
|
|
4432
4436
|
] });
|
|
4433
4437
|
}
|
|
@@ -4435,7 +4439,7 @@ function ToolApproval({ part, strings, active, onDecision }) {
|
|
|
4435
4439
|
return /* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-approval`, "data-testid": TID.toolApproval, children: [
|
|
4436
4440
|
/* @__PURE__ */ jsxs10("div", { class: `${p12}-tool-head`, children: [
|
|
4437
4441
|
/* @__PURE__ */ jsx13("span", { class: `${p12}-tool-badge`, children: strings.approvalRequired }),
|
|
4438
|
-
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: part.toolName })
|
|
4442
|
+
/* @__PURE__ */ jsx13("strong", { class: `${p12}-tool-title`, children: displayToolName(part.toolName) })
|
|
4439
4443
|
] }),
|
|
4440
4444
|
args ? /* @__PURE__ */ jsx13("pre", { class: `${p12}-tool-args`, children: args }) : null,
|
|
4441
4445
|
active ? /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
@@ -4545,10 +4549,17 @@ function num(v) {
|
|
|
4545
4549
|
// src/ui/tool-ask-input.tsx
|
|
4546
4550
|
import { jsx as jsx14, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
4547
4551
|
var p13 = BRAND.cssPrefix;
|
|
4548
|
-
function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
4552
|
+
function ToolAskInput({ part, strings, active, onSubmit, onDecision }) {
|
|
4549
4553
|
const state = useComputed3(() => part.stateSig.value);
|
|
4554
|
+
const approval = useComputed3(() => part.approvalSig.value);
|
|
4550
4555
|
const request = useComputed3(() => parseAskUserInput(part.inputSig.value));
|
|
4551
|
-
const decided = state.value === "output" || state.value === "error";
|
|
4556
|
+
const decided = state.value === "output" || state.value === "error" || approval.value?.approved !== void 0;
|
|
4557
|
+
const viaApproval = approval.value !== void 0;
|
|
4558
|
+
const resolve = (answer, accepted) => {
|
|
4559
|
+
if (viaApproval) onDecision(part.toolCallId, accepted, answer);
|
|
4560
|
+
else if (request.value.responseType === "confirmation") onSubmit(part.toolCallId, { confirmed: accepted });
|
|
4561
|
+
else onSubmit(part.toolCallId, accepted ? { answer } : {});
|
|
4562
|
+
};
|
|
4552
4563
|
if (decided) {
|
|
4553
4564
|
return /* @__PURE__ */ jsx14(DecidedSummary, { part, strings });
|
|
4554
4565
|
}
|
|
@@ -4570,7 +4581,7 @@ function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
|
4570
4581
|
{
|
|
4571
4582
|
type: "button",
|
|
4572
4583
|
class: `${p13}-form-skip`,
|
|
4573
|
-
onClick: () =>
|
|
4584
|
+
onClick: () => resolve(void 0, false),
|
|
4574
4585
|
"data-testid": TID.toolInputSkip,
|
|
4575
4586
|
children: strings.reject
|
|
4576
4587
|
}
|
|
@@ -4580,7 +4591,7 @@ function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
|
4580
4591
|
{
|
|
4581
4592
|
type: "button",
|
|
4582
4593
|
class: `${p13}-form-submit`,
|
|
4583
|
-
onClick: () =>
|
|
4594
|
+
onClick: () => resolve(void 0, true),
|
|
4584
4595
|
"data-testid": TID.toolInputSubmit,
|
|
4585
4596
|
children: strings.approve
|
|
4586
4597
|
}
|
|
@@ -4591,9 +4602,9 @@ function ToolAskInput({ part, strings, active, onSubmit }) {
|
|
|
4591
4602
|
fields: askInputToFields(req),
|
|
4592
4603
|
strings,
|
|
4593
4604
|
submitLabel: strings.inputSubmit,
|
|
4594
|
-
onSubmit: (values) =>
|
|
4605
|
+
onSubmit: (values) => resolve(values.answer ?? Object.values(values).join(", "), true),
|
|
4595
4606
|
skipLabel: req.required === false ? strings.inputSkip : void 0,
|
|
4596
|
-
onSkip: req.required === false ? () =>
|
|
4607
|
+
onSkip: req.required === false ? () => resolve(void 0, false) : void 0,
|
|
4597
4608
|
submitTestId: TID.toolInputSubmit,
|
|
4598
4609
|
skipTestId: TID.toolInputSkip
|
|
4599
4610
|
}
|
|
@@ -4608,10 +4619,12 @@ function Header({ strings, title }) {
|
|
|
4608
4619
|
}
|
|
4609
4620
|
function DecidedSummary({ part, strings }) {
|
|
4610
4621
|
const output = useComputed3(() => part.outputSig.value);
|
|
4611
|
-
const
|
|
4622
|
+
const approval = useComputed3(() => part.approvalSig.value);
|
|
4623
|
+
const answer = approval.value?.approved !== void 0 ? approval.value.reason ?? "" : summarizeOutput(output.value);
|
|
4624
|
+
const skipped = approval.value?.approved === false;
|
|
4612
4625
|
return /* @__PURE__ */ jsxs11("div", { class: `${p13}-tool-ask-input ${p13}-tool-decided`, "data-testid": TID.toolDecision, children: [
|
|
4613
|
-
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-label`, children: strings.inputSubmitted }),
|
|
4614
|
-
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-value`, children:
|
|
4626
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-label`, children: skipped ? strings.inputSkip : strings.inputSubmitted }),
|
|
4627
|
+
/* @__PURE__ */ jsx14("span", { class: `${p13}-tool-decided-value`, children: skipped ? "" : answer || strings.inputSubmitted })
|
|
4615
4628
|
] });
|
|
4616
4629
|
}
|
|
4617
4630
|
function summarizeOutput(output) {
|
|
@@ -4741,12 +4754,21 @@ function ToolPartView({
|
|
|
4741
4754
|
const state = useComputed4(() => part.stateSig.value);
|
|
4742
4755
|
const hasApproval = useComputed4(() => part.approvalSig.value !== void 0);
|
|
4743
4756
|
if (tool?.humanInLoop) {
|
|
4757
|
+
if (isAskUserInputTool(part.toolName) || state.value === "awaiting-input") {
|
|
4758
|
+
return /* @__PURE__ */ jsx16(
|
|
4759
|
+
ToolAskInput,
|
|
4760
|
+
{
|
|
4761
|
+
part,
|
|
4762
|
+
strings,
|
|
4763
|
+
active: interactive,
|
|
4764
|
+
onSubmit: tool.onResult,
|
|
4765
|
+
onDecision: tool.onDecision
|
|
4766
|
+
}
|
|
4767
|
+
);
|
|
4768
|
+
}
|
|
4744
4769
|
if (hasApproval.value || state.value === "awaiting-approval") {
|
|
4745
4770
|
return /* @__PURE__ */ jsx16(ToolApproval, { part, strings, active: interactive, onDecision: tool.onDecision });
|
|
4746
4771
|
}
|
|
4747
|
-
if (isAskUserInputTool(part.toolName) || state.value === "awaiting-input") {
|
|
4748
|
-
return /* @__PURE__ */ jsx16(ToolAskInput, { part, strings, active: interactive, onSubmit: tool.onResult });
|
|
4749
|
-
}
|
|
4750
4772
|
}
|
|
4751
4773
|
return showToolCalls ? /* @__PURE__ */ jsx16(ToolChip, { part, strings }) : null;
|
|
4752
4774
|
}
|
|
@@ -4809,19 +4831,23 @@ function MessageList({
|
|
|
4809
4831
|
const [showJump, setShowJump] = useState6(false);
|
|
4810
4832
|
const [scrolling, setScrolling] = useState6(false);
|
|
4811
4833
|
const hasHydratedRef = useRef5(false);
|
|
4834
|
+
const detachedRef = useRef5(false);
|
|
4835
|
+
const autoPinAtRef = useRef5(0);
|
|
4836
|
+
const pinBottom = (el) => {
|
|
4837
|
+
autoPinAtRef.current = performance.now();
|
|
4838
|
+
el.scrollTop = el.scrollHeight;
|
|
4839
|
+
};
|
|
4812
4840
|
const firstMessageId = messages.value[0]?.id;
|
|
4813
4841
|
useLayoutEffect(() => {
|
|
4814
4842
|
const el = ref.current;
|
|
4815
4843
|
if (!el) return;
|
|
4816
4844
|
if (messages.value.length === 0) return;
|
|
4817
4845
|
hasHydratedRef.current = true;
|
|
4818
|
-
const
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
pinBottom();
|
|
4822
|
-
const resizeObs = new ResizeObserver(pinBottom);
|
|
4846
|
+
const pinNow = () => pinBottom(el);
|
|
4847
|
+
pinNow();
|
|
4848
|
+
const resizeObs = new ResizeObserver(pinNow);
|
|
4823
4849
|
resizeObs.observe(el);
|
|
4824
|
-
const mutationObs = new MutationObserver(
|
|
4850
|
+
const mutationObs = new MutationObserver(pinNow);
|
|
4825
4851
|
mutationObs.observe(el, { childList: true, subtree: true, characterData: true });
|
|
4826
4852
|
const timerId = setTimeout(() => {
|
|
4827
4853
|
resizeObs.disconnect();
|
|
@@ -4837,8 +4863,14 @@ function MessageList({
|
|
|
4837
4863
|
const el = ref.current;
|
|
4838
4864
|
if (!el) return;
|
|
4839
4865
|
if (!hasHydratedRef.current) return;
|
|
4866
|
+
if (messages.value.at(-1)?.role === "user") {
|
|
4867
|
+
detachedRef.current = false;
|
|
4868
|
+
pinBottom(el);
|
|
4869
|
+
return;
|
|
4870
|
+
}
|
|
4871
|
+
if (detachedRef.current) return;
|
|
4840
4872
|
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4841
|
-
if (distanceFromBottom < STICK_THRESHOLD) el
|
|
4873
|
+
if (distanceFromBottom < STICK_THRESHOLD) pinBottom(el);
|
|
4842
4874
|
}, [messages.value.length]);
|
|
4843
4875
|
useEffect8(() => {
|
|
4844
4876
|
const el = ref.current;
|
|
@@ -4846,8 +4878,9 @@ function MessageList({
|
|
|
4846
4878
|
const last = messages.value.at(-1);
|
|
4847
4879
|
if (!last) return;
|
|
4848
4880
|
const pinIfNear = () => {
|
|
4881
|
+
if (detachedRef.current) return;
|
|
4849
4882
|
const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4850
|
-
if (distance < STICK_THRESHOLD * 2) el
|
|
4883
|
+
if (distance < STICK_THRESHOLD * 2) pinBottom(el);
|
|
4851
4884
|
};
|
|
4852
4885
|
if (last.status !== "streaming") {
|
|
4853
4886
|
const rafId = requestAnimationFrame(pinIfNear);
|
|
@@ -4861,8 +4894,8 @@ function MessageList({
|
|
|
4861
4894
|
const activeFormId = form?.form.id;
|
|
4862
4895
|
useLayoutEffect(() => {
|
|
4863
4896
|
const el = ref.current;
|
|
4864
|
-
if (!el || !activeFormId) return;
|
|
4865
|
-
el
|
|
4897
|
+
if (!el || !activeFormId || detachedRef.current) return;
|
|
4898
|
+
pinBottom(el);
|
|
4866
4899
|
}, [activeFormId]);
|
|
4867
4900
|
useEffect8(() => {
|
|
4868
4901
|
const el = ref.current;
|
|
@@ -4871,6 +4904,9 @@ function MessageList({
|
|
|
4871
4904
|
let idleTimer;
|
|
4872
4905
|
const onScroll = () => {
|
|
4873
4906
|
syncJump();
|
|
4907
|
+
if (performance.now() - autoPinAtRef.current > 150) {
|
|
4908
|
+
detachedRef.current = el.scrollHeight - el.scrollTop - el.clientHeight > 8;
|
|
4909
|
+
}
|
|
4874
4910
|
setScrolling(true);
|
|
4875
4911
|
clearTimeout(idleTimer);
|
|
4876
4912
|
idleTimer = setTimeout(() => setScrolling(false), DIVIDER_IDLE_MS);
|
|
@@ -4884,7 +4920,9 @@ function MessageList({
|
|
|
4884
4920
|
}, []);
|
|
4885
4921
|
const jumpToBottom = () => {
|
|
4886
4922
|
const el = ref.current;
|
|
4887
|
-
if (el)
|
|
4923
|
+
if (!el) return;
|
|
4924
|
+
detachedRef.current = false;
|
|
4925
|
+
pinBottom(el);
|
|
4888
4926
|
};
|
|
4889
4927
|
const rows = [];
|
|
4890
4928
|
let prevDay = "";
|