Skip to content

fix(core): seed tool-execution timeout on the always-on boot path (#5027)#5078

Merged
senamakel merged 5 commits into
tinyhumansai:mainfrom
oxoxDev:fix/5027-tool-timeout-seed-decouple
Jul 21, 2026
Merged

fix(core): seed tool-execution timeout on the always-on boot path (#5027)#5078
senamakel merged 5 commits into
tinyhumansai:mainfrom
oxoxDev:fix/5027-tool-timeout-seed-decouple

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Moves the tool-execution timeout seed off the chat-channel startup path onto the always-on boot path, so a user's configured [agent].agent_timeout_secs takes effect on every boot — not only when a chat channel is connected.
  • Retires a dead legacy no-op (register_workflow_cleanup_subscriber) whose real successor is already registered on the always-on path.
  • Core-only; desktop behaviour unchanged.

Problem

start_channels is skipped entirely when no chat integration is configured (spawn_channels_service early-returns on !has_listening_integrations(), and also under OPENHUMAN_DISABLE_CHANNEL_LISTENERS=1). Two things were still wired inside it:

  1. The tool-timeout seed — the only boot-time call of set_tool_timeout_secs. On channel-less installs the persisted [agent].agent_timeout_secs was silently ignored and tools ran on the built-in default until a Settings save happened to re-seed it.
  2. register_workflow_cleanup_subscriber — a documented legacy no-op (pub fn …() {}); its successor ensure_triggered_workflow_subscriber is already registered on the always-on boot path. Moving a no-op would only mislead readers.

Same coupling class as #5003 (learning subscribers), which this file already carries a NOTE about.

Solution

  • Seed on the always-on path. The seed moves into the ungated INFRA: Once block of register_domain_subscribers, right after tokenjuice::install_from_config. That block is the file's home for config-derived process-global boot seeds, is DomainSet-independent (so the timeout seeds even under harness()/none()), runs exactly once with config in scope, and runs earlier than start_channels did — so the configured timeout is live strictly sooner.
  • Delete the seed from start_channels, leaving a fix(learning): email-signature subscriber + rebuild trigger silently depend on channels being configured #5003-style NOTE pointing at the new home and why.
  • Retire the no-op: delete the call site, the pub fn, its doc, its _is_a_safe_noop test, and the matching stub fn (keeping ensure_triggered_workflow_subscriber). Post-change git grep register_workflow_cleanup_subscriber is empty.
  • Doc sweep: tool_timeout/README.md now names core::jsonrpc::register_domain_subscribers as the seed site.

Submission Checklist

  • Tests added: tool_timeout_seeds_on_channelless_core_boot — channel-less Config (agent_timeout_secs = 1234), minimal DomainSet::none(), asserts the effective timeout is seeded (the failure the fix targets: without the move, a channel-less boot leaves the default). ENV_LOCK-serialized, OPENHUMAN_TOOL_TIMEOUT_SECS cleared.
  • Diff coverage ≥ 80% — the added seed line is exercised by the new test; the rest of the diff is deletions (dead no-op + moved seed). Enforced on merge by CI.
  • N/A: behaviour-only change — no coverage-matrix feature rows added/removed/renamed.
  • No matrix feature IDs affected — see ## Related.
  • No new external network dependencies introduced.
  • N/A: does not touch a release-cut manual-smoke surface (internal boot wiring; desktop path byte-identical).
  • Linked issue closed via Closes #5027 in ## Related.

Impact

  • Platform: core only. Desktop (channel-configured) behaviour unchanged — same seed value, now applied on a path that also runs channel-less.
  • User-visible: channel-less users get their configured action-timeout honoured from the first tool call instead of after a Settings re-save.
  • Binary size / migration: none.
  • Risk: low. Seed is an idempotent atomic store under Once; the settings-update RPC path still re-seeds on change. Verified: cargo check (default + gates-off), fmt/clippy -D warnings clean, tool_timeout 14 passed, core::jsonrpc 94 passed (incl. new test), skills::bus 16 passed.

Related


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

Linear Issue

Commit & Branch

  • Branch: fix/5027-tool-timeout-seed-decouple
  • Commit SHA: 11394080f

Validation Run

  • N/A: pnpm typecheck / format:check — no TypeScript or frontend files changed
  • cargo fmt --check clean; cargo check (default) clean; cargo clippy -- -D warnings clean
  • Gates-off compiles: GGML_NATIVE=OFF cargo check --no-default-features --features tokenjuice-treesitter
  • Focused tests: cargo test --lib openhuman::tool_timeout (14) + core::jsonrpc (94, incl. new) + skills::bus (16)

Behavior Changes

  • Intended behavior change: the configured tool-execution timeout is seeded on every core boot, including channel-less installs.
  • User-visible effect: channel-less users' [agent].agent_timeout_secs is honoured from the first tool call.

Parity Contract

  • Legacy behavior preserved: channel-configured desktop boots seed the same value as before; the settings-update RPC still re-seeds on change.
  • Guard/fallback/dispatch parity checks: register_workflow_cleanup_subscriber was a no-op; its successor ensure_triggered_workflow_subscriber remains registered on the always-on path.

Duplicate / Superseded PR Handling

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

Summary by CodeRabbit

  • Improvements
    • Tool-execution timeouts are now seeded from saved agent settings during core startup, including channel-less and web-chat-only configurations.
    • Updated startup behavior ensures the live timeout source is consistent across initialization paths.
  • Documentation
    • Clarified tool-timeout resolution order and the exact startup location responsible for runtime seeding.
  • Tests
    • Added a regression test to verify timeout seeding when running without channels.
  • Maintenance
    • Removed the obsolete workflow-cleanup subscriber registration from channel/skills startup paths.

oxoxDev added 3 commits July 21, 2026 15:35
…mansai#5027)

Move the [agent].agent_timeout_secs seed into the ungated INFRA: Once block
of register_domain_subscribers, so channel-less / web-chat-only cores (where
start_channels is skipped) still honour the configured tool-execution timeout
from the first tool call. The seed is DomainSet-independent, so even a minimal
DomainSet::none() boot applies it. Add a channel-less regression test.
…umansai#5027)

The seed now lives on the always-on core boot path in
core::jsonrpc::register_domain_subscribers (previous commit). Leave a
tinyhumansai#5003-style NOTE pointing at the new home and explaining why start_channels
is the wrong place (skipped for channel-less cores).
…-op (tinyhumansai#5027)

The legacy no-op has been superseded by ensure_triggered_workflow_subscriber
(already registered on the always-on path in core::jsonrpc). Delete its
call in start_channels, the empty fn + safe-noop test in skills::bus, and the
stub in skills::stub. Sweep the tool_timeout README to name the seed's new
home (core::jsonrpc::register_domain_subscribers).
@oxoxDev
oxoxDev requested a review from a team July 21, 2026 10:17
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: babf2fe5-5c4b-4b6e-9572-b1abffd5b5bb

📥 Commits

Reviewing files that changed from the base of the PR and between 1139408 and 849c476.

📒 Files selected for processing (2)
  • src/core/jsonrpc.rs
  • src/core/jsonrpc_tests.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/core/jsonrpc.rs
  • src/core/jsonrpc_tests.rs

📝 Walkthrough

Walkthrough

Core boot now seeds the global tool-execution timeout from persisted configuration, including channel-less cores. Channel startup no longer performs that seed or registers the legacy workflow-cleanup subscriber, whose APIs and no-op test were removed.

Changes

Core boot initialization

Layer / File(s) Summary
Always-on tool-timeout seeding
src/core/jsonrpc.rs, src/openhuman/channels/runtime/startup.rs, src/core/jsonrpc_tests.rs, src/openhuman/tool_timeout/README.md
The timeout is initialized during core subscriber registration, removed from channel startup, tested on channel-less boot, and documented at its new location.
Legacy workflow-cleanup removal
src/openhuman/channels/runtime/startup.rs, src/openhuman/skills/bus.rs, src/openhuman/skills/stub.rs
Channel startup no longer calls the legacy registration, and the production, stub, and no-op test surfaces are removed.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: rust-core, bug

Suggested reviewers: m3ga-mind

Poem

I’m a rabbit watching boot seeds grow,
Timeouts bloom where core winds blow.
Channels rest, yet clocks stay bright,
Old cleanup hops out of sight.
Thump, thump—tests guard the flow!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Clear and specific; it names the core change of seeding the tool-execution timeout on the always-on boot path.
Linked Issues check ✅ Passed The timeout seed and legacy workflow-cleanup registration were moved off start_channels, matching #5027's always-on bootstrap requirement.
Out of Scope Changes check ✅ Passed Changes stay focused on #5027: code, test, docs, and removal of the obsolete no-op helper.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@coderabbitai coderabbitai Bot added bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 21, 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: 11394080f0

ℹ️ 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 thread src/core/jsonrpc.rs Outdated
Comment on lines +1917 to +1918
let effective_timeout =
crate::openhuman::tool_timeout::set_tool_timeout_secs(config.agent.agent_timeout_secs);

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 Re-seed timeout outside the boot Once

When the desktop core is bounced in the same Tauri process (checked CoreProcessHandle::restart and reset_local_data, both stop the task and then call ensure_running), this INFRA Once is already consumed, so the restarted core never applies the newly loaded [agent].agent_timeout_secs. For example, after Clear Local Data deletes the old config and restarts into defaults, the process-global tool timeout can remain at the previous user's value until Settings is opened/saved; set_tool_timeout_secs is idempotent, so it should run on each bootstrap rather than only inside this Once.

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.

Good catch — valid. `bootstrap_core_runtime` does re-run on an in-process restart (`CoreProcessHandle::restart` → `ensure_running`, and `reset_local_data`) with a freshly reloaded `Config`, but the `INFRA: Once` is already consumed, so the seed never re-fired. Moved `set_tool_timeout_secs` out of the `Once` in `e61aaed8c` — it now re-seeds on every `register_domain_subscribers` call (idempotent atomic store), so a restart re-applies the current config.

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

🤖 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/core/jsonrpc_tests.rs`:
- Around line 98-103: Update the test setup around TEST_ENV_LOCK and
OPENHUMAN_TOOL_TIMEOUT_SECS to use an RAII or equivalent deferred-cleanup guard
that captures the original value, removes it for the test, and restores or
removes it on scope exit. Ensure cleanup runs even if setup, boot registration,
or assertions panic, including the corresponding restoration logic near the
additional referenced section.
- Around line 81-95: Update the test setup around the
OPENHUMAN_TOOL_TIMEOUT_SECS environment variable to use the existing RAII
environment guard pattern instead of manual cleanup. Ensure the guard captures
and restores the previous value even when the assertion panics, while preserving
the TEST_ENV_LOCK serialization and config-derived timeout behavior.
🪄 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: 79e97ce5-1a14-4115-8fd2-7e2dd78ccf30

📥 Commits

Reviewing files that changed from the base of the PR and between 9420a29 and 1139408.

📒 Files selected for processing (6)
  • src/core/jsonrpc.rs
  • src/core/jsonrpc_tests.rs
  • src/openhuman/channels/runtime/startup.rs
  • src/openhuman/skills/bus.rs
  • src/openhuman/skills/stub.rs
  • src/openhuman/tool_timeout/README.md
💤 Files with no reviewable changes (1)
  • src/openhuman/skills/bus.rs

Comment thread src/core/jsonrpc_tests.rs Outdated
Comment thread src/core/jsonrpc_tests.rs Outdated
oxoxDev added 2 commits July 21, 2026 17:51
…mansai#5027)

Move the tool-execution-timeout seed out of the process-global INFRA:Once
block in register_domain_subscribers. bootstrap_core_runtime re-runs on an
in-process core restart (CoreProcessHandle::restart -> ensure_running, and
reset_local_data / Clear-Local-Data) with a freshly reloaded Config, but the
Once is already consumed, so the previous config's timeout stayed pinned until
Settings was re-saved. set_tool_timeout_secs is idempotent (atomic store
honouring the env override), so re-seeding on every call re-applies the current
config each boot at no cost.
…humansai#5027)

Replace the channelless-boot seed test's manual TEST_ENV_LOCK acquisition +
end-of-test env restore with an EnvVarGuard (new remove_many) so a panicking
assertion still restores OPENHUMAN_TOOL_TIMEOUT_SECS on unwind — a shared-lock
sibling can no longer inherit the cleared var. Refresh the doc comment to match
the seed now living just before INFRA:Once (re-runs every boot), not inside it.
@oxoxDev

oxoxDev commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed both reviews (pushed `e61aaed8c` + `849c4767b`):

  • Codex — re-seed outside the boot `Once` (valid): `bootstrap_core_runtime` re-runs on an in-process restart (`CoreProcessHandle::restart`/`reset_local_data`) with a freshly reloaded config, but `INFRA: Once` was already consumed → stale timeout until Settings re-saved. Moved `set_tool_timeout_secs` just before `INFRA: Once` so it re-seeds every `register_domain_subscribers` call (idempotent atomic store).
  • CodeRabbit — panic-safe env restore in the seed test (valid): switched the manual `TEST_ENV_LOCK` + end-of-test restore to an `EnvVarGuard` (new `remove_many`) so `Drop` restores `OPENHUMAN_TOOL_TIMEOUT_SECS` on unwind.

Gates: `cargo check`/`fmt --check`/`clippy -D warnings` clean, gates-off `--no-default-features --features tokenjuice-treesitter` clean, `core::jsonrpc` + `openhuman::tool_timeout` tests green (`tool_timeout_seeds_on_channelless_core_boot` passes).

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

@oxoxDev: Thanks for the detailed follow-up. I’ll review the updated commits, including the per-restart timeout reseed and panic-safe environment restoration.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@senamakel
senamakel merged commit e2f9014 into tinyhumansai:main Jul 21, 2026
23 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Move workflow-cleanup subscriber + tool-timeout boot seed out of start_channels

2 participants