@tangle-network/agent-app 0.45.64 → 0.45.66
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.js +2 -2
- package/dist/chat-react/index.js +1 -1
- package/dist/{chunk-FZKNVQYP.js → chunk-23J72UUA.js} +104 -15
- package/dist/chunk-23J72UUA.js.map +1 -0
- package/dist/{chunk-OMGV3CX2.js → chunk-AWM4H5XR.js} +142 -34
- package/dist/chunk-AWM4H5XR.js.map +1 -0
- package/dist/{chunk-HSBJB46C.js → chunk-E2CWFUUP.js} +3 -58
- package/dist/chunk-E2CWFUUP.js.map +1 -0
- package/dist/stories/chat-controls/fixtures.d.ts +5 -1
- package/dist/stories/studio/fixtures.d.ts +0 -4
- package/dist/studio/generation.d.ts +2 -51
- package/dist/studio/index.d.ts +1 -2
- package/dist/studio/index.js +1 -11
- package/dist/studio-react/composer-hero.d.ts +1 -3
- package/dist/studio-react/index.d.ts +3 -5
- package/dist/studio-react/index.js +303 -510
- package/dist/studio-react/index.js.map +1 -1
- package/dist/studio-react/studio-workspace.d.ts +2 -4
- package/dist/web-react/chat-composer.d.ts +87 -5
- package/dist/web-react/composer-file-accept.d.ts +77 -0
- package/dist/web-react/index.d.ts +1 -0
- package/dist/web-react/index.js +10 -2
- package/dist/web-react/use-composer-attachments.d.ts +3 -4
- package/package.json +1 -1
- package/dist/chunk-FZKNVQYP.js.map +0 -1
- package/dist/chunk-HSBJB46C.js.map +0 -1
- package/dist/chunk-OMGV3CX2.js.map +0 -1
- package/dist/studio-react/publish-package-composer.d.ts +0 -18
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ChatComposer — the shared message input every agent app used to hand-roll:
|
|
3
3
|
* an auto-resizing textarea (Enter sends, Shift+Enter inserts a newline), an
|
|
4
|
-
* opt-in attach + drag-and-drop surface with pending-file
|
|
5
|
-
* Stop/Send toggle, a slot for inline controls (model
|
|
6
|
-
* effort), and a Cmd/Ctrl+L focus shortcut.
|
|
4
|
+
* opt-in attach + drag-and-drop + clipboard-paste surface with pending-file
|
|
5
|
+
* chips, a streaming Stop/Send toggle, a slot for inline controls (model
|
|
6
|
+
* picker, reasoning effort), and a Cmd/Ctrl+L focus shortcut.
|
|
7
|
+
*
|
|
8
|
+
* Files arrive by three routes — the picker dialog, a drop, and a paste — and
|
|
9
|
+
* all three funnel through `accept` (`./composer-file-accept`) before they
|
|
10
|
+
* reach `onAttach`, so a type the picker will not offer cannot get in by
|
|
11
|
+
* another route. What `accept` refuses goes to `onRejectFiles` with a reason;
|
|
12
|
+
* without that prop a refusal is silent, which is what the native picker also
|
|
13
|
+
* does. Size and count limits stay the host's job — `useComposerAttachments`
|
|
14
|
+
* owns them, because they depend on what is already staged.
|
|
7
15
|
*
|
|
8
16
|
* A REJECTED send never destroys the draft. The input clears optimistically —
|
|
9
17
|
* the composer stays editable while a turn streams precisely so the next
|
|
@@ -25,6 +33,7 @@
|
|
|
25
33
|
* fallbacks when a host hasn't defined a private chat-token set.
|
|
26
34
|
*/
|
|
27
35
|
import { type ReactNode } from 'react';
|
|
36
|
+
import { type ComposerFileRejection } from './composer-file-accept';
|
|
28
37
|
import { type DictationAudio } from './use-dictation';
|
|
29
38
|
/** Prompt-part descriptor an uploaded file carries (the upload route's
|
|
30
39
|
* `UploadedChatFile.part`), echoed back in the turn body on send. Mirrors
|
|
@@ -48,6 +57,25 @@ export interface ComposerFile {
|
|
|
48
57
|
/** Uploaded part descriptor; set once the upload route returns. Only
|
|
49
58
|
* `status: 'ready'` files with a part travel on a parts-aware send. */
|
|
50
59
|
part?: ComposerFilePart;
|
|
60
|
+
/** Object URL for an image thumbnail on the chip. The host owns the URL's
|
|
61
|
+
* whole life — `URL.createObjectURL` when the file is staged,
|
|
62
|
+
* `URL.revokeObjectURL` when it leaves — and the composer only reads it.
|
|
63
|
+
* `useComposerAttachments` already does both. */
|
|
64
|
+
previewUrl?: string;
|
|
65
|
+
/** Why this file failed, shown on the chip while `status: 'error'`. Without
|
|
66
|
+
* it an error chip is red and mute, which tells the user nothing. */
|
|
67
|
+
errorMessage?: string;
|
|
68
|
+
}
|
|
69
|
+
/** A piece of context the agent will see beside the next message — an open
|
|
70
|
+
* file, a selected record, a pinned document. Rendered as its own chip row,
|
|
71
|
+
* separate from staged attachments: context is what the turn already carries,
|
|
72
|
+
* an attachment is what the user is adding to it. */
|
|
73
|
+
export interface ComposerContextItem {
|
|
74
|
+
id: string;
|
|
75
|
+
label: string;
|
|
76
|
+
icon?: ReactNode;
|
|
77
|
+
/** Omit for a chip the user cannot dismiss. */
|
|
78
|
+
onRemove?: () => void;
|
|
51
79
|
}
|
|
52
80
|
/** A send the host refused. `error` is shown verbatim in the composer's notice;
|
|
53
81
|
* omit it for the generic copy. */
|
|
@@ -169,14 +197,68 @@ export interface ChatComposerProps {
|
|
|
169
197
|
*/
|
|
170
198
|
controlsPlacement?: 'above' | 'inline';
|
|
171
199
|
/** Attachments are opt-in: pass `onAttach` to show the attach button, accept
|
|
172
|
-
* drag-and-drop onto the input, and render
|
|
200
|
+
* drag-and-drop and clipboard paste onto the input, and render
|
|
201
|
+
* `pendingFiles` chips. */
|
|
173
202
|
onAttach?: (files: FileList) => void;
|
|
174
203
|
onAttachFolder?: (files: FileList) => void;
|
|
175
204
|
pendingFiles?: ComposerFile[];
|
|
176
205
|
onRemoveFile?: (id: string) => void;
|
|
206
|
+
/** Pass it and a chip with `status: 'error'` gains a retry button. */
|
|
207
|
+
onRetryFile?: (id: string) => void;
|
|
208
|
+
/**
|
|
209
|
+
* File types the composer takes, in the native `<input accept>` grammar.
|
|
210
|
+
* Enforced on every ingress route — the picker dialog (which the user can
|
|
211
|
+
* override with "All Files"), drag-and-drop, and clipboard paste — so a type
|
|
212
|
+
* the picker will not offer cannot arrive by another route. A non-matching
|
|
213
|
+
* file goes to `onRejectFiles` and never reaches `onAttach`. Folder attach is
|
|
214
|
+
* exempt: directory selection has no native accept semantics.
|
|
215
|
+
*/
|
|
177
216
|
accept?: string;
|
|
217
|
+
/** Called with the files `accept` removed from a pick, drop, or paste, each
|
|
218
|
+
* with a reason. Without it a refusal is silent — the same feedback the
|
|
219
|
+
* native picker gives for a type it will not offer. */
|
|
220
|
+
onRejectFiles?: (rejections: ComposerFileRejection[]) => void;
|
|
178
221
|
dropTitle?: string;
|
|
179
222
|
dropDescription?: string;
|
|
223
|
+
/** Context the agent will see beside the next message, as its own chip row
|
|
224
|
+
* above the input. */
|
|
225
|
+
contextItems?: ReadonlyArray<ComposerContextItem>;
|
|
226
|
+
/**
|
|
227
|
+
* Let a staged file stand in for message text, so the send control stays live
|
|
228
|
+
* while an upload is in flight instead of going dead with nothing to explain
|
|
229
|
+
* it. Default false, where an empty message needs a `ready` file.
|
|
230
|
+
*
|
|
231
|
+
* It does NOT make an unfinished file sendable. A turn whose only content is a
|
|
232
|
+
* file that is still uploading or has failed never reaches the send handler —
|
|
233
|
+
* it would arrive empty and the attachment would be lost. The composer
|
|
234
|
+
* refuses it and names the reason in its notice
|
|
235
|
+
* ({@link attachmentsNotReadyMessage}). So the flag decides whether the
|
|
236
|
+
* control is live, and the composer keeps the integrity gate rather than
|
|
237
|
+
* leaving each host to re-derive it.
|
|
238
|
+
*/
|
|
239
|
+
canSubmitAttachmentsOnly?: boolean;
|
|
240
|
+
/** Notice copy when a send is refused because no staged file is ready yet.
|
|
241
|
+
* Defaults to wording chosen from whether a file failed or is still
|
|
242
|
+
* uploading. */
|
|
243
|
+
attachmentsNotReadyMessage?: string;
|
|
244
|
+
/**
|
|
245
|
+
* Let Enter and Send keep firing while `isStreaming`, for a surface that
|
|
246
|
+
* queues the next turn rather than blocking on the current one. Default
|
|
247
|
+
* false. The button still flips to Stop while a turn streams, so this opens
|
|
248
|
+
* the keyboard path, not a second button.
|
|
249
|
+
*/
|
|
250
|
+
canSubmitWhileBusy?: boolean;
|
|
251
|
+
/** Focus the input on mount — for a surface whose whole job is the input
|
|
252
|
+
* (an entry/hero composer), never for one docked under a transcript. */
|
|
253
|
+
autoFocus?: boolean;
|
|
254
|
+
/** Rows the input shows before it grows. Default 2. */
|
|
255
|
+
minRows?: number;
|
|
256
|
+
/** Pixel height the input grows to before it scrolls. Default 168. */
|
|
257
|
+
maxHeight?: number;
|
|
258
|
+
/** Content between the controls slot and Send — a token meter, a cost, a
|
|
259
|
+
* status line. It sits outside the controls slot and never shrinks, so a
|
|
260
|
+
* wrapping picker set cannot push it away. */
|
|
261
|
+
trailing?: ReactNode;
|
|
180
262
|
/** `/` commands offered when the draft is exactly a leading slash token.
|
|
181
263
|
* Omit (or pass []) and `/` types as ordinary text. */
|
|
182
264
|
slashCommands?: SlashCommand[];
|
|
@@ -204,4 +286,4 @@ export interface ChatComposerProps {
|
|
|
204
286
|
sendVariant?: 'pill' | 'icon';
|
|
205
287
|
className?: string;
|
|
206
288
|
}
|
|
207
|
-
export declare function ChatComposer({ onSend, onSendParts, onSendFailed, sendFailureMessage, onCancel, isStreaming, disabled, placeholder, value, onValueChange, initialValue, seed, onSeedApplied, controls, controlsPlacement, onAttach, onAttachFolder, pendingFiles, onRemoveFile, accept, dropTitle, dropDescription, slashCommands, onDictate, onDictateError, focusShortcut, floating, sendLabel, sendVariant, className, }: ChatComposerProps): import("react").JSX.Element;
|
|
289
|
+
export declare function ChatComposer({ onSend, onSendParts, onSendFailed, sendFailureMessage, onCancel, isStreaming, disabled, placeholder, value, onValueChange, initialValue, seed, onSeedApplied, controls, controlsPlacement, onAttach, onAttachFolder, pendingFiles, onRemoveFile, onRetryFile, accept, onRejectFiles, dropTitle, dropDescription, contextItems, canSubmitAttachmentsOnly, attachmentsNotReadyMessage, canSubmitWhileBusy, autoFocus, minRows, maxHeight, trailing, slashCommands, onDictate, onDictateError, focusShortcut, floating, sendLabel, sendVariant, className, }: ChatComposerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composer's file-ingress filter, and the clipboard rename that goes with
|
|
3
|
+
* it.
|
|
4
|
+
*
|
|
5
|
+
* A file reaches a composer by three routes — the picker dialog, a drag-and-drop,
|
|
6
|
+
* and a clipboard paste — and only the picker gets a native `accept` filter (one
|
|
7
|
+
* the user can defeat with "All Files"). Every route therefore funnels through
|
|
8
|
+
* {@link filterAcceptedFiles}, so a type the picker will not offer cannot arrive
|
|
9
|
+
* by another route instead.
|
|
10
|
+
*
|
|
11
|
+
* One route can still reach a different verdict, and it does so deliberately.
|
|
12
|
+
* Paste is the only route that RENAMES, and {@link renamePastedImages} names a
|
|
13
|
+
* file after the type it declares. So a clipboard bitmap called `image.png` that
|
|
14
|
+
* declares `image/heic` is judged as `.heic` on paste, while the picker and a
|
|
15
|
+
* drop judge the name they were handed and admit it under `accept=".png"`. The
|
|
16
|
+
* filter is the same on all three; what differs is the name it is given, and
|
|
17
|
+
* paste is stricter precisely because a rename that kept the contradicting name
|
|
18
|
+
* would let the composer manufacture its own way past the filter.
|
|
19
|
+
*
|
|
20
|
+
* ONE accept matcher serves the package: `ChatComposer` gates its ingress on it
|
|
21
|
+
* and `useComposerAttachments` gates `addFiles` on it. A second implementation
|
|
22
|
+
* of the `accept` grammar is how the two ends of the same staging path start
|
|
23
|
+
* disagreeing about what a file is.
|
|
24
|
+
*
|
|
25
|
+
* Pure data in, pure data out — nothing here throws, logs, or touches the DOM,
|
|
26
|
+
* so a caller decides how a rejection is surfaced. Import-free beyond the
|
|
27
|
+
* browser's own `File`, which keeps it usable from `/web-react`'s client bundle.
|
|
28
|
+
*/
|
|
29
|
+
/** A file the `accept` list refused, with the reason to show for it. */
|
|
30
|
+
export interface ComposerFileRejection {
|
|
31
|
+
file: File;
|
|
32
|
+
reason: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Checks one file against a comma-separated `accept` list, using the grammar of
|
|
36
|
+
* the native `<input accept>` attribute: extensions (`.png`), exact MIME types
|
|
37
|
+
* (`image/png`), and MIME wildcards (`image/*`). An absent or empty list accepts
|
|
38
|
+
* everything, which is what an unset `accept` prop means.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isAcceptedFileType(file: File, accept?: string): boolean;
|
|
41
|
+
/** The reason an `accept` list refused a file. One wording for every ingress
|
|
42
|
+
* route, so the same file reads the same whether it was picked or dropped. */
|
|
43
|
+
export declare function acceptRejectionReason(file: File, accept: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Splits a batch into what the `accept` list admits and what it refuses. Size
|
|
46
|
+
* and count limits are NOT applied here: they belong to the staging queue, which
|
|
47
|
+
* knows what is already staged (`useComposerAttachments`), while this runs at the
|
|
48
|
+
* composer's edge where that is unknown.
|
|
49
|
+
*/
|
|
50
|
+
export declare function filterAcceptedFiles(files: File[] | FileList, accept?: string): {
|
|
51
|
+
accepted: File[];
|
|
52
|
+
rejected: ComposerFileRejection[];
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Gives every generically-named clipboard image a distinct
|
|
56
|
+
* `pasted-image-<n>.<ext>` name. Two pastes of the same bitmap otherwise arrive
|
|
57
|
+
* as `image.png` twice, and a staging queue that keys on the name treats the
|
|
58
|
+
* second as a duplicate of the first.
|
|
59
|
+
*
|
|
60
|
+
* A number is never reused. The search avoids every `pasted-image-<n>` already
|
|
61
|
+
* present in `stagedNames` (the queue the host still holds, which outlives this
|
|
62
|
+
* composer's own count) and in the batch itself (one paste can carry a file
|
|
63
|
+
* already named that way beside a raw bitmap), so a collision is not reachable
|
|
64
|
+
* rather than merely unlikely. `startIndex` is the caller's running count, and
|
|
65
|
+
* `nextIndex` is the count to hand the next paste.
|
|
66
|
+
*
|
|
67
|
+
* Files that already carry a real name pass through untouched, so a copied
|
|
68
|
+
* `report.pdf` keeps being `report.pdf`. So does an image whose extension
|
|
69
|
+
* cannot be derived from what it declares — a renamed file must never claim a
|
|
70
|
+
* format it is not. Only the name changes: the bytes, the type and the
|
|
71
|
+
* modification time travel with it, so downstream fingerprinting still sees
|
|
72
|
+
* the file the user pasted.
|
|
73
|
+
*/
|
|
74
|
+
export declare function renamePastedImages(files: File[], startIndex: number, stagedNames?: Iterable<string>): {
|
|
75
|
+
files: File[];
|
|
76
|
+
nextIndex: number;
|
|
77
|
+
};
|
|
@@ -30,6 +30,7 @@ import type { WorkProductPersistedPart } from '../work-product/types';
|
|
|
30
30
|
export * from './chat-stream';
|
|
31
31
|
export * from './chat-interactions';
|
|
32
32
|
export * from './chat-composer';
|
|
33
|
+
export * from './composer-file-accept';
|
|
33
34
|
export * from './interaction-card-support';
|
|
34
35
|
export * from './interaction-question-card';
|
|
35
36
|
export * from './interaction-plan-card';
|
package/dist/web-react/index.js
CHANGED
|
@@ -137,7 +137,7 @@ import {
|
|
|
137
137
|
withoutRecordGridCreated,
|
|
138
138
|
withoutRecordGridRemoved,
|
|
139
139
|
withoutRecordGridUpdate
|
|
140
|
-
} from "../chunk-
|
|
140
|
+
} from "../chunk-AWM4H5XR.js";
|
|
141
141
|
import "../chunk-FBVLEGEG.js";
|
|
142
142
|
import {
|
|
143
143
|
EvidenceLineageTable,
|
|
@@ -165,14 +165,18 @@ import {
|
|
|
165
165
|
OVERLAY_SHADOW,
|
|
166
166
|
POPOVER_SURFACE_ATTR,
|
|
167
167
|
PopoverSurface,
|
|
168
|
+
acceptRejectionReason,
|
|
168
169
|
effortLevelLabel,
|
|
169
170
|
effortLevelsFromIds,
|
|
170
171
|
effortMeterFill,
|
|
172
|
+
filterAcceptedFiles,
|
|
173
|
+
isAcceptedFileType,
|
|
171
174
|
reconcileEffortLevels,
|
|
175
|
+
renamePastedImages,
|
|
172
176
|
useComposerAttachments,
|
|
173
177
|
usePending,
|
|
174
178
|
usePopover
|
|
175
|
-
} from "../chunk-
|
|
179
|
+
} from "../chunk-23J72UUA.js";
|
|
176
180
|
import {
|
|
177
181
|
ProviderLogo
|
|
178
182
|
} from "../chunk-MLG6XKPV.js";
|
|
@@ -303,6 +307,7 @@ export {
|
|
|
303
307
|
Sparkline,
|
|
304
308
|
WorkProductCard,
|
|
305
309
|
__resetAttachmentFileCacheForTests,
|
|
310
|
+
acceptRejectionReason,
|
|
306
311
|
activityTone,
|
|
307
312
|
attachmentInputToPart,
|
|
308
313
|
attachmentKindForMime,
|
|
@@ -338,6 +343,7 @@ export {
|
|
|
338
343
|
fieldAnswer,
|
|
339
344
|
fieldValuesFromAnswers,
|
|
340
345
|
fileMentionsToParts,
|
|
346
|
+
filterAcceptedFiles,
|
|
341
347
|
formatActivityCost,
|
|
342
348
|
formatActivityDuration,
|
|
343
349
|
formatDictationElapsed,
|
|
@@ -360,6 +366,7 @@ export {
|
|
|
360
366
|
interactionSubmissionSignature,
|
|
361
367
|
interactionTerminalNotes,
|
|
362
368
|
interactionToPersistedPart,
|
|
369
|
+
isAcceptedFileType,
|
|
363
370
|
isChatAttachmentPart,
|
|
364
371
|
isLateAnswerableStatus,
|
|
365
372
|
isRecordGridCellApplicable,
|
|
@@ -401,6 +408,7 @@ export {
|
|
|
401
408
|
recordGridFail,
|
|
402
409
|
recordGridOk,
|
|
403
410
|
recordGridRowLabel,
|
|
411
|
+
renamePastedImages,
|
|
404
412
|
resolveChatInteraction,
|
|
405
413
|
resolveProvenanceStanding,
|
|
406
414
|
responseErrorMessage,
|
|
@@ -15,10 +15,9 @@
|
|
|
15
15
|
* the URL and a `RequestInit` override, e.g. an auth header);
|
|
16
16
|
* - `sonner` toasts become `onReject` (client pre-validation, never hits the
|
|
17
17
|
* network) and `onError` (a request that reached the server and failed);
|
|
18
|
-
* - the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* stays free of the sandbox-ui peer;
|
|
18
|
+
* - the `accept`-string gate comes from `./composer-file-accept`, the one
|
|
19
|
+
* matcher `ChatComposer` also funnels its picker/drop/paste ingress
|
|
20
|
+
* through, so both ends of the staging path admit the same files;
|
|
22
21
|
* - the response is expected to be `{ files: ChatAttachmentInput[] }` (full
|
|
23
22
|
* server-authoritative descriptors — size/mediaType/kind — not gtm's
|
|
24
23
|
* `{path, name}`), so `references` is a verbatim pass-through with no
|
package/package.json
CHANGED