Skip to content

perf(core): update_provider_instructions calls blocking load_instructions inside async Box::pin context #3866

@bug-ops

Description

@bug-ops

Description

#3829 fixed load_instructions blocking I/O in runner.rs (startup) and agent/mod.rs (hot-reload watcher) by wrapping them in spawn_blocking. However, a third async call site was not addressed.

provider_cmd.rs::update_provider_instructions calls load_instructions synchronously. It is invoked via provider_switch_as_string → handle_provider_command_as_string, which is wrapped in:

// agent_access_impl.rs:518
Box::pin(async move { self.handle_provider_command_as_string(arg) })

This async block has no .await points, but the synchronous filesystem I/O (canonicalize, File::open, read_to_string, read_dir) still executes on the Tokio worker thread polling the future.

The PR #3854 commit message described this as "the remaining non-async call site" — but the call site is inside an async move block, which is an async context.

Reproduction Steps

  1. Configure multiple providers with instruction files.
  2. Run cargo run --features full -- --config .local/config/testing.toml.
  3. Type /provider <other-provider-name> to trigger a provider switch.
  4. Blocking I/O runs on Tokio worker thread during provider switch.

Expected Behavior

update_provider_instructions should use load_instructions_async (or mark itself async and await it), as the other two call sites now do.

Actual Behavior

Synchronous filesystem I/O runs on Tokio worker thread during /provider command.

Environment

  • Version: HEAD (c16c4dc)
  • File: crates/zeph-core/src/agent/provider_cmd.rs:317, crates/zeph-core/src/agent/agent_access_impl.rs:518
  • Severity: Low (infrequent path — only on explicit /provider command)

Metadata

Metadata

Assignees

Labels

P4Long-term / exploratory

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions