anthropics / anthropics/anthropic-sdk-python

environments work poller: ack-before-yield makes any consumer failure permanently strand the work item — request deferred ack or a nack/fail API

Đang mở
#1,746 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
3.9k
Fork
853
Merge trung bình
1 ngày 18 giờ
Pull request đã merge (30 ngày)
11

Mô tả

`anthropic.lib.environments._poller` acknowledges every work item **before** yielding it to the consumer (`_poller.py:234`; docstring at `:66`: "Each yielded `BetaSelfHostedWork` has already been ack'd"). There is no deferred-ack option and no nack/fail API. Verified identical from 0.109.1 through 0.116.0.

For self-hosted managed-agents environments this makes any consumer-side exception after the yield permanently strand that session:

- the acked item freezes in `state='starting'` with `latest_heartbeat_at=null`;
- `reclaim_older_than_ms` cannot reach it (it only reaches unacknowledged items), and lease-TTL re-queue never fires (requires a first heartbeat);
- the platform keeps one work item per session, so all subsequent `user.message` events park in `requires_action` with **no new work enqueued** — the session is wedged until an operator runs `work.stop(work_id, force=True)` and sends a `user.interrupt`.

We hit this in production twice in one day (different consumer exceptions, same terminal state) and separately counted 29 items stuck in `starting` with null heartbeats.

## Ask

Either of:
1. **Deferred ack**: an opt-in poller mode that acks after the consumer callback returns successfully (at-least-once semantics), or
2. **nack/fail API**: a way for a consumer to return a failed item to a re-pendable state.

Related, happy to file separately: documenting which work-item states re-enqueue on which user events (empirically: `stopped` re-pends on message/interrupt; a dead-heartbeat `started` item only after a server-side stop ~5 min later; an acked-but-never-heartbeated `starting` item never), and a server-side janitor for `starting` + null-heartbeat items older than a TTL.

## Workaround we ship today

Consumer retry + `work.stop(force=True)` on final failure, plus a scheduled sweep that force-stops stale `starting` items and interrupts sessions parked in `requires_action` with no live worker. Effective, but every self-hosted-environment consumer will independently rediscover this failure class — ack-after-success semantics in the SDK would eliminate it.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.