Skip to content

fix(sdk/typescript): stop retrying permanent status callbacks - #1126

Merged
santoshkumarradha merged 1 commit into
Agent-Field:mainfrom
ShryukGrandhi:fix/issue-1088-python-ts-sdks-align-status-callback-ret
Oct 26, 2026
Merged

santoshkumarradha merged 1 commit into
Agent-Field:mainfrom
ShryukGrandhi:fix/issue-1088-python-ts-sdks-align-status-callback-ret

Conversation

@ShryukGrandhi

Copy link
Copy Markdown
Contributor

Summary

The Python half of #1088 landed in #1109; this ports the same status-callback retry policy to the TypeScript SDK so it matches the Go SDK's postExecutionStatus (#1081).

  • AgentFieldClient.reportExecutionResult used to retry every non-2xx response 5 times with 1+2+4+8s backoff. That meant a 409 terminal-status conflict took about 15s before it gave up. It now retries only transport errors, 408, 429 and 5xx. Any other status returns false right away. Like Python after fix(sdk/python): stop retrying permanent status callbacks #1109, 404 is treated as permanent now that Legacy /reasoners/:id and /skills/:id never create the executions row, so status callbacks 404 #1086 persists the execution row.
  • updateExecutionStatus, which WorkflowReporter.progress calls, used to send only once. It now uses the same retry helper and throws the last error if every attempt fails. It also gets an explicit 30s per-attempt timeout and URL-encodes the execution id, like reportExecutionResult already did.
  • Requests are now signed inside the retry loop, so each retry gets a fresh DID timestamp and nonce. Before, every retry reused one signature.

I did not touch the fire-and-forget publishWorkflowEvent start event. Its main risk was progress arriving before the execution existed, and that no longer causes a 404 now that #1086 has landed.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Docs only
  • Tests only
  • CI / tooling
  • Breaking change

Test plan

  • cd sdk/typescript && npx vitest run (93 files, 1088 passed, 1 skipped)
  • cd sdk/typescript && npm run lint (tsc --noEmit, clean)

New tests in tests/agentfield_client_async.test.ts run against a real local HTTP server:

  • 400/401/403/404/409/422 are sent exactly once
  • 408/429/503 are retried and then succeed
  • transport errors return false
  • each attempt has a different X-DID-Nonce
  • updateExecutionStatus retries a 503 and throws on a 409 after one attempt

Without the fix, the 4xx cases time out because they are retried with backoff, and the nonce test fails because the signature is reused.

Test coverage

  • I ran tests for the surface(s) I changed locally.
  • New code paths are covered by tests in this PR (no bare additions).
  • If I removed code, I updated coverage-baseline.json in this PR only if the removal caused a legitimate regression and I called it out in the summary above.
  • The coverage gate check is green in CI before requesting review.

Checklist

Related issues / PRs

Fixes #1088

Follows #1081 (Go) and #1109 (Python).

Align reportExecutionResult and updateExecutionStatus with the Go SDK's
postExecutionStatus: retry transport errors, 408, 429 and 5xx with
1+2+4+8s backoff, and fail fast on any other status (e.g. a 409
terminal-status conflict). Each attempt is signed with a fresh DID
timestamp/nonce instead of reusing one signature across retries.

Fixes Agent-Field#1088

Signed-off-by: ShryukGrandhi <85529990+ShryukGrandhi@users.noreply.github.com>
@ShryukGrandhi
ShryukGrandhi requested review from a team and AbirAbbas as code owners October 21, 2026 23:06
@github-actions

Copy link
Copy Markdown
Contributor

Performance

SDK Memory Δ Latency Δ Tests Status
TS 440 B +26% 3.08 µs +54% ✓ ✗

⚠ Regression detected:

  • TypeScript memory: 350 B → 440 B (+26%)

@github-actions

Copy link
Copy Markdown
Contributor

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 84%, aggregate ≥ 85%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 88.20% 87.40% ↑ +0.80 pp 🟡
sdk-go 93.40% 92.00% ↑ +1.40 pp 🟢
sdk-python 94.72% 93.73% ↑ +0.99 pp 🟢
sdk-typescript 91.92% 90.42% ↑ +1.50 pp 🟢
web-ui 84.90% 84.79% ↑ +0.11 pp 🟡
aggregate 86.12% 85.75% ↑ +0.37 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions

Copy link
Copy Markdown
Contributor

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 0 — ➖ no changes
sdk-go 0 — ➖ no changes
sdk-python 0 — ➖ no changes
sdk-typescript 18 100.00% ✅
web-ui 0 — ➖ no changes

✅ Patch gate passed

Every surface whose lines were touched by this PR has patch coverage at or above the threshold.

@santoshkumarradha santoshkumarradha left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the current head and focused validation. This looks good to me.

@santoshkumarradha
santoshkumarradha added this pull request to the merge queue Oct 26, 2026
Merged via the queue into Agent-Field:main with commit 7004561 Oct 26, 2026
24 checks passed
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.

Python/TS SDKs: align status-callback retry policy with the Go SDK (#1081)

2 participants