Skip to content

v0.1.13 — ADR-017 SendMessageConfiguration honoured on all transports

Choose a tag to compare

@hortovanyi hortovanyi released this 24 Apr 08:10
· 95 commits to main since this release

What changed

Three silent bugs closed in core_send_message (shared by HTTP /message:send, JSON-RPC SendMessage, and gRPC SendMessage — a single guard covers all three transports).

1. AWS Lambda: return_immediately=true now rejects (ADR-017 Bug 1)

Breaking for Lambda adopters who relied on the previous silent behaviour. Previously the flag was accepted but the background executor had no guarantee of completing in the Lambda execution environment (ADR-008, ADR-013 §4.4), leaving tasks stuck in Working indefinitely with no push callback.

Now returns UnsupportedOperationError (HTTP 400 / JSON-RPC -32004 / gRPC INVALID_ARGUMENT) with a tracing::warn! log. No task persists on this path.

Migration on Lambda: remove returnImmediately: true or switch to blocking send. Adopters needing fire-and-forget-style work should invoke their durable mechanism (Step Functions / SQS / EventBridge) from inside their AgentExecutor::execute body — the A2A task is Completed for workflow accepted / started, not workflow finished. If the A2A task is meant to track the full workflow lifecycle, the workflow itself must call back into turul-a2a storage. See ADR-017 §"Alternatives considered" Pattern A.

Deferred: framework-managed durable continuation. If/when it lands, the adopter surface will be a capability-taking builder method (with_durable_return_immediately(handler)), never a public boolean setter.

2. Inline taskPushNotificationConfig honoured (ADR-017 Bug 2)

SendMessageConfiguration.taskPushNotificationConfig is now registered atomically with task creation on all runtimes. URL parses up front (malformed URL → HTTP 400 with zero task persisted). On storage failure, the task is compensated to TASK_STATE_FAILED with an agent Message reading inline push notification config registration failed: <error>, and the executor never spawns. Callers that previously worked around the silent drop with a separate CreateTaskPushNotificationConfig round-trip may remove that workaround.

3. historyLength tri-state honoured (ADR-017 Bug 3)

Response message history is trimmed on both return_immediately=true and blocking send responses, matching GetTask. Proto semantics preserved exactly (a2a.proto:150-154): unset = no limit, 0 = empty history, n > 0 = last n messages. Callers that relied on receiving the full history regardless of the flag must omit historyLength — setting it to 0 now correctly clears the response history per the proto contract.

Added

  • RuntimeConfig.supports_return_immediately: bool (default true) — capability flag consumed by core_send_message. LambdaA2aServerBuilder::build() sets it to false. pub on a #[non_exhaustive] struct as an escape hatch for tests and advanced internal consumers; not an adopter surface.

Test matrix

  • 12 new tests in crates/turul-a2a/tests/adr017_tests.rs covering: Lambda reject (HTTP + JSON-RPC), inline push config (HTTP + JSON-RPC + invalid URL + missing URL + storage-failure compensation), and historyLength tri-state (zero-empties, unset-unbounded, n=1 return-immediately, n=1 blocking).
  • Full gate green: cargo test --workspace (650), cargo test --workspace --features sqlite (714), cargo test -p turul-a2a --features grpc (486).
  • All 5 HTTP examples live-smoked; callback-agent end-to-end webhook smoke test passes (exercises the exact Bug 2 wire surface on the binary server).

Documentation

  • ADR-017 — return_immediately Lambda gate + inline push config + history_length.

Crates published (crates.io)

All at 0.1.13: turul-a2a-proto, turul-a2a-types, turul-a2a, turul-a2a-client, turul-a2a-auth, turul-a2a-aws-lambda.