Skip to content

Commit a32afe8

Browse files
feat!: return full FetchResponse from context.fetch() (#20)
* Return full FetchResponse from context.fetch() (#12) Add FetchResponse dataclass (status, headers, data) and update ExecutionContext.fetch() to return it instead of the raw parsed body. Export FetchResponse from the package. * Update docs and samples for FetchResponse (#12) Update all code examples, docstrings, and prose to use response.data instead of the raw response body, reflecting the new FetchResponse return type from context.fetch(). * Add migration plan for FetchResponse rollout (#12) * Complete migration plan with full file inventory (#12) Add 43 missing production files and 13 test files to the autohive-integrations audit list. * fix: restore ActionError in public exports * docs: update remaining response → response.data in README_PYPI and ActionError example * docs: add ActionError, FetchResponse, HTTPError/RateLimitError to module docstring * Update apidocs for 2.0.0 * Add API docs maintenance guidelines to RELEASING.md and AGENTS.md
1 parent bea46ac commit a32afe8

16 files changed

Lines changed: 2710 additions & 2060 deletions

File tree

AGENTS.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Agents Guidelines — Integrations SDK
2+
3+
## API Documentation
4+
5+
- API docs are generated with `pdoc` and live in `docs/apidocs/`.
6+
- These files are **tracked in version control** — do not add them to `.gitignore`.
7+
- Regenerate whenever the public API surface changes (new/modified classes, functions, or docstrings in `src/autohive_integrations_sdk/`):
8+
```
9+
pdoc -o docs/apidocs src/autohive_integrations_sdk
10+
```
11+
- Always commit the regenerated docs alongside the code changes that caused them.
12+
13+
## Releasing
14+
15+
- Follow the process in [RELEASING.md](RELEASING.md).
16+
- API docs must be regenerated and committed before a release.

README_PYPI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class FetchData(ActionHandler):
2929
"https://api.example.com/data",
3030
headers={"Authorization": f"Bearer {context.auth['api_key']}"}
3131
)
32-
return ActionResult(data=response)
32+
return ActionResult(data=response.data)
3333
```
3434

3535
## Key Features

RELEASING.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@
3232
* Building wheel...
3333
Successfully built autohive_integrations_sdk-<a.b.c>.tar.gz and autohive_integrations_sdk-<a.b.c>-py3-none-any.whl
3434
```
35-
Upload:
35+
* Regenerate API docs:
36+
- `pdoc` is required (`python3 -m pip install --upgrade pdoc`)
37+
```
38+
pdoc -o docs/apidocs src/autohive_integrations_sdk
39+
```
40+
- Commit the updated `docs/apidocs/` files — these are tracked in version control.
41+
42+
* Release to PyPi — Upload:
3643
```
3744
# Upload to PyPi, use API token from our secrets management
3845
python3 -m twine upload dist/autohive_integrations_sdk-<a.b.c>*

docs/apidocs/autohive_integrations_sdk.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@ <h1 class="modulename">
5151
<label class="view-source-button" for="mod-autohive_integrations_sdk-view-source"><span>View Source</span></label>
5252

5353
<div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">1</span></a><span class="c1"># Version</span>
54-
</span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;1.0.2&quot;</span>
54+
</span><span id="L-2"><a href="#L-2"><span class="linenos">2</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;1.1.1&quot;</span>
5555
</span><span id="L-3"><a href="#L-3"><span class="linenos">3</span></a>
5656
</span><span id="L-4"><a href="#L-4"><span class="linenos">4</span></a><span class="c1"># Re-export classes from integration module</span>
5757
</span><span id="L-5"><a href="#L-5"><span class="linenos">5</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">autohive_integrations_sdk.integration</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
5858
</span><span id="L-6"><a href="#L-6"><span class="linenos">6</span></a> <span class="n">Integration</span><span class="p">,</span> <span class="n">ExecutionContext</span><span class="p">,</span> <span class="n">ActionHandler</span><span class="p">,</span> <span class="n">PollingTriggerHandler</span><span class="p">,</span> <span class="n">ConnectedAccountHandler</span><span class="p">,</span>
59-
</span><span id="L-7"><a href="#L-7"><span class="linenos">7</span></a> <span class="n">ConnectedAccountInfo</span><span class="p">,</span> <span class="n">ValidationError</span><span class="p">,</span> <span class="n">ActionResult</span><span class="p">,</span> <span class="n">IntegrationResult</span><span class="p">,</span> <span class="n">ResultType</span>
60-
</span><span id="L-8"><a href="#L-8"><span class="linenos">8</span></a><span class="p">)</span>
59+
</span><span id="L-7"><a href="#L-7"><span class="linenos">7</span></a> <span class="n">ConnectedAccountInfo</span><span class="p">,</span> <span class="n">ValidationError</span><span class="p">,</span> <span class="n">HTTPError</span><span class="p">,</span> <span class="n">RateLimitError</span><span class="p">,</span>
60+
</span><span id="L-8"><a href="#L-8"><span class="linenos">8</span></a> <span class="n">ActionResult</span><span class="p">,</span> <span class="n">ActionError</span><span class="p">,</span> <span class="n">IntegrationResult</span><span class="p">,</span> <span class="n">ResultType</span><span class="p">,</span> <span class="n">FetchResponse</span>
61+
</span><span id="L-9"><a href="#L-9"><span class="linenos">9</span></a><span class="p">)</span>
6162
</span></pre></div>
6263

6364

docs/apidocs/autohive_integrations_sdk/integration.html

Lines changed: 2413 additions & 2019 deletions
Large diffs are not rendered by default.

docs/apidocs/search.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/manual/billing.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class CallApiAction(ActionHandler):
6262
response = await context.fetch(url, headers={"Authorization": f"Bearer {api_key}"})
6363

6464
return ActionResult(
65-
data={"result": response},
65+
data={"result": response.data},
6666
cost_usd=0.05
6767
)
6868
```
@@ -93,11 +93,11 @@ class GenerateContentAction(ActionHandler):
9393
)
9494

