Skip to content

feat(artifacts): Save-As dialog + in-progress wiring + failed-card retry (#3162)#4127

Merged
senamakel merged 15 commits into
tinyhumansai:mainfrom
oxoxDev:feat/3162-artifact-ux-polish
Jun 25, 2026
Merged

feat(artifacts): Save-As dialog + in-progress wiring + failed-card retry (#3162)#4127
senamakel merged 15 commits into
tinyhumansai:mainfrom
oxoxDev:feat/3162-artifact-ux-polish

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Problem

#3017 landed ArtifactCard + the Tauri download command + backend ArtifactReady/ArtifactFailed events, but three AC items from #2779 were deferred:

  1. AC#3 — native Save-As dialog was not wired: tauri-plugin-dialog pulls tauri-plugin-fs, which conflicts with the workspace's pinned schemars version. The shipped behaviour copied into ~/Downloads/ and revealed the file — functional but not the user-chosen-destination AC.
  2. AC#1 — in-progress state: ArtifactCard only rendered once the core published ArtifactReady/Failed — no spinner during generation, despite the backend now emitting artifact_pending (feat(artifacts): publish ArtifactPending event + artifact_pending socket bridge (#3162 backend) #3277).
  3. AC#4 — Retry: the failed-card Retry affordance existed in the component but was never wired to an action.

Solution

AC#1 — in-progress (artifact_pending). Added ArtifactPendingEvent + an onArtifactPending socket listener (mirrors ready/failed; validates the envelope, no size/path yet), dispatched to upsertArtifactInProgressForThread. Added a no-downgrade guard to that reducer so a late/duplicate pending can never regress a ready card back to a spinner; failed -> in_progress is allowed because that is an explicit retry.

AC#3 — Save-As dialog (rfd). New save_artifact_via_dialog Tauri command backed by rfd (talks to the OS dialog APIs directly, no tauri-plugin-fs → no schemars conflict). rfd is added with default-features = false + xdg-portal so Linux stays off GTK. The command returns the saved path, or null on cancel (surfaced as CANCELLED, treated as a no-op). The artifact_commands module is cross-platform (both export commands compile on macOS/Windows/Linux). New allow-artifact-save capability. The service-layer saveArtifactViaDialog falls back to the Downloads copy when the dialog itself is unavailable (e.g. headless Linux without a portal). Both commands restrict the source to the OpenHuman data dir's artifacts/ tree so the renderer cannot copy an arbitrary local file out.

AC#4 — Retry = full re-dispatch (core-persisted args). The producing tool now persists its verbatim args as an args.json sidecar next to meta.json. A new openhuman.ai_regenerate RPC reloads meta + args, rebuilds the PresentationTool + a fresh SecurityPolicy, and re-runs it inside a REGENERATE_TARGET_ID task-local (so create_artifact reuses the original id + directory — the card swaps in place) and an APPROVAL_CHAT_CONTEXT scope (so the fresh pending/ready/failed events route back to the originating thread + socket). Presentation-only today — the one producer that persists args. onRetry is wired at the Conversations call site.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — core/tauri/FE happy + failure paths covered by the added specs; enforced by the CI coverage-gate (Rust core/tauri cargo-llvm-cov jobs green; FE Vitest coverage in CI)
  • N/A: Coverage matrix — no artifact-UX feature row exists in docs/TEST-COVERAGE-MATRIX.md; this extends the feat(chat): ArtifactCard + Tauri download + backend artifact events (#2779) #3017 artifact surface, no row add/rename
  • N/A: matrix feature IDs — no matrix feature ID maps to this surface (see item above)
  • No new external network dependencies introduced (rfd is an OS-dialog crate, no network; mock policy unaffected)
  • N/A: manual smoke — artifact export/retry is not on the release-cut manual-smoke list; covered by unit + integration tests
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Platform: desktop only (macOS/Windows/Linux). rfd is a new build dependency (no network, no schemars). Both export commands (Save-As + Downloads) are now cross-platform — the artifact_commands module was previously macOS/Linux-gated.
  • Compatibility: args.json is additive — artifacts created before this change simply have no sidecar and surface a clear "not regenerable" error on Retry rather than failing silently. meta.json shape is unchanged.
  • Security: both export commands validate the source is an existing file inside the artifacts/ tree (canonicalized) and sanitize the filename hint; ai_regenerate re-runs under the same SecurityPolicy::from_config the agent harness uses.
  • Performance: regenerate re-runs the native ppt-rs engine in place — no LLM round-trip.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

Commit & Branch

  • Branch: feat/3162-artifact-ux-polish
  • Commit SHA: 6e4562a6a

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: core cargo test --lib openhuman::artifacts (62), tauri cargo test -p OpenHuman artifact_commands (12), FE vitest artifact specs (62)
  • Rust fmt/check (if changed): cargo fmt --check + cargo check (core)
  • Tauri fmt/check (if changed): cargo fmt --check + cargo check (app/src-tauri)

Validation Blocked

  • command: pnpm test:coverage / diff-cover (full coverage build)
  • error: not run locally — heavy build
  • impact: diff-coverage gate validated in CI instead

Behavior Changes

  • Intended behavior change: in-progress spinner card; native Save-As export; functional failed-card Retry (full re-dispatch).
  • User-visible effect: artifact cards now show a spinner while generating, a system Save-As dialog on export, and a working Retry on failed cards.

Parity Contract

  • Legacy behavior preserved: Downloads-copy + reveal retained as the dialog fallback; meta.json shape unchanged; non-regenerate generation still mints a fresh UUID.
  • Guard/fallback/dispatch parity checks: no-downgrade guard on in-progress upsert; dialog-unavailable → Downloads fallback; missing args.json → explicit non-regenerable error.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none
  • Canonical PR: this
  • Resolution (closed/superseded/updated): N/A

oxoxDev added 13 commits June 25, 2026 23:19
…umansai#3162)

Add args.json sidecar (save_artifact_args/read_artifact_args) next to
meta.json, plus a REGENERATE_TARGET_ID task-local so create_artifact can
reuse an existing artifact id/dir in place instead of minting a fresh
UUID. Foundation for the failed-card Retry re-dispatch.
…sai#3162)

After reserving the artifact, write the verbatim tool args to args.json
(best-effort) so a failed card can re-dispatch the same deck spec
deterministically without round-tripping through the LLM.
…inyhumansai#3162)

Add openhuman.ai_regenerate: reloads meta + args.json, rebuilds the
producer tool + SecurityPolicy, and re-runs it inside
REGENERATE_TARGET_ID + APPROVAL_CHAT_CONTEXT scopes so the same
artifact id is reused and pending/ready/failed events route back to the
originating chat. Presentation-only for now (the one producer that
persists args). Wires the controller into the registry + updates the
coverage tests (3 -> 4 functions).
…i#3162)

default-features off + xdg-portal so Linux stays off GTK; tokio feature
drives the async dialog backend. rfd talks to the OS dialog APIs
directly and avoids the tauri-plugin-fs/schemars conflict that blocked
a dialog in tinyhumansai#2779.
…3162)

Add save_artifact_via_dialog: rfd-backed native Save-As pre-filled with
the artifact filename, copies to the chosen path, returns Ok(None) on
cancel. Factor shared validate_source + copy_to_path helpers; keep the
macOS/Linux Downloads fallback gated and add unit tests for the new
path.
…nsai#3162)

Ungate the artifact_commands module (Save-As is cross-platform; the
Downloads command stays macOS/Linux-gated inside), add the handler entry,
and wire the allow-artifact-save permission into the default capability.
…umansai#3162)

Add ArtifactPendingEvent + onArtifactPending socket listener (mirrors
ready/failed, no size/path yet) so the chat runtime can render an
in-progress card the moment a producer reserves an artifact. Add
aiRegenerate() which calls openhuman.ai_regenerate with the socket
client_id for event routing.
…inyhumansai#3162)

Dispatch upsertArtifactInProgressForThread on onArtifactPending so the
spinner shows before any bytes land, then swaps in place on ready/failed.
Add a no-downgrade guard to the reducer: a late/duplicate pending must
not regress a 'ready' card back to a spinner (failed -> in_progress is
allowed — that is an explicit retry).
…3162)

ArtifactCard Download now calls saveArtifactViaDialog (OS Save-As
pre-filled with the filename), treating cancel as a no-op. Factor the
shared ai_get_artifact resolve out of downloadArtifact; the dialog path
falls back to the Downloads copy when no portal is available. Add the
CANCELLED arm to the files-panel error localizer.
Pass onRetry on the live ArtifactCard so a failed deck re-dispatches via
ai_regenerate, reusing the artifact id so the card swaps in place. Remove
the stale tinyhumansai#3162 placeholder comment.
…umansai#3162)

Store: args.json round-trip, missing-args error, fresh-UUID vs reused-id
inside REGENERATE_TARGET_ID scope. Ops: ai_regenerate input guards,
non-presentation + missing-args rejections, and a full happy-path that
re-runs the engine in place and lands the reused id at Ready.
…sai#3162)

Add specs for the artifact_pending socket listener (flatten + drop
malformed), the slice no-downgrade guard (ready stays ready;
failed->in_progress allowed), saveArtifactViaDialog (save/cancel/
fallback/resolve-fail), aiRegenerate routing, and the provider
onArtifactPending dispatch. Point the ArtifactCard download specs at
the new Save-As path.
@oxoxDev oxoxDev requested a review from a team June 25, 2026 18:24
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a native save-file export path for artifacts, wires artifact_pending events into chat state, and introduces an artifact regeneration RPC with retry handling from the UI.

Changes

Artifact UX flow

Layer / File(s) Summary
Save-as command and permissions
app/src-tauri/Cargo.toml, app/src-tauri/capabilities/default.json, app/src-tauri/permissions/allow-artifact-save.toml, app/src-tauri/src/artifact_commands.rs, app/src-tauri/src/lib.rs
Adds the desktop save-dialog command, registers its capability and permission entries, and exposes it through Tauri with shared export helpers and tests.
Save-as export flow
app/src/services/artifactDownloadService.ts, app/src/services/__tests__/artifactDownloadService.test.ts, app/src/components/chat/ArtifactCard.tsx, app/src/components/chat/ArtifactCard.test.tsx, app/src/components/chat/__tests__/ArtifactCard.test.tsx, app/src/components/chat/ChatFilesPanel.tsx
Routes artifact export through saveArtifactViaDialog, handles CANCELLED, and updates the card flow, error localization, and related tests.
Pending artifact state
app/src/services/chatService.ts, app/src/services/__tests__/chatService.artifactEvents.test.ts, app/src/providers/ChatRuntimeProvider.tsx, app/src/providers/__tests__/ChatRuntimeProvider.artifacts.test.tsx, app/src/store/chatRuntimeSlice.ts, app/src/store/__tests__/chatRuntimeSlice.artifacts.test.tsx
Adds the artifact_pending event contract and listener plumbing, upserts in-progress artifacts into chat runtime state, and prevents ready artifacts from being downgraded.
Retry regeneration flow
app/src/pages/Conversations.tsx, app/src/services/chatService.ts, app/src/services/__tests__/chatService.artifactEvents.test.ts, src/openhuman/artifacts/schemas.rs, src/openhuman/artifacts/ops.rs, src/openhuman/artifacts/ops_tests.rs, src/openhuman/artifacts/store.rs, src/openhuman/artifacts/store_tests.rs, src/openhuman/tools/impl/presentation/mod.rs
Adds aiRegenerate, exposes the regenerate controller, persists artifact args, reruns presentation generation from saved args, and passes retry actions from conversations.

Sequence Diagram(s)

sequenceDiagram
  participant Conversations
  participant chatService
  participant handle_regenerate
  participant ops_ai_regenerate as ops::ai_regenerate
  participant store
  participant PresentationTool
  Conversations->>chatService: onRetry(artifactId, threadId)
  chatService->>handle_regenerate: openhuman.ai_regenerate
  handle_regenerate->>ops_ai_regenerate: ai_regenerate(...)
  ops_ai_regenerate->>store: read_artifact_args(workspace_dir, artifact_id)
  ops_ai_regenerate->>PresentationTool: execute(...)
  PresentationTool->>store: save_artifact_args(workspace_dir, meta.id, args)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

feature, rust-core

Suggested reviewers

  • senamakel
  • graycyrus

Poem

I hop where save-points softly glow,
And retry sprouts where failed cards show.
A dialog opens, paths align,
New artifact trails in tidy rhyme. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main artifact Save-As, in-progress, and retry changes.
Linked Issues check ✅ Passed The PR implements the native save dialog, downloads fallback, in-progress artifact wiring, retry behavior, and coverage tests for #3162.
Out of Scope Changes check ✅ Passed No clearly unrelated changes stand out; the regeneration and persistence work supports the retry flow and artifact UX.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jun 25, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 688f3578af

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +43 to +46

// `rfd` drives the OS-native dialog. On Linux this is the xdg-desktop
// portal (no GTK link); on macOS/Windows the system panel. The await
// resolves when the user picks a path or cancels.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict Save-As sources to artifact files

When the renderer invokes this new command directly, source_path only has to be an absolute path that exists, so any readable local file can be copied through the Save-As dialog under an artifact-looking filename. Since the command is exposed by the Tauri capability, validate that the source resolves under the workspace artifacts/ root (or accept an artifact id and resolve it in Rust) before opening the dialog/copying.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 6e4562a — both export commands now reject any source that does not canonicalize to inside the OpenHuman data dir's artifacts/ tree (via assert_artifact_source), so the renderer can no longer copy an arbitrary local file out through the dialog.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src-tauri/src/lib.rs (1)

3616-3623: 🩺 Stability & Availability | 🟡 Minor

Windows can still strand users if the Save-As dialog throws.

save_artifact_via_dialog falls back to downloadArtifact(), but that path invokes download_artifact_to_downloads, which is still gated to macOS/Linux here and in artifact_commands.rs. If the dialog ever fails on Windows, the recovery path becomes a missing-command error instead of a Downloads copy. Either make the download command available on Windows too, or skip that fallback there and surface the dialog error directly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src-tauri/src/lib.rs` around lines 3616 - 3623, The fallback path for
`save_artifact_via_dialog` is broken on Windows because it calls
`downloadArtifact()` while `download_artifact_to_downloads` remains gated to
macOS/Linux. Update the handler registration in `lib.rs` and the corresponding
definition in `artifact_commands.rs` so the download command is available on
Windows too, or change `save_artifact_via_dialog` to avoid that fallback on
Windows and return the dialog error directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/artifacts/store.rs`:
- Around line 449-459: Preserve the original created_at on the regenerate path
in Store::create_artifact (or the artifact metadata write path near the
REGENERATE_TARGET_ID handling), since reusing an existing artifact id should not
bump it to the top of the created_at-sorted list. Update the logic that
builds/writes the artifact meta so it only sets created_at to Utc::now() for new
UUIDs and reuses the existing timestamp when REGENERATE_TARGET_ID is present and
non-empty.

---

Outside diff comments:
In `@app/src-tauri/src/lib.rs`:
- Around line 3616-3623: The fallback path for `save_artifact_via_dialog` is
broken on Windows because it calls `downloadArtifact()` while
`download_artifact_to_downloads` remains gated to macOS/Linux. Update the
handler registration in `lib.rs` and the corresponding definition in
`artifact_commands.rs` so the download command is available on Windows too, or
change `save_artifact_via_dialog` to avoid that fallback on Windows and return
the dialog error directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3fa4aa6f-e970-47aa-be06-fd0ee82e6cbf

📥 Commits

Reviewing files that changed from the base of the PR and between 5984083 and 688f357.

⛔ Files ignored due to path filters (1)
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • app/src-tauri/Cargo.toml
  • app/src-tauri/capabilities/default.json
  • app/src-tauri/permissions/allow-artifact-save.toml
  • app/src-tauri/src/artifact_commands.rs
  • app/src-tauri/src/lib.rs
  • app/src/components/chat/ArtifactCard.test.tsx
  • app/src/components/chat/ArtifactCard.tsx
  • app/src/components/chat/ChatFilesPanel.tsx
  • app/src/components/chat/__tests__/ArtifactCard.test.tsx
  • app/src/pages/Conversations.tsx
  • app/src/providers/ChatRuntimeProvider.tsx
  • app/src/providers/__tests__/ChatRuntimeProvider.artifacts.test.tsx
  • app/src/services/__tests__/artifactDownloadService.test.ts
  • app/src/services/__tests__/chatService.artifactEvents.test.ts
  • app/src/services/artifactDownloadService.ts
  • app/src/services/chatService.ts
  • app/src/store/__tests__/chatRuntimeSlice.artifacts.test.ts
  • app/src/store/chatRuntimeSlice.ts
  • src/openhuman/artifacts/ops.rs
  • src/openhuman/artifacts/ops_tests.rs
  • src/openhuman/artifacts/schemas.rs
  • src/openhuman/artifacts/store.rs
  • src/openhuman/artifacts/store_tests.rs
  • src/openhuman/tools/impl/presentation/mod.rs

Comment thread src/openhuman/artifacts/store.rs Outdated
oxoxDev added 2 commits June 26, 2026 00:25
Reusing an artifact id in place must not bump created_at to now — that
would reorder the artifact to the top of the created_at-sorted list/
panel even though it is the same logical artifact. Read the prior meta's
timestamp when REGENERATE_TARGET_ID is set. (CodeRabbit on tinyhumansai#4127)
tinyhumansai#3162)

Two review fixes on the artifact export surface:
- Un-gate download_artifact_to_downloads to all desktop. It compiles on
  Windows (directories + tokio::fs::copy), and the Save-As Downloads
  fallback was previously broken there (missing-command error).
  (CodeRabbit on tinyhumansai#4127)
- Restrict both export commands to sources inside the OpenHuman data
  dir's artifacts/ tree (canonicalized, with an 'artifacts' path
  component), so a compromised renderer can't copy an arbitrary local
  file out through the Save-As dialog. (Codex P2 on tinyhumansai#4127)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/src-tauri/src/artifact_commands.rs (1)

17-18: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the cancel documentation with the actual contract.

The frontend treats Ok(None) as CANCELLED/no-op; fallback is only for dialog failures, not user cancellation.

Proposed doc fix
-//!    unavailable (e.g. no portal on headless Linux) or the user cancels.
+//!    unavailable (e.g. no portal on headless Linux).
+//!    User cancellation returns `Ok(None)` and is treated as a no-op.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src-tauri/src/artifact_commands.rs` around lines 17 - 18, The
fallback/cancel comment in the artifact dialog docs is inaccurate: the frontend
maps Ok(None) to CANCELLED/no-op, and fallback should only describe dialog
failures, not user cancellation. Update the documentation comment in the
artifact command area to reflect the actual contract around the dialog result
handling (especially the artifact command and its frontend fallback behavior),
so it clearly distinguishes cancel from unavailable dialog errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src-tauri/src/artifact_commands.rs`:
- Around line 109-112: The artifact detection in `source_path` is checking the
absolute `canon_source`, so any parent directory named `artifacts` can
incorrectly satisfy the condition. Update the `artifacts` check to inspect only
the path relative to the OpenHuman root before calling `.components().any(...)`,
using the existing `canon_source`/root path logic in `artifact_commands.rs`.
Adjust the check so only files actually inside the root’s `artifacts` directory
are accepted, and keep the rest of the flow unchanged.

---

Nitpick comments:
In `@app/src-tauri/src/artifact_commands.rs`:
- Around line 17-18: The fallback/cancel comment in the artifact dialog docs is
inaccurate: the frontend maps Ok(None) to CANCELLED/no-op, and fallback should
only describe dialog failures, not user cancellation. Update the documentation
comment in the artifact command area to reflect the actual contract around the
dialog result handling (especially the artifact command and its frontend
fallback behavior), so it clearly distinguishes cancel from unavailable dialog
errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 38b89631-9617-4dc8-b05b-e3367d576594

📥 Commits

Reviewing files that changed from the base of the PR and between 688f357 and 6e4562a.

📒 Files selected for processing (4)
  • app/src-tauri/src/artifact_commands.rs
  • app/src-tauri/src/lib.rs
  • src/openhuman/artifacts/store.rs
  • src/openhuman/artifacts/store_tests.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/openhuman/artifacts/store.rs
  • src/openhuman/artifacts/store_tests.rs

Comment thread app/src-tauri/src/artifact_commands.rs
@oxoxDev

oxoxDev commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the outside-diff finding (Save-As fallback broken on Windows) in 6e4562a: download_artifact_to_downloads is now un-gated to all desktop targets (it compiles on Windows — directories + tokio::fs::copy), so the saveArtifactViaDialog → Downloads fallback works on Windows instead of hitting a missing-command error. Both export commands are registered unconditionally in the handler list.

@senamakel senamakel merged commit d9c0663 into tinyhumansai:main Jun 25, 2026
33 of 35 checks passed
oxoxDev added a commit to oxoxDev/openhuman that referenced this pull request Jun 25, 2026
…3162)

assert_artifact_source searched the full absolute path for an 'artifacts'
component, so a root (or ancestor) named 'artifacts' would let any file
under the root pass. Strip the root prefix first and check the relative
path; add a regression test. Also correct the module doc: dialog cancel
returns Ok(None) (no-op), it does not trigger the Downloads fallback.
(CodeRabbit on tinyhumansai#4127)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Artifact UX polish: native save-file dialog + ChatToolCallEvent in-progress wiring

2 participants