@tangle-network/agent-app 0.43.4 → 0.43.5
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/assistant/index.d.ts +4 -0
- package/dist/assistant/index.js +93 -19
- package/dist/assistant/index.js.map +1 -1
- package/dist/{chunk-VKHB7VP4.js → chunk-4X7OOVII.js} +38 -8
- package/dist/chunk-4X7OOVII.js.map +1 -0
- package/dist/web-react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-VKHB7VP4.js.map +0 -1
|
@@ -397,6 +397,10 @@ interface AssistantState {
|
|
|
397
397
|
code: string;
|
|
398
398
|
message: string;
|
|
399
399
|
} | null;
|
|
400
|
+
/** True when the most-recent turn stopped at the per-turn step limit before the
|
|
401
|
+
* model finished (a partial reply). Drives the one-click "Continue" affordance;
|
|
402
|
+
* cleared when the next turn starts. */
|
|
403
|
+
capped: boolean;
|
|
400
404
|
}
|
|
401
405
|
|
|
402
406
|
/**
|
package/dist/assistant/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ChatMessages,
|
|
4
4
|
ModelPicker,
|
|
5
5
|
ProviderLogo
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-4X7OOVII.js";
|
|
7
7
|
import "../chunk-65P3HJY3.js";
|
|
8
8
|
import "../chunk-2QI7XV2T.js";
|
|
9
9
|
import "../chunk-E7QYOOON.js";
|
|
@@ -779,7 +779,8 @@ function initialAssistantState() {
|
|
|
779
779
|
usage: null,
|
|
780
780
|
model: null,
|
|
781
781
|
reasoning: null,
|
|
782
|
-
error: null
|
|
782
|
+
error: null,
|
|
783
|
+
capped: false
|
|
783
784
|
};
|
|
784
785
|
}
|
|
785
786
|
function selectVisibleState(state, userId) {
|
|
@@ -915,13 +916,14 @@ function applyStreamEvent(state, event) {
|
|
|
915
916
|
};
|
|
916
917
|
case "done": {
|
|
917
918
|
let messages = dropEmptyStreaming(state.messages, state.streamingId);
|
|
918
|
-
|
|
919
|
+
const capped = event.data.capped === true;
|
|
920
|
+
if (capped) {
|
|
919
921
|
messages = capMessages([
|
|
920
922
|
...messages,
|
|
921
923
|
{
|
|
922
924
|
id: `cap-${event.data.turnId}`,
|
|
923
925
|
role: "status",
|
|
924
|
-
text: "
|
|
926
|
+
text: "Paused after a lot of steps \u2014 continue when you're ready and I'll pick up where I left off."
|
|
925
927
|
}
|
|
926
928
|
]);
|
|
927
929
|
}
|
|
@@ -929,6 +931,7 @@ function applyStreamEvent(state, event) {
|
|
|
929
931
|
...state,
|
|
930
932
|
messages,
|
|
931
933
|
streamingId: null,
|
|
934
|
+
capped,
|
|
932
935
|
status: state.pendingProposals.length > 0 ? "awaiting_confirm" : "idle"
|
|
933
936
|
};
|
|
934
937
|
}
|
|
@@ -963,6 +966,8 @@ function assistantReducer(state, action) {
|
|
|
963
966
|
// from this base, so they stay unique across turns.
|
|
964
967
|
streamBaseId: action.assistantId,
|
|
965
968
|
segmentSeq: 0,
|
|
969
|
+
// A new turn clears the prior turn's cap state (and its Continue button).
|
|
970
|
+
capped: false,
|
|
966
971
|
usage: null,
|
|
967
972
|
reasoning: null,
|
|
968
973
|
error: null
|
|
@@ -1520,12 +1525,12 @@ function useAssistantThreads(userId) {
|
|
|
1520
1525
|
import { MessageSquare } from "lucide-react";
|
|
1521
1526
|
import {
|
|
1522
1527
|
useEffect as useEffect6,
|
|
1523
|
-
useRef as
|
|
1528
|
+
useRef as useRef7
|
|
1524
1529
|
} from "react";
|
|
1525
1530
|
|
|
1526
1531
|
// src/assistant/AssistantPanel.tsx
|
|
1527
1532
|
import { History, MessageSquarePlus, Minus, Plus, X } from "lucide-react";
|
|
1528
|
-
import { useEffect as useEffect5, useMemo as useMemo3, useRef as
|
|
1533
|
+
import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef5, useState as useState6 } from "react";
|
|
1529
1534
|
|
|
1530
1535
|
// src/assistant/AssistantHistory.tsx
|
|
1531
1536
|
import { Search, Trash2 } from "lucide-react";
|
|
@@ -2086,6 +2091,32 @@ function useIsDesktop() {
|
|
|
2086
2091
|
return isDesktop;
|
|
2087
2092
|
}
|
|
2088
2093
|
|
|
2094
|
+
// src/assistant/use-stick-to-bottom.ts
|
|
2095
|
+
import { useCallback as useCallback5, useLayoutEffect, useRef as useRef4 } from "react";
|
|
2096
|
+
var STICK_SLACK_PX = 48;
|
|
2097
|
+
function useStickToBottom(ref, { enabled, contentSignature, streamingId, threadId }) {
|
|
2098
|
+
const stuckRef = useRef4(true);
|
|
2099
|
+
const prevStreamingRef = useRef4(streamingId);
|
|
2100
|
+
const prevThreadRef = useRef4(threadId);
|
|
2101
|
+
const onScroll = useCallback5(() => {
|
|
2102
|
+
if (!enabled) return;
|
|
2103
|
+
const el = ref.current;
|
|
2104
|
+
if (!el) return;
|
|
2105
|
+
stuckRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < STICK_SLACK_PX;
|
|
2106
|
+
}, [ref, enabled]);
|
|
2107
|
+
useLayoutEffect(() => {
|
|
2108
|
+
const turnStarted = streamingId != null && streamingId !== prevStreamingRef.current;
|
|
2109
|
+
const threadChanged = threadId !== prevThreadRef.current;
|
|
2110
|
+
prevStreamingRef.current = streamingId;
|
|
2111
|
+
prevThreadRef.current = threadId;
|
|
2112
|
+
if (turnStarted || threadChanged) stuckRef.current = true;
|
|
2113
|
+
if (!enabled || !stuckRef.current) return;
|
|
2114
|
+
const el = ref.current;
|
|
2115
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
2116
|
+
}, [ref, enabled, contentSignature, streamingId, threadId]);
|
|
2117
|
+
return { onScroll };
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2089
2120
|
// src/assistant/AssistantPanel.tsx
|
|
2090
2121
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2091
2122
|
var EMPTY_STATE = "Ask me to create a workflow, check your usage, or manage your API keys.";
|
|
@@ -2144,15 +2175,15 @@ function AssistantPanel({
|
|
|
2144
2175
|
const threads = useAssistantThreads(userId);
|
|
2145
2176
|
const font = useFontScale();
|
|
2146
2177
|
const [view, setView] = useState6("chat");
|
|
2147
|
-
const historyButtonRef =
|
|
2148
|
-
const logRef =
|
|
2178
|
+
const historyButtonRef = useRef5(null);
|
|
2179
|
+
const logRef = useRef5(null);
|
|
2149
2180
|
const pickerModels = useMemo3(
|
|
2150
2181
|
() => toPickerModels(models, chat.selectedModel),
|
|
2151
2182
|
[models, chat.selectedModel]
|
|
2152
2183
|
);
|
|
2153
2184
|
const pickerValue = chat.selectedModel ?? models.default ?? "";
|
|
2154
2185
|
const { state } = chat;
|
|
2155
|
-
const chatRef =
|
|
2186
|
+
const chatRef = useRef5(chat);
|
|
2156
2187
|
chatRef.current = chat;
|
|
2157
2188
|
useEffect5(() => {
|
|
2158
2189
|
if (view !== "history") return;
|
|
@@ -2176,6 +2207,26 @@ function AssistantPanel({
|
|
|
2176
2207
|
document.addEventListener("keydown", onKeyDownCapture, true);
|
|
2177
2208
|
return () => document.removeEventListener("keydown", onKeyDownCapture, true);
|
|
2178
2209
|
}, [view]);
|
|
2210
|
+
const contentSignature = useMemo3(() => {
|
|
2211
|
+
let sig = `${state.reasoning?.length ?? 0}|${state.status}`;
|
|
2212
|
+
for (const m of state.messages) {
|
|
2213
|
+
sig += `|${m.text?.length ?? 0}`;
|
|
2214
|
+
if (m.tool) sig += `:${m.tool.status}`;
|
|
2215
|
+
}
|
|
2216
|
+
for (const p of state.pendingProposals) sig += `|p:${p.callId}`;
|
|
2217
|
+
return sig;
|
|
2218
|
+
}, [
|
|
2219
|
+
state.messages,
|
|
2220
|
+
state.reasoning,
|
|
2221
|
+
state.status,
|
|
2222
|
+
state.pendingProposals
|
|
2223
|
+
]);
|
|
2224
|
+
const { onScroll: handleConversationScroll } = useStickToBottom(logRef, {
|
|
2225
|
+
enabled: view === "chat",
|
|
2226
|
+
contentSignature,
|
|
2227
|
+
streamingId: state.streamingId,
|
|
2228
|
+
threadId: state.threadId
|
|
2229
|
+
});
|
|
2179
2230
|
const effectiveBalance = state.usage?.balanceUsd ?? balanceUsd;
|
|
2180
2231
|
const errorView = state.error ? presentError(state.error.code, state.error.message) : null;
|
|
2181
2232
|
const low = isLowBalance(effectiveBalance) && !errorView;
|
|
@@ -2326,6 +2377,7 @@ function AssistantPanel({
|
|
|
2326
2377
|
ref: logRef,
|
|
2327
2378
|
tabIndex: -1,
|
|
2328
2379
|
"aria-label": "Conversation",
|
|
2380
|
+
onScroll: handleConversationScroll,
|
|
2329
2381
|
role: view === "chat" ? "log" : void 0,
|
|
2330
2382
|
"aria-live": view === "chat" ? "polite" : void 0,
|
|
2331
2383
|
className: "min-h-0 flex-1 overflow-y-auto focus:outline-none",
|
|
@@ -2403,6 +2455,28 @@ function AssistantPanel({
|
|
|
2403
2455
|
]
|
|
2404
2456
|
}
|
|
2405
2457
|
),
|
|
2458
|
+
state.capped && state.status === "idle" && !chat.restoring && view === "chat" && /* @__PURE__ */ jsxs4(
|
|
2459
|
+
"div",
|
|
2460
|
+
{
|
|
2461
|
+
role: "status",
|
|
2462
|
+
className: "mx-4 mb-2 flex items-center gap-3 rounded-lg border border-border bg-muted/40 px-3 py-2 text-sm",
|
|
2463
|
+
children: [
|
|
2464
|
+
/* @__PURE__ */ jsx5("p", { className: "min-w-0 flex-1 text-foreground", children: "Paused after a lot of steps." }),
|
|
2465
|
+
/* @__PURE__ */ jsx5(
|
|
2466
|
+
"button",
|
|
2467
|
+
{
|
|
2468
|
+
type: "button",
|
|
2469
|
+
onClick: () => {
|
|
2470
|
+
setView("chat");
|
|
2471
|
+
chat.send("continue");
|
|
2472
|
+
},
|
|
2473
|
+
className: "shrink-0 rounded-lg bg-primary px-3 py-1.5 font-semibold text-primary-foreground text-xs transition hover:bg-primary/90 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2474
|
+
children: "Continue"
|
|
2475
|
+
}
|
|
2476
|
+
)
|
|
2477
|
+
]
|
|
2478
|
+
}
|
|
2479
|
+
),
|
|
2406
2480
|
/* @__PURE__ */ jsxs4("div", { className: "border-border border-t p-2", children: [
|
|
2407
2481
|
streaming && /* @__PURE__ */ jsx5("div", { className: "px-2 pb-1.5", "aria-label": "Assistant is working", children: /* @__PURE__ */ jsx5(WorkingIndicator, {}) }),
|
|
2408
2482
|
/* @__PURE__ */ jsx5(
|
|
@@ -2433,7 +2507,7 @@ function AssistantPanel({
|
|
|
2433
2507
|
// src/assistant/launcher.tsx
|
|
2434
2508
|
import {
|
|
2435
2509
|
createContext as createContext2,
|
|
2436
|
-
useCallback as
|
|
2510
|
+
useCallback as useCallback6,
|
|
2437
2511
|
useContext as useContext2,
|
|
2438
2512
|
useMemo as useMemo4,
|
|
2439
2513
|
useState as useState7
|
|
@@ -2445,12 +2519,12 @@ function AssistantLauncherProvider({
|
|
|
2445
2519
|
}) {
|
|
2446
2520
|
const [open, setOpen] = useState7(false);
|
|
2447
2521
|
const [seed, setSeed] = useState7(null);
|
|
2448
|
-
const openAssistant =
|
|
2522
|
+
const openAssistant = useCallback6((next) => {
|
|
2449
2523
|
if (next != null) setSeed(next);
|
|
2450
2524
|
setOpen(true);
|
|
2451
2525
|
}, []);
|
|
2452
|
-
const closeAssistant =
|
|
2453
|
-
const clearSeed =
|
|
2526
|
+
const closeAssistant = useCallback6(() => setOpen(false), []);
|
|
2527
|
+
const clearSeed = useCallback6(() => setSeed(null), []);
|
|
2454
2528
|
const value = useMemo4(
|
|
2455
2529
|
() => ({ open, seed, openAssistant, closeAssistant, clearSeed }),
|
|
2456
2530
|
[open, seed, openAssistant, closeAssistant, clearSeed]
|
|
@@ -2468,7 +2542,7 @@ function useAssistantLauncher() {
|
|
|
2468
2542
|
}
|
|
2469
2543
|
|
|
2470
2544
|
// src/assistant/ResizeHandle.tsx
|
|
2471
|
-
import { useRef as
|
|
2545
|
+
import { useRef as useRef6 } from "react";
|
|
2472
2546
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2473
2547
|
function ResizeHandle({
|
|
2474
2548
|
width,
|
|
@@ -2477,7 +2551,7 @@ function ResizeHandle({
|
|
|
2477
2551
|
onCommit,
|
|
2478
2552
|
onNudge
|
|
2479
2553
|
}) {
|
|
2480
|
-
const dragRef =
|
|
2554
|
+
const dragRef = useRef6(null);
|
|
2481
2555
|
const onPointerDown = (e) => {
|
|
2482
2556
|
if (e.button !== 0) return;
|
|
2483
2557
|
e.preventDefault();
|
|
@@ -2568,10 +2642,10 @@ function AssistantDock({
|
|
|
2568
2642
|
const chat = useAssistantChat(userId, { onWorkflowMutation });
|
|
2569
2643
|
const isDesktop = useIsDesktop();
|
|
2570
2644
|
const { width, maxWidth, setWidth, previewWidth, nudgeWidth } = usePanelWidth();
|
|
2571
|
-
const launcherRef =
|
|
2572
|
-
const dialogRef =
|
|
2573
|
-
const returnFocusRef =
|
|
2574
|
-
const wasOpenRef =
|
|
2645
|
+
const launcherRef = useRef7(null);
|
|
2646
|
+
const dialogRef = useRef7(null);
|
|
2647
|
+
const returnFocusRef = useRef7(null);
|
|
2648
|
+
const wasOpenRef = useRef7(false);
|
|
2575
2649
|
useEffect6(() => {
|
|
2576
2650
|
if (!open) return;
|
|
2577
2651
|
const onKeyDown = (e) => {
|