9595
# Calculate cost based on usage returned by the API
96-
tokens_used = response.get("usage", {}).get("total_tokens", 0)
96+
tokens_used = response.data.get("usage", {}).get("total_tokens", 0)
9797
cost = tokens_used * 0.00001 # $0.01 per 1000 tokens
9898

9999
return ActionResult(
100-
data={"content": response["result"]},
100+
data={"content": response.data["result"]},
101101
cost_usd=cost
102102
)
103103
```

docs/manual/building_your_first_integration.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class GetItemsAction(ActionHandler):
223223
params={"limit": limit}
224224
)
225225

226-
items = response.get("data", [])
226+
items = response.data.get("data", [])
227227

228228
return ActionResult(
229229
data={
@@ -254,7 +254,7 @@ class GetItemsAction(ActionHandler):
254254
**`ActionHandler`** — Base class for all action handlers. You must implement the `async def execute()` method.
255255

256256
**`ExecutionContext`** — Provided to every handler. Gives you:
257-
- `context.fetch(url, ...)` — Make HTTP requests with automatic auth handling
257+
- `context.fetch(url, ...)` — Make HTTP requests with automatic auth handling; returns a `FetchResponse` with `.status`, `.headers`, and `.data` attributes
258258
- `context.auth` — Access authentication credentials
259259

260260
**`ActionResult`** — The required return type for all action handlers. Contains:
@@ -263,7 +263,7 @@ class GetItemsAction(ActionHandler):
263263

264264
### Making HTTP Requests
265265

266-
Use `context.fetch()` for all HTTP calls. It handles authentication headers, retries, timeouts, and response parsing automatically.
266+
Use `context.fetch()` for all HTTP calls. It handles authentication headers, retries, timeouts, and response parsing automatically. It returns a `FetchResponse` object — access the parsed body via `.data`, the HTTP status via `.status`, and response headers via `.headers`.
267267

268268
```python
269269
# GET with query parameters
@@ -272,6 +272,7 @@ response = await context.fetch(
272272
method="GET",
273273
params={"limit": 10, "status": "active"}
274274
)
275+
items = response.data # parsed response body
275276

276277
# POST with JSON body
277278
response = await context.fetch(
@@ -280,6 +281,7 @@ response = await context.fetch(
280281
headers={"Content-Type": "application/json"},
281282
json={"name": "New Item", "status": "active"}
282283
)
284+
new_item = response.data
283285

284286
# POST with form-encoded body
285287
response = await context.fetch(
@@ -288,6 +290,7 @@ response = await context.fetch(
288290
headers={"Content-Type": "application/x-www-form-urlencoded"},
289291
data={"name": "New Item"}
290292
)
293+
result = response.data
291294
```
292295

293296
### Handling Inputs
@@ -325,7 +328,7 @@ class MyActionHandler(ActionHandler):
325328
cost_usd=0.01 # API call was made, cost was still incurred
326329
)
327330

328-
return ActionResult(data=response)
331+
return ActionResult(data=response.data)
329332
```
330333

331334
Use `ActionError` for expected, application-level failures. For unexpected infrastructure errors, let exceptions propagate normally.

docs/manual/connected_account.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,13 @@ class MyConnectedAccountHandler(ConnectedAccountHandler):
104104
# Fetch user info from the API
105105
# For platform OAuth, context.fetch() auto-injects the Authorization header.
106106
# For custom auth, pass headers manually using context.auth.get("credentials", {}).get("api_key")
107-
user_data = await context.fetch(
107+
response = await context.fetch(
108108
"https://api.example.com/user",
109109
method="GET"
110110
)
111111

112112
# Return ConnectedAccountInfo with available fields
113+
user_data = response.data
113114
name = user_data.get("name", "")
114115
name_parts = name.split(maxsplit=1) if name else []
115116

@@ -138,13 +139,14 @@ class GithubConnectedAccountHandler(ConnectedAccountHandler):
138139
async def get_account_info(self, context: ExecutionContext) -> ConnectedAccountInfo:
139140
"""Fetch GitHub user information"""
140141
# context.fetch() auto-injects the Authorization header for platform OAuth
141-
user_data = await context.fetch(
142+
response = await context.fetch(
142143
"https://api.github.com/user",
143144
method="GET",
144145
headers={"Accept": "application/vnd.github.v3+json"}
145146
)
146147

147148
# Parse name into first/last
149+
user_data = response.data
148150
name = user_data.get("name", "")
149151
name_parts = name.split(maxsplit=1) if name else []
150152

@@ -173,11 +175,12 @@ class LinkedInConnectedAccountHandler(ConnectedAccountHandler):
173175
async def get_account_info(self, context: ExecutionContext) -> ConnectedAccountInfo:
174176
"""Fetch LinkedIn user information"""
175177
# context.fetch() auto-injects the Authorization header for platform OAuth
176-
user_data = await context.fetch(
178+
response = await context.fetch(
177179
"https://api.linkedin.com/v2/userinfo",
178180
method="GET"
179181
)
180182

183+
user_data = response.data
181184
return ConnectedAccountInfo(
182185
email=user_data.get("email"),
183186
first_name=user_data.get("given_name"),

docs/manual/integration_structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ Required fields:
179179
Optional fields:
180180
- `scopes`: array of OAuth scopes to request
181181

182-
With platform auth, `context.fetch()` automatically injects the `Authorization` header.
182+
With platform auth, `context.fetch()` automatically injects the `Authorization` header and returns a `FetchResponse` object (with `.status`, `.headers`, and `.data` attributes).
183183

184184
#### No Auth
185185

0 commit comments

Comments
 (0)