Skip to content

feat(integrations): stock-price tools and expanded Parallel surface#911

Merged
senamakel merged 5 commits into
tinyhumansai:mainfrom
senamakel:feat/parallel-stock-v2
Apr 25, 2026
Merged

feat(integrations): stock-price tools and expanded Parallel surface#911
senamakel merged 5 commits into
tinyhumansai:mainfrom
senamakel:feat/parallel-stock-v2

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Apr 25, 2026

Summary

Add five stock_* tools and four new parallel_* tools so research-style agents can answer questions like "what is the price of BTC?" with a dedicated market-data call instead of a generic web search, and tackle deeper, structured research without bouncing through search/extract loops.

Backed by:

  • backend #654 — Alpha Vantage market data under /agent-integrations/financial-apis/*
  • backend #653 — Parallel chat / deep research / enrich / dataset

Changes

New module — src/openhuman/integrations/stock_prices.rs (5 tools, all backend-proxied):

  • stock_quoteGLOBAL_QUOTE for stocks/indices (AAPL, SPY)
  • stock_exchange_rate — FX and crypto spot price (BTC/USD, EUR/USD) — the canonical "price of BTC" path
  • stock_options — realtime options chain (optional greeks)
  • stock_crypto_series — daily OHLCV
  • stock_commodity — WTI / BRENT / NATURAL_GAS

Extended — src/openhuman/integrations/parallel.rs (4 new tools):

  • parallel_chat — research-grounded chat (speed/lite/base/core)
  • parallel_research — Task API deep research; blocks inline (wait=true)
  • parallel_enrich — sync structured enrichment with required output schema
  • parallel_dataset — FindAll dataset generation, returns findall_id

Wiring:

  • IntegrationsConfig.stock_prices: IntegrationToggle (defaults on, like the others)
  • tools/ops.rs registers all new tools, gated by their respective toggles
  • Researcher (agents/researcher/agent.toml) gains the full Parallel + stock-prices surface
  • Planner (agents/planner/agent.toml) gains read-only research and stock tools so plans can be grounded in real numbers

Per the renaming ask, the user-facing name is stock_prices rather than "alphavantage" — the Alpha Vantage provider is an implementation detail of the backend route.

Test plan

  • cargo check clean
  • cargo test --lib openhuman::integrations:: — 66/66 pass (16 new tests for the new tools: metadata, schema-required fields, validation rejection, response deserialisation)
  • Live smoke test against staging once backend PRs land — "what is the price of BTC?" should route to stock_exchange_rate
  • Spot-check researcher/planner sessions actually see the new tool names in their tool schema

Summary by CodeRabbit

  • New Features

    • Agents (planner & researcher) now support parallelized operations: concurrent search, chat, research, enrichment, and dataset workflows.
    • New financial market-data tools: stock quotes, exchange rates, options, cryptocurrency series, and commodity pricing with concise user-facing summaries and metered cost reporting.
    • New config toggles to enable parallel and market-data integrations.
  • Tests

    • Added tests and synchronization for parallel and market-data integrations and improved validation for new tools.

Adds five new `stock_*` tools (quote, exchange_rate, options, crypto_series,
commodity) backed by the financial-apis backend route, and four new
`parallel_*` tools (chat, research, enrich, dataset) for the expanded
Parallel API. Wires both surfaces into the researcher and planner agents
so questions like "what is the price of BTC?" route to a dedicated
data tool instead of the generic web search. New `integrations.stock_prices`
toggle gates registration.
@senamakel senamakel requested a review from a team April 25, 2026 04:20
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1fa8b01b-4267-4d98-a2f7-8d7c3a36268d

📥 Commits

Reviewing files that changed from the base of the PR and between 7e00e2a and 3b8ce0d.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • src/openhuman/voice/postprocess.rs

📝 Walkthrough

Walkthrough

Expanded integrations with new parallel tools and a new stock_prices integration; updated planner/researcher agent tool allowlists; added config toggle for stock_prices; and wired conditional runtime registration of the new tools.

Changes

