Skip to content

feat(tools): add Truth Bear GAUGE tools (official-source signals, offline-verifiable, no API key) - #6752

Open
CHANGCHINFU wants to merge 1 commit into
crewAIInc:mainfrom
CHANGCHINFU:feat/truthbear-gauge-tools
Open

feat(tools): add Truth Bear GAUGE tools (official-source signals, offline-verifiable, no API key)#6752
CHANGCHINFU wants to merge 1 commit into
crewAIInc:mainfrom
CHANGCHINFU:feat/truthbear-gauge-tools

Conversation

@CHANGCHINFU

Copy link
Copy Markdown

What this adds

Three tools for querying Truth Bear GAUGE, a pay-per-call source of official-record signals (US federal agencies and named registries: USGS, NOAA, NWS, EPA, SEC EDGAR, openFDA, EIA, BLS, FAA, US CBP, USTR, USITC, Federal Register, plus IMF PortWatch and UNFCCC feeds).

Tool Cost What it does
TruthBearCoverageTool free Does this signal line exist, how many objects it covers, how fresh those readings are, and whether the source agency is on schedule or overdue
TruthBearCatalogTool free Which entity ids are valid for a signal line (signal_id and entity must be used as a pair)
TruthBearRecordTool paid, x402 Requests one official record; returns the HTTP 402 payment challenge untouched

Why it may be useful here

Every paid record ships a canonical sha256 record_hash that the caller can recompute offline from the delivered payload, so an agent does not have to trust the endpoint it just paid. Readings are stated against the official threshold ladder published by the source agency rather than a scale we invented, and each record carries a same-season percentile so an agent can tell routine from unusual.

The service is descriptive only: no forecast, no recommendation, no adjudication.

Notes for reviewers

  • No new dependency. Standard library only (urllib, json) plus pydantic, which crewai-tools already requires.
  • No API key, no account, no signup for the two free tools.
  • This PR adds no code that moves money. TruthBearRecordTool returns the x402 challenge (network, asset, amount, recipient) to the caller and stops. Settling it is the caller's own wallet's job; nothing here holds keys or signs anything.
  • The catalog filter is required, not optional. The unfiltered catalog response is about 1.5 MB, which would flood an agent's context, so TruthBearCatalogTool rejects a call with neither signal_id nor industry.
  • A "not found" is an empty signals list with HTTP 200, not an error — the tool converts that to an explicit {"found": false} so the agent does not mistake an empty answer for a failed call.
  • Charging on the paid endpoint is bound to HTTP 200. A query with no data returns 422 and is not billed.
  • tool.specs.json was regenerated with python -m crewai_tools.generate_tool_specs; the diff is additive only (96 → 99 tools).

Testing

tests/tools/truthbear_gauge_tool_test.py covers the three tools with mocked HTTP: coverage hit, coverage miss (empty signals), the required-filter guard on the catalog tool, the 402 challenge being returned intact rather than raised as an error, and a paid success passing through unchanged.

6 passed

Run under this repo's own pytest configuration, including --block-network, so the mocks are verified to make no real network calls.

The endpoint behaviour the tools rely on was also verified against the live service before opening this PR: coverage returns 1 signal for a valid id and 0 for an unknown one; a filtered catalog response is 1.8 KB with 10 entities; the paid endpoint answers 402 with a well-formed accepts entry carrying network, asset, payTo and amount.

…line-verifiable, no API key)

Adds three tools for querying official-record signals from US federal agencies
and named registries (USGS, NOAA, NWS, EPA, SEC EDGAR, openFDA, EIA, BLS and others):

- TruthBearCoverageTool (free): does a signal line exist, how many objects it
  covers, how fresh those readings are, and whether the source agency is on
  schedule or overdue.
- TruthBearCatalogTool (free): which entity ids are valid for a signal line.
- TruthBearRecordTool (paid via x402): requests one official record and returns
  the HTTP 402 payment challenge untouched.

Standard library only - no new dependency. No API key for the free tools.
No code here holds keys, signs, or moves funds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Added three CrewAI tools for Truth Bear GAUGE coverage, catalog, and official-record queries. The tools expose JSON responses, validate catalog filters, preserve x402 payment challenges, and are documented, tested, and exported through the package API.

Changes

Truth Bear GAUGE integration

Layer / File(s) Summary
GAUGE tool contracts and API implementation
lib/crewai-tools/tools/truthbear_gauge_tool/truthbear_gauge_tool.py, lib/crewai-tools/tool.specs.json
Added coverage, catalog, and record tools with filtering, response handling, and x402 challenge passthrough.
Tool exposure and usage documentation
lib/crewai-tools/src/crewai_tools/__init__.py, lib/crewai-tools/src/crewai_tools/tools/__init__.py, lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md, lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md
Exported the tools and documented installation, arguments, responses, filtering, freshness, and payment behavior.
GAUGE behavior validation
lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py
Added mocked tests for coverage results, catalog validation, successful records, and HTTP 402 responses.

