Skip to content

Extensions system - #40

Draft
cxnmai wants to merge 54 commits into
mainfrom
extensions-system
Draft

cxnmai wants to merge 54 commits into
mainfrom
extensions-system

Conversation

@cxnmai

@cxnmai cxnmai commented Jul 13, 2026 •

Copy link
Copy Markdown
Collaborator

Adds an extension system via packaging wasmtime, a webassembly interpreter along with an exposed api to edit flowstate documents. Extensions can be written in any language and compiled to webassembly.

Summary by CodeRabbit

  • New Features
    • Added support for discovering, installing, and running trusted WebAssembly extensions.
    • Added an Extensions panel with actions, status updates, output, cancellation, and trust approval.
    • Extensions can inspect and edit documents, refresh from disk, request directory access, and use controlled runtime capabilities.
    • Added generation-checked document editing with support for text, blocks, tables, and assets.
  • Documentation
    • Added extension installation, manifest, permissions, runtime, and document API guidance.
  • Examples
    • Added an all-capabilities extension demonstrating supported workflows.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a WebAssembly extension subsystem spanning manifest discovery, trust verification, Wasmtime execution, editor document APIs, workspace integration, UI controls, persistence, tests, documentation, and an all-capabilities example extension.

Changes

Extension contracts and discovery

Layer / File(s) Summary
Manifest, discovery, trust, and public API
crates/flowstate-extension/..., docs/extensions.md
Defines the extension manifest and WIT contract, validates identifiers and component paths, discovers installed extensions, computes component digests, tracks trust decisions, and documents the system.
Editor snapshots and edits
crates/gpui-flowtext/...
Adds typed snapshots, generation-checked edits, JSON wire conversion, asset normalization, disk refresh, and validation tests.
Wasmtime runtime
crates/flowstate-extension/src/runtime*, crates/flowstate-extension/tests/...
Adds WASI component execution, host callbacks, caching, limits, cancellation, serialized runs, directory grants, fixtures, and end-to-end tests.
Workspace service and host bridge
crates/flowstate/src/workspace/extensions_panel/..., crates/flowstate/src/workspace/extension_host_loop.rs
Connects runtime calls to workspace editor operations through typed request/reply channels, event queues, persisted trust, and directory grants.
Extensions panel and workspace wiring
crates/flowstate/src/workspace/...
Adds panel state, trust prompts, action invocation and cancellation, extension rendering, toolkit routing, workspace initialization, and refresh handling.
All-capabilities example
examples/extensions/all-capabilities/...
Adds a buildable guest extension demonstrating document edits, filesystem access, networking, runtime capabilities, directory grants, output capture, and cancellation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ExtensionsPanel
  participant ExtensionService
  participant Runtime
  participant RichTextEditor
  participant GuestExtension
  User->>ExtensionsPanel: select extension action
  ExtensionsPanel->>ExtensionService: invoke action with host bridge
  ExtensionService->>Runtime: execute component
  Runtime->>GuestExtension: call run(action-id)
  GuestExtension->>RichTextEditor: request snapshot or apply edits
  RichTextEditor-->>GuestExtension: return JSON result
  GuestExtension-->>Runtime: return action result and output
  Runtime-->>ExtensionService: emit lifecycle and output events
  ExtensionService-->>ExtensionsPanel: update action state and output
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.60% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is related to the PR, but it's too broad to clearly convey the main change or scope. Use a more specific title like "Add Wasmtime-based Flowstate extensions system".
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch extensions-system

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@cxnmai
cxnmai marked this pull request as draft July 13, 2026 06:38

@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: 4

🧹 Nitpick comments (4)
crates/gpui-flowtext/Cargo.toml (1)

22-22: 🗄️ Data Integrity & Integration | 🔵 Trivial

