@tangle-network/sandbox-ui 0.104.1 → 0.105.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/chat.d.ts +53 -48
- package/dist/{chunk-7KB22BLB.js → chunk-FW77EXKG.js} +63 -21
- package/dist/{chunk-4VLVVKQZ.js → chunk-MXQT46AZ.js} +1 -1
- package/dist/{chunk-NAWEV5UJ.js → chunk-NT6SCOY2.js} +1 -1
- package/dist/hooks.d.ts +3 -2
- package/dist/hooks.js +1 -1
- package/dist/index.js +3 -3
- package/dist/terminal.js +2 -2
- package/dist/workbench.js +3 -3
- package/package.json +1 -1
package/dist/chat.d.ts
CHANGED
|
@@ -60,10 +60,9 @@ declare function ReasoningLevelPicker({ value, onChange, disabled, className, tr
|
|
|
60
60
|
/**
|
|
61
61
|
* Limits applied when staging files onto a composer.
|
|
62
62
|
*
|
|
63
|
-
* @
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* breaking release.
|
|
63
|
+
* Serves {@link AgentComposer}'s attachment lifecycle. `ChatComposer` in
|
|
64
|
+
* `@tangle-network/agent-app/web-react` stages files without a validation or
|
|
65
|
+
* retry step, so it has no equivalent.
|
|
67
66
|
*/
|
|
68
67
|
interface ComposerFileValidationConfig {
|
|
69
68
|
/** Reject any single file larger than this. */
|
|
@@ -81,10 +80,9 @@ interface ComposerFileValidationConfig {
|
|
|
81
80
|
}
|
|
82
81
|
/** A file that failed validation, paired with a human-readable reason.
|
|
83
82
|
*
|
|
84
|
-
* @
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* breaking release. */
|
|
83
|
+
* Serves {@link AgentComposer}'s attachment lifecycle. `ChatComposer` in
|
|
84
|
+
* `@tangle-network/agent-app/web-react` stages files without a validation or
|
|
85
|
+
* retry step, so it has no equivalent. */
|
|
88
86
|
interface ComposerFileRejection {
|
|
89
87
|
file: File;
|
|
90
88
|
reason: string;
|
|
@@ -94,10 +92,9 @@ interface ComposerFileRejection {
|
|
|
94
92
|
* grammar as the native `<input accept>` attribute. An undefined or empty
|
|
95
93
|
* `accept` accepts everything.
|
|
96
94
|
*
|
|
97
|
-
* @
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* breaking release.
|
|
95
|
+
* Serves {@link AgentComposer}'s attachment lifecycle. `ChatComposer` in
|
|
96
|
+
* `@tangle-network/agent-app/web-react` stages files without a validation or
|
|
97
|
+
* retry step, so it has no equivalent.
|
|
101
98
|
*/
|
|
102
99
|
declare function isAcceptedType(file: File, accept?: string): boolean;
|
|
103
100
|
/**
|
|
@@ -107,10 +104,9 @@ declare function isAcceptedType(file: File, accept?: string): boolean;
|
|
|
107
104
|
* file and the limit it broke. Pure data in, pure data out — no throwing,
|
|
108
105
|
* no console noise, so callers decide how to surface rejections.
|
|
109
106
|
*
|
|
110
|
-
* @
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* breaking release.
|
|
107
|
+
* Serves {@link AgentComposer}'s attachment lifecycle. `ChatComposer` in
|
|
108
|
+
* `@tangle-network/agent-app/web-react` stages files without a validation or
|
|
109
|
+
* retry step, so it has no equivalent.
|
|
114
110
|
*/
|
|
115
111
|
declare function validateComposerFiles(files: File[] | FileList, config: ComposerFileValidationConfig): {
|
|
116
112
|
accepted: File[];
|
|
@@ -120,9 +116,9 @@ declare function validateComposerFiles(files: File[] | FileList, config: Compose
|
|
|
120
116
|
/** A selectable item in the `@`-mention popover. Generic — file semantics live
|
|
121
117
|
* in the consuming app, not here.
|
|
122
118
|
*
|
|
123
|
-
*
|
|
124
|
-
* `@tangle-network/agent-app/web-react`
|
|
125
|
-
*
|
|
119
|
+
* Part of the {@link AgentComposer} API. `ChatComposer` in
|
|
120
|
+
* `@tangle-network/agent-app/web-react` has no equivalent — see
|
|
121
|
+
* {@link AgentComposer} for which composer fits a surface. */
|
|
126
122
|
interface MentionItem {
|
|
127
123
|
id: string;
|
|
128
124
|
label: string;
|
|
@@ -134,9 +130,9 @@ interface MentionItem {
|
|
|
134
130
|
* TipTap rich input that renders mentions as atomic pills; absent ⇒ exactly
|
|
135
131
|
* today's plain-textarea behavior. Data-agnostic: the app supplies items.
|
|
136
132
|
*
|
|
137
|
-
*
|
|
138
|
-
* `@tangle-network/agent-app/web-react`
|
|
139
|
-
*
|
|
133
|
+
* Part of the {@link AgentComposer} API. `ChatComposer` in
|
|
134
|
+
* `@tangle-network/agent-app/web-react` has no equivalent — see
|
|
135
|
+
* {@link AgentComposer} for which composer fits a surface.
|
|
140
136
|
*/
|
|
141
137
|
interface AgentComposerMention {
|
|
142
138
|
/** The character that opens the popover. Default "@". */
|
|
@@ -159,9 +155,9 @@ interface AgentComposerMention {
|
|
|
159
155
|
}
|
|
160
156
|
/** A staged attachment shown as a chip above the input.
|
|
161
157
|
*
|
|
162
|
-
*
|
|
163
|
-
* `@tangle-network/agent-app/web-react`
|
|
164
|
-
*
|
|
158
|
+
* Part of the {@link AgentComposer} API. `ChatComposer` in
|
|
159
|
+
* `@tangle-network/agent-app/web-react` has no equivalent — see
|
|
160
|
+
* {@link AgentComposer} for which composer fits a surface. */
|
|
165
161
|
interface ComposerFile {
|
|
166
162
|
id: string;
|
|
167
163
|
name: string;
|
|
@@ -181,9 +177,9 @@ interface ComposerFile {
|
|
|
181
177
|
}
|
|
182
178
|
/** Context the agent will see alongside the next message.
|
|
183
179
|
*
|
|
184
|
-
*
|
|
185
|
-
* `@tangle-network/agent-app/web-react`
|
|
186
|
-
*
|
|
180
|
+
* Part of the {@link AgentComposer} API. `ChatComposer` in
|
|
181
|
+
* `@tangle-network/agent-app/web-react` has no equivalent — see
|
|
182
|
+
* {@link AgentComposer} for which composer fits a surface. */
|
|
187
183
|
interface ComposerContextItem {
|
|
188
184
|
id: string;
|
|
189
185
|
label: string;
|
|
@@ -192,11 +188,11 @@ interface ComposerContextItem {
|
|
|
192
188
|
onRemove?: () => void;
|
|
193
189
|
}
|
|
194
190
|
/**
|
|
195
|
-
* Props of
|
|
191
|
+
* Props of {@link AgentComposer}.
|
|
196
192
|
*
|
|
197
|
-
*
|
|
198
|
-
* `@tangle-network/agent-app/web-react`
|
|
199
|
-
*
|
|
193
|
+
* Part of the {@link AgentComposer} API. `ChatComposer` in
|
|
194
|
+
* `@tangle-network/agent-app/web-react` has no equivalent — see
|
|
195
|
+
* {@link AgentComposer} for which composer fits a surface.
|
|
200
196
|
*/
|
|
201
197
|
interface AgentComposerProps {
|
|
202
198
|
/** Composer text (controlled). */
|
|
@@ -288,25 +284,35 @@ interface AgentComposerProps {
|
|
|
288
284
|
autoFocus?: boolean;
|
|
289
285
|
}
|
|
290
286
|
/**
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* `sendVariant="icon"`. Plan a port, not a rename: 14 of the 28 props here
|
|
295
|
-
* have no same-named counterpart there, among them `contextItems`, `mention`,
|
|
296
|
-
* `trailing`, `maxHeight`, `minRows`, and `autoFocus`. The control model also
|
|
297
|
-
* differs — this component requires `value` and `onChange` and calls
|
|
298
|
-
* `onSubmit` with no arguments, while `ChatComposer` can own its draft and
|
|
299
|
-
* gives the message to a refusable `onSend`. This slot-shell is frozen and
|
|
300
|
-
* will be removed at sandbox-ui's next breaking release.
|
|
287
|
+
* Sibling of `ChatComposer` in `@tangle-network/agent-app/web-react`, not a
|
|
288
|
+
* predecessor of it. The two composers cover different jobs, and neither is a
|
|
289
|
+
* superset of the other, so pick by the features a surface needs.
|
|
301
290
|
*
|
|
302
|
-
*
|
|
291
|
+
* Reach for `AgentComposer` when the surface needs `@`-mentions (`mention`,
|
|
292
|
+
* backed by a lazily loaded rich-text input that renders mention pills),
|
|
293
|
+
* `contextItems`, or the full attachment lifecycle — `attachments` plus
|
|
294
|
+
* `onRejectFiles` and `onRetryFile`. It also owns `autoFocus`,
|
|
295
|
+
* `canSubmitAttachmentsOnly`, `trailing`, `maxHeight`, and `minRows`.
|
|
296
|
+
*
|
|
297
|
+
* Reach for `ChatComposer` when the surface is a plain send box. It owns
|
|
298
|
+
* send-failure recovery (`onSendFailed`, `sendFailureMessage`), one-shot
|
|
299
|
+
* prefill (`seed`), `controlsPlacement`, `floating`, `sendVariant`,
|
|
300
|
+
* parts-aware sends (`onSendParts`), and an uncontrolled mode
|
|
301
|
+
* (`initialValue`) — none of which exist here.
|
|
302
|
+
*
|
|
303
|
+
* Moving between them is a port, not a rename: the control models differ. This
|
|
304
|
+
* component requires `value` and `onChange` and calls `onSubmit` with no
|
|
305
|
+
* arguments, while `ChatComposer` can own its draft and hands the message to a
|
|
306
|
+
* refusable `onSend`.
|
|
307
|
+
*
|
|
308
|
+
* The input itself: one rounded surface holding an auto-growing
|
|
303
309
|
* textarea and a bottom row that runs left → right — attach buttons, the
|
|
304
310
|
* control strip (supplied via the required `controls` prop), trailing slot,
|
|
305
311
|
* and the send button on the far right. The strip is explicit: the canonical
|
|
306
312
|
* pickers are `ModelPicker` / `EffortPicker` / `AgentSessionControls` from
|
|
307
313
|
* `@tangle-network/agent-app/web-react` — this component only owns the slot.
|
|
308
314
|
*
|
|
309
|
-
* Opt-in extras
|
|
315
|
+
* Opt-in extras cover what apps otherwise hand-roll:
|
|
310
316
|
* file/folder attachments with drag-and-drop + chips + clipboard paste
|
|
311
317
|
* (`onAttach` also gates pasting files onto the textarea, auto-naming
|
|
312
318
|
* generic clipboard image blobs `pasted-image-<n>.<ext>`), a streaming Stop
|
|
@@ -323,10 +329,9 @@ declare function AgentComposer({ value, onChange, onSubmit, placeholder, disable
|
|
|
323
329
|
* importing it never pulls the lazily-loaded editor chunk into a consumer's
|
|
324
330
|
* bundle.
|
|
325
331
|
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
* sandbox-ui's next breaking release.
|
|
332
|
+
* Mention-pill contract of {@link AgentComposer}'s mention feature.
|
|
333
|
+
* `ChatComposer` in `@tangle-network/agent-app/web-react` has no mention
|
|
334
|
+
* support, so it has no equivalent.
|
|
330
335
|
*/
|
|
331
336
|
declare const MENTION_PILL_CLASS: string;
|
|
332
337
|
|
|
@@ -3,7 +3,7 @@ import { useState, useEffect, useRef, useCallback } from "react";
|
|
|
3
3
|
function createEmptyBatch() {
|
|
4
4
|
return { data: "", waiters: [] };
|
|
5
5
|
}
|
|
6
|
-
var
|
|
6
|
+
var WS_READY_TIMEOUT_MS = 1e4;
|
|
7
7
|
function toWsUrl(apiUrl, sessionId) {
|
|
8
8
|
try {
|
|
9
9
|
const base = typeof window !== "undefined" ? window.location.href : void 0;
|
|
@@ -64,6 +64,7 @@ function usePtySession({
|
|
|
64
64
|
const reconnectRef = useRef(null);
|
|
65
65
|
const shouldDeleteSessionRef = useRef(false);
|
|
66
66
|
const transportReadyRef = useRef(false);
|
|
67
|
+
const protocolFailureRef = useRef(false);
|
|
67
68
|
const colsRef = useRef(DEFAULT_TERMINAL_COLS);
|
|
68
69
|
const rowsRef = useRef(DEFAULT_TERMINAL_ROWS);
|
|
69
70
|
const wsRef = useRef(null);
|
|
@@ -169,13 +170,25 @@ function usePtySession({
|
|
|
169
170
|
resolve(ok);
|
|
170
171
|
};
|
|
171
172
|
const handshakeTimer = setTimeout(() => {
|
|
172
|
-
if (opened) return;
|
|
173
173
|
try {
|
|
174
174
|
ws.close();
|
|
175
175
|
} catch {
|
|
176
176
|
}
|
|
177
177
|
settle(false);
|
|
178
|
-
},
|
|
178
|
+
}, WS_READY_TIMEOUT_MS);
|
|
179
|
+
const failProtocol = (message) => {
|
|
180
|
+
protocolFailureRef.current = true;
|
|
181
|
+
transportReadyRef.current = false;
|
|
182
|
+
if (wsRef.current === ws) wsRef.current = null;
|
|
183
|
+
setIsConnected(false);
|
|
184
|
+
setError(message);
|
|
185
|
+
rejectPendingInput(message);
|
|
186
|
+
try {
|
|
187
|
+
ws.close();
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
settle(false);
|
|
191
|
+
};
|
|
179
192
|
ws.onopen = () => {
|
|
180
193
|
opened = true;
|
|
181
194
|
if (pendingWsRef.current !== ws || !mountedRef.current) {
|
|
@@ -212,12 +225,8 @@ function usePtySession({
|
|
|
212
225
|
return;
|
|
213
226
|
}
|
|
214
227
|
}
|
|
228
|
+
if (protocolFailureRef.current) return;
|
|
215
229
|
wsRef.current = ws;
|
|
216
|
-
transportReadyRef.current = true;
|
|
217
|
-
setIsConnected(true);
|
|
218
|
-
setError(null);
|
|
219
|
-
retryCountRef.current = 0;
|
|
220
|
-
settle(true);
|
|
221
230
|
};
|
|
222
231
|
ws.onmessage = (ev) => {
|
|
223
232
|
if (!mountedRef.current) return;
|
|
@@ -239,17 +248,38 @@ function usePtySession({
|
|
|
239
248
|
if (typeof data === "string") {
|
|
240
249
|
try {
|
|
241
250
|
const event = JSON.parse(text);
|
|
242
|
-
if (event
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
if (event !== null && typeof event === "object" && !Array.isArray(event)) {
|
|
252
|
+
const controlFrame = event;
|
|
253
|
+
switch (controlFrame.type) {
|
|
254
|
+
case "ready":
|
|
255
|
+
transportReadyRef.current = true;
|
|
256
|
+
setIsConnected(true);
|
|
257
|
+
setError(null);
|
|
258
|
+
retryCountRef.current = 0;
|
|
259
|
+
settle(true);
|
|
260
|
+
return;
|
|
261
|
+
case "error": {
|
|
262
|
+
const message = typeof controlFrame.message === "string" ? controlFrame.message : "Terminal WebSocket error";
|
|
263
|
+
if (!transportReadyRef.current) {
|
|
264
|
+
failProtocol(message);
|
|
265
|
+
} else {
|
|
266
|
+
setError(message);
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
case "exit":
|
|
271
|
+
transportReadyRef.current = false;
|
|
272
|
+
setIsConnected(false);
|
|
273
|
+
return;
|
|
274
|
+
case "rec":
|
|
275
|
+
case "rec.done":
|
|
276
|
+
return;
|
|
277
|
+
default: {
|
|
278
|
+
const frameType = typeof controlFrame.type === "string" ? controlFrame.type : "<missing type>";
|
|
279
|
+
failProtocol(`Unknown terminal control frame: ${frameType}`);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
253
283
|
}
|
|
254
284
|
} catch {
|
|
255
285
|
}
|
|
@@ -263,6 +293,7 @@ function usePtySession({
|
|
|
263
293
|
pendingWsRef.current = null;
|
|
264
294
|
}
|
|
265
295
|
const wasActive = wsRef.current === ws;
|
|
296
|
+
const wasReady = wasActive && transportReadyRef.current;
|
|
266
297
|
if (wasActive) {
|
|
267
298
|
wsRef.current = null;
|
|
268
299
|
transportReadyRef.current = false;
|
|
@@ -271,7 +302,11 @@ function usePtySession({
|
|
|
271
302
|
settle(false);
|
|
272
303
|
return;
|
|
273
304
|
}
|
|
274
|
-
if (!
|
|
305
|
+
if (!wasReady) {
|
|
306
|
+
settle(false);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (protocolFailureRef.current || !wasActive || !mountedRef.current) return;
|
|
275
310
|
setIsConnected(false);
|
|
276
311
|
if (sessionIdRef.current) {
|
|
277
312
|
retryTimerRef.current = setTimeout(() => {
|
|
@@ -286,7 +321,7 @@ function usePtySession({
|
|
|
286
321
|
}
|
|
287
322
|
};
|
|
288
323
|
});
|
|
289
|
-
}, [apiUrl]);
|
|
324
|
+
}, [apiUrl, rejectPendingInput]);
|
|
290
325
|
const connectStream = useCallback(async (sessionId) => {
|
|
291
326
|
if (exactAttachRequiredRef.current) {
|
|
292
327
|
throw new Error(
|
|
@@ -387,6 +422,7 @@ function usePtySession({
|
|
|
387
422
|
const connect = useCallback(async () => {
|
|
388
423
|
cleanup();
|
|
389
424
|
const myGen = ++connectGenRef.current;
|
|
425
|
+
protocolFailureRef.current = false;
|
|
390
426
|
retryCountRef.current = 0;
|
|
391
427
|
setError(null);
|
|
392
428
|
if (exactAttachRequiredRef.current && (!incarnationIdRef.current || !controlRef.current)) {
|
|
@@ -402,6 +438,7 @@ function usePtySession({
|
|
|
402
438
|
inputAbortRef.current = new AbortController();
|
|
403
439
|
const directWsOk = await connectWs(connectionId, { initOnOpen: true });
|
|
404
440
|
if (!mountedRef.current || connectGenRef.current !== myGen) return;
|
|
441
|
+
if (protocolFailureRef.current) return;
|
|
405
442
|
ensureDrainRunningRef.current?.();
|
|
406
443
|
if (directWsOk) {
|
|
407
444
|
return;
|
|
@@ -442,6 +479,7 @@ function usePtySession({
|
|
|
442
479
|
inputAbortRef.current = new AbortController();
|
|
443
480
|
const wsOk = await connectWs(sessionId, { initOnOpen: true });
|
|
444
481
|
if (!mountedRef.current || connectGenRef.current !== myGen) return;
|
|
482
|
+
if (protocolFailureRef.current) return;
|
|
445
483
|
ensureDrainRunningRef.current?.();
|
|
446
484
|
if (wsOk) {
|
|
447
485
|
return;
|
|
@@ -564,6 +602,10 @@ function usePtySession({
|
|
|
564
602
|
resolve();
|
|
565
603
|
return;
|
|
566
604
|
}
|
|
605
|
+
if (protocolFailureRef.current) {
|
|
606
|
+
reject(new Error("Terminal protocol failure"));
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
567
609
|
pendingBatchRef.current.data += command;
|
|
568
610
|
pendingBatchRef.current.waiters.push({ resolve, reject });
|
|
569
611
|
ensureDrainRunning();
|
package/dist/hooks.d.ts
CHANGED
|
@@ -51,8 +51,9 @@ interface UsePtySessionReturn {
|
|
|
51
51
|
* - Server → client: BINARY frames carrying PTY output; TEXT frames
|
|
52
52
|
* carrying lifecycle/control messages.
|
|
53
53
|
* - Client → server: TEXT frames carrying JSON input/resize messages.
|
|
54
|
-
* 2. If direct WS does not reach
|
|
55
|
-
* errors before
|
|
54
|
+
* 2. If direct WS does not reach server `ready` within
|
|
55
|
+
* WS_READY_TIMEOUT_MS, or it errors before ready, fall back to the older
|
|
56
|
+
* terminal contract:
|
|
56
57
|
* - POST /terminals creates the session.
|
|
57
58
|
* - GET /terminals/:id/ws tries the older WS transport.
|
|
58
59
|
* - GET /terminals/:id/stream (SSE for output)
|
package/dist/hooks.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -153,7 +153,7 @@ import {
|
|
|
153
153
|
buildUnifiedPatch,
|
|
154
154
|
computeDiffStats,
|
|
155
155
|
resolveLanguage
|
|
156
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-NT6SCOY2.js";
|
|
157
157
|
import {
|
|
158
158
|
FileArtifactPane,
|
|
159
159
|
FilePreview,
|
|
@@ -238,10 +238,10 @@ import {
|
|
|
238
238
|
UsageChart,
|
|
239
239
|
formatPrice
|
|
240
240
|
} from "./chunk-OMUIPJQZ.js";
|
|
241
|
-
import "./chunk-
|
|
241
|
+
import "./chunk-MXQT46AZ.js";
|
|
242
242
|
import {
|
|
243
243
|
usePtySession
|
|
244
|
-
} from "./chunk-
|
|
244
|
+
} from "./chunk-FW77EXKG.js";
|
|
245
245
|
import {
|
|
246
246
|
Avatar,
|
|
247
247
|
AvatarFallback,
|
package/dist/terminal.js
CHANGED
package/dist/workbench.js
CHANGED
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
buildUnifiedPatch,
|
|
13
13
|
computeDiffStats,
|
|
14
14
|
resolveLanguage
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-NT6SCOY2.js";
|
|
16
16
|
import "./chunk-PZVUIUUW.js";
|
|
17
17
|
import "./chunk-K4Q4E7D7.js";
|
|
18
18
|
import "./chunk-OMUIPJQZ.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-MXQT46AZ.js";
|
|
20
|
+
import "./chunk-FW77EXKG.js";
|
|
21
21
|
import "./chunk-2XPJ2XF7.js";
|
|
22
22
|
import "./chunk-RQZRXKMR.js";
|
|
23
23
|
import "./chunk-BGVEHENC.js";
|
package/package.json
CHANGED