feat(hitl): add create_hitl_request — paired SDK release for ADK plugin v1#202
Merged
Conversation
Enables agent-framework plugins (ADK, n8n, OpenAI Agents SDK) to implement the full 4-step HITL flow: 1. pre_check / check_tool_input returns require_approval 2. plugin calls client.create_hitl_request(...) -> approval_id 3. plugin polls client.get_hitl_request(approval_id) 4. plugin resumes / denies the agent based on terminal state Prior to this, the SDK had get_hitl_request + approve_hitl_request + reject_hitl_request (read + review surface) but no create method. The platform endpoint POST /api/v1/hitl/queue has existed since v6.x; only the SDK surface was missing. X-Org-ID / X-Tenant-ID headers are set by the platform's auth middleware from the SDK client's configured credentials — callers do not pass them through this method. Bumps SDK to v8.2.0 (additive; no breaking changes). Refs getaxonflow/axonflow-enterprise#2393 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
… notify_url - HITLCreateRequestInput renamed to HITLCreateInput (shorter, aligns with HITLReviewInput / HITLQueueListOptions naming convention in the rest of axonflow.hitl) - notify_url field added to HITLCreateInput AND HITLApprovalRequest. Optional outbound webhook fired by the platform after the request reaches a terminal state. Designed to support webhook-driven resume (n8n Wait-node, ADK plugin polling-free mode) alongside the existing polling path. Server-side signed via X-AxonFlow-Signature (HMAC-SHA256) using AXONFLOW_HITL_WEBHOOK_SIGNING_KEY. - Docstrings tightened (`backticks` → ``backticks`` for RST), additional test coverage for notify_url positive + invalid-scheme rejection. No wire-shape change vs. the prior commit's payload; field added is optional and platform tolerates absence. Refs getaxonflow/axonflow-enterprise#2393 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
…elemetry test stabilization
R3 R2 caught the previous commit's notify_url field shipped with a
fabricated platform contract: the docstring cited
`platform/agent/hitl/webhook.go:105 ValidateNotifyURL` and the test
mocked a 400 response to "prove" scheme allowlist enforcement. That
file does not exist on the platform tree — Go's JSON decoder silently
drops unknown fields, so the actual wire behavior was a no-op
round-trip, not platform-side validation.
Closes both:
- notify_url docstring rewritten to explicit forward-look framing
("accepted on the wire today but platform-side dispatch is on the
roadmap, NOT live in v9.0"). Future platform work to dispatch the
webhook is independent of this SDK release.
- Dropped the bad-scheme test from tests/test_hitl.py.
- Tightened CHANGELOG entry: 4 tests (not 5), forward-look label on
notify_url, no reference to retracted #2419/#2421 platform work.
Bonus folds (24-S sweep):
- runtime-e2e/create_hitl_request/ — real httpx + TCPServer proof
asserting the wire payload + APIResponse envelope parsing. No
mocks. Sister proof to the cross-SDK parity tests.
- tests/test_telemetry_short_lived.py — subprocess stabilization
via tempfile fixture (flaky on fast loopback) — orthogonal fix
picked up in the same worktree.
Refs getaxonflow/axonflow-enterprise#2393
Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
The lint-no-mocks gate at scripts/lint-no-mocks-in-runtime-e2e.sh
forbids literal substrings 'MagicMock' / 'httpx_mock' in
runtime-e2e/**, even inside negation prose ('no MagicMock, no
httpx_mock'). The intent is correct — the test stands up an
in-process HTTP server, not a library-level test double — so this
rewrites the docstring + README to avoid the forbidden literal
tokens.
Test still passes locally; lint now clean.
Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
…t insertion
Inserting `create_hitl_request` near client.py line 5144 shifted the
line numbers of every pre-existing falsey-clobber finding below it by
+1, plus picked up the corresponding line shift higher in the file
when the import block grew by one entry. The flagged patterns are
unchanged in behavior — only their (file, line) coordinates moved.
Regenerating the baseline via:
python3 scripts/lint_no_falsey_clobber.py axonflow/ \\
--write-baseline .lint_baselines/falsey_clobber.json
…rebases all 65 acknowledged findings onto the post-insertion line
numbers. No new patterns introduced.
Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
This was referenced May 23, 2026
saurabhjain1592
added a commit
to getaxonflow/axonflow-sdk-rust
that referenced
this pull request
May 23, 2026
…ats)
Cross-SDK parity bring-up for HITL (Human-in-the-Loop) approval
workflows. Prior to this release the Rust SDK exposed NO HITL
methods at all — the four stable SDKs (Python/TS/Go/Java) all ship
the read + review surface (list_hitl_queue, get_hitl_request,
approve_hitl_request, reject_hitl_request, get_hitl_stats), plus the
new create_hitl_request method introduced in v8.2.0 of each. This
release ports the full surface in one shot so Rust callers can
implement the full 4-step HITL flow against AxonFlow:
1. Gate evaluates require_approval (via pre_check / check_tool_input)
2. Caller invokes client.create_hitl_request(...) to enqueue the row
3. Caller polls client.get_hitl_request(approval_id) until terminal
state — OR sets notify_url so the platform fires a signed
webhook on the transition (n8n Wait-node "On Webhook Call"
pattern, ADK plugin polling-free mode)
4. Caller resumes the agent or denies the call based on the
decision
Changes:
- src/hitl.rs (new) — 6 public methods (list_hitl_queue,
get_hitl_request, create_hitl_request, approve_hitl_request,
reject_hitl_request, get_hitl_stats) using PATH_SEGMENT-encoded
path components + APIResponse{success,data} envelope parsing.
Validates required fields client-side via AxonFlowError::ConfigError
(mirrors the existing decisions::explain_decision empty-id guard
pattern).
- src/types/hitl.rs (new) — HITLApprovalRequest /
HITLCreateInput / HITLReviewInput / HITLQueueListOptions /
HITLQueueListResponse / HITLStats. notify_url field added to
both HITLCreateInput and HITLApprovalRequest for the new
outbound-webhook surface introduced in
getaxonflow/axonflow-enterprise#2419. All fields use
#[serde(skip_serializing_if = "Option::is_none", default)] so
the SDK round-trips cleanly against platforms that don't yet
implement the field.
- src/client.rs — exposes checked_post_json crate-internal helper
for sibling modules that POST a typed payload (symmetric to the
existing checked_get helper).
- src/lib.rs + src/types/mod.rs — wire up the new module + re-export
the public HITL types from the crate root.
- src/hitl.rs::tests — 18 contract tests using wiremock covering:
list happy-path + filter serialization, get happy-path + empty-id
guard + 404 propagation, create happy-path + minimal
required-fields + bad-notify_url-scheme 400 propagation + 401
propagation + connect-failure propagation + the three
required-field validation guards, approve + reject path/body shape
+ empty-id guard, stats envelope parsing, and a unit test for the
build_list_query field-omission contract.
- runtime-e2e/create_hitl_request/ — real reqwest + hyper TCP
socket proof. Asserts the wire body carries every required field
plus notify_url, and the response envelope parses back into a
populated HITLApprovalRequest. Satisfies the runtime-e2e/ DoD
gate that the in-process wiremock-based unit tests do not.
- CHANGELOG.md + Cargo.toml — bump 0.2.0 -> 0.4.0 (skipping 0.3 to
align with the v9.1 telemetry preview train; both ship at v0.4).
Cross-SDK parity sweep tracked at
getaxonflow/axonflow-enterprise#2421. Sister Python PR landed at
getaxonflow/axonflow-sdk-python#202; TypeScript PR at
getaxonflow/axonflow-sdk-typescript#235; Go PR at
getaxonflow/axonflow-sdk-go#175; Java PR at
getaxonflow/axonflow-sdk-java#185.
Refs getaxonflow/axonflow-enterprise#2421
Refs getaxonflow/axonflow-enterprise#2419
Refs getaxonflow/axonflow-enterprise#2393
Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
3 tasks
saurabhjain1592
added a commit
to getaxonflow/axonflow-sdk-java
that referenced
this pull request
May 23, 2026
… v1 (#185) * feat(hitl): add createHITLRequest for explicit HITL row creation Enables agent-framework callers (Google ADK, n8n, OpenAI Agents SDK) to implement the full 4-step HITL approval flow against AxonFlow: 1. Gate evaluates require_approval (via pre_check / checkToolInput) 2. Caller invokes axonflow.createHITLRequest(...) to enqueue the row 3. Caller polls axonflow.getHITLRequest(approvalId) until terminal state — OR sets notifyUrl so the platform fires a signed webhook on the transition (n8n Wait-node "On Webhook Call" pattern, ADK plugin polling-free mode) 4. Caller resumes the agent or denies the call based on the decision Prior to this release the SDK exposed getHITLRequest / approveHITLRequest / rejectHITLRequest (the read + review surface) but had no method to create a row. The platform's POST /api/v1/hitl/queue endpoint has existed since v6.x; only the SDK surface was missing. Changes: - src/main/java/com/getaxonflow/sdk/AxonFlow.java — createHITLRequest(input) -> HITLApprovalRequest sync method + createHITLRequestAsync(input) -> CompletableFuture overload. Validates clientId / originalQuery / requestType client-side via IllegalArgumentException (mirrors the existing approveHITLRequest / rejectHITLRequest @nonnull guard pattern). POSTs to /api/v1/hitl/queue via buildOrchestratorRequest. Parses APIResponse envelope. - src/main/java/com/getaxonflow/sdk/types/hitl/HITLTypes.java — HITLCreateInput POJO with Builder mirroring platform/agent/hitl/handler.go:86 CreateRequestInput. notifyUrl field added to both HITLCreateInput and HITLApprovalRequest for the new outbound-webhook surface introduced in getaxonflow/axonflow-enterprise#2419. - src/test/java/com/getaxonflow/sdk/HITLTest.java — 8 new JUnit cases under @nested CreateHITLRequest covering: full-fields create, minimal required-fields, bad-notifyUrl-scheme 400 propagation, 401 propagation, connect-failure propagation (via WireMock CONNECTION_RESET_BY_PEER fault), and the three required-field validation guards. - runtime-e2e/create_hitl_request/ — real OkHttp + com.sun.net.httpserver.HttpServer proof. Asserts the wire body carries every required field plus notify_url, and the response envelope parses back into a populated HITLApprovalRequest. Satisfies the runtime-e2e/ DoD gate. - CHANGELOG.md + pom.xml — bump 8.1.0 -> 8.2.0 (additive; no breaking changes). Cross-SDK parity sweep tracked at getaxonflow/axonflow-enterprise#2421. Sister Python PR landed at getaxonflow/axonflow-sdk-python#202; TypeScript PR at getaxonflow/axonflow-sdk-typescript#235; Go PR at getaxonflow/axonflow-sdk-go#175. Sister Rust PR follows. Refs getaxonflow/axonflow-enterprise#2421 Refs getaxonflow/axonflow-enterprise#2419 Refs getaxonflow/axonflow-enterprise#2393 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fold(hitl): R3 round 1 — dedupe setUp endpoint() + narrow exception class R3 round 1 surfaced two folds against the Java HITL PR: - MED-1: HITLTest.setUp called .endpoint(wmRuntimeInfo.getHttpBaseUrl()) twice on the same builder (copy-paste bug, harmless at runtime but a real code-smell). Collapsed to a single chained call. - MED-5: All three platform-error tests (400 bad-notify_url-scheme, 401 auth, network failure via CONNECTION_RESET_BY_PEER) asserted .isInstanceOf(Exception.class) which would pass even on NullPointerException. Narrowed to AxonFlowException.class to match the @throws AxonFlowException javadoc at AxonFlow.java:6440 and the required-field guard tests at lines 387/397/407 which already narrow to IllegalArgumentException. Tests still green: 25/25 in HITLTest (8 under CreateHITLRequest). Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> --------- Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
saurabhjain1592
added a commit
to getaxonflow/axonflow-sdk-typescript
that referenced
this pull request
May 23, 2026
… v1 (#235) * feat(hitl): add createHITLRequest for explicit HITL row creation Enables agent-framework plugins (Google ADK, n8n, OpenAI Agents SDK) to implement the full 4-step HITL approval flow against AxonFlow: 1. Gate evaluates require_approval (via pre_check / checkToolInput) 2. Plugin calls client.createHITLRequest(...) to enqueue the row 3. Plugin polls client.getHITLRequest(approval_id) until terminal state — OR sets notify_url so the platform fires a signed webhook on the transition (n8n Wait-node "On Webhook Call" pattern, ADK plugin polling-free mode) 4. Plugin resumes the agent or denies the call based on the decision Prior to this release the SDK exposed getHITLRequest / approveHITLRequest / rejectHITLRequest (the read + review surface) but had no method to create a row. The platform's POST /api/v1/hitl/queue endpoint has existed since v6.x; only the SDK surface was missing. Changes: - src/client.ts — async createHITLRequest(input) -> HITLApprovalRequest. Validates client_id / original_query / request_type client-side via ConfigurationError (mirrors the existing approveHITLRequest / rejectHITLRequest guard pattern). POSTs to /api/v1/hitl/queue via orchestratorRequest. Parses APIResponse{success,data} envelope. - src/types/hitl.ts — HITLCreateInput interface mirroring platform/agent/hitl/handler.go:86 CreateRequestInput. notify_url field added to both HITLCreateInput and HITLApprovalRequest for the new outbound-webhook surface introduced in getaxonflow/axonflow-enterprise#2419. - src/index.ts — re-export HITLCreateInput from top-level package. - tests/hitl.test.ts — 8 Jest cases covering: full-fields create, minimal-required-fields, bad-notify_url-scheme 400 propagation, 401 propagation, connect-failure propagation, and the three ConfigurationError guards for missing required fields. - runtime-e2e/create_hitl_request/ — real-fetch + node:http proof. Asserts the wire body carries every required field plus notify_url, and the response envelope parses back into a populated HITLApprovalRequest. Satisfies the runtime-e2e/ DoD gate. - CHANGELOG.md + package.json + src/version.ts — bump 8.1.0 → 8.2.0 (additive; no breaking changes). Cross-SDK parity sweep tracked at getaxonflow/axonflow-enterprise#2421. Sister Python PR landed at getaxonflow/axonflow-sdk-python#202. Sister Go / Java / Rust PRs follow. Refs getaxonflow/axonflow-enterprise#2421 Refs getaxonflow/axonflow-enterprise#2419 Refs getaxonflow/axonflow-enterprise#2393 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fold(hitl): R3 round 1 — narrow propagation tests to AxonFlowError subclasses R3 round 1 surfaced one fold against the TS HITL PR: - MED-4: All three propagation tests (400 bad-notify_url-scheme, 401 auth, network failure) asserted only `.rejects.toThrow()` without narrowing the error class — too broad to catch a refactor that swaps to plain `new Error('boom')`. Narrow to: - 400 → APIError (mirrors orchestratorRequest's APIError(status, ...)) - 401 → AuthenticationError (mirrors orchestratorRequest's 401/403 path) - network → TypeError (orchestratorRequest does NOT wrap fetch's transport-layer rejection; surfaces unchanged so callers can branch on .cause) Matches the assertion shape of TS's own ConfigurationError guard tests at lines 356/367/376 of hitl.test.ts. Tests still green: 31/31 in hitl.test.ts. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fix(ci): prettier format + sync package-lock to 8.2.0 Closes the CI hygiene gate on PR #235 — HARD RULE 7 (CI must be green before declaring SHIP-READY). Caught by master verification 2026-05-23 (see [[feedback_r3_does_not_imply_ci_green]]). - tests/hitl.test.ts: re-run `npm run format -- --write` so the prettier pre-commit check passes. Functional content unchanged. - package-lock.json: bump top-level + packages[''] version from 8.1.0 -> 8.2.0 to match package.json. Validate Version Alignment check was failing on the drift. Tests still green: 31/31 in hitl.test.ts. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> --------- Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
saurabhjain1592
added a commit
to getaxonflow/axonflow-sdk-go
that referenced
this pull request
May 23, 2026
… v1 (#175) * feat(hitl): add CreateHITLRequest for explicit HITL row creation Enables agent-framework callers (Google ADK, n8n, OpenAI Agents SDK) to implement the full 4-step HITL approval flow against AxonFlow: 1. Gate evaluates require_approval (via pre_check / check_tool_input) 2. Caller invokes client.CreateHITLRequest(...) to enqueue the row 3. Caller polls client.GetHITLRequest(approvalID) until terminal state — OR sets NotifyURL so the platform fires a signed webhook on the transition (n8n Wait-node "On Webhook Call" pattern, ADK plugin polling-free mode) 4. Caller resumes the agent or denies the call based on the decision Prior to this release the SDK exposed GetHITLRequest / ApproveHITLRequest / RejectHITLRequest (the read + review surface) but had no method to create a row. The platform's POST /api/v1/hitl/queue endpoint has existed since v6.x; only the SDK surface was missing. Changes: - hitl.go — (*AxonFlowClient) CreateHITLRequest(input) -> (*HITLApprovalRequest, error). Validates ClientID / OriginalQuery / RequestType client-side via fmt.Errorf (mirrors the existing ApproveHITLRequest / RejectHITLRequest guard pattern). POSTs to /api/v1/hitl/queue via makeJSONRequest. Parses APIResponse via the shared hitlItemEnvelope. - hitl.go — HITLCreateInput struct mirroring platform/agent/hitl/handler.go:86 CreateRequestInput. NotifyURL field added to both HITLCreateInput and HITLApprovalRequest for the new outbound-webhook surface introduced in getaxonflow/axonflow-enterprise#2419. - hitl_test.go — 6 new tests covering: full-fields create, minimal required-fields, bad-NotifyURL-scheme 400 propagation, 401 propagation, connect-failure propagation, and the three required-field validation guards (as subtests). - runtime-e2e/create_hitl_request/ — real net/http + net.Listen proof. Asserts the wire body carries every required field plus notify_url, and the response envelope parses back into a populated HITLApprovalRequest. Satisfies the runtime-e2e/ DoD gate. - CHANGELOG.md + version.go — bump 8.1.0 -> 8.2.0 (additive; no breaking changes). Cross-SDK parity sweep tracked at getaxonflow/axonflow-enterprise#2421. Sister Python PR landed at getaxonflow/axonflow-sdk-python#202; sister TypeScript PR at getaxonflow/axonflow-sdk-typescript#235. Sister Java / Rust PRs follow. Refs getaxonflow/axonflow-enterprise#2421 Refs getaxonflow/axonflow-enterprise#2419 Refs getaxonflow/axonflow-enterprise#2393 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fold(hitl): R3 round 1 — swap Header().Set order before WriteHeader R3 round 1 surfaced one HIGH against the Go HITL PR: - HIGH-3: hitl_test.go:360-361 and :410-411 + runtime-e2e/main.go:56-57 set Content-Type AFTER WriteHeader. Go's net/http flushes headers when WriteHeader is called, after which Header().Set is a no-op. The tests still pass today because the SDK's JSON decoder doesn't care about Content-Type, but the test isn't validating what it appears to validate, and the same pattern in production would silently lose the header. Swap the order in all three sites. Tests + runtime-e2e re-verified green post-fix. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fold(hitl): R3 R2 — fix Header/WriteHeader order regression in bad-scheme test R3 round 2 caught that the HIGH-2 fold added in R1 (bad-notify_url scheme test) reintroduced the exact WriteHeader-before-Header.Set anti-pattern that R1 flagged at the original 3 sites. Swap the order so Content-Type actually takes effect on the wire. Same fix as the R1 fold for hitl_test.go:360 / :410 / runtime-e2e/main.go:57; applied to the new bad-scheme handler at :454. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fix(ci): drop httptest.NewServer substring from runtime-e2e README Closes the lint-no-mocks-in-runtime-e2e gate on PR #175. The companion-unit-coverage section in runtime-e2e/create_hitl_request/README.md mentioned `httptest.NewServer` to explain what the runtime proof is NOT — but the lint script greps for that exact substring as a forbidden mock pattern (scripts/lint-no-mocks-in-runtime-e2e.sh:39) and the prose-vs-code distinction is invisible to grep. Paraphrase to 'in-process test HTTP server' — same meaning, no trigger. Verified locally: $ bash scripts/lint-no-mocks-in-runtime-e2e.sh; echo $? 0 HARD RULE 7 (CI green before SHIP-READY) — captured rule [[feedback_r3_does_not_imply_ci_green]] from master verification. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> --------- Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
saurabhjain1592
added a commit
to getaxonflow/axonflow-sdk-rust
that referenced
this pull request
May 23, 2026
…n v1 (#49) * feat(hitl): port full HITL surface (list/get/create/approve/reject/stats) Cross-SDK parity bring-up for HITL (Human-in-the-Loop) approval workflows. Prior to this release the Rust SDK exposed NO HITL methods at all — the four stable SDKs (Python/TS/Go/Java) all ship the read + review surface (list_hitl_queue, get_hitl_request, approve_hitl_request, reject_hitl_request, get_hitl_stats), plus the new create_hitl_request method introduced in v8.2.0 of each. This release ports the full surface in one shot so Rust callers can implement the full 4-step HITL flow against AxonFlow: 1. Gate evaluates require_approval (via pre_check / check_tool_input) 2. Caller invokes client.create_hitl_request(...) to enqueue the row 3. Caller polls client.get_hitl_request(approval_id) until terminal state — OR sets notify_url so the platform fires a signed webhook on the transition (n8n Wait-node "On Webhook Call" pattern, ADK plugin polling-free mode) 4. Caller resumes the agent or denies the call based on the decision Changes: - src/hitl.rs (new) — 6 public methods (list_hitl_queue, get_hitl_request, create_hitl_request, approve_hitl_request, reject_hitl_request, get_hitl_stats) using PATH_SEGMENT-encoded path components + APIResponse{success,data} envelope parsing. Validates required fields client-side via AxonFlowError::ConfigError (mirrors the existing decisions::explain_decision empty-id guard pattern). - src/types/hitl.rs (new) — HITLApprovalRequest / HITLCreateInput / HITLReviewInput / HITLQueueListOptions / HITLQueueListResponse / HITLStats. notify_url field added to both HITLCreateInput and HITLApprovalRequest for the new outbound-webhook surface introduced in getaxonflow/axonflow-enterprise#2419. All fields use #[serde(skip_serializing_if = "Option::is_none", default)] so the SDK round-trips cleanly against platforms that don't yet implement the field. - src/client.rs — exposes checked_post_json crate-internal helper for sibling modules that POST a typed payload (symmetric to the existing checked_get helper). - src/lib.rs + src/types/mod.rs — wire up the new module + re-export the public HITL types from the crate root. - src/hitl.rs::tests — 18 contract tests using wiremock covering: list happy-path + filter serialization, get happy-path + empty-id guard + 404 propagation, create happy-path + minimal required-fields + bad-notify_url-scheme 400 propagation + 401 propagation + connect-failure propagation + the three required-field validation guards, approve + reject path/body shape + empty-id guard, stats envelope parsing, and a unit test for the build_list_query field-omission contract. - runtime-e2e/create_hitl_request/ — real reqwest + hyper TCP socket proof. Asserts the wire body carries every required field plus notify_url, and the response envelope parses back into a populated HITLApprovalRequest. Satisfies the runtime-e2e/ DoD gate that the in-process wiremock-based unit tests do not. - CHANGELOG.md + Cargo.toml — bump 0.2.0 -> 0.4.0 (skipping 0.3 to align with the v9.1 telemetry preview train; both ship at v0.4). Cross-SDK parity sweep tracked at getaxonflow/axonflow-enterprise#2421. Sister Python PR landed at getaxonflow/axonflow-sdk-python#202; TypeScript PR at getaxonflow/axonflow-sdk-typescript#235; Go PR at getaxonflow/axonflow-sdk-go#175; Java PR at getaxonflow/axonflow-sdk-java#185. Refs getaxonflow/axonflow-enterprise#2421 Refs getaxonflow/axonflow-enterprise#2419 Refs getaxonflow/axonflow-enterprise#2393 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fold(hitl): R3 R2 — runtime-e2e shell add -e flag R3 round 2 caught this: `set -uo pipefail` should be `set -euo pipefail` so command failures inside the script abort it. Without `-e` the runtime-e2e gate can green-light a broken SDK. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> * fix(ci): cargo fmt collapsable Some() / closure blocks in hitl tests Closes the cargo fmt --check gate on PR #49. The R3 round 1 folds (rebase + the bad-scheme test) left a handful of `Some(\n "long-string".into(),\n)` blocks that rustfmt collapses to a single line, plus one `.respond_with(\n ...\n)` chain that should be a single call. Applied `cargo fmt` — mechanical-only diff, no semantic change. Verified locally: $ cargo fmt --check (no output) $ cargo test --lib hitl test result: ok. 18 passed; 0 failed HARD RULE 7 (CI green before SHIP-READY) — captured rule [[feedback_r3_does_not_imply_ci_green]] from master verification. Refs getaxonflow/axonflow-enterprise#2421 Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com> --------- Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
client.create_hitl_request(...)for explicit creation of HITLapproval rows via
POST /api/v1/hitl/queue. This is the paired SDKrelease that unblocks the Google ADK plugin v1 fixup
(getaxonflow/axonflow-enterprise#2410) — without this method, the
plugin's HITL polling path can't actually enqueue a row to poll.
Part of the cross-SDK parity sweep tracked at
getaxonflow/axonflow-enterprise#2421 (umbrella) — sister PRs for
TypeScript / Go / Java land in the same v8.1.0 train.
Why now
The platform's
POST /api/v1/hitl/queueendpoint has existed sincev6.x (handler at
platform/agent/hitl/handler.go:177). The Python SDKexposed the read + review surface (
get_hitl_request,approve_hitl_request,reject_hitl_request) but had nocreate_*counterpart. Agent-framework plugins detecting
require_approvalfrompre_check/check_tool_inputneed to create the row themselvesbefore polling — the gate endpoints set
BlockReason="require_approval"and mint a correlation ID, but do not call
CreateApprovalRequestthemselves.
Changes
axonflow/client.py—async create_hitl_request(request) -> HITLApprovalRequestSyncAxonFlow.axonflow/hitl.py—HITLCreateInputPydantic model mirroringplatform/agent/hitl/handler.go:86 CreateRequestInput. Requiredfields:
client_id,original_query,request_type. Optionalfields cover policy attribution, severity, compliance framework,
expiry override, and the new
notify_urlfield(getaxonflow/axonflow-enterprise#2419 platform companion). The
notify_urlfield also surfaces onHITLApprovalRequestso callerscan read back the value the platform stored.
tests/test_hitl.py— 4 new tests covering: full-fields create,minimal required-fields create, 401 →
AuthenticationError,connection failure →
ConnectionError.runtime-e2e/create_hitl_request/— real-stack proof: realhttpxtransport against a
socketserver.TCPServermimicking the platformhandler. Asserts the wire body carries every required field +
notify_url, and the response envelope parses back into a populatedHITLApprovalRequest. Satisfies theRuntime E2E required for user-facing changesDoD gate.tests/test_telemetry_short_lived.py— drive-by stabilization(orthogonal): the subprocess test was silently failing whenever the
global stamp file at
~/Library/Caches/axonflow/python-telemetry-last-sentalready existed from a prior test run, because the heartbeat gate's
7-day delivered-cadence short-circuits the ping. Isolated via
tempfile.TemporaryDirectory+HOME/XDG_CACHE_HOME/LOCALAPPDATAenv overrides so the per-platform stamp resolver lands in an empty
directory. Picked up in this PR because it failed on a clean run of
the full suite — HARD RULE fix: datetime parsing fails with nanosecond timestamps #1 (no "pre-existing issues").
CHANGELOG.md+pyproject.toml+_version.py— bump 8.1.0 →8.2.0 (additive; no breaking changes).
Test plan
pytest tests/test_hitl.py -vgreen (29 tests, including 4 new)pytest tests/green (992 passed, 29 skipped — full suite)python runtime-e2e/create_hitl_request/test.pyPASSruff check .cleanHow the new method is consumed
The Google ADK plugin's
before_model_callback/before_tool_callbackdetects
block_reason == "require_approval", callsclient.create_hitl_request(...)with policy attribution + originalquery, then polls
client.get_hitl_request(returned.request_id)untilthe row reaches a terminal state. See the linked plugin PR for the
end-to-end shape.
Refs getaxonflow/axonflow-enterprise#2421 (umbrella),
getaxonflow/axonflow-enterprise#2419 (notify_url platform companion),
getaxonflow/axonflow-enterprise#2393 (driving epic),
getaxonflow/axonflow-enterprise#2410 (ADK plugin v1 fixup)