diff --git a/cueapi/cli.py b/cueapi/cli.py index 1a00162..b7d8369 100644 --- a/cueapi/cli.py +++ b/cueapi/cli.py @@ -2966,6 +2966,17 @@ def subscriptions() -> None: help="Delivery mechanism: pull (poll via `cueapi events list`) or webhook (server POSTs).") @click.option("--webhook-url", "webhook_url", default=None, help="Required for delivery-target=webhook; HTTPS only.") +@click.option("--inline-body", "inline_body", is_flag=True, default=False, + help=( + "Opt into body embedding on emitted events (hosted PR #791, " + "Item 1). When set, the source message body is embedded in " + "event payloads as `payload.body` — eliminates the extra " + "GET /v1/messages/{id} round-trip on the consumer side. " + "Bodies > 32KB are NOT embedded; the payload instead carries " + "`payload.body_omitted = \"size_too_large\"` + " + "`payload.body_size_bytes = N` so consumers fall back to the " + "fetch. Default unset = server default (False)." + )) @click.pass_context def subscriptions_create( ctx: click.Context, @@ -2973,6 +2984,7 @@ def subscriptions_create( event_type: str, delivery_target: str, webhook_url: Optional[str], + inline_body: bool, ) -> None: """Create a subscription for an agent. @@ -2987,6 +2999,13 @@ def subscriptions_create( body: dict = {"event_type": event_type, "delivery_target": delivery_target} if webhook_url: body["webhook_url"] = webhook_url + # is_flag means click defaults to False when unset; only send the + # field when explicitly opted in (matches SDK convention — keeps the + # wire format identical to pre-#791 callers for the common no-embed + # case). Sending False when the user explicitly opted out would also + # work but adds payload noise; the server default handles it. + if inline_body: + body["inline_body"] = True try: with CueAPIClient(api_key=ctx.obj.get("api_key"), profile=ctx.obj.get("profile")) as client: resp = client.post(f"/agents/{ref}/subscriptions", json=body) diff --git a/tests/test_cli.py b/tests/test_cli.py index 4312e97..14e44dc 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3643,3 +3643,74 @@ def test_bulk_delete_rejects_more_than_100_ids_pre_request(): # exit code shape is implementation-detail (echo_error may raise # SystemExit). What matters is the cap message appears. assert "100" in result.output + + +# --- subscriptions --inline-body (hosted PR #791 / Item 1 parity) --- + + +def test_subscriptions_create_inline_body_flag_default_omits_field(monkeypatch): + """Default (no --inline-body flag) MUST NOT send inline_body on the wire. + Preserves pre-#791 caller compatibility — server default of False applies.""" + holder: dict = {} + _patch_client( + monkeypatch, + holder, + responses={ + ("POST", "/agents/agt_x/subscriptions"): lambda: _FakeResp( + 201, + { + "id": "sub_uuid", + "event_type": "message.received", + "delivery_target": "pull", + "inline_body": False, + }, + ) + }, + ) + result = runner.invoke( + main, + ["subscriptions", "create", "agt_x", + "--event-type", "message.received", + "--delivery-target", "pull"], + ) + assert result.exit_code == 0, result.output + body = holder["client"].calls[-1][2] + assert "inline_body" not in body + + +def test_subscriptions_create_inline_body_flag_opts_in(monkeypatch): + """--inline-body opts into body-embedding on emitted events.""" + holder: dict = {} + _patch_client( + monkeypatch, + holder, + responses={ + ("POST", "/agents/agt_x/subscriptions"): lambda: _FakeResp( + 201, + { + "id": "sub_uuid", + "event_type": "message.received", + "delivery_target": "pull", + "inline_body": True, + }, + ) + }, + ) + result = runner.invoke( + main, + ["subscriptions", "create", "agt_x", + "--event-type", "message.received", + "--delivery-target", "pull", + "--inline-body"], + ) + assert result.exit_code == 0, result.output + body = holder["client"].calls[-1][2] + assert body["inline_body"] is True + + +def test_subscriptions_create_help_lists_inline_body(): + result = runner.invoke(main, ["subscriptions", "create", "--help"]) + assert result.exit_code == 0 + assert "--inline-body" in result.output + # Mention the 32KB cap so users discover it via --help + assert "32KB" in result.output or "body_omitted" in result.output