feat: add runtime action SDK clients - #252
Conversation
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
| throw new RuntimeActionTimeoutError(actionId, timeout, lastAction); | ||
| } | ||
|
|
||
| const waitMs = Math.max(1_000, Math.min(maxServerWaitMs, remainingTime)); |
There was a problem hiding this comment.
[🟡 Medium] [🔵 Bug]
waitRuntimeAction computes remainingTime correctly, but then forces waitMs to at least 1000, which can exceed the remaining deadline. Because fetchWithTimeout uses this.config.timeout (default 30s), a final wait request can run well past the user-specified options.timeout before RuntimeActionTimeoutError is thrown. Compute wait duration from remaining deadline (or timeout immediately when the remaining budget is below the minimum server wait) so the method honors its timeout contract.
// packages/sdk/src/cloud/client.ts
const remainingTime = deadline - Date.now();
if (remainingTime <= 0) {
throw new RuntimeActionTimeoutError(actionId, timeout, lastAction);
}
const waitMs = Math.max(1_000, Math.min(maxServerWaitMs, remainingTime));| if client_timeout_seconds > 1.5 | ||
| else client_timeout_seconds, | ||
| ) | ||
| timeout_ms = max(1_000, int(server_wait_seconds * 1000)) |
There was a problem hiding this comment.
[🟡 Medium] [🔵 Bug]
wait_runtime_action derives timeout_ms from client session timeout each loop and never clamps it to the remaining opts.timeout budget. If the remaining deadline is short, it can still issue a long wait request and only raise RuntimeActionTimeoutError after that request returns, violating caller timeout expectations. Recompute timeout_ms from remaining deadline on each iteration (or fail immediately when remaining time is below the minimum wait) to keep wait behavior bounded by options.timeout.
# packages/sdk-python/veto/cloud/client.py
client_timeout_seconds = self._config.timeout / 1000
server_wait_seconds = min(
30.0,
client_timeout_seconds - 0.5
if client_timeout_seconds > 1.5
else client_timeout_seconds,
)
timeout_ms = max(1_000, int(server_wait_seconds * 1000))
What changed
createRuntimeAction(...)posts to/v1/runtime/actionswaitRuntimeAction(...)long-polls/v1/runtime/actions/:id/waitRuntimeActionTimeoutErrorpreserves the last observed pending actioncreate_runtime_action(...)wait_runtime_action(...)RuntimeActionCreateRequest,RuntimeActionData, andRuntimeActionTimeoutErrorveto-sdkand@veto/python-release.Why
The platform runtime API is now the canonical SDK release valve for the iOS approval wallet. Agents need a first-class client path to create a pending runtime action and block until the iOS biometric approval flow resolves it.
Validation
PYTHONPATH=packages/sdk-python /opt/homebrew/bin/python3.11 -m pytest packages/sdk-python/tests/test_cloud_client.py -q→ 3 passedpnpm --filter veto-sdk exec vitest run tests/cloud/client.test.ts→ 17 passedpnpm --filter veto-sdk exec eslint src/cloud/client.ts src/cloud/types.ts src/index.ts tests/cloud/client.test.ts/opt/homebrew/bin/python3.11 -m ruff check packages/sdk-python/veto/cloud/client.py packages/sdk-python/veto/cloud/types.py packages/sdk-python/veto/cloud/__init__.py packages/sdk-python/veto/__init__.py packages/sdk-python/tests/test_cloud_client.pypnpm --filter veto-sdk exec tsc --noEmit -p tsconfig.jsonpnpm --filter veto-sdk buildhttps://api.veto.so/healthreturns 200 andPOST /v1/runtime/actionsreturns401 invalid_api_key, proving the deployed route is present and protected.Not covered here
A real production create/wait/resolve E2E requires a project-scoped
VETO_API_KEYand an available iOS approval device. NoVETO_API_KEYis present in the current environment.