feat: add app_tools toolset — 500+ external app integrations via Nous tool gateway - #31047
alt-glitch wants to merge 17 commits into
Conversation
The items() ordered tuple now includes 'app_tools', so test fixtures that construct NousSubscriptionFeatures must include the key to avoid KeyError when iterating.
_gateway_post() was using gateway_origin directly, which fails on *.localhost subdomains (Python DNS can't resolve them). Now uses resolved_origin (127.0.0.1 rewrite) and sets the Host header for reverse-proxy routing. Also disables TLS verification for rewritten localhost origins (self-signed dev certs).
… client" This reverts commit bc2ba13.
The LLM was loading skills like 'linear', 'composio', 'airtable' instead of calling app_search_tools directly. Explicitly name the skills to avoid and make the preference stronger.
Users who previously ran 'hermes tools' have explicit platform_toolsets lists in config.yaml. The v24 migration added portal.app_tools config but didn't inject app_tools into those saved lists, so the toolset was invisible at runtime despite check_fn passing.
- Remove unused build_app_tools_prompt import from run_agent.py - Remove unnecessary portal config write from migration (deep-merge handles it); keep platform_toolsets injection which deep-merge can't - Deduplicate _read_portal_app_tools_enabled into tool_backend_helpers.py - Cache httpx.Client at module level (thread-safe, staleness-checked) to avoid TCP+TLS setup per tool call - Extract local vars for triple-repeated gateway availability expression in get_nous_subscription_features - Update test mocks to accept **kw for per-request timeout kwarg - Add autouse fixture to reset cached http client between tests
…ECUTE_STRIP_KEYS
- 'if session:' drops empty dict {} which is schema-valid
- 'if session_id:' drops empty string which shouldn't be silently eaten
- _EXECUTE_STRIP_KEYS frozenset was defined but never referenced (handler
uses allowlist approach instead)
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-import |
3 |
no-matching-overload |
1 |
unresolved-attribute |
1 |
First entries
hermes_cli/nous_subscription.py:242: [no-matching-overload] no-matching-overload: No overload of bound method `dict.get` matches arguments
plugins/web/firecrawl/provider.py:241: [unresolved-attribute] unresolved-attribute: Attribute `resolved_origin` is not defined on `None` in union `ManagedToolGatewayConfig | None`
tests/tools/test_app_tools.py:8: [unresolved-import] unresolved-import: Cannot resolve imported module `httpx`
tools/app_tools.py:19: [unresolved-import] unresolved-import: Cannot resolve imported module `httpx`
tests/tools/test_app_tools.py:9: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
✅ Fixed issues (1):
| Rule | Count |
|---|---|
unresolved-attribute |
1 |
First entries
plugins/web/firecrawl/provider.py:241: [unresolved-attribute] unresolved-attribute: Attribute `gateway_origin` is not defined on `None` in union `ManagedToolGatewayConfig | None`
Unchanged: 4804 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
Summary
Test Plan
This targets #31047's feature branch directly so it can be merged/cherry-picked before the app_tools PR lands. |
|
Opened CI unblocker against this PR branch: #31060 |
PR Review - #31047: feat: add app_tools toolsetReviewer: Automated review via Claude Code CI: FAILING (30 test failures, 5/6 shards red)CRITICAL-1: Missing build_app_tools_prompt in run_agent.py imports (24 failures)agent/system_prompt.py now calls build_app_tools_prompt() from agent/prompt_builder.py. The existing tests mock run_agent module attributes because run_agent.py imports those at module level (line 127-133). Since build_app_tools_prompt was not added to the run_agent.py import block, tests break with: Fix: Add build_app_tools_prompt to the import block in run_agent.py, or update test mocks. CRITICAL-2: Missing resolved_origin on mock gateway objects (6 failures)tests/tools/test_managed_modal_environment.py constructs fake gateway objects via types.SimpleNamespace which lack the new resolved_origin and gateway_host_header properties added to ManagedToolGatewayConfig. Fix: Add these attributes to mock objects, or use ManagedToolGatewayConfig directly. AnalysisCorrectness: tools/app_tools.py is well-structured. Gateway POST never raises -- HTTP errors and network failures are returned as error dicts (right pattern for LLM tool results). Session tracking design is clear. max_result_size_chars=50_000 is a sensible guard. Config migration v23->v24 correctly patches platform_toolsets. Security: Auth handling is sound. Bearer token from resolve_managed_tool_gateway('tools') is reused, no hardcoded secrets. *.localhost DNS rewrite with Host header preservation is correct. TOOL_GATEWAY_USER_TOKEN env var short-circuit bypasses subscription check (intentional for CI/dev, but worth noting). Test coverage: New tests in test_app_tools.py (21 tests) are solid -- cover check_fn gating, URL/auth, model injection, param stripping, HTTP errors, network failures, session asymmetry, registry entries. test_managed_tool_gateway.py additions (7 tests) for _rewrite_localhost_origin are thorough. But existing test fixtures were not updated (the CRITICAL issues above). Code quality: Well-documented. Behavioral prompt is detailed and well-structured for LLM guidance. The refactoring from gateway_origin to resolved_origin across 5 consumer files is clean. portal_app_tools_enabled is duplicated in two places with slightly different implementations -- consider consolidating. IssuesCRITICAL (BLOCK merge):
WARNING:
INFO:
Points Positifs
Recommendation
The implementation quality is high and the design is sound. The blocking issues are test fixture updates missed when extending ManagedToolGatewayConfig and adding build_app_tools_prompt. Once C1 and C2 are fixed, this should be ready to merge. |
|
Call-graph-assisted review (calldiff over ✅ Looks good
🟡 Questions on defaults / shared-state
🟡 Minor
🔴 Staleness — substantial rebase requiredMerge-base is 2026-05-22 (~2.7 months, the oldest of this batch). |
|
Superseded by #106842 (merged |
Summary
Adds a new
app_toolstoolset that exposes 4 meta tools for 500+ external app integrations (Gmail, Slack, GitHub, Jira, Notion, Linear, HubSpot, etc.), routed through the Nous tool gateway.Architecture
Thin HTTP handlers in
tools/app_tools.pyPOST JSON totools-gateway.nousresearch.com/v1/*endpoints. Auth reusesresolve_managed_tool_gateway("tools")— Nous subscription + TOOL_GATEWAY_USER_TOKEN. Gated byportal.app_toolsconfig flag (default: true).Tools
app_search_toolsapp_tool_schemasapp_execute_toolsapp_manage_connectionsChanges
New files:
tools/app_tools.py— 4 tool handlers + gateway HTTP client + registry callstests/tools/test_app_tools.py— 21 unit testsModified files:
hermes_cli/config.py—portal.app_toolsconfig key + migration to inject into saved platform_toolsetstoolsets.py—app_toolstoolset +_HERMES_CORE_TOOLSentrieshermes_cli/tools_config.py—CONFIGURABLE_TOOLSETSentryagent/prompt_builder.py— behavioral guidance prompt injectionagent/system_prompt.py— prompt assembly integrationhermes_cli/nous_subscription.py— subscription features/status integrationtools/tool_backend_helpers.py— sharedportal_app_tools_enabled()helpertools/managed_tool_gateway.py—*.localhostDNS rewrite for dev compatrun_agent.py— import cleanupTesting
Key design decisions
max_result_size_chars=50000onapp_execute_toolsto prevent context blowout