Sequence Diagram(s)

sequenceDiagram
  participant CrewAIAgent
  participant TruthBearTool
  participant TruthBearAPI
  participant Wallet
  CrewAIAgent->>TruthBearTool: Submit GAUGE query
  TruthBearTool->>TruthBearAPI: Request coverage, catalog, or record data
  TruthBearAPI-->>TruthBearTool: Return JSON or x402 challenge
  TruthBearTool-->>CrewAIAgent: Return serialized response
  CrewAIAgent->>Wallet: Settle x402 challenge when required
Loading

Suggested reviewers: lorenzejay

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% 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
Title check ✅ Passed The title clearly and concisely describes the addition of Truth Bear GAUGE tools.
Description check ✅ Passed The description directly explains the three tools, their behaviors, constraints, tests, and specification updates.
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 unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🧹 Nitpick comments (3)
lib/crewai-tools/tool.specs.json (1)

26662-26754: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add the required filter constraint to the generated JSON Schema for TruthBearCatalogInput.

TruthBearCatalogInput enforces signal_id or industry at runtime via _require_a_filter, but TruthBearCatalogInput in tool.specs.json still exposes no required fields or anyOf/if-then constraint. Schema-only callers can plan an invalid catalog request by omitting both filters. Add a JSON Schema anyOf between signal_id and industry.

🤖 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 `@lib/crewai-tools/tool.specs.json` around lines 26662 - 26754, Update the
TruthBearCatalogInput run_params_schema to require at least one filter by adding
an anyOf constraint referencing signal_id and industry. Preserve both properties
as optional individually while ensuring schema-only callers cannot omit both
filters.
lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py (2)

96-123: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert complete pass-through payloads for both record paths.

Both tests validate selected fields only. The API contract requires preservation of the complete x402 challenge and successful record.

  • lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py#L96-L123: assert result["challenge"] == challenge.
  • lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py#L125-L133: assert result == payload.
🤖 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 `@lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py` around lines 96 -
123, Strengthen the pass-through assertions in
lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py at lines 96-123 by
asserting result["challenge"] exactly equals challenge, preserving the complete
x402 payload. At lines 125-133, assert the record-path result exactly equals
payload, preserving the complete successful response.

73-87: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a behavior test for the industry filter.

The catalog contract accepts either signal_id or industry. The current tests cover only signal_id and the missing-filter error. Add a test that calls TruthBearCatalogTool().run(industry="hydrology") and verifies the returned signal and entities.

As per coding guidelines, **/tests/**/*.py: Write unit tests for new functionality that focus on behavior rather than implementation details.

🤖 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 `@lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py` around lines 73 -
87, Add a unit test alongside test_catalog_filtered that calls
TruthBearCatalogTool().run(industry="hydrology") with a mocked catalog response,
then verifies the returned signal and entity values. Keep the assertion focused
on the observable filtered-catalog behavior rather than implementation details.

Source: Coding guidelines

🤖 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 `@lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md`:
- Line 3: Update the first section heading in Examples.md from the H3 “Tool
Initialization” heading to an H2, preserving its existing text and icon so the
document follows the H1-to-H2 heading hierarchy.

In `@lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md`:
- Line 27: Update the TruthBearCatalogTool description in
lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md:27 to
state that catalog filtering accepts signal_id or industry, not entity. Update
the catalog lookup description in
lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md:64 with
the same contract; the signal_id and entity pair applies only to
TruthBearRecordTool.

In
`@lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/truthbear_gauge_tool.py`:
- Around line 37-44: Update the HTTP error helper to return the status code
separately from the parsed payload, preserving the 402 response body unchanged.
In the coverage flow, use the separate status to treat all non-2xx responses as
errors instead of interpreting missing signals as not found, and update
TruthBearRecordTool to return the 402 payload directly without wrapping it.

---

Nitpick comments:
In `@lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py`:
- Around line 96-123: Strengthen the pass-through assertions in
lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py at lines 96-123 by
asserting result["challenge"] exactly equals challenge, preserving the complete
x402 payload. At lines 125-133, assert the record-path result exactly equals
payload, preserving the complete successful response.
- Around line 73-87: Add a unit test alongside test_catalog_filtered that calls
TruthBearCatalogTool().run(industry="hydrology") with a mocked catalog response,
then verifies the returned signal and entity values. Keep the assertion focused
on the observable filtered-catalog behavior rather than implementation details.

In `@lib/crewai-tools/tool.specs.json`:
- Around line 26662-26754: Update the TruthBearCatalogInput run_params_schema to
require at least one filter by adding an anyOf constraint referencing signal_id
and industry. Preserve both properties as optional individually while ensuring
schema-only callers cannot omit both filters.
🪄 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 Plus

Run ID: c1c2d5c2-ac85-40af-bf8a-f391861a7491

📥 Commits

Reviewing files that changed from the base of the PR and between ebe0082 and b376851.

📒 Files selected for processing (8)
  • lib/crewai-tools/src/crewai_tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/truthbear_gauge_tool.py
  • lib/crewai-tools/tests/tools/truthbear_gauge_tool_test.py
  • lib/crewai-tools/tool.specs.json

@@ -0,0 +1,137 @@
# 🐻 Truth Bear GAUGE Tools — Usage Examples

### 🔧 Tool Initialization

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use an H2 for the first section heading.

Line 3 skips from the H1 at Line 1 to an H3. Change ### 🔧 Tool Initialization to ## 🔧 Tool Initialization to satisfy markdownlint MD001.

🧰 Tools
🪛 markdownlint-cli2 (0.23.1)

[warning] 3-3: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 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 `@lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md` at
line 3, Update the first section heading in Examples.md from the H3 “Tool
Initialization” heading to an H2, preserving its existing text and icon so the
document follows the H1-to-H2 heading hierarchy.

Source: Linters/SAST tools

| Tool | Cost | Purpose |
| ---- | ---- | ------- |
| `TruthBearCoverageTool` | free | Does a signal line exist, how many objects it covers, how fresh those readings are, and whether the source agency is on schedule or overdue |
| `TruthBearCatalogTool` | free | Which entity ids are valid for a signal line — `signal_id` and `entity` must be used as a pair |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Use the actual catalog contract in both documents.

TruthBearCatalogTool accepts one of signal_id or industry. It does not accept entity. The signal_id plus entity pair applies to TruthBearRecordTool.

  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md#L27-L27: describe catalog filtering with signal_id or industry.
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md#L64-L64: state that the catalog lookup uses signal_id or industry.
📍 Affects 2 files
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md#L27-L27 (this comment)
  • lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md#L64-L64
🤖 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 `@lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md` at
line 27, Update the TruthBearCatalogTool description in
lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/README.md:27 to
state that catalog filtering accepts signal_id or industry, not entity. Update
the catalog lookup description in
lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/Examples.md:64 with
the same contract; the signal_id and entity pair applies only to
TruthBearRecordTool.

Comment on lines +37 to +44
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
try:
payload = json.loads(body)
except json.JSONDecodeError:
payload = {"raw": body[:2000]}
# In x402 a 402 is not a failure, it is the price quote. Return it intact.
return {"http_status": exc.code, **payload}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the HTTP status separate from the response payload.

This helper converts every HTTP error into a payload dictionary. A 429 or 5xx response from /gauge/coverage then has no signals field, so Lines 80-82 incorrectly report found: false. The record tool also wraps the 402 body at Lines 166-174, but the PR objective requires payment challenges to be returned unchanged.

Return (status, payload) internally. Handle non-2xx coverage responses as errors. Return the 402 payload itself from TruthBearRecordTool.

Proposed fix
-def _get_json(path: str, params: Optional[dict] = None) -> dict:
+def _get_json(path: str, params: Optional[dict] = None) -> tuple[int, dict]:
     ...
     try:
         with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as resp:
-            return json.loads(resp.read().decode("utf-8"))
+            return resp.status, json.loads(resp.read().decode("utf-8"))
     except urllib.error.HTTPError as exc:
         ...
-        return {"http_status": exc.code, **payload}
+        return exc.code, payload
-        data = _get_json("/gauge/coverage", params)
+        status, data = _get_json("/gauge/coverage", params)
+        if not 200 <= status < 300:
+            return json.dumps({"http_status": status, "error": data}, ensure_ascii=False)
-        data = _get_json("/gauge", {"signal_id": args.signal_id, "entity": args.entity})
-        if data.get("http_status") == 402:
-            return json.dumps(
-                {
-                    "payment_required": True,
-                    "note": "Settle this x402 challenge with your own wallet, then retry the same URL.",
-                    "challenge": {k: v for k, v in data.items() if k != "http_status"},
-                },
-                ensure_ascii=False,
-            )
+        _, data = _get_json("/gauge", {"signal_id": args.signal_id, "entity": args.entity})
         return json.dumps(data, ensure_ascii=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
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
try:
payload = json.loads(body)
except json.JSONDecodeError:
payload = {"raw": body[:2000]}
# In x402 a 402 is not a failure, it is the price quote. Return it intact.
return {"http_status": exc.code, **payload}
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
try:
payload = json.loads(body)
except json.JSONDecodeError:
payload = {"raw": body[:2000]}
# In x402 a 402 is not a failure, it is the price quote. Return it intact.
return exc.code, payload
🤖 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
`@lib/crewai-tools/src/crewai_tools/tools/truthbear_gauge_tool/truthbear_gauge_tool.py`
around lines 37 - 44, Update the HTTP error helper to return the status code
separately from the parsed payload, preserving the 402 response body unchanged.
In the coverage flow, use the separate status to treat all non-2xx responses as
errors instead of interpreting missing signals as not found, and update
TruthBearRecordTool to return the 402 payload directly without wrapping it.

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