langchain-hyperresearch 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ .venv/
2
+ dist/
3
+ __pycache__/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .mypy_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thalient Labs Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.5
2
+ Name: langchain-hyperresearch
3
+ Version: 0.1.0
4
+ Summary: LangChain integration for Hyperresearch Answers: a cited, quote-checked answer tool, a raw-source search tool and a retriever.
5
+ Project-URL: Homepage, https://hyperresearch.ai/answers
6
+ Project-URL: Documentation, https://hyperresearch.ai/docs/answers/langchain
7
+ Project-URL: Repository, https://github.com/jordan-gibbs/hyperresearch-answers
8
+ Project-URL: Source, https://github.com/jordan-gibbs/hyperresearch-answers/tree/main/packages/langchain-python
9
+ Project-URL: Issues, https://github.com/jordan-gibbs/hyperresearch-answers/issues
10
+ Author: Hyperresearch
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: agents,answers,citations,hyperresearch,langchain,retriever,search,tools,web-search
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Requires-Python: <4.0,>=3.10
19
+ Requires-Dist: httpx<1.0,>=0.27
20
+ Requires-Dist: langchain-core<2.0.0,>=1.0.0
21
+ Description-Content-Type: text/markdown
22
+
23
+ # langchain-hyperresearch
24
+
25
+ This package contains the LangChain integration for [Hyperresearch Answers](https://hyperresearch.ai/answers): cited, quote-checked answers and ranked raw sources for agents.
26
+
27
+ ## Overview
28
+
29
+ ### Details
30
+
31
+ | Class | Package | Serializable | JS support |
32
+ | :--- | :--- | :---: | :---: |
33
+ | `HyperresearchAnswerTool` | `langchain-hyperresearch` | ❌ | ✅ (`@hyperresearch/langchain`) |
34
+ | `HyperresearchSearchTool` | `langchain-hyperresearch` | ❌ | ✅ |
35
+ | `HyperresearchRetriever` | `langchain-hyperresearch` | ❌ | ✅ |
36
+
37
+ ### Features
38
+
39
+ - **`HyperresearchAnswerTool`** (`hyperresearch_answer`): one factual question in, one short answer out, with the quotes it rests on, each checked word for word against its page. When nothing supports an answer it returns `not_found` instead of a guess. The research runs on the Hyperresearch side: one tool call instead of a loop of searches, and no pages in the agent's context.
40
+ - **`HyperresearchSearchTool`** (`hyperresearch_search`): ranked raw sources from the open web and about 45 structured sources (company filings, statistics agencies, scholarly indexes, books, government records), with word-for-word passages. No summary.
41
+ - **`HyperresearchRetriever`**: `search` as a retriever, one `Document` per ranked source.
42
+ - Sync and async (`invoke` / `ainvoke`). Tools use `response_format="content_and_artifact"`: the model reads a compact JSON string, and `ToolMessage.artifact` holds the full API response.
43
+
44
+ ## Setup
45
+
46
+ ### Credentials
47
+
48
+ Create an API key with the `answers:ask` scope at <https://console.hyperresearch.ai/#/keys>. Every account gets $5 of free credit, no card needed.
49
+
50
+ ```python
51
+ import getpass
52
+ import os
53
+
54
+ if "HYPERRESEARCH_API_KEY" not in os.environ:
55
+ os.environ["HYPERRESEARCH_API_KEY"] = getpass.getpass("Enter your Hyperresearch API key: ")
56
+ ```
57
+
58
+ ### Installation
59
+
60
+ ```bash
61
+ pip install -U langchain-hyperresearch
62
+ # or
63
+ uv add langchain-hyperresearch
64
+ ```
65
+
66
+ ## Instantiation
67
+
68
+ ```python
69
+ from langchain_hyperresearch import HyperresearchAnswerTool, HyperresearchSearchTool
70
+
71
+ answer = HyperresearchAnswerTool() # the model picks the mode
72
+ cheap = HyperresearchAnswerTool(mode="fast", max_cost_cents=5)
73
+ search = HyperresearchSearchTool(max_results=5)
74
+ ```
75
+
76
+ | Parameter | Default | |
77
+ |---|---|---|
78
+ | `api_key` | `HYPERRESEARCH_API_KEY` | |
79
+ | `mode` | the model's choice, else `standard` | Fix the mode. Ask: `fast` 5¢ · `standard` 10¢ (20¢ when it digs deeper) · `max` 50¢. Search: `standard` 5¢ · `max` 15¢. |
80
+ | `max_cost_cents` | none | Answer tool. Caps every call; a standard ask under 20 never escalates. |
81
+ | `max_results` | the model's choice, else 10 | Search tool and retriever. 1-25. |
82
+ | `client` | new client | Share one `HyperresearchClient` (it also takes `base_url`, timeouts, `max_retries`). |
83
+
84
+ ## Invocation
85
+
86
+ ### Directly
87
+
88
+ ```python
89
+ answer.invoke({"question": "How old must a US senator be?", "mode": "fast"})
90
+ ```
91
+
92
+ ```json
93
+ {"id": "ans_01J...", "status": "answered", "answer": "At least 30 years old (US Constitution, Article I, Section 3).", "evidence": [{"url": "https://www.archives.gov/founding-docs/constitution-transcript", "title": "The Constitution of the United States: A Transcription", "quote": "No Person shall be a Senator who shall not have attained to the Age of thirty Years", "check": "verified"}], "price_cents": 5}
94
+ ```
95
+
96
+ `status` is one of `answered`, `false_premise`, `unconfirmed`, `not_found` or `error`.
97
+
98
+ ```python
99
+ search.invoke({"query": "minimum age to serve as a US senator"})
100
+ ```
101
+
102
+ ### As a ToolCall
103
+
104
+ ```python
105
+ model_generated_tool_call = {
106
+ "args": {"question": "How old must a US senator be?"},
107
+ "id": "1",
108
+ "name": answer.name,
109
+ "type": "tool_call",
110
+ }
111
+ msg = answer.invoke(model_generated_tool_call)
112
+ msg.content # the compact JSON the model reads
113
+ msg.artifact # the full API response, including balance_cents
114
+ ```
115
+
116
+ ### Within an agent
117
+
118
+ ```python
119
+ from langchain.agents import create_agent
120
+
121
+ agent = create_agent(
122
+ model="claude-sonnet-4-6",
123
+ tools=[HyperresearchAnswerTool(), HyperresearchSearchTool()],
124
+ )
125
+
126
+ agent.invoke(
127
+ {"messages": [{"role": "user", "content": "What was the US federal deficit in fiscal 2025, with a source?"}]}
128
+ )
129
+ ```
130
+
131
+ ## Retriever
132
+
133
+ ```python
134
+ from langchain_hyperresearch import HyperresearchRetriever
135
+
136
+ retriever = HyperresearchRetriever(max_results=5)
137
+ docs = retriever.invoke("minimum age to serve as a US senator")
138
+ docs[0].page_content # the matched passages, verbatim
139
+ docs[0].metadata # url, title, rank, source, published, verified, call_id
140
+ ```
141
+
142
+ Each retrieval is one billed `search` call.
143
+
144
+ ## Pricing
145
+
146
+ | Call | Price | If not found |
147
+ |---|---|---|
148
+ | ask · fast | 5¢ | 1¢–5¢ |
149
+ | ask · standard (default) | 10¢, 20¢ when it digs deeper | 2¢–20¢ |
150
+ | ask · max | 50¢ | 10¢–50¢ |
151
+ | search · standard (default) | 5¢ | 0¢–5¢ |
152
+ | search · max | 15¢ | 0¢–15¢ |
153
+
154
+ A call that fails on our side costs nothing. Current list: <https://hyperresearch.ai/answers#pricing>.
155
+
156
+ ## API contract
157
+
158
+ The package calls the Answers REST API at `https://api.hyperresearch.ai` with `Authorization: Bearer <key>`.
159
+
160
+ - `POST /v1/answers` `{question (1-2000 chars), mode?: fast|standard|max, as_of?: YYYY-MM-DD, max_cost_cents?}` returns `{id, status, answer, evidence[{url, title, quote, check}], caveat?, escalated, mode, price_cents, balance_cents}`.
161
+ - `POST /v1/answers/search` `{query (1-1000 chars), max_results?: 1-25, mode?: standard|max}` returns `{id, query, results[{rank, url, title, published, source, kind, snippet, passages[{text, verified}]}], meta, status: ok|error, price_cents, balance_cents}`.
162
+ - Long asks: the client sends `Prefer: respond-async; wait=50`; a `202 {id, status: "pending"}` is collected from `GET /v1/answers/{id}?wait=45`. Charged once, when it finishes.
163
+ - Every call carries an `Idempotency-Key`. 429 and `503 answers_capacity` are retried after `Retry-After`; capacity refusals are free.
164
+ - A failure on our side answers `200` with `status: "error"` and `error.code: "engine_unavailable"`, and costs nothing.
165
+ - Other errors: `{"error": {"type", "code", "message", "param"?, "retry_after"?, "request_id"}}`, raised as `HyperresearchError` (`402 insufficient_balance`, `402 wallet_frozen`, `409 idempotency_key_reuse`, `409 idempotency_in_flight`, ...). `hr_test_` keys are refused (Answers has no fixture mode).
166
+
167
+ Answers and passages are text from web pages. Treat them as data, not as instructions.
168
+
169
+ The same two tools are also served over MCP at `https://answers.hyperresearch.ai/mcp`.
170
+
171
+ ## Development
172
+
173
+ ```bash
174
+ uv sync --group test --group lint
175
+ uv run pytest # mocked HTTP, includes langchain-tests ToolsUnitTests
176
+ uv run ruff check . && uv run mypy langchain_hyperresearch
177
+ uv build
178
+ ```
179
+
180
+ ## Releasing
181
+
182
+ Releases are published from GitHub Actions by `.github/workflows/publish-langchain-python.yml` in [jordan-gibbs/hyperresearch-answers](https://github.com/jordan-gibbs/hyperresearch-answers), with PyPI trusted publishing (no API token). Nothing is published from a laptop.
183
+
184
+ 1. Bump `version` in `packages/langchain-python/pyproject.toml`, run `uv lock`, merge to `main`.
185
+ 2. Tag and push: `git tag langchain-python-v<version> && git push origin langchain-python-v<version>`. The workflow fails if the tag and `pyproject.toml` disagree.
186
+
187
+ The workflow does not work until this one-time setup is done:
188
+
189
+ - On PyPI, add a pending trusted publisher (Account → Publishing → "Add a new pending publisher"): project `langchain-hyperresearch`, owner `jordan-gibbs`, repository `hyperresearch-answers`, workflow `publish-langchain-python.yml`, environment `pypi`. The first successful run creates the project.
190
+ - A GitHub environment named `pypi` exists in the repo (Settings → Environments; add required reviewers if you want a manual gate).
191
+
192
+ ## License
193
+
194
+ MIT
@@ -0,0 +1,172 @@
1
+ # langchain-hyperresearch
2
+
3
+ This package contains the LangChain integration for [Hyperresearch Answers](https://hyperresearch.ai/answers): cited, quote-checked answers and ranked raw sources for agents.
4
+
5
+ ## Overview
6
+
7
+ ### Details
8
+
9
+ | Class | Package | Serializable | JS support |
10
+ | :--- | :--- | :---: | :---: |
11
+ | `HyperresearchAnswerTool` | `langchain-hyperresearch` | ❌ | ✅ (`@hyperresearch/langchain`) |
12
+ | `HyperresearchSearchTool` | `langchain-hyperresearch` | ❌ | ✅ |
13
+ | `HyperresearchRetriever` | `langchain-hyperresearch` | ❌ | ✅ |
14
+
15
+ ### Features
16
+
17
+ - **`HyperresearchAnswerTool`** (`hyperresearch_answer`): one factual question in, one short answer out, with the quotes it rests on, each checked word for word against its page. When nothing supports an answer it returns `not_found` instead of a guess. The research runs on the Hyperresearch side: one tool call instead of a loop of searches, and no pages in the agent's context.
18
+ - **`HyperresearchSearchTool`** (`hyperresearch_search`): ranked raw sources from the open web and about 45 structured sources (company filings, statistics agencies, scholarly indexes, books, government records), with word-for-word passages. No summary.
19
+ - **`HyperresearchRetriever`**: `search` as a retriever, one `Document` per ranked source.
20
+ - Sync and async (`invoke` / `ainvoke`). Tools use `response_format="content_and_artifact"`: the model reads a compact JSON string, and `ToolMessage.artifact` holds the full API response.
21
+
22
+ ## Setup
23
+
24
+ ### Credentials
25
+
26
+ Create an API key with the `answers:ask` scope at <https://console.hyperresearch.ai/#/keys>. Every account gets $5 of free credit, no card needed.
27
+
28
+ ```python
29
+ import getpass
30
+ import os
31
+
32
+ if "HYPERRESEARCH_API_KEY" not in os.environ:
33
+ os.environ["HYPERRESEARCH_API_KEY"] = getpass.getpass("Enter your Hyperresearch API key: ")
34
+ ```
35
+
36
+ ### Installation
37
+
38
+ ```bash
39
+ pip install -U langchain-hyperresearch
40
+ # or
41
+ uv add langchain-hyperresearch
42
+ ```
43
+
44
+ ## Instantiation
45
+
46
+ ```python
47
+ from langchain_hyperresearch import HyperresearchAnswerTool, HyperresearchSearchTool
48
+
49
+ answer = HyperresearchAnswerTool() # the model picks the mode
50
+ cheap = HyperresearchAnswerTool(mode="fast", max_cost_cents=5)
51
+ search = HyperresearchSearchTool(max_results=5)
52
+ ```
53
+
54
+ | Parameter | Default | |
55
+ |---|---|---|
56
+ | `api_key` | `HYPERRESEARCH_API_KEY` | |
57
+ | `mode` | the model's choice, else `standard` | Fix the mode. Ask: `fast` 5¢ · `standard` 10¢ (20¢ when it digs deeper) · `max` 50¢. Search: `standard` 5¢ · `max` 15¢. |
58
+ | `max_cost_cents` | none | Answer tool. Caps every call; a standard ask under 20 never escalates. |
59
+ | `max_results` | the model's choice, else 10 | Search tool and retriever. 1-25. |
60
+ | `client` | new client | Share one `HyperresearchClient` (it also takes `base_url`, timeouts, `max_retries`). |
61
+
62
+ ## Invocation
63
+
64
+ ### Directly
65
+
66
+ ```python
67
+ answer.invoke({"question": "How old must a US senator be?", "mode": "fast"})
68
+ ```
69
+
70
+ ```json
71
+ {"id": "ans_01J...", "status": "answered", "answer": "At least 30 years old (US Constitution, Article I, Section 3).", "evidence": [{"url": "https://www.archives.gov/founding-docs/constitution-transcript", "title": "The Constitution of the United States: A Transcription", "quote": "No Person shall be a Senator who shall not have attained to the Age of thirty Years", "check": "verified"}], "price_cents": 5}
72
+ ```
73
+
74
+ `status` is one of `answered`, `false_premise`, `unconfirmed`, `not_found` or `error`.
75
+
76
+ ```python
77
+ search.invoke({"query": "minimum age to serve as a US senator"})
78
+ ```
79
+
80
+ ### As a ToolCall
81
+
82
+ ```python
83
+ model_generated_tool_call = {
84
+ "args": {"question": "How old must a US senator be?"},
85
+ "id": "1",
86
+ "name": answer.name,
87
+ "type": "tool_call",
88
+ }
89
+ msg = answer.invoke(model_generated_tool_call)
90
+ msg.content # the compact JSON the model reads
91
+ msg.artifact # the full API response, including balance_cents
92
+ ```
93
+
94
+ ### Within an agent
95
+
96
+ ```python
97
+ from langchain.agents import create_agent
98
+
99
+ agent = create_agent(
100
+ model="claude-sonnet-4-6",
101
+ tools=[HyperresearchAnswerTool(), HyperresearchSearchTool()],
102
+ )
103
+
104
+ agent.invoke(
105
+ {"messages": [{"role": "user", "content": "What was the US federal deficit in fiscal 2025, with a source?"}]}
106
+ )
107
+ ```
108
+
109
+ ## Retriever
110
+
111
+ ```python
112
+ from langchain_hyperresearch import HyperresearchRetriever
113
+
114
+ retriever = HyperresearchRetriever(max_results=5)
115
+ docs = retriever.invoke("minimum age to serve as a US senator")
116
+ docs[0].page_content # the matched passages, verbatim
117
+ docs[0].metadata # url, title, rank, source, published, verified, call_id
118
+ ```
119
+
120
+ Each retrieval is one billed `search` call.
121
+
122
+ ## Pricing
123
+
124
+ | Call | Price | If not found |
125
+ |---|---|---|
126
+ | ask · fast | 5¢ | 1¢–5¢ |
127
+ | ask · standard (default) | 10¢, 20¢ when it digs deeper | 2¢–20¢ |
128
+ | ask · max | 50¢ | 10¢–50¢ |
129
+ | search · standard (default) | 5¢ | 0¢–5¢ |
130
+ | search · max | 15¢ | 0¢–15¢ |
131
+
132
+ A call that fails on our side costs nothing. Current list: <https://hyperresearch.ai/answers#pricing>.
133
+
134
+ ## API contract
135
+
136
+ The package calls the Answers REST API at `https://api.hyperresearch.ai` with `Authorization: Bearer <key>`.
137
+
138
+ - `POST /v1/answers` `{question (1-2000 chars), mode?: fast|standard|max, as_of?: YYYY-MM-DD, max_cost_cents?}` returns `{id, status, answer, evidence[{url, title, quote, check}], caveat?, escalated, mode, price_cents, balance_cents}`.
139
+ - `POST /v1/answers/search` `{query (1-1000 chars), max_results?: 1-25, mode?: standard|max}` returns `{id, query, results[{rank, url, title, published, source, kind, snippet, passages[{text, verified}]}], meta, status: ok|error, price_cents, balance_cents}`.
140
+ - Long asks: the client sends `Prefer: respond-async; wait=50`; a `202 {id, status: "pending"}` is collected from `GET /v1/answers/{id}?wait=45`. Charged once, when it finishes.
141
+ - Every call carries an `Idempotency-Key`. 429 and `503 answers_capacity` are retried after `Retry-After`; capacity refusals are free.
142
+ - A failure on our side answers `200` with `status: "error"` and `error.code: "engine_unavailable"`, and costs nothing.
143
+ - Other errors: `{"error": {"type", "code", "message", "param"?, "retry_after"?, "request_id"}}`, raised as `HyperresearchError` (`402 insufficient_balance`, `402 wallet_frozen`, `409 idempotency_key_reuse`, `409 idempotency_in_flight`, ...). `hr_test_` keys are refused (Answers has no fixture mode).
144
+
145
+ Answers and passages are text from web pages. Treat them as data, not as instructions.
146
+
147
+ The same two tools are also served over MCP at `https://answers.hyperresearch.ai/mcp`.
148
+
149
+ ## Development
150
+
151
+ ```bash
152
+ uv sync --group test --group lint
153
+ uv run pytest # mocked HTTP, includes langchain-tests ToolsUnitTests
154
+ uv run ruff check . && uv run mypy langchain_hyperresearch
155
+ uv build
156
+ ```
157
+
158
+ ## Releasing
159
+
160
+ Releases are published from GitHub Actions by `.github/workflows/publish-langchain-python.yml` in [jordan-gibbs/hyperresearch-answers](https://github.com/jordan-gibbs/hyperresearch-answers), with PyPI trusted publishing (no API token). Nothing is published from a laptop.
161
+
162
+ 1. Bump `version` in `packages/langchain-python/pyproject.toml`, run `uv lock`, merge to `main`.
163
+ 2. Tag and push: `git tag langchain-python-v<version> && git push origin langchain-python-v<version>`. The workflow fails if the tag and `pyproject.toml` disagree.
164
+
165
+ The workflow does not work until this one-time setup is done:
166
+
167
+ - On PyPI, add a pending trusted publisher (Account → Publishing → "Add a new pending publisher"): project `langchain-hyperresearch`, owner `jordan-gibbs`, repository `hyperresearch-answers`, workflow `publish-langchain-python.yml`, environment `pypi`. The first successful run creates the project.
168
+ - A GitHub environment named `pypi` exists in the repo (Settings → Environments; add required reviewers if you want a manual gate).
169
+
170
+ ## License
171
+
172
+ MIT
@@ -0,0 +1,27 @@
1
+ """LangChain integration for Hyperresearch Answers."""
2
+
3
+ from langchain_hyperresearch._client import (
4
+ DEFAULT_BASE_URL,
5
+ HyperresearchClient,
6
+ HyperresearchError,
7
+ __version__,
8
+ )
9
+ from langchain_hyperresearch.retrievers import HyperresearchRetriever
10
+ from langchain_hyperresearch.tools import (
11
+ HyperresearchAnswerInput,
12
+ HyperresearchAnswerTool,
13
+ HyperresearchSearchInput,
14
+ HyperresearchSearchTool,
15
+ )
16
+
17
+ __all__ = [
18
+ "DEFAULT_BASE_URL",
19
+ "HyperresearchAnswerInput",
20
+ "HyperresearchAnswerTool",
21
+ "HyperresearchClient",
22
+ "HyperresearchError",
23
+ "HyperresearchRetriever",
24
+ "HyperresearchSearchInput",
25
+ "HyperresearchSearchTool",
26
+ "__version__",
27
+ ]