Cohort / File(s) Summary
Agent tool allowlists
src/openhuman/agent/agents/planner/agent.toml, src/openhuman/agent/agents/researcher/agent.toml
Expanded each agent's [tools].named to include additional parallel_* tools and multiple stock_* market-data tools.
Parallel integrations
src/openhuman/integrations/parallel.rs
Added ParallelChatTool, ParallelResearchTool, ParallelEnrichTool, ParallelDatasetTool with schemas, validation, POST calls to /agent-integrations/parallel/..., response deserialization, formatted ToolResult output, and tests.
Stock/market-data integrations
src/openhuman/integrations/stock_prices.rs, src/openhuman/integrations/mod.rs
New stock_prices module implementing StockQuoteTool, StockExchangeRateTool, StockOptionsTool, StockCryptoSeriesTool, StockCommodityTool; response types include costUsd; module re-exports added.
Config & registration
src/openhuman/config/schema/tools.rs, src/openhuman/tools/ops.rs
Added stock_prices: IntegrationToggle to IntegrationsConfig. all_tools_with_runtime now conditionally registers expanded parallel tools and the five stock tools behind integration flags, with debug logging.
Tests / test harness
src/openhuman/integrations/..., src/openhuman/voice/postprocess.rs
Added unit tests for new tools and synchronized test access to LOCAL_AI_TEST_MUTEX in voice postprocess tests to avoid shared-state races.

Sequence Diagram(s)

sequenceDiagram
participant Agent as Agent (planner / researcher)
participant Runtime as Runtime / Tool Registry
participant Integration as Integration Client
participant Backend as Integrations Backend

Agent->>Runtime: Request plan or invoke tool (e.g., `parallel_research` / `stock_quote`)
Runtime->>Integration: Validate params, build payload, POST /agent-integrations/{parallel|stock}/...
Integration->>Backend: Forward POST to backend endpoint
Backend-->>Integration: 200 OK + JSON (result, costUsd, optional findallId)
Integration-->>Runtime: Return ToolResult (formatted text + cost metadata)
Runtime-->>Agent: Deliver ToolResult
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through modules, nibbling new cues,
Parallel threads and market-price views,
I sketched tiny paths where tools now meet,
CostUsd counted — a carrot-sweet treat. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding stock-price tools and expanding the Parallel surface with new tools (parallel_chat, parallel_research, parallel_enrich, parallel_dataset). It is concise, specific, and clearly conveys the primary purpose of the changeset.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/openhuman/integrations/parallel.rs (1)

1-920: Consider splitting this file in a follow-up.

The file now exceeds ~1200 lines (including tests). Per coding guidelines, source files should be ≤ ~500 lines. Consider extracting the new tools into a sibling file (e.g., parallel_advanced.rs or parallel_chat.rs + parallel_research.rs) to improve maintainability.

This is a non-blocking suggestion for a future cleanup. As per coding guidelines: "Source files should be ≤ ~500 lines; split modules when growing to improve maintainability."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/openhuman/integrations/parallel.rs` around lines 1 - 920, The file is too
large; split the Parallel integration into smaller modules to meet the
≤~500-line guideline—extract related tools and their response types into new
files and re-export them from the parent module. For example, move
ParallelChatTool (plus ChatResponse/ChatChoice/ChatMessage),
ParallelResearchTool (ResearchResponse), ParallelEnrichTool (EnrichResponse),
and ParallelDatasetTool (DatasetResponse) into one or more new files (e.g.,
parallel_chat.rs, parallel_research.rs, parallel_enrich.rs /
parallel_dataset.rs) while keeping ParallelSearchTool, ParallelExtractTool, and
shared utilities (truncate_chars, IntegrationClient use, async_trait/serde
imports) in the original file or a shared helpers file; update the module
declarations to pub use or pub mod the new files and adjust imports (retain
symbols: ParallelChatTool, ParallelResearchTool, ParallelEnrichTool,
ParallelDatasetTool, ParallelSearchTool, ParallelExtractTool, truncate_chars,
SearchResponse, ExtractResponse) so callers keep the same API.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/openhuman/integrations/parallel.rs`:
- Around line 1-920: The file is too large; split the Parallel integration into
smaller modules to meet the ≤~500-line guideline—extract related tools and their
response types into new files and re-export them from the parent module. For
example, move ParallelChatTool (plus ChatResponse/ChatChoice/ChatMessage),
ParallelResearchTool (ResearchResponse), ParallelEnrichTool (EnrichResponse),
and ParallelDatasetTool (DatasetResponse) into one or more new files (e.g.,
parallel_chat.rs, parallel_research.rs, parallel_enrich.rs /
parallel_dataset.rs) while keeping ParallelSearchTool, ParallelExtractTool, and
shared utilities (truncate_chars, IntegrationClient use, async_trait/serde
imports) in the original file or a shared helpers file; update the module
declarations to pub use or pub mod the new files and adjust imports (retain
symbols: ParallelChatTool, ParallelResearchTool, ParallelEnrichTool,
ParallelDatasetTool, ParallelSearchTool, ParallelExtractTool, truncate_chars,
SearchResponse, ExtractResponse) so callers keep the same API.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4bcfbd35-cc73-4afd-9542-df8ae06b42e1