Audit serde_json consumers for arbitrary_precision fallout. This feature will be unified into every workspace crate that depends on serde_json; check crates/flowstate-flow/src/persistence.rs (from_value on Value) and vendor/gpui-component/src/highlighter/registry.rs (#[serde(flatten)]) for round-trip regressions.

🤖 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 `@crates/gpui-flowtext/Cargo.toml` at line 22, Audit serde_json consumers
affected by enabling the workspace-wide arbitrary_precision feature, focusing on
Value::from_value in persistence.rs and the #[serde(flatten)] handling in
highlighter registry code. Verify JSON round trips preserve existing behavior,
and adjust the affected consumers or deserialization logic as needed to prevent
regressions.
crates/flowstate-extension/src/runtime.rs (1)

119-153: 🩺 Stability & Availability | 🔵 Trivial

Consider adding an automatic execution timeout alongside epoch-based cancellation.

The epoch interruption mechanism only fires when cancel() is called externally. If an extension enters an infinite loop and cancellation is never triggered (e.g., panel closed, background execution), the invocation runs indefinitely, holding a thread and blocking further actions for that extension. Wasmtime recommends a background epoch ticker for automatic timeouts. Consider spawning a timer that periodically calls engine.increment_epoch(), or implementing a deadline-based timeout that auto-cancels after a configurable duration.

🤖 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 `@crates/flowstate-extension/src/runtime.rs` around lines 119 - 153, Add an
automatic execution timeout to invoke, alongside the existing
epoch_deadline_callback cancellation handling, so extensions that are never
externally cancelled cannot run indefinitely. Use a configurable duration and a
background timer or deadline mechanism to drive engine.increment_epoch() or
cancellation, ensure the timer is stopped when invoke completes, and preserve
the existing RuntimeError::Cancelled behavior.
crates/flowstate/src/workspace/workspace/documents.rs (1)

4-8: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Extension discovery and component hashing run synchronously during window construction.

ExtensionService::new builds a Wasmtime engine and this.extensions.reload() triggers installed(), which walks the extensions directory and computes ComponentDigest::from_file (reading and hashing each full .wasm) — all on the UI thread inside Workspace::new. With several or large components this can visibly delay window startup. Consider deferring the initial reload() to a background task / next frame, similar to how tub indexing and initial document loading are deferred here.

Also applies to: 130-130

🤖 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 `@crates/flowstate/src/workspace/workspace/documents.rs` around lines 4 - 8,
Defer extension initialization and initial discovery out of the synchronous
Workspace construction path around ExtensionService::new and
ExtensionPanelController::new. Create the service/controller without triggering
the blocking reload, then schedule the initial extensions reload asynchronously
or on the next frame, preserving the existing disconnected-controller fallback
and ensuring the controller receives refreshed results when discovery completes.
crates/flowstate/src/workspace/extension_host_loop.rs (1)

20-21: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Fixed 16 ms polling adds latency to every synchronous host round-trip.

The guest blocks on each host call (snapshot, selection, apply_edits, …) via the bounded reply channel, but requests are only drained once per 16 ms tick. An action that makes several host calls in sequence therefore pays up to ~16 ms per call, which can feel sluggish for chatty extensions. Consider signalling the loop on request arrival (e.g. a notify/wake channel) rather than fixed-interval polling. Please confirm the expected call volume per action to gauge impact.

Also applies to: 139-139

🤖 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 `@crates/flowstate/src/workspace/extension_host_loop.rs` around lines 20 - 21,
Replace the fixed 16 ms polling in the request-processing loop around
requests.try_recv() with request-arrival signalling, such as a notify or wake
channel, so each host request is drained immediately and synchronous guest
round-trips avoid per-call polling latency. Preserve the existing request
handling and bounded reply-channel behavior, and account for actions issuing
multiple sequential host calls when wiring the wake path.
🤖 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 `@crates/flowstate-extension/Cargo.toml`:
- Around line 9-18: Update the wasmtime, wasmtime-wasi, and wasmtime-wasi-http
dependency entries to version 38.0.4 or newer, keeping all three family members
aligned or moving them to a newer major together. Leave the existing sha2
dependency and trust.rs Digest::digest usage unchanged.

In `@crates/flowstate-extension/src/runtime.rs`:
- Around line 28-30: Update RuntimeConfig::default so allow_network defaults to
false, ensuring extensions do not receive network access unless explicitly
enabled by the workspace or another existing configuration path. Preserve the
current memory_limit and output_limit defaults.

In `@crates/flowstate/src/workspace/extension_host_loop.rs`:
- Around line 129-139: Update the terminal assignment in the workspace host loop
to default to true when workspace.update fails, so a dropped Workspace causes
the loop to break instead of continuing to wake every 16ms; preserve the
existing state-based terminal result on successful updates.

In `@examples/extensions/all-capabilities/src/actions/mod.rs`:
- Around line 10-29: Update run so it does not overwrite status messages set by
successful actions such as document::inspect, filesystem operations, and
runtime::exercise; preserve the action-provided status on success. On failure,
report the underlying error text in the status instead of replacing it with
plain “Failed,” while retaining the existing Result return behavior.

---

Nitpick comments:
In `@crates/flowstate-extension/src/runtime.rs`:
- Around line 119-153: Add an automatic execution timeout to invoke, alongside
the existing epoch_deadline_callback cancellation handling, so extensions that
are never externally cancelled cannot run indefinitely. Use a configurable
duration and a background timer or deadline mechanism to drive
engine.increment_epoch() or cancellation, ensure the timer is stopped when
invoke completes, and preserve the existing RuntimeError::Cancelled behavior.

In `@crates/flowstate/src/workspace/extension_host_loop.rs`:
- Around line 20-21: Replace the fixed 16 ms polling in the request-processing
loop around requests.try_recv() with request-arrival signalling, such as a
notify or wake channel, so each host request is drained immediately and
synchronous guest round-trips avoid per-call polling latency. Preserve the
existing request handling and bounded reply-channel behavior, and account for
actions issuing multiple sequential host calls when wiring the wake path.

In `@crates/flowstate/src/workspace/workspace/documents.rs`:
- Around line 4-8: Defer extension initialization and initial discovery out of
the synchronous Workspace construction path around ExtensionService::new and
ExtensionPanelController::new. Create the service/controller without triggering
the blocking reload, then schedule the initial extensions reload asynchronously
or on the next frame, preserving the existing disconnected-controller fallback
and ensuring the controller receives refreshed results when discovery completes.

In `@crates/gpui-flowtext/Cargo.toml`:
- Line 22: Audit serde_json consumers affected by enabling the workspace-wide
arbitrary_precision feature, focusing on Value::from_value in persistence.rs and
the #[serde(flatten)] handling in highlighter registry code. Verify JSON round
trips preserve existing behavior, and adjust the affected consumers or
deserialization logic as needed to prevent regressions.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: a69c2c60-6857-4113-bf2f-a9f211166791

📥 Commits

Reviewing files that changed from the base of the PR and between bc51a51 and 61e9f62.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • examples/extensions/all-capabilities/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (44)
  • crates/flowstate-extension/Cargo.toml
  • crates/flowstate-extension/src/discovery.rs
  • crates/flowstate-extension/src/lib.rs
  • crates/flowstate-extension/src/manifest.rs
  • crates/flowstate-extension/src/runtime.rs
  • crates/flowstate-extension/src/runtime/host_state.rs
  • crates/flowstate-extension/src/trust.rs
  • crates/flowstate-extension/tests/fixtures/success.wat
  • crates/flowstate-extension/tests/fixtures/wasi_environment.wat
  • crates/flowstate-extension/tests/manifest.rs
  • crates/flowstate-extension/tests/runtime_e2e.rs
  • crates/flowstate-extension/wit/extension.wit
  • crates/flowstate/Cargo.toml
  • crates/flowstate/src/workspace/extension_host_loop.rs
  • crates/flowstate/src/workspace/extensions_panel/bridge.rs
  • crates/flowstate/src/workspace/extensions_panel/mod.rs
  • crates/flowstate/src/workspace/extensions_panel/model.rs
  • crates/flowstate/src/workspace/extensions_panel/service.rs
  • crates/flowstate/src/workspace/extensions_tool.rs
  • crates/flowstate/src/workspace/mod.rs
  • crates/flowstate/src/workspace/toolkit_panel.rs
  • crates/flowstate/src/workspace/workspace/documents.rs
  • crates/flowstate/src/workspace/workspace/mod.rs
  • crates/gpui-flowtext/Cargo.toml
  • crates/gpui-flowtext/src/rich_text/editor/extension_api.rs
  • crates/gpui-flowtext/src/rich_text/editor/extension_snapshot.rs
  • crates/gpui-flowtext/src/rich_text/editor/extension_wire.rs
  • crates/gpui-flowtext/src/rich_text/editor/lifecycle.rs
  • crates/gpui-flowtext/src/rich_text/editor/mod.rs
  • docs/extensions.md
  • examples/extensions/all-capabilities/.gitignore
  • examples/extensions/all-capabilities/Cargo.toml
  • examples/extensions/all-capabilities/README.md
  • examples/extensions/all-capabilities/extension.toml
  • examples/extensions/all-capabilities/src/actions/blocks.rs
  • examples/extensions/all-capabilities/src/actions/document.rs
  • examples/extensions/all-capabilities/src/actions/filesystem.rs
  • examples/extensions/all-capabilities/src/actions/mod.rs
  • examples/extensions/all-capabilities/src/actions/network.rs
  • examples/extensions/all-capabilities/src/actions/runtime.rs
  • examples/extensions/all-capabilities/src/actions/table.rs
  • examples/extensions/all-capabilities/src/bindings.rs
  • examples/extensions/all-capabilities/src/lib.rs
  • examples/extensions/all-capabilities/wit/extension.wit

Comment on lines +9 to +18
bytes = "1.12.1"
hex = "0.4.3"
parking_lot = "0.12.5"
serde = { workspace = true, features = ["derive"] }
sha2 = "0.11.0"
thiserror = "2.0.18"
toml.workspace = true
wasmtime = { version = "38", features = ["component-model", "cranelift", "runtime"] }
wasmtime-wasi = "38"
wasmtime-wasi-http = "38"

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the latest version of the wasmtime crate on crates.io as of July 2026, and are there any known security advisories for wasmtime version 38?

💡 Result:

As of July 13, 2026, the latest version of the wasmtime crate available on crates.io is 45.0.1 [1][2]. Regarding wasmtime version 38, there are known security advisories associated with this release series: 1. GHSA-4h67-722j-5pmc (CVE-2025-62711): Versions 38.0.0, 38.0.1, and 38.0.2 contained a bug in the implementation of component-model related host-to-wasm trampolines. This vulnerability could allow a carefully crafted component to crash the host with a segfault or assertion failure [3][4]. This was patched in version 38.0.3 [3][4]. 2. GHSA-hc7m-r6v8-hg9q (RUSTSEC-2025-0118): This advisory identified an unsound API interaction where WebAssembly shared linear memory could be improperly accessed, potentially leading to data races. Versions up to and including 38.0.3 were affected [5][6]. This was addressed in version 38.0.4 [5][6].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## files\n'
git ls-files crates/flowstate-extension/Cargo.toml crates/flowstate-extension

printf '\n## Cargo.toml\n'
cat -n crates/flowstate-extension/Cargo.toml

printf '\n## trust.rs locations\n'
rg -n "Sha256::digest|Digest::digest|use sha2|sha2" crates/flowstate-extension -S

Repository: realartists-gitmo/flowstate

Length of output: 1691


🌐 Web query:

Does sha2 0.11.0 still expose the Digesttrait andSha256::digest API used in sha2 0.10.x? Also, what is the current latest 38.x patch release for wasmtime on crates.io?

💡 Result:

Yes, the sha2 crate in version 0.11.0 continues to expose the Digest trait and the Sha256::digest API, maintaining compatibility with the one-shot API patterns used in version 0.10.x [1][2][3]. Regarding the wasmtime crate, the latest 38.x patch release available on crates.io is 38.0.4 [4][5].

Citations:


Bump the wasmtime family to 38.0.4+
wasmtime 38.0.0-38.0.3 have known advisories; keep wasmtime, wasmtime-wasi, and wasmtime-wasi-http on at least 38.0.4 (or a newer major). The sha2 0.11.0 Digest::digest call in trust.rs is still valid.

🤖 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 `@crates/flowstate-extension/Cargo.toml` around lines 9 - 18, Update the
wasmtime, wasmtime-wasi, and wasmtime-wasi-http dependency entries to version
38.0.4 or newer, keeping all three family members aligned or moving them to a
newer major together. Leave the existing sha2 dependency and trust.rs
Digest::digest usage unchanged.

Comment on lines +28 to +30
impl Default for RuntimeConfig {
fn default() -> Self { Self { memory_limit: 1024 * 1024 * 1024, output_limit: OUTPUT_LIMIT, allow_network: true } }
}

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

allow_network: true default grants network access to all extensions without per-extension opt-in.

RuntimeConfig::default() sets allow_network: true, so any Runtime constructed with default config gives extensions HTTP, DNS, and socket access. While the trust prompt informs users about network access, there is no per-extension capability declaration — extensions that don't need network still receive it. Consider defaulting to false and having the workspace explicitly enable network, or adding per-extension capability declarations in the manifest.

As per coding guidelines, this file matches **/*.rs; the gpui-component and clippy guidelines do not apply to this security concern.

🔒 Proposed fix: default to least-privilege
 impl Default for RuntimeConfig {
-    fn default() -> Self { Self { memory_limit: 1024 * 1024 * 1024, output_limit: OUTPUT_LIMIT, allow_network: true } }
+    fn default() -> Self { Self { memory_limit: 1024 * 1024 * 1024, output_limit: OUTPUT_LIMIT, allow_network: false } }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
impl Default for RuntimeConfig {
fn default() -> Self { Self { memory_limit: 1024 * 1024 * 1024, output_limit: OUTPUT_LIMIT, allow_network: true } }
}
impl Default for RuntimeConfig {
fn default() -> Self { Self { memory_limit: 1024 * 1024 * 1024, output_limit: OUTPUT_LIMIT, allow_network: false } }
}
🤖 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 `@crates/flowstate-extension/src/runtime.rs` around lines 28 - 30, Update
RuntimeConfig::default so allow_network defaults to false, ensuring extensions
do not receive network access unless explicitly enabled by the workspace or
another existing configuration path. Preserve the current memory_limit and
output_limit defaults.

Comment on lines +129 to +139
let terminal = workspace
.update(cx, |workspace, cx| {
let events = workspace.extension_service.as_ref().map_or_else(Vec::new, |service| service.drain_events_for(extension_id.as_ref()));
for event in events { workspace.extensions.apply(event); }
let terminal = !matches!(workspace.extensions.state(extension_id.as_ref()), ExtensionRunState::Running { .. });
if terminal { cx.notify(); }
terminal
})
.unwrap_or(false);
if terminal { break }
Timer::after(Duration::from_millis(16)).await;

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file structure first
ast-grep outline crates/flowstate/src/workspace/extension_host_loop.rs --view expanded

# Show the relevant section with line numbers
sed -n '1,260p' crates/flowstate/src/workspace/extension_host_loop.rs

# Search for the workspace loop/task and any cancellation/drop handling
rg -n "extension_host_loop|Timer::after|update\\(cx|unwrap_or\\(false\\)|Workspace|spawn|cancel|drop" crates/flowstate/src/workspace -S

Repository: realartists-gitmo/flowstate

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the similar polling loop in toolkit_panel
sed -n '340,380p' crates/flowstate/src/workspace/toolkit_panel.rs

# Look for other async spawn loops that handle update failures differently
rg -n "\.unwrap_or\((false|true)\);|Timer::after\(Duration::from_millis\(" crates/flowstate/src/workspace -S

# Check whether the spawned workspace task is treated like a cancellable weak entity elsewhere
rg -n "cx\.spawn\(async move \|workspace, cx\|" crates/flowstate/src/workspace -S | head -n 40

Repository: realartists-gitmo/flowstate

Length of output: 3357


🌐 Web query:

GPUI cx.spawn async move |entity, cx| task canceled when entity dropped update returns Err semantics

💡 Result:

In GPUI, when you use cx.spawn, the provided entity handle is a WeakEntity, which is designed to prevent leaks during long-running asynchronous operations [1][2]. If the underlying entity is dropped, calling update on the WeakEntity returns Err, signifying that the operation cannot be completed because the target entity no longer exists [2][3]. Key points regarding these semantics: 1. Handling Entity Lifecycle: Because the entity might be dropped while an async task is running, you must always handle the Result returned by WeakEntity::update [2][3]. Common patterns include using.ok to discard the error if you only care about updating the entity if it still exists, or handling the Err branch to perform cleanup if necessary [2][4][3]. 2. Task Cancellation: GPUI tasks (returned by cx.spawn) are futures that are cancelled if they are dropped [5][6]. If you want a task to run to completion regardless of the parent entity's lifecycle, you must either: - Detach the task using task.detach, which allows it to run to completion in the background without needing to hold onto the Task handle [5][2][6]. - Store the Task in a struct field, which binds the task's lifetime to the lifetime of that struct [2][6]. 3. Async Contexts: cx.spawn provides an AsyncApp or AsyncWindowContext (depending on the caller context), which are specifically designed to be held across await points [7][4][6]. These contexts maintain a weak reference to the application state, ensuring that even if the App or a Window is dropped, the system does not panic, though the internal WeakEntity updates will return Err as noted [7][4]. For scenarios where you need to perform cleanup precisely when an entity is dropped, you can use the on_drop method on an entity handle, which schedules a callback to run upon the entity's destruction [1][7][4].

Citations:


Break the host loop when the workspace is gone
workspace.update(cx, …) returns Err once the Workspace entity is dropped, and this detached task will keep waking every 16ms forever. Default the terminal check to true on update failure so the loop exits.

🔒️ Break the loop when the workspace is gone
       })
-      .unwrap_or(false);
+      .unwrap_or(true);
     if terminal { break }
     Timer::after(Duration::from_millis(16)).await;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let terminal = workspace
.update(cx, |workspace, cx| {
let events = workspace.extension_service.as_ref().map_or_else(Vec::new, |service| service.drain_events_for(extension_id.as_ref()));
for event in events { workspace.extensions.apply(event); }
let terminal = !matches!(workspace.extensions.state(extension_id.as_ref()), ExtensionRunState::Running { .. });
if terminal { cx.notify(); }
terminal
})
.unwrap_or(false);
if terminal { break }
Timer::after(Duration::from_millis(16)).await;
let terminal = workspace
.update(cx, |workspace, cx| {
let events = workspace.extension_service.as_ref().map_or_else(Vec::new, |service| service.drain_events_for(extension_id.as_ref()));
for event in events { workspace.extensions.apply(event); }
let terminal = !matches!(workspace.extensions.state(extension_id.as_ref()), ExtensionRunState::Running { .. });
if terminal { cx.notify(); }
terminal
})
.unwrap_or(true);
if terminal { break }
Timer::after(Duration::from_millis(16)).await;
🤖 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 `@crates/flowstate/src/workspace/extension_host_loop.rs` around lines 129 -
139, Update the terminal assignment in the workspace host loop to default to
true when workspace.update fails, so a dropped Workspace causes the loop to
break instead of continuing to wake every 16ms; preserve the existing
state-based terminal result on successful updates.

Comment on lines +10 to +29
pub fn run(action_id: &str) -> Result<(), String> {
host::set_status(&format!("Running {action_id}…"));
let result = match action_id {
"inspect" => document::inspect(),
"replace-selection" => document::replace_selection(),
"delete-selection" => document::delete_selection(),
"insert-blocks" => blocks::insert(),
"replace-table-cell" => table::replace_selected_cell(),
"refresh" => document::refresh(),
"filesystem" => filesystem::exercise(),
"network" => network::fetch_example(),
"request-directory" => filesystem::request_directory(),
"access-last-grant" => filesystem::access_last_grant(),
"runtime" => runtime::exercise(),
"cancellable-loop" => runtime::cancellable_loop(),
_ => Err(format!("unknown action: {action_id}")),
};
host::set_status(if result.is_ok() { "Finished" } else { "Failed" });
result
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the action dispatcher and the status helper usage.
git ls-files 'examples/extensions/all-capabilities/src/actions/*' 'examples/extensions/all-capabilities/src/*' | sed -n '1,120p'

printf '\n--- outline ---\n'
ast-grep outline examples/extensions/all-capabilities/src/actions/mod.rs --view expanded || true

printf '\n--- status helper search ---\n'
rg -n "set_status|status" examples/extensions/all-capabilities/src -g '!**/target/**' || true

Repository: realartists-gitmo/flowstate

Length of output: 2175


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the dispatcher and the action implementations that are mentioned in the comment.
sed -n '1,120p' examples/extensions/all-capabilities/src/actions/mod.rs

printf '\n--- document.rs ---\n'
sed -n '1,220p' examples/extensions/all-capabilities/src/actions/document.rs

printf '\n--- filesystem.rs ---\n'
sed -n '1,260p' examples/extensions/all-capabilities/src/actions/filesystem.rs

printf '\n--- runtime.rs ---\n'
sed -n '1,220p' examples/extensions/all-capabilities/src/actions/runtime.rs

printf '\n--- host status helper ---\n'
rg -n "fn set_status|set_status\(" examples/extensions/all-capabilities/src -g '!**/target/**' || true

Repository: realartists-gitmo/flowstate

Length of output: 8518


Preserve the action’s status message
Line 27 overwrites statuses set by inspect(), filesystem::*, and runtime::exercise(), so the final UI message loses the action’s result. Keep the action-set status on success; if failure handling is needed, include the error text instead of plain Failed.

🤖 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 `@examples/extensions/all-capabilities/src/actions/mod.rs` around lines 10 -
29, Update run so it does not overwrite status messages set by successful
actions such as document::inspect, filesystem operations, and runtime::exercise;
preserve the action-provided status on success. On failure, report the
underlying error text in the status instead of replacing it with plain “Failed,”
while retaining the existing Result return behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant