Skip to content

fix(helpers): give the Atoms REST helpers a request timeout - #114

Closed
CaptainAni187 wants to merge 1 commit into
smallest-inc:mainfrom
CaptainAni187:fix_helper_requests_timeout
Closed

CaptainAni187 wants to merge 1 commit into
smallest-inc:mainfrom
CaptainAni187:fix_helper_requests_timeout

Conversation

@CaptainAni187

@CaptainAni187 CaptainAni187 commented Sep 12, 2026

Copy link
Copy Markdown

requests applies no timeout unless you pass one, so a call without timeout= blocks until the OS gives up on the socket, which on a half-open connection can be many minutes. The Atoms REST helpers make 31 calls and 28 of them had none:

# call.py
response = requests.get(url, headers=self._get_headers())

# kb.py
response = requests.post(url, headers=self._get_headers(), json=payload)

AgentTools, the fifth helper in the same package, already gets this right. It takes a keyword-only request_timeout: float = 30.0, stores it, and passes it to every call:

def _get(self, path: str) -> Any:
    resp = requests.get(f"{self.base_url}/{path}", headers=self._headers(), timeout=self.request_timeout)

So this is Audience, CallAnalytics, Campaign and KB catching up with the one helper beside them that already does it.

It matters most where these helpers are actually used. A voice agent reading call analytics or a knowledge base inside a request path has no way to bound the wait today, and the generated client next to it enforces 60s by default, so the hand-written helpers are the one place where a hang can happen.

The change

The same keyword-only request_timeout param, the same 30.0 default, stored on the instance and passed to all 28 call sites. Nothing else moves: no new module, no shared constant to import, no change to any existing argument, and the param is keyword-only so no positional call breaks.

versioning.py and _envelope.py make no HTTP calls, so they are untouched.

Tests

tests/custom/test_helpers_request_timeout.py walks every public method on each of the four managers with requests replaced by a recorder, then asserts that no recorded call went out without a timeout. Driving it by reflection rather than naming 28 methods means a helper method added later is covered the day it lands.

Twelve cases: every call carries a timeout, a caller-supplied value reaches all of them, and the default equals the one AgentTools already uses so the two cannot drift. All twelve fail on main.

src/smallestai/atoms/helpers/** is .fernignored, so a regen keeps this.

Worth saying: 30.0 matches AgentTools, not the generated client's 60. I took the sibling helper as the closer precedent, but happy to move all five to 60 if you would rather they match the client.

requests applies no timeout of its own, so the 28 calls in Audience,
CallAnalytics, Campaign and KB wait forever on a half-open connection.
AgentTools, the fifth helper in the same package, already threads a
request_timeout through every call, so take the same keyword-only param
and default there.
@crim-app

crim-app Bot commented Sep 12, 2026

Copy link
Copy Markdown

crim doesn't review pull requests automatically here.

Comment crim review on this pull request whenever you want a review.

@CaptainAni187

Copy link
Copy Markdown
Author

crim review

@crim-app

crim-app Bot commented Sep 12, 2026

Copy link
Copy Markdown

crim is reviewing this pull request. Findings will be posted shortly.

@crim-app crim-app 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.

LGTM

One-sentence assessment: A correct, backward-compatible fix that closes real hang-forever risk by giving every Atoms REST helper call a request timeout.

What this PR does

Adds a keyword-only request_timeout parameter (default DEFAULT_REQUEST_TIMEOUT = 30.0) to the Audience, CallAnalytics, Campaign, and KB constructors and passes timeout=self.request_timeout to every requests call in those helpers. This matches the pattern already used by AgentTools, whose 30.0 default the new tests assert against. A parametrized test suite verifies every helper request carries a timeout, honors a caller-supplied value, and that the default matches AgentTools.

Findings

No issues found.

  • The new parameter is keyword-only with a default, so existing positional callers (base_url, api_key) are unaffected.
  • requests timeout is per-connect/per-read, not a total deadline, so the 30s default does not prematurely abort large multipart uploads in kb.upload_document / audience.create that keep making progress.
  • Default value is kept in sync with AgentTools via an explicit test.

@crim-app

crim-app Bot commented Sep 12, 2026

Copy link
Copy Markdown

Good to merge

Every request finally wears a watch instead of waiting forever on a half-open socket, and there's a test that fails if anyone forgets to strap one on. Genuinely tidy work.

@abhishekmishragithub

Copy link
Copy Markdown
Collaborator

Superseded by #120 (re-homed onto an upstream branch so CI could run; your commit is included with authorship preserved, and the test type-check gaps for #112/#118 were fixed there). Shipping in 5.12.1.

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.

2 participants