@tangle-network/agent-app 0.43.49 → 0.43.51
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/README.md +17 -0
- package/dist/assistant/index.d.ts +1 -1
- package/dist/assistant/index.js +2 -2
- package/dist/attachment-validation-DX2KIzMC.d.ts +219 -0
- package/dist/chat-routes/index.d.ts +90 -20
- package/dist/chat-routes/index.js +308 -169
- package/dist/chat-routes/index.js.map +1 -1
- package/dist/chunk-3EKOSBYL.js +239 -0
- package/dist/chunk-3EKOSBYL.js.map +1 -0
- package/dist/{chunk-O6H2WD3I.js → chunk-EIG7ZQW2.js} +854 -369
- package/dist/chunk-EIG7ZQW2.js.map +1 -0
- package/dist/web-react/index.d.ts +175 -5
- package/dist/web-react/index.js +15 -2
- package/package.json +1 -1
- package/dist/chunk-LCNY3DCM.js +0 -84
- package/dist/chunk-LCNY3DCM.js.map +0 -1
- package/dist/chunk-O6H2WD3I.js.map +0 -1
- package/dist/file-index-b26ee-_R.d.ts +0 -114
|
@@ -5,14 +5,14 @@ export { d as ComposerAnswerDelivery, I as INTERACTION_CANCEL_EVENT, e as INTERA
|
|
|
5
5
|
import { ChatPlan } from '../plans/index.js';
|
|
6
6
|
import { InteractionData } from '@tangle-network/agent-interface';
|
|
7
7
|
export { InteractionData, InteractionOutcome, InteractionRequest } from '@tangle-network/agent-interface';
|
|
8
|
-
import { K as FileMention, f as ChatMentionPart } from '../parts-IB-Kbb7z.js';
|
|
9
|
-
export {
|
|
8
|
+
import { K as FileMention, f as ChatMentionPart, a as ChatAttachmentPart, C as ChatAttachmentKind, O as ChatAttachmentInput } from '../parts-IB-Kbb7z.js';
|
|
9
|
+
export { e as ChatMentionKind, N as ChatTurnFilePartInput, M as ChatTurnPartInput, L as ChatTurnRequestPayload, R as DISPATCH_MAX_MEDIA_PARTS, T as DISPATCH_MAX_PARTS, U as DISPATCH_REQUEST_MAX_BYTES, V as DISPATCH_STRUCTURAL_RESERVE_BYTES, t as attachmentInputToPart, u as attachmentKindForMime, v as attachmentPartsFromMessageParts, $ as base64WireLen, a0 as buildMentionPromptBlock, a1 as chatTurnRequestInit, a2 as fileMentionsToParts, y as isChatAttachmentPart, a4 as mediaTypeForMentionPath, H as mentionInputToPart, a5 as mentionKindForPath, I as mentionPartsFromMessageParts } from '../parts-IB-Kbb7z.js';
|
|
10
10
|
import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
|
|
11
11
|
import { a as FlowTrace } from '../flow-types-Cb_AblZs.js';
|
|
12
12
|
export { S as SandboxTerminalConnection, a as SandboxTerminalConnectionResponse, U as UseSandboxTerminalConnectionOptions, b as UseSandboxTerminalConnectionResult, t as tabTerminalConnectionId, u as useSandboxTerminalConnection } from '../sandbox-terminal-BIIC__CP.js';
|
|
13
13
|
import { CatalogModel } from '../catalog/index.js';
|
|
14
14
|
import { Harness } from '../harness/index.js';
|
|
15
|
-
export {
|
|
15
|
+
export { a as ATTACHMENT_ACCEPT, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse } from '../attachment-validation-DX2KIzMC.js';
|
|
16
16
|
export { d as attachmentPartKey } from '../stream-normalizer-DWvtmY6F.js';
|
|
17
17
|
|
|
18
18
|
type DurablePlanDecision = 'approved' | 'rejected';
|
|
@@ -672,6 +672,170 @@ declare function segmentMentionContent(content: string, parts: ReadonlyArray<Cha
|
|
|
672
672
|
matched: Set<ChatMentionPart>;
|
|
673
673
|
};
|
|
674
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Renders a message's attachment parts (images + files) as thumbnails and
|
|
677
|
+
* download chips — the transcript-side counterpart to `ChatComposer`'s
|
|
678
|
+
* staged-upload chips. Ported from gtm-agent's `chat-attachment-parts.tsx`
|
|
679
|
+
* onto agent-app's RAW-BYTES download contract: the host supplies
|
|
680
|
+
* `resolveFileUrl(part)`, a URL that serves the attachment's raw bytes
|
|
681
|
+
* directly, so this module never parses a JSON `{file:{blobUrl,body}}`
|
|
682
|
+
* envelope or decodes a `[base64]` marker the way gtm's vault route did.
|
|
683
|
+
*
|
|
684
|
+
* No icon-library or primitives dependency (`ChatComposer`'s house style):
|
|
685
|
+
* the loading skeleton is an inline `animate-pulse` span and the few glyphs
|
|
686
|
+
* are inline SVGs.
|
|
687
|
+
*/
|
|
688
|
+
|
|
689
|
+
/** Typed outcome of fetching one attachment's raw bytes. Callers must check
|
|
690
|
+
* `ok` before touching `blob` — a failed fetch never produces a blank
|
|
691
|
+
* render, it produces a visible error state. */
|
|
692
|
+
type AttachmentFileResult = {
|
|
693
|
+
ok: true;
|
|
694
|
+
blob: Blob;
|
|
695
|
+
} | {
|
|
696
|
+
ok: false;
|
|
697
|
+
message: string;
|
|
698
|
+
};
|
|
699
|
+
declare function __resetAttachmentFileCacheForTests(): void;
|
|
700
|
+
/** Fetches (and caches) the raw bytes behind one attachment url. Concurrent
|
|
701
|
+
* callers for the SAME url dedupe to one in-flight fetch. Only a successful
|
|
702
|
+
* settlement stays cached — evicting failures means a remount or click-retry
|
|
703
|
+
* after a transient error issues a fresh fetch. */
|
|
704
|
+
declare function loadAttachmentFile(url: string, fetchFile?: (url: string) => Promise<Response>): Promise<AttachmentFileResult>;
|
|
705
|
+
/** Drives an anchor-click download from an already-resolved blob. Returns a
|
|
706
|
+
* typed outcome rather than throwing — a chip that fails to synthesize the
|
|
707
|
+
* download must show the failure, not silently no-op. */
|
|
708
|
+
declare function triggerAttachmentDownload(name: string, blob: Blob): {
|
|
709
|
+
ok: true;
|
|
710
|
+
} | {
|
|
711
|
+
ok: false;
|
|
712
|
+
message: string;
|
|
713
|
+
};
|
|
714
|
+
interface MessageAttachmentsProps {
|
|
715
|
+
parts: ChatAttachmentPart[];
|
|
716
|
+
/** URL serving the attachment's RAW bytes. */
|
|
717
|
+
resolveFileUrl: (part: ChatAttachmentPart) => string;
|
|
718
|
+
/** Row alignment — a user-bubble attachment row is right-aligned by
|
|
719
|
+
* default; pass `"start"` for an assistant-turn attachment, which sits
|
|
720
|
+
* inline with the rest of the transcript. */
|
|
721
|
+
justify?: 'start' | 'end';
|
|
722
|
+
/** Override the fetch used to load an attachment's bytes. Default:
|
|
723
|
+
* `fetch(url, { credentials: 'same-origin' })`. */
|
|
724
|
+
fetchFile?: (url: string) => Promise<Response>;
|
|
725
|
+
}
|
|
726
|
+
/** Renders a message's attachment parts as a row of image thumbnails and file
|
|
727
|
+
* chips. `null` when there are none, so callers can render unconditionally
|
|
728
|
+
* without an extra length check. */
|
|
729
|
+
declare function MessageAttachments({ parts, resolveFileUrl, justify, fetchFile }: MessageAttachmentsProps): ReactNode;
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* `useComposerAttachments` — the composer's staged-upload lifecycle: validate
|
|
733
|
+
* selected/dropped/pasted files against the shared limits (the SAME
|
|
734
|
+
* `sniffBinary`/`checkAttachmentType`/size-cap vocabulary the store-backed
|
|
735
|
+
* upload route enforces server-side, `../chat-routes/attachment-validation`
|
|
736
|
+
* + `../chat-routes/binary-sniff`), upload each accepted file with one POST
|
|
737
|
+
* request per file (so a single failure never poisons the batch), and track
|
|
738
|
+
* every file's status so a host composer can render chips and gate sending.
|
|
739
|
+
*
|
|
740
|
+
* Ported from gtm-agent's `src/components/composer-attachments.tsx`
|
|
741
|
+
* (gtm#584/#592/#593 hardened the sniff gate and batch semantics this leans
|
|
742
|
+
* on), de-gtm-ified:
|
|
743
|
+
* - the hardcoded `/api/vault/upload?workspaceId=` URL becomes
|
|
744
|
+
* `uploadUrl`/`buildUploadRequest` (the latter wins — it hands back both
|
|
745
|
+
* the URL and a `RequestInit` override, e.g. an auth header);
|
|
746
|
+
* - `sonner` toasts become `onReject` (client pre-validation, never hits the
|
|
747
|
+
* network) and `onError` (a request that reached the server and failed);
|
|
748
|
+
* - the sandbox-ui `validateComposerFiles` import becomes a small
|
|
749
|
+
* accept-list matcher re-implemented locally (`isAcceptedFileType`,
|
|
750
|
+
* mirroring its `accept`-string matching byte-for-byte) — this module
|
|
751
|
+
* stays free of the sandbox-ui peer;
|
|
752
|
+
* - the response is expected to be `{ files: ChatAttachmentInput[] }` (full
|
|
753
|
+
* server-authoritative descriptors — size/mediaType/kind — not gtm's
|
|
754
|
+
* `{path, name}`), so `references` is a verbatim pass-through with no
|
|
755
|
+
* client recompute;
|
|
756
|
+
* - `workspaceId`'s truthiness gate becomes `enabled` (default `true`).
|
|
757
|
+
*
|
|
758
|
+
* Import-free beyond React + the browser-safe `/chat-routes` validation core:
|
|
759
|
+
* this module ships through `/web-react` into client bundles
|
|
760
|
+
* (`tests/browser-safe-subpaths.test.ts` walks the graph), so nothing here
|
|
761
|
+
* may reach a Node builtin, `sandbox-ui`, or an engine package.
|
|
762
|
+
*/
|
|
763
|
+
|
|
764
|
+
interface UseComposerAttachmentsOptions {
|
|
765
|
+
/** Simple upload target: every file POSTs here. Ignored when
|
|
766
|
+
* `buildUploadRequest` is provided. */
|
|
767
|
+
uploadUrl?: string;
|
|
768
|
+
/** Full request-building seam (auth headers, per-file routing, …) — wins
|
|
769
|
+
* over `uploadUrl` when both are set. */
|
|
770
|
+
buildUploadRequest?: (args: {
|
|
771
|
+
file: File;
|
|
772
|
+
name: string;
|
|
773
|
+
form: FormData;
|
|
774
|
+
}) => {
|
|
775
|
+
url: string;
|
|
776
|
+
init?: Omit<RequestInit, 'body' | 'signal'>;
|
|
777
|
+
};
|
|
778
|
+
/** Client pre-validation rejections — a file that never reaches the
|
|
779
|
+
* network (bad type, over a size cap, over count, disallowed kind). */
|
|
780
|
+
onReject?: (reason: string, file?: File) => void;
|
|
781
|
+
/** A file that reached the upload endpoint and failed (HTTP error,
|
|
782
|
+
* transport error, malformed response). */
|
|
783
|
+
onError?: (reason: string) => void;
|
|
784
|
+
limits?: {
|
|
785
|
+
maxCount?: number;
|
|
786
|
+
maxBinaryBytes?: number;
|
|
787
|
+
maxTextBytes?: number;
|
|
788
|
+
maxTotalBytes?: number;
|
|
789
|
+
};
|
|
790
|
+
/** Attachment kinds accepted, checked against the sniffed content's
|
|
791
|
+
* mime. Default: both (`['image', 'file']` — i.e. no restriction). */
|
|
792
|
+
allowedKinds?: ChatAttachmentKind[];
|
|
793
|
+
/** `<input accept>`-style gate for the file picker/drop/paste path.
|
|
794
|
+
* Default {@link ATTACHMENT_ACCEPT}. */
|
|
795
|
+
accept?: string;
|
|
796
|
+
/** When `false`, `addFiles` rejects every call via `onReject` (and
|
|
797
|
+
* `blockReason` explains why) instead of staging anything — the
|
|
798
|
+
* replacement for gtm's `workspaceId`-truthiness gate (e.g. no workspace
|
|
799
|
+
* loaded yet). Default `true`. */
|
|
800
|
+
enabled?: boolean;
|
|
801
|
+
}
|
|
802
|
+
interface UseComposerAttachmentsResult {
|
|
803
|
+
/** Chip models for `ChatComposer`'s `pendingFiles` prop, one per staged
|
|
804
|
+
* file — `kind` is always `'file'` (agent-app's `ComposerFile.kind`
|
|
805
|
+
* discriminates file-vs-folder chips, not attachment media type). */
|
|
806
|
+
composerFiles: ComposerFile[];
|
|
807
|
+
/** Ready-to-send attachment descriptors — only files whose upload
|
|
808
|
+
* succeeded, straight from the server's response (no recompute). Feed
|
|
809
|
+
* this into `ChatTurnRequestPayload.attachments`. */
|
|
810
|
+
references: ChatAttachmentInput[];
|
|
811
|
+
/** Validate + stage + upload the given files, one request per file. */
|
|
812
|
+
addFiles: (files: File[] | FileList) => Promise<void>;
|
|
813
|
+
/** Re-upload a failed entry using its retained `File`. */
|
|
814
|
+
retry: (id: string) => void;
|
|
815
|
+
/** Drop one staged entry, aborting its upload and revoking its preview. */
|
|
816
|
+
removeAttachment: (id: string) => void;
|
|
817
|
+
/** Forget every staged entry (call after a successful send). */
|
|
818
|
+
clear: () => void;
|
|
819
|
+
/** True while any file is still pending or uploading. */
|
|
820
|
+
hasPending: boolean;
|
|
821
|
+
/** True while any file failed to upload. */
|
|
822
|
+
hasError: boolean;
|
|
823
|
+
/** Why a send is blocked, or `null` when the queue is clean. */
|
|
824
|
+
blockReason: string | null;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Owns the composer's attachment lifecycle: validate selected/dropped/pasted
|
|
828
|
+
* files against the shared limits, upload each accepted file to the
|
|
829
|
+
* product's store (one request per file), and track every file's status so
|
|
830
|
+
* the composer can render chips and gate sending.
|
|
831
|
+
*
|
|
832
|
+
* Failures surface loud — a rejected file calls `onReject` and is never
|
|
833
|
+
* uploaded; a failed upload calls `onError` and leaves an error chip the user
|
|
834
|
+
* can retry or remove. `references` only ever contains files whose upload the
|
|
835
|
+
* server actually confirmed.
|
|
836
|
+
*/
|
|
837
|
+
declare function useComposerAttachments(options: UseComposerAttachmentsOptions): UseComposerAttachmentsResult;
|
|
838
|
+
|
|
675
839
|
/**
|
|
676
840
|
* Provider brand marks — real logo path data (simple-icons / SVG Logos, both
|
|
677
841
|
* CC0) inlined so the picker shows actual provider identity instead of
|
|
@@ -1063,6 +1227,12 @@ interface ChatMessagesProps {
|
|
|
1063
1227
|
* preserve the current layout; pass `{ title }` (or your own node via
|
|
1064
1228
|
* `header`) to show the Tangle mark + product title in the chat shell. */
|
|
1065
1229
|
header?: ReactNode;
|
|
1230
|
+
/** Resolve a raw-bytes download URL for one attachment part. When set, any
|
|
1231
|
+
* message carrying attachment parts (`file`/`image` parts with a `path`,
|
|
1232
|
+
* see `attachmentPartsFromMessageParts`) renders them as a `MessageAttachments`
|
|
1233
|
+
* row next to the bubble — thumbnails for images, download chips for files.
|
|
1234
|
+
* Absent → today's rendering, byte-identical (no attachment row). */
|
|
1235
|
+
resolveAttachmentUrl?: (part: ChatAttachmentPart) => string;
|
|
1066
1236
|
}
|
|
1067
1237
|
/** One starting "door" in the chat first-run state — a concrete, labeled action
|
|
1068
1238
|
* (start from a template, do it by hand, ask the agent), not a placeholder. */
|
|
@@ -1105,6 +1275,6 @@ declare function useThinkingSeconds(active: boolean): number;
|
|
|
1105
1275
|
* model id, tokens/sec, and cost, plus a collapsible thinking section and
|
|
1106
1276
|
* tool-call chips.
|
|
1107
1277
|
*/
|
|
1108
|
-
declare function ChatMessages({ messages, models, renderMarkdown, renderExtras, durableCards, userLabel, agentLabel, loading, approval, onToolCallClick, toolRenderers, error, onRetry, renderEmpty, emptyState, header, }: ChatMessagesProps): react.JSX.Element;
|
|
1278
|
+
declare function ChatMessages({ messages, models, renderMarkdown, renderExtras, durableCards, userLabel, agentLabel, loading, approval, onToolCallClick, toolRenderers, error, onRetry, renderEmpty, emptyState, header, resolveAttachmentUrl, }: ChatMessagesProps): react.JSX.Element;
|
|
1109
1279
|
|
|
1110
|
-
export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, CatalogModel, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, ChatInteraction, ChatInteractionField, type ChatInteractionRestoreMode, ChatInteractionStatus, ChatMentionPart, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, ChatSelectField, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ComposerFilePart, type ComposerMentionProp, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, DEFAULT_MENTION_EMPTY_TEXT, DEFAULT_MENTION_LIMIT, type DurableChatCard, DurableChatCards, type DurableChatCardsProps, type DurableInteractionAnswerSubmitterOptions, DurablePlanCard, type DurablePlanCardProps, DurablePlanClientError, type DurablePlanCurrentInput, type DurablePlanDecision, type DurablePlanDecisionClient, type DurablePlanDecisionClientOptions, type DurablePlanDecisionInput, type DurablePlanDecisionResult, type DurablePlanFollowUpReceipt, type EffortLevel, EffortPicker, type EffortPickerProps, type FieldValues, FileMention, FlowWaterfall, type FlowWaterfallProps, INDEX_REFRESH_AFTER_MS, INTERACTION_SUBMIT_TIMEOUT_MESSAGE, INTERACTION_SUBMIT_TIMEOUT_MS, InteractionActionButton, type InteractionAnswerSubmission, type InteractionAnswerSubmitterOptions, InteractionAnswers, type InteractionAttemptStore, InteractionBadge, type InteractionBadgeVariant, InteractionCancelData, InteractionPlanCard, type InteractionPlanCardProps, InteractionQuestionCard, type InteractionQuestionCardProps, InteractionRequestWire, type InteractionSubmitResult, type MentionItem, type MentionTextSegment, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, QuestionOptionList, type QuestionOptionListProps, type RestoreChatInteractionsOptions, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type SubmitInteractionAnswer, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseChatInteractionsOptions, type UseChatInteractionsResult, type UseDurablePlanFlowOptions, type UseDurablePlanFlowResult, type UseFileMentionsOptions, type UseFileMentionsResult, type WaterfallRow, activityTone, buildAnswerData, cancelChatInteraction, consumeChatStream, createDurableInteractionAnswerSubmitter, createDurablePlanDecisionClient, createInteractionAnswerSubmitter, createMemoryInteractionAttemptStore, createSessionInteractionAttemptStore, dispatchChatStreamLine, durableChatCardsFromParts, fieldAnswer, fieldValuesFromAnswers, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, hasSecretField, hydrateChatInteractions, interactionStatusLabels, interactionSubmissionSignature, interactionTerminalNotes, isLateAnswerableStatus, lateAnswerMessage, mergeActivityPages, nextRevealCount, pendingApprovalOf, rankFileMentions, resolveChatInteraction, responseErrorMessage, restoreChatInteractions, segmentMentionContent, streamChatTurn, terminalizePendingChatInteractions, upsertChatInteraction, useChatInteractions, useDurablePlanFlow, useFileMentions, usePending, usePopover, useSmoothText, useThinkingSeconds, waterfallLayout };
|
|
1280
|
+
export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, type AttachmentFileResult, CatalogModel, ChatAttachmentInput, ChatAttachmentKind, ChatAttachmentPart, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, ChatInteraction, ChatInteractionField, type ChatInteractionRestoreMode, ChatInteractionStatus, ChatMentionPart, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, ChatSelectField, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ComposerFilePart, type ComposerMentionProp, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, DEFAULT_MENTION_EMPTY_TEXT, DEFAULT_MENTION_LIMIT, type DurableChatCard, DurableChatCards, type DurableChatCardsProps, type DurableInteractionAnswerSubmitterOptions, DurablePlanCard, type DurablePlanCardProps, DurablePlanClientError, type DurablePlanCurrentInput, type DurablePlanDecision, type DurablePlanDecisionClient, type DurablePlanDecisionClientOptions, type DurablePlanDecisionInput, type DurablePlanDecisionResult, type DurablePlanFollowUpReceipt, type EffortLevel, EffortPicker, type EffortPickerProps, type FieldValues, FileMention, FlowWaterfall, type FlowWaterfallProps, INDEX_REFRESH_AFTER_MS, INTERACTION_SUBMIT_TIMEOUT_MESSAGE, INTERACTION_SUBMIT_TIMEOUT_MS, InteractionActionButton, type InteractionAnswerSubmission, type InteractionAnswerSubmitterOptions, InteractionAnswers, type InteractionAttemptStore, InteractionBadge, type InteractionBadgeVariant, InteractionCancelData, InteractionPlanCard, type InteractionPlanCardProps, InteractionQuestionCard, type InteractionQuestionCardProps, InteractionRequestWire, type InteractionSubmitResult, type MentionItem, type MentionTextSegment, MessageAttachments, type MessageAttachmentsProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, QuestionOptionList, type QuestionOptionListProps, type RestoreChatInteractionsOptions, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type SubmitInteractionAnswer, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseChatInteractionsOptions, type UseChatInteractionsResult, type UseComposerAttachmentsOptions, type UseComposerAttachmentsResult, type UseDurablePlanFlowOptions, type UseDurablePlanFlowResult, type UseFileMentionsOptions, type UseFileMentionsResult, type WaterfallRow, __resetAttachmentFileCacheForTests, activityTone, buildAnswerData, cancelChatInteraction, consumeChatStream, createDurableInteractionAnswerSubmitter, createDurablePlanDecisionClient, createInteractionAnswerSubmitter, createMemoryInteractionAttemptStore, createSessionInteractionAttemptStore, dispatchChatStreamLine, durableChatCardsFromParts, fieldAnswer, fieldValuesFromAnswers, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, hasSecretField, hydrateChatInteractions, interactionStatusLabels, interactionSubmissionSignature, interactionTerminalNotes, isLateAnswerableStatus, lateAnswerMessage, loadAttachmentFile, mergeActivityPages, nextRevealCount, pendingApprovalOf, rankFileMentions, resolveChatInteraction, responseErrorMessage, restoreChatInteractions, segmentMentionContent, streamChatTurn, terminalizePendingChatInteractions, triggerAttachmentDownload, upsertChatInteraction, useChatInteractions, useComposerAttachments, useDurablePlanFlow, useFileMentions, usePending, usePopover, useSmoothText, useThinkingSeconds, waterfallLayout };
|
package/dist/web-react/index.js
CHANGED
|
@@ -19,12 +19,14 @@ import {
|
|
|
19
19
|
InteractionBadge,
|
|
20
20
|
InteractionPlanCard,
|
|
21
21
|
InteractionQuestionCard,
|
|
22
|
+
MessageAttachments,
|
|
22
23
|
MissionActivityLane,
|
|
23
24
|
ModelPicker,
|
|
24
25
|
ProviderLogo,
|
|
25
26
|
QuestionOptionList,
|
|
26
27
|
RunDrillIn,
|
|
27
28
|
SeatPaywall,
|
|
29
|
+
__resetAttachmentFileCacheForTests,
|
|
28
30
|
activityTone,
|
|
29
31
|
buildAnswerData,
|
|
30
32
|
cancelChatInteraction,
|
|
@@ -49,6 +51,7 @@ import {
|
|
|
49
51
|
interactionTerminalNotes,
|
|
50
52
|
isLateAnswerableStatus,
|
|
51
53
|
lateAnswerMessage,
|
|
54
|
+
loadAttachmentFile,
|
|
52
55
|
mergeActivityPages,
|
|
53
56
|
nextRevealCount,
|
|
54
57
|
pendingApprovalOf,
|
|
@@ -59,8 +62,10 @@ import {
|
|
|
59
62
|
segmentMentionContent,
|
|
60
63
|
streamChatTurn,
|
|
61
64
|
terminalizePendingChatInteractions,
|
|
65
|
+
triggerAttachmentDownload,
|
|
62
66
|
upsertChatInteraction,
|
|
63
67
|
useChatInteractions,
|
|
68
|
+
useComposerAttachments,
|
|
64
69
|
useDurablePlanFlow,
|
|
65
70
|
useFileMentions,
|
|
66
71
|
usePending,
|
|
@@ -68,12 +73,14 @@ import {
|
|
|
68
73
|
useSmoothText,
|
|
69
74
|
useThinkingSeconds,
|
|
70
75
|
waterfallLayout
|
|
71
|
-
} from "../chunk-
|
|
76
|
+
} from "../chunk-EIG7ZQW2.js";
|
|
72
77
|
import {
|
|
73
78
|
tabTerminalConnectionId,
|
|
74
79
|
useSandboxTerminalConnection
|
|
75
80
|
} from "../chunk-65P3HJY3.js";
|
|
76
|
-
import
|
|
81
|
+
import {
|
|
82
|
+
ATTACHMENT_ACCEPT
|
|
83
|
+
} from "../chunk-3EKOSBYL.js";
|
|
77
84
|
import "../chunk-2QI7XV2T.js";
|
|
78
85
|
import {
|
|
79
86
|
DISPATCH_MAX_MEDIA_PARTS,
|
|
@@ -124,6 +131,7 @@ import {
|
|
|
124
131
|
import "../chunk-SIXYZ2FB.js";
|
|
125
132
|
import "../chunk-MCJSS6SM.js";
|
|
126
133
|
export {
|
|
134
|
+
ATTACHMENT_ACCEPT,
|
|
127
135
|
AgentActivityPanel,
|
|
128
136
|
AgentSessionControls,
|
|
129
137
|
ChatComposer,
|
|
@@ -151,12 +159,14 @@ export {
|
|
|
151
159
|
InteractionBadge,
|
|
152
160
|
InteractionPlanCard,
|
|
153
161
|
InteractionQuestionCard,
|
|
162
|
+
MessageAttachments,
|
|
154
163
|
MissionActivityLane,
|
|
155
164
|
ModelPicker,
|
|
156
165
|
ProviderLogo,
|
|
157
166
|
QuestionOptionList,
|
|
158
167
|
RunDrillIn,
|
|
159
168
|
SeatPaywall,
|
|
169
|
+
__resetAttachmentFileCacheForTests,
|
|
160
170
|
activityTone,
|
|
161
171
|
attachmentInputToPart,
|
|
162
172
|
attachmentKindForMime,
|
|
@@ -202,6 +212,7 @@ export {
|
|
|
202
212
|
isSafeInteractionFieldKey,
|
|
203
213
|
isTerminalInteractionStatus,
|
|
204
214
|
lateAnswerMessage,
|
|
215
|
+
loadAttachmentFile,
|
|
205
216
|
mediaTypeForMentionPath,
|
|
206
217
|
mentionInputToPart,
|
|
207
218
|
mentionKindForPath,
|
|
@@ -225,8 +236,10 @@ export {
|
|
|
225
236
|
streamChatTurn,
|
|
226
237
|
tabTerminalConnectionId,
|
|
227
238
|
terminalizePendingChatInteractions,
|
|
239
|
+
triggerAttachmentDownload,
|
|
228
240
|
upsertChatInteraction,
|
|
229
241
|
useChatInteractions,
|
|
242
|
+
useComposerAttachments,
|
|
230
243
|
useDurablePlanFlow,
|
|
231
244
|
useFileMentions,
|
|
232
245
|
usePending,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.43.
|
|
3
|
+
"version": "0.43.51",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
package/dist/chunk-LCNY3DCM.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// src/chat-routes/file-index.ts
|
|
2
|
-
var DEFAULT_IGNORE_SEGMENTS = [
|
|
3
|
-
"node_modules",
|
|
4
|
-
"dist",
|
|
5
|
-
"build",
|
|
6
|
-
"out",
|
|
7
|
-
"coverage",
|
|
8
|
-
"target",
|
|
9
|
-
"__pycache__",
|
|
10
|
-
"venv"
|
|
11
|
-
];
|
|
12
|
-
function isIgnored(relPath, ignoreSegments) {
|
|
13
|
-
for (const segment of relPath.split("/")) {
|
|
14
|
-
if (!segment) continue;
|
|
15
|
-
if (segment.startsWith(".")) return true;
|
|
16
|
-
if (ignoreSegments.has(segment)) return true;
|
|
17
|
-
}
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
function relativeTo(root, path) {
|
|
21
|
-
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
22
|
-
if (path.startsWith(prefix)) return path.slice(prefix.length);
|
|
23
|
-
if (path === root) return "";
|
|
24
|
-
return path;
|
|
25
|
-
}
|
|
26
|
-
function basename(path) {
|
|
27
|
-
const segments = path.split("/").filter(Boolean);
|
|
28
|
-
return segments[segments.length - 1] ?? path;
|
|
29
|
-
}
|
|
30
|
-
function isMissingRootError(err, root) {
|
|
31
|
-
if (!(err instanceof Error)) return false;
|
|
32
|
-
if (err.code !== "VALIDATION_ERROR") return false;
|
|
33
|
-
return /ENOENT/.test(err.message) && /no such file or directory/.test(err.message) && new RegExp(`\\blstat '${escapeRegExp(root)}'`).test(err.message);
|
|
34
|
-
}
|
|
35
|
-
function escapeRegExp(value) {
|
|
36
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
37
|
-
}
|
|
38
|
-
function createSandboxFileIndexRoute(options) {
|
|
39
|
-
const maxDepth = options.maxDepth ?? 12;
|
|
40
|
-
const maxEntries = options.maxEntries ?? 5e3;
|
|
41
|
-
const cacheTtlSeconds = options.cacheTtlSeconds ?? 20;
|
|
42
|
-
const staticIgnore = /* @__PURE__ */ new Set([...DEFAULT_IGNORE_SEGMENTS, ...options.ignore ?? []]);
|
|
43
|
-
return async function fileIndex(request) {
|
|
44
|
-
const auth = await options.authorize({ request });
|
|
45
|
-
if (auth.status === "denied") return auth.response;
|
|
46
|
-
if (auth.status === "warming") {
|
|
47
|
-
return Response.json({ status: "warming" });
|
|
48
|
-
}
|
|
49
|
-
const cache = options.cache;
|
|
50
|
-
if (cache && auth.cacheKey) {
|
|
51
|
-
const cached = await cache.get(auth.cacheKey);
|
|
52
|
-
if (cached) return Response.json(cached);
|
|
53
|
-
}
|
|
54
|
-
const ignoreSegments = auth.ignore?.length ? /* @__PURE__ */ new Set([...staticIgnore, ...auth.ignore]) : staticIgnore;
|
|
55
|
-
let scan;
|
|
56
|
-
try {
|
|
57
|
-
scan = await auth.fs.tree(auth.root, { maxDepth });
|
|
58
|
-
} catch (err) {
|
|
59
|
-
if (!isMissingRootError(err, auth.root)) throw err;
|
|
60
|
-
return Response.json({ status: "warming" });
|
|
61
|
-
}
|
|
62
|
-
const filtered = scan.files.filter((f) => !isIgnored(relativeTo(scan.root, f.path), ignoreSegments));
|
|
63
|
-
const truncated = scan.stats.truncated || filtered.length > maxEntries;
|
|
64
|
-
const files = filtered.slice(0, maxEntries).map((f) => {
|
|
65
|
-
const path = relativeTo(scan.root, f.path);
|
|
66
|
-
const entry = { path, name: basename(path) };
|
|
67
|
-
if (typeof f.size === "number") entry.size = f.size;
|
|
68
|
-
return entry;
|
|
69
|
-
});
|
|
70
|
-
const body = {
|
|
71
|
-
status: "ready",
|
|
72
|
-
files,
|
|
73
|
-
truncated,
|
|
74
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
75
|
-
};
|
|
76
|
-
if (cache && auth.cacheKey) await cache.put(auth.cacheKey, body, { ttlSeconds: cacheTtlSeconds });
|
|
77
|
-
return Response.json(body);
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export {
|
|
82
|
-
createSandboxFileIndexRoute
|
|
83
|
-
};
|
|
84
|
-
//# sourceMappingURL=chunk-LCNY3DCM.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/chat-routes/file-index.ts"],"sourcesContent":["/**\n * `createSandboxFileIndexRoute` — server side of `@`-file-mentions\n * (companion to sandbox-ui#184's composer mention primitive). Serves a flat,\n * ignore-filtered listing of the workspace sandbox so `useFileMentions`\n * (`/web-react`) can filter it client-side without a round trip per\n * keystroke.\n *\n * Same seam style as `createUploadRoute`: `authorize({ request })` resolves a\n * structural `{ tree(path, opts) }` handle (the shape of the sandbox SDK's\n * `box.fs.tree`) — no SDK import here. `authorize` also carries the\n * cold-box signal: a sandbox that isn't running yet answers `{ status:\n * 'warming' }` directly, never provisions-and-waits inside this route.\n *\n * A box can also be running with its workspace root not yet materialised, which\n * `authorize` cannot see; the route recognises that one signal off `fs.tree`\n * and answers `warming` too, so every consumer gets the retry-and-wait state\n * instead of a 500. Every other `tree()` failure propagates.\n */\n\nimport type { FileMention } from './wire'\n\n/** One entry from a structural `tree()` scan. Mirrors the sandbox SDK's\n * `FileTreeFile` (`path`, `size`, `mtime`) — `mtime` is unused here so it's\n * omitted from the structural match. */\nexport interface SandboxTreeFile {\n path: string\n size: number\n}\n\n/** Structural match of the sandbox SDK's `box.fs.tree` result shape\n * (`FileTreeResult`). `stats.truncated` is the only stat this route reads;\n * the rest ride through unread on the real SDK type. */\nexport interface SandboxTreeResult {\n root: string\n files: SandboxTreeFile[]\n stats: { truncated: boolean }\n}\n\n/** Structural match of the sandbox SDK's `box.fs` tree surface. */\nexport interface SandboxFileTreeSource {\n tree(path: string, options?: { maxDepth?: number }): Promise<SandboxTreeResult>\n}\n\nexport interface FileIndexReadyResponse {\n status: 'ready'\n /** Workspace-relative entries. Same shape as `FileMention` (`./wire`) so a\n * client can hand a response entry straight to `fileMentionsToParts` /\n * `buildMentionPromptBlock` without remapping. */\n files: FileMention[]\n /** True when either the underlying scan truncated (SDK-side cap) or this\n * route's own `maxEntries` cap trimmed the filtered list. The client\n * should show \"showing first N files\" rather than imply completeness. */\n truncated: boolean\n generatedAt: string\n}\n\n/** Cold-box answer: no provisioning happened, no files were scanned. The\n * client shows a warming state and retries — this route never blocks on a\n * box coming up. Two situations produce it: `authorize` reporting a box that\n * is not running, and a running box whose workspace root does not exist yet\n * (see `isMissingRootError`). */\nexport interface FileIndexWarmingResponse {\n status: 'warming'\n}\n\nexport type FileIndexResponse = FileIndexReadyResponse | FileIndexWarmingResponse\n\n/** Short-TTL cache seam so repeat popover opens in the same session don't\n * re-scan the workspace. Host-provided (e.g. a KV binding); `key` is\n * whatever `authorize` returns as `cacheKey` — this route treats it opaquely. */\nexport interface FileIndexCache {\n get(key: string): Promise<FileIndexReadyResponse | null> | FileIndexReadyResponse | null\n put(key: string, value: FileIndexReadyResponse, options?: { ttlSeconds?: number }): Promise<void> | void\n}\n\nexport type FileIndexAuthorization =\n | {\n status: 'ready'\n /** Structural sandbox `fs` handle, usually `ensureWorkspaceSandbox(...)` → `box.fs`. */\n fs: SandboxFileTreeSource\n /** Workspace root to index (e.g. `/home/agent`). */\n root: string\n /** Extra ignore segments for this request, merged with the route's\n * defaults + `CreateSandboxFileIndexRouteOptions.ignore`. */\n ignore?: string[]\n /** Opaque cache key for the optional cache seam. Omit to skip caching\n * for this request (e.g. a workspace the host chooses not to cache). */\n cacheKey?: string\n }\n | { status: 'warming' }\n | { status: 'denied'; response: Response }\n\nexport interface CreateSandboxFileIndexRouteOptions {\n /** Authenticate the caller, resolve the sandbox `fs` handle, and signal a\n * cold box — never provisions or waits. */\n authorize(args: { request: Request }): Promise<FileIndexAuthorization>\n /** Extra ignore segments beyond the route's defaults (node_modules, .git,\n * dotfiles/dot-dirs, common build dirs). Matched as exact path-segment\n * names, same rule as the defaults. */\n ignore?: string[]\n /** Passed to `fs.tree` as `options.maxDepth`. Default 12. */\n maxDepth?: number\n /** Hard cap on entries returned after filtering. Default 5000. */\n maxEntries?: number\n /** Optional host-provided cache seam. */\n cache?: FileIndexCache\n /** Cache TTL in seconds when `cache` is set. Default 20. */\n cacheTtlSeconds?: number\n}\n\n/** Segment names ignored anywhere in a path, beyond the generic dotfile rule\n * below. Intentionally small and language/framework-agnostic — callers\n * extend it via `ignore` for anything domain-specific (e.g. a vault's\n * `uploads` dir). */\nconst DEFAULT_IGNORE_SEGMENTS = [\n 'node_modules',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n 'target',\n '__pycache__',\n 'venv',\n]\n\n/** A path segment starting with `.` (`.git`, `.env`, `.next`, `.cache`, …) is\n * always ignored — this single rule covers most dot-prefixed VCS/tooling\n * dirs and dotfiles without enumerating them. */\nfunction isIgnored(relPath: string, ignoreSegments: ReadonlySet<string>): boolean {\n for (const segment of relPath.split('/')) {\n if (!segment) continue\n if (segment.startsWith('.')) return true\n if (ignoreSegments.has(segment)) return true\n }\n return false\n}\n\n/** Strips the tree result's echoed `root` prefix so entries are always\n * workspace-relative, whichever convention the structural `fs.tree` uses\n * (root-relative already, or root-prefixed). */\nfunction relativeTo(root: string, path: string): string {\n const prefix = root.endsWith('/') ? root : `${root}/`\n if (path.startsWith(prefix)) return path.slice(prefix.length)\n if (path === root) return ''\n return path\n}\n\nfunction basename(path: string): string {\n const segments = path.split('/').filter(Boolean)\n return segments[segments.length - 1] ?? path\n}\n\n/**\n * A box can answer `running` before it has materialised the workspace root —\n * `authorize` has already committed to `ready` by then, so `fs.tree` is the\n * first thing to notice, and it rejects with the sandbox SDK's\n * `ValidationError` wrapping a box-side `ENOENT … lstat` on the root. That is\n * the SAME \"not usable yet\" state `authorize` collapses onto `warming` for an\n * absent or stopped box, just discovered one step later, so it gets the same\n * answer instead of escaping as a 500.\n *\n * Matched STRUCTURALLY, not with `instanceof`: importing the SDK's error class\n * would make `@tangle-network/sandbox` a hard dependency of a route factory\n * whose entire `fs` seam is structural (`SandboxFileTreeSource`), and would\n * break any host feeding it a non-SDK handle.\n *\n * Deliberately narrow — the error code, `ENOENT`, the ENOENT message text, AND\n * the failing syscall's own operand all have to line up. A permission error, a\n * timeout, an auth failure, or an ENOENT on some other path inside the tree is\n * a real failure and still surfaces.\n *\n * The operand is matched as the quoted `lstat '<root>'` clause rather than by\n * substring, because the root is a PREFIX of everything under it: a plain\n * `includes(root)` would also swallow an ENOENT on `<root>/gone/x.md`, and on\n * a prefix sibling like `/home/agent-old/...`.\n */\nfunction isMissingRootError(err: unknown, root: string): boolean {\n if (!(err instanceof Error)) return false\n if ((err as { code?: unknown }).code !== 'VALIDATION_ERROR') return false\n return (\n /ENOENT/.test(err.message) &&\n /no such file or directory/.test(err.message) &&\n new RegExp(`\\\\blstat '${escapeRegExp(root)}'`).test(err.message)\n )\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function createSandboxFileIndexRoute(\n options: CreateSandboxFileIndexRouteOptions,\n): (request: Request) => Promise<Response> {\n const maxDepth = options.maxDepth ?? 12\n const maxEntries = options.maxEntries ?? 5000\n const cacheTtlSeconds = options.cacheTtlSeconds ?? 20\n const staticIgnore = new Set([...DEFAULT_IGNORE_SEGMENTS, ...(options.ignore ?? [])])\n\n return async function fileIndex(request: Request): Promise<Response> {\n const auth = await options.authorize({ request })\n if (auth.status === 'denied') return auth.response\n if (auth.status === 'warming') {\n return Response.json({ status: 'warming' } satisfies FileIndexWarmingResponse)\n }\n\n const cache = options.cache\n if (cache && auth.cacheKey) {\n const cached = await cache.get(auth.cacheKey)\n if (cached) return Response.json(cached)\n }\n\n const ignoreSegments = auth.ignore?.length\n ? new Set([...staticIgnore, ...auth.ignore])\n : staticIgnore\n\n let scan: SandboxTreeResult\n try {\n scan = await auth.fs.tree(auth.root, { maxDepth })\n } catch (err) {\n if (!isMissingRootError(err, auth.root)) throw err\n return Response.json({ status: 'warming' } satisfies FileIndexWarmingResponse)\n }\n const filtered = scan.files.filter((f) => !isIgnored(relativeTo(scan.root, f.path), ignoreSegments))\n const truncated = scan.stats.truncated || filtered.length > maxEntries\n const files: FileMention[] = filtered.slice(0, maxEntries).map((f) => {\n const path = relativeTo(scan.root, f.path)\n const entry: FileMention = { path, name: basename(path) }\n if (typeof f.size === 'number') entry.size = f.size\n return entry\n })\n\n const body: FileIndexReadyResponse = {\n status: 'ready',\n files,\n truncated,\n generatedAt: new Date().toISOString(),\n }\n\n if (cache && auth.cacheKey) await cache.put(auth.cacheKey, body, { ttlSeconds: cacheTtlSeconds })\n\n return Response.json(body)\n }\n}\n"],"mappings":"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","names":[]}
|