mirror of
https://github.com/stablyai/orca.git
synced 2026-11-06 03:57:35 +00:00
fe3cb24a04445d2b5e30aba9a38013ba6fa677ae
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
726c572da7 |
Attach a long paste as a text file, and say a message is too large before it is sent (#30398)
* fix(native-chat): attach a long paste as a text file, and say a message is too large before it is sent A paste of 32 KB or more (or one that would push the message past the 256 KB send limit) into a structured chat is saved as a file the agent reads, through the same pending-chip and @path route a dropped file takes: Orca's paste folder here, or the chat's attachment store on its paired server. Claude gets the paste folder as an allowed directory. A message still over the limit is handed back before it is sent, on desktop and the phone, with words naming the limit instead of the generic 'not sent, send it again'. * test: Claude launch parity snapshot grants the paste folder * fix(native-chat): a long paste replaces the selection at once and settles in place A long paste now puts an inline Pasted text pill where it went, replacing any selected text immediately, and the saved file (or inline text, or the original selection on failure) replaces that same pill when the save finishes, in its own chat's draft. Nothing reads the caret later, so order and position hold. The paste never joins the image row, so image numbers are unchanged. The size check measures the real message body with the selection replaced and images included. A server that keeps no files takes the paste inline when the message still fits. A pending paste a restart lost shows Paste not saved, and Send says so. * fix(native-chat): type the pasted-text parser and the composer's missing draft scope * fix(native-chat): admit paste references before goals and commands * fix(native-chat): resolve staged paste paths without editing the draft * fix(native-chat): consolidate paste imports for code quality checks * fix(native-chat): retain checked string types for saved paste paths * fix(native-chat): retain completed paste facts through history and delimit paths * fix(native-chat): keep structured question rendering within file limit * fix(native-chat): pasted or inserted text that looks like a paste token stays literal * fix(web): keep the browser's UI bridge under the file length limit * style: format the files #29982 merged unformatted * fix(native-chat): retain oversized drafts before send admission * fix(native-chat): keep the composer handle's merge resolution to main's destructure |
||
|
|
3d0973d0d4 |
A chat's visuals and sent images live as long as the chat (#30413)
* fix(native-chat): a chat's visuals folder lives as long as the chat A chat's scratch folder was deleted once the chat had gone 30 days unused, so an old chat's inline visuals turned into "Visualization unavailable" while the chat and its history stayed. The common pattern keeps a chat's files for as long as the chat and never deletes them on an "unused for N days" timer. The sweep now removes only folders no chat record maps to, plus leftover .expired folders older builds parked. Everything that existed only to make the age rule safe goes with it: the per-folder save lock and its expiry candidates, the session-lane idle check, the journal last-activity query, and the migration's fresh-window timestamp. The visuals skill no longer tells agents the folder is temporary. * fix(native-chat): an image sent in a local chat lives as long as the chat A local chat's pasted images lived in one paste folder that deleted every file older than 30 days, sent or not, so an old chat's images turned into label chips. Paired-server chats already keep pastes in the host's attachment store, where the send that names a file claims it for its chat and only unclaimed files are ever swept: the common pattern. A local composer paste now goes into this machine's own attachment store (starting the local chat host first), so its send claims it the same way. The old paste folder is no longer written or swept: messages sent before this change may name its files. Restored drafts still read it. An unclaimed upload now waits 30 days instead of one before the sweep takes it. A draft names its image by this path, so the window is how long an unsent draft keeps its image; 30 days is what local drafts had, and it outlasts the host's send-id window so a resent draft still finds its image. A chat folder an older build set aside as unused (<hash>.expired) goes back to its chat instead of being deleted. * fix(native-chat): a terminal-backed chat's pastes are never swept A terminal-backed chat has no journal, so no send claims its pastes and nothing can tell a sent one from an abandoned one. Its pastes therefore stay in the paste folder, which is no longer swept, rather than in the attachment store, whose sweep would take them after 30 days unclaimed. Only a local structured chat's paste (forStructuredChat) goes to the store, where its send claims it. * fix(native-chat): keep the attachment owner's literal kind for structured local chats * test(ipc): expect the local chat store option on the clipboard registrar * fix(native-chat): preserve attachment ownership and restore held files safely * fix(native-chat): settle restored image checks independently * test(native-chat): assert restored image outcomes without batching * Re-check draft images when the attachment sweep removes their upload A draft checks its pasted images once, when its composer comes back. Every chat in an open workspace mounts its composer at launch, so that check ran before the store sweep (60 s after host start, then every 6 h) deleted an expired unsent upload, and nothing checked again: the chip lost its picture with no Not kept feedback and Send stayed enabled. The sweep now reports each removal attempt; the main process forwards it to its window, and the draft store starts a fresh finite check for every loaded local draft image in that folder, mounted or not. A notice is a reason to check, never proof of absence. * Let the app effect remove the draft re-check listener it adds startNativeChatDraftLoad dropped the unsubscribe for the upload-removal listener, so each recovery through the root error boundary's Retry remounted App and added another listener. Return it so the effect's cleanup removes it. |
||
|
|
cf7423c8f4 |
feat(mobile): redesign the chat composer with file attachments and inline skills (#30359)
* refactor(native-chat): move the slash picker builder and upload chunking to shared Mobile builds the same skill and command list as desktop. * feat(mobile): redesign the chat composer with file attachments and inline skills * fix(mobile): the composer field owns its input style The page's font-size census cannot follow a style passed in as a prop. |
||
|
|
990c62e6c6 |
feat(native-chat): attach files to a structured chat on a paired server (#25146)
* feat(native-chat): a paired server keeps a store for chat attachments A structured chat on a paired Orca server had nowhere to put a file the client attached. The server now keeps a per-chat attachment store under its userData, filled through agentSessionAttachment.uploadStart/Append/Commit/Abort and read back for previews through agentSessionAttachment.read, behind the structured session gate and advertised as agent-session.attachments.v1. Nothing records cleanup as owed: a sweep re-derives what may go from the host's chat records and journal (unfinished uploads after an hour, uploads for a chat that never existed or that its journal never mentions after a day). The clipboard RPC's in-flight bookkeeping moves into a shared ChunkedUploadRegistry both use. * feat(native-chat): upload attached files into a paired server's chat store Main streams dropped or picked files (fs:uploadPathsToAgentSessionAttachments) and pasted images (clipboard:saveImageAsTempFile with agentSessionAttachment) into the chat's store on its paired server, reusing the file-import slice streamer and pinning every call to the pairing revision and server process. The browser client's paste takes the same route. * feat(native-chat): attach files to a structured chat on a paired server Pasted images, files dropped from Finder/Explorer and the file picker no longer refuse with "Local attachments are not available for remote sessions." in a structured chat on a paired server: they upload into that server's chat store and the chat gets only the stored path. Dropped files show as pending chips at once so Send waits for them; every attached item carries the server, pairing and chat it was stored for, and a send to anywhere else drops it with the existing "changed hosts" notice. Chips and transcript images read stored files back through the server, never from this machine's disk. An older server gets an update notice instead of an upload. The terminal-backed chat keeps refusing. * test(native-chat): type the attachment test doubles without bare casts * refactor(native-chat): keep the clipboard RPC on its own upload bookkeeping The chunked upload registry stays for the chat attachment store only, beside it. * feat(native-chat): claim chat attachments when the host admits a message A message's references into the host's attachment store are claimed in the same journal transaction that makes it durable (a direct send, a queued draft, a /clear carry). The sweep deletes an upload only after marking it in that database while no claim exists, so a send and a sweep can never both win: a client's send that names an expired or foreign upload is refused whole with the new attachmentExpired reason, before anything is recorded. This replaces scanning chat transcripts for paths. The store is now <root>/<upload id>/<name>, refuses uploads for chats the host does not hold, caps stored names in UTF-8 bytes and avoids Windows device names. The preview read goes through the protected bounded read and the request's reply budget, so an image too large for one reply is refused instead of closing the connection. * feat(native-chat): let structured Claude read the host's chat attachment store Attached non-image files live outside the workspace; the store root is passed as an added directory so the agent reads them without asking, the common pattern. * fix(native-chat): skip a dropped folder before staging walks into it * fix(native-chat): pin the browser client's chat paste to its server Every upload call goes to the environment the paste was meant for and checks its pairing and server process, as the desktop upload does; a re-pair ends the upload instead of storing the image on another server. * refactor(native-chat): let the host's claim be the only attachment check The composer no longer records which server and pairing each attachment came from, and Send no longer strips attachments it judges foreign: the host refuses an expired or unknown stored path when it admits the message, which also covers retries, Stop-restores and queued edits the client check missed. Previews of stored files route through the chat's own server by path. Removing a file's chip while it uploads now keeps its @path out of the draft. A dropped or picked file shows its name and kind on its chip while it uploads, with no separate progress toast, and files that did not attach are named in one notice. A rich-text paste into a chat on an older server no longer shows the update notice beside the pasted text. * chore(native-chat): keep the claim hook beside the draft consume and fit the line budgets The submission's claim runs in the same append hook as a draft's consume, owned by the queued-message collaborator, so the journal store stays within its size limit. Formats the new files and regenerates the runtime-required English catalog. * test(native-chat): pin the attachment store grant in the Claude launch, restore upload result types * fix(native-chat): create the attachment store at install and claim only exact store paths Claude drops an added directory that does not exist when it starts, so the store root is created when the host installs it, best effort. A commit keeps its upload in flight until the rename lands, so a sweep never takes a slow upload's part file. Only a path under this host's exact store root is claimed and required; any other mention of a store path is plain text and never refuses the message. * refactor(native-chat): reuse the newer-Orca notice and drop leftover attach options An older server's refusal to store attachments uses the notice every other write it refuses already shows, so one string fewer in every catalog; the attach callbacks lose an options parameter no caller passes since the provenance check went. * fix(native-chat): give a message refused for an expired attachment back to the composer Sending the same message again can never bring the attachment back, so instead of a Retry that always fails the message's text and images return to the composer, as a Stop's withdrawn message does, and the notice says what to remove. * fix(native-chat): keep uploads across a prompt, say why a file did not attach An upload that finishes while a prompt card has replaced the composer lands in the scope's attachment and draft caches, which the composer reads back when it returns, instead of the unmounted composer. The single failure notice names the cause the files share, such as the size limit. Rich text pasted into a chat on an older server no longer flashes an image chip: the chip waits for the server to take the image. A picked command waits, as Send does, while an attachment is still uploading. * fix(native-chat): keep a paste's upload across a prompt; pin the Claude grant hand-off A paste uploading into a paired server's store keeps its chip live when a prompt card unmounts the composer, and its result is filed for the composer's return, as a drop's is. A failure cause ending in full-width punctuation gets no extra full stop. A runtime test pins that the store root reaches Claude's launch resolver through the adapter. * test(native-chat): type the grant hand-off captures without casts * test(native-chat): pin that the composer files a paste's upload across a prompt * fix(native-chat): retry a held rename at commit and keep cut names Windows-safe A commit renames the part file with the Windows retry the app uses elsewhere, so an antivirus or indexer holding it briefly no longer loses the upload. A name cut to the byte limit is stripped of trailing dots and spaces again. The upload pump's result cast states why it holds. * fix(native-chat): keep attachments still on their way in the pane's attachment cache A prompt card unmounts the composer, and an attachment still saving or uploading lived only in that composer: one that came back showed no pending chip, so Send went out without the file and the file then landed in the next draft. Pending chips now live in the pane's attachment cache beside settled ones and settle there whichever composer is showing, so Send waits for them after a remount too. A stored file's @path goes into the pane's draft cache, which keeps it through an input-method composition and a remount. A rich-text paste's image is registered as a hidden pending chip before the server is asked, so Send waits for it from the start, and it shows only once the server takes it. * test(native-chat): a dropped file still uploading stays pending across a remount * fix(native-chat): reveal a rich-text image in a composer that came back; keep caret inserts A rich-text paste's held image is revealed through the pane's attachment cache, so a composer a prompt card remounted during the server's answer shows it rather than holding Send on an invisible chip. A stored file's @path goes in at the caret while the composer is showing and not composing, as every other attach does; only mid-composition or after a remount does it go to the pane's draft. * fix(native-chat): never evict a pane's attachments while a composer shows them or one is on its way The pane attachment cache is now where chips live, so its 128-scope bound passes over a scope a mounted composer subscribes to or that still holds a pending attachment, and evicts the oldest scope nobody uses instead. Protected scopes are bounded by mounted composers and attachments in flight. * fix(native-chat): never evict the scope just written when every older one is in use * fix(native-chat): keep the attachment store out of the RPC method table's imports The method table is imported far and wide (the SSH relay's CLI included), and the attachment RPCs pulled in the store, whose preview read loads modules that read fs constants at load: any test that mocks fs/promises without them failed to import. The installed store now lives in a small registry module; only the host wiring loads the store itself. * refactor(native-chat): the submission hook gets its own module Merging main added the operation receipt to the queued-message insert, which put journal-queued-messages.ts over the 300-line limit. The submission hook only uses the queued-messages object's public methods, so it moves out. * refactor(native-chat): fit the attachment sweep and paste upload into main's line budgets After merging main, the record store and the clipboard handlers each ran a few lines over the 300-line budget. The sweep now asks the record store whether a chat is recorded through the two lookups it already has (readable or unreadable) instead of a new id-listing method, and the paired-server paste upload lives beside the other attachment uploads. No behavior changes. * fix(native-chat): pending chips sit beside main's saved draft, which keeps server-stored images Main now saves a composer's draft (text and settled images) in one store that survives a reload or quit. This branch kept every chip, settled or not, in its own pane cache. After the merge the saved draft owns settled images and the pane cache holds only chips still on their way: they come back pending in a composer a prompt card remounted, hold Send, settle into the saved draft whichever composer is showing, and are never saved themselves, so a restored draft cannot bring back an upload as if it were attached. An image a paired server stored for the chat is saved with the draft as the real image (a pasted one is no longer turned into a "Not kept" placeholder), and the restore check leaves it to that server, whose claim at Send refuses one it no longer holds, instead of asking this machine's disk for a path that only exists on the server. Also: previews and the pending subscription move into their own small hooks to fit the line budget, the "local attachments" notice moves to the composer-target module so the attachments hook no longer pulls in the upload module's imports, and tests follow main's new mocks. * test(native-chat): give the claims test main's provider handle and message source * fix(native-chat): a paste still uploading dies with its tab or workspace A pasted image still uploading to a paired server sits in the pending chip cache, which by design outlives the composer and its tab. Removing the workspace deleted its saved drafts but left those chips, so the upload finishing afterwards recreated and saved the deleted draft. With the workspace's tabs gone it had no owner either, so no later workspace cleanup could ever remove it. A pending chip now records the owner its draft would have, resolved the way the draft store resolves one when the chip is added. Workspace removal and a user's tab close drop pending chips by the same owner, conversation and tab matches they delete drafts by, and a chip that settles after its chat's tab closed writes its draft under the owner it was begun in. * fix(native-chat): the claim type uses the journal's own SQLite type * refactor(native-chat): read the pending-image handlers off the composer's attachments Main's multi-file picker (#23956) and this branch together took NativeChatComposer over the 400-line limit; reading the two pending-image handlers the way the neighbouring ones already are keeps it at the limit. * test(native-chat): pass the launch-args resolver main now requires in the attachment grant test * fix(native-chat): grant the attachment store beside folders the saved Claude Arguments add Main (#25721) now builds additionalDirectories from the user's --add-dir arguments; this branch's attachment-store grant replaced that list instead of adding to it. Both are granted now. Moves the Claude session-id derivation to its own module to keep the resolver under the line limit. * test(native-chat): run the attachment store's SQLite tests in the Node runtime project * test(native-chat): follow main's attach ownership recheck (#25749) in the attachment tests * test(native-chat): a named upload chip still shows when the agent takes no images * fix(native-chat): a paired-server image paste failure keeps its error apart, as main's notice card does * fix(native-chat): the attachment sweep reads the chat list directly now that records have no import still owed |