📥 Commits

Reviewing files that changed from the base of the PR and between a472bee and f056299.

📒 Files selected for processing (7)
  • src/openhuman/agent/agents/planner/agent.toml
  • src/openhuman/agent/agents/researcher/agent.toml
  • src/openhuman/config/schema/tools.rs
  • src/openhuman/integrations/mod.rs
  • src/openhuman/integrations/parallel.rs
  • src/openhuman/integrations/stock_prices.rs
  • src/openhuman/tools/ops.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/openhuman/tools/ops.rs`:
- Around line 303-338: Add unit tests that assert the tool registry includes the
new Parallel* (ParallelChatTool, ParallelResearchTool, ParallelEnrichTool,
ParallelDatasetTool) and Stock* (StockQuoteTool, StockExchangeRateTool,
StockOptionsTool, StockCryptoSeriesTool, StockCommodityTool) registrations when
their respective toggles (root_config.integrations.parallel.enabled and
root_config.integrations.stock_prices.enabled) are true, and that they are
absent when those toggles are false; locate the registry-building function that
pushes these tools (the code that calls
crate::openhuman::integrations::ParallelChatTool::new,
ParallelResearchTool::new, ParallelEnrichTool::new, ParallelDatasetTool::new,
StockQuoteTool::new, StockExchangeRateTool::new, StockOptionsTool::new,
StockCryptoSeriesTool::new, StockCommodityTool::new) and add focused tests that
construct a minimal root_config with toggles on/off, run the registry creation,
and assert presence/absence of the corresponding tool types (and add similar
assertions to the relevant JSON-RPC e2e test file if integration coverage is
required).
🪄 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: 4794addf-1a59-43a6-ac83-19139a00a034

📥 Commits

Reviewing files that changed from the base of the PR and between f056299 and 0dd545a.

📒 Files selected for processing (2)
  • src/openhuman/config/schema/tools.rs
  • src/openhuman/tools/ops.rs

Comment on lines +303 to +338
tools.push(Box::new(
crate::openhuman::integrations::ParallelChatTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::ParallelResearchTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::ParallelEnrichTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::ParallelDatasetTool::new(Arc::clone(&client)),
));
tracing::debug!("[integrations] registered parallel tools");
} else {
tracing::debug!("[integrations] parallel disabled — skipping");
}
if root_config.integrations.stock_prices.enabled {
tools.push(Box::new(
crate::openhuman::integrations::StockQuoteTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::StockExchangeRateTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::StockOptionsTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::StockCryptoSeriesTool::new(Arc::clone(&client)),
));
tools.push(Box::new(
crate::openhuman::integrations::StockCommodityTool::new(Arc::clone(&client)),
));
tracing::debug!("[integrations] registered stock_prices tools");
} else {
tracing::debug!("[integrations] stock_prices disabled — skipping");
}
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.

⚠️ Potential issue | 🟠 Major

Add regression tests for new toggle-gated tool registrations.

Lines 303-338 add nine new tool registrations, but this file’s tests do not assert presence/absence of these new parallel_* and stock_* tools under enabled/disabled toggles. Please add focused registry tests to lock this behavior.

✅ Suggested test scaffold
+    #[test]
+    fn all_tools_registers_new_parallel_and_stock_tools_when_enabled() {
+        let tmp = TempDir::new().unwrap();
+        let security = Arc::new(SecurityPolicy::default());
+        let mem_cfg = MemoryConfig {
+            backend: "markdown".into(),
+            ..MemoryConfig::default()
+        };
+        let mem: Arc<dyn Memory> =
+            Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path()).unwrap());
+        let browser = BrowserConfig::default();
+        let http = crate::openhuman::config::HttpRequestConfig::default();
+        let mut cfg = test_config(&tmp);
+        cfg.integrations.parallel.enabled = true;
+        cfg.integrations.stock_prices.enabled = true;
+
+        let tools = all_tools(
+            Arc::new(cfg.clone()),
+            &security,
+            mem,
+            &browser,
+            &http,
+            tmp.path(),
+            &HashMap::new(),
+            &cfg,
+        );
+        let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
+        for expected in [
+            "parallel_chat",
+            "parallel_research",
+            "parallel_enrich",
+            "parallel_dataset",
+            "stock_quote",
+            "stock_exchange_rate",
+            "stock_options",
+            "stock_crypto_series",
+            "stock_commodity",
+        ] {
+            assert!(names.contains(&expected), "{expected} must be registered; got: {names:?}");
+        }
+    }
+
+    #[test]
+    fn all_tools_skips_new_parallel_and_stock_tools_when_disabled() {
+        let tmp = TempDir::new().unwrap();
+        let security = Arc::new(SecurityPolicy::default());
+        let mem_cfg = MemoryConfig {
+            backend: "markdown".into(),
+            ..MemoryConfig::default()
+        };
+        let mem: Arc<dyn Memory> =
+            Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path()).unwrap());
+        let browser = BrowserConfig::default();
+        let http = crate::openhuman::config::HttpRequestConfig::default();
+        let mut cfg = test_config(&tmp);
+        cfg.integrations.parallel.enabled = false;
+        cfg.integrations.stock_prices.enabled = false;
+
+        let tools = all_tools(
+            Arc::new(cfg.clone()),
+            &security,
+            mem,
+            &browser,
+            &http,
+            tmp.path(),
+            &HashMap::new(),
+            &cfg,
+        );
+        let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
+        for unexpected in [
+            "parallel_chat",
+            "parallel_research",
+            "parallel_enrich",
+            "parallel_dataset",
+            "stock_quote",
+            "stock_exchange_rate",
+            "stock_options",
+            "stock_crypto_series",
+            "stock_commodity",
+        ] {
+            assert!(
+                !names.contains(&unexpected),
+                "{unexpected} must NOT be registered; got: {names:?}"
+            );
+        }
+    }

As per coding guidelines: “Ship unit tests and coverage for behavior you are adding or changing before building additional features on top” and “Rust code must be unit-tested for new/changed behavior before stacking features; run via cargo test and extend tests/json_rpc_e2e.rs for RPC integration tests”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/openhuman/tools/ops.rs` around lines 303 - 338, Add unit tests that
assert the tool registry includes the new Parallel* (ParallelChatTool,
ParallelResearchTool, ParallelEnrichTool, ParallelDatasetTool) and Stock*
(StockQuoteTool, StockExchangeRateTool, StockOptionsTool, StockCryptoSeriesTool,
StockCommodityTool) registrations when their respective toggles
(root_config.integrations.parallel.enabled and
root_config.integrations.stock_prices.enabled) are true, and that they are
absent when those toggles are false; locate the registry-building function that
pushes these tools (the code that calls
crate::openhuman::integrations::ParallelChatTool::new,
ParallelResearchTool::new, ParallelEnrichTool::new, ParallelDatasetTool::new,
StockQuoteTool::new, StockExchangeRateTool::new, StockOptionsTool::new,
StockCryptoSeriesTool::new, StockCommodityTool::new) and add focused tests that
construct a minimal root_config with toggles on/off, run the registry creation,
and assert presence/absence of the corresponding tool types (and add similar
assertions to the relevant JSON-RPC e2e test file if integration coverage is
required).

The two echo-style postprocess tests (whitespace-only context and
conversation context) shared the global LocalAiService singleton and
OPENHUMAN_OLLAMA_BASE_URL env var with sibling tests but did not
acquire LOCAL_AI_TEST_MUTEX, allowing another test's mock response
('Hello, world.') to leak in and fail the exact-equality assertion.
@senamakel senamakel merged commit 13242cc into tinyhumansai:main Apr 25, 2026
9 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
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