Skip to content
This repository was archived by the owner on Aug 4, 2026. It is now read-only.

Releases: emiltsoi/hermes-agent-a2a

v3.3.9

Choose a tag to compare

@github-actions github-actions released this 23 Jul 19:20
chore: bump to v3.3.9

v3.3.8

Choose a tag to compare

@github-actions github-actions released this 14 Jul 19:18
chore: bump to v3.3.8 — critical hotfix release

Updates deprecation notice: 'no further releases' → 'critical hotfix releases only'

v3.3.7 — Extract Task Queue + Payloads; Unify Inbound/Outbound

Choose a tag to compare

@github-actions github-actions released this 28 Jun 11:10

v3.3.7 — Extract Task Queue + Payloads; Unify Inbound/Outbound Paths

Three architectural moves that complete the refactoring arc started in v3.3.3.


1. Extract task_queue.py (290 lines)

_PendingTask + TaskQueue decoupled from HTTP transport. The state machine for inbound tasks is now independent of the transport that receives them. server.py imports and re-exports for backward compatibility.

2. Extract payloads.py (121 lines)

A2A wire-format builders (_build_task_object, _build_status_update_payload, _build_paginated_task_list) as pure functions. No socket knowledge. No HTTP header knowledge. Just dict shapes.

3. Unify inbound and outbound paths

INBOUND_prepare_and_enqueue() shared by all three send paths:

  • _handle_task_send (JSON-RPC)
  • _rest_send_message (REST)
  • _rest_send_message_stream (SSE streaming)

Security fix: The streaming endpoint previously bypassed _enqueue_and_await_task's idempotency and task-ID collision guards. Idempotent replay and task-ID collision attacks were possible through the SSE path that JSON-RPC and REST correctly blocked. _prepare_and_enqueue() closes this — all three paths now share one preamble.

OUTBOUND_resolve_rpc_target() + _rpc_call() shared by:

  • handle_send_protocol_task
  • handle_cancel_protocol_task
  • _handle_call_mode3

_resolve_target (9 parameters, threw ValueError) → _resolve_rpc_target (1 parameter, returns structured error dicts). Callers got thinner. _rpc_call() consolidates the JSON-RPC POST + error-parse triad that was duplicated across three outbound paths.


Numbers

server.py:  2,044 → 1,490  (-554)
task_queue.py:  290  (new)
payloads.py:    121  (new)
─────────────────────────
Net:  8,344 → 8,147  (-197)
Tests:   625/625 ✅

Attribution

Refactoring by Emil. Britney gated and tested.

Previous

  • v3.3.6 — CI flake fix
  • v3.3.5 — extract shared core + SSE unification
  • v3.3.3 — cross-model security audit

v3.3.6 — CI Flake Fix

Choose a tag to compare

@github-actions github-actions released this 28 Jun 05:10

v3.3.6 — CI Flake Fix: Concurrent Test Retry + Audit Directory

Two CI-environment fixes that reproduce only on GitHub Actions runners.

1. ConnectionResetError retry: 20 threads overflow TCP accept() on Python 3.12 CI even with the readiness probe. Added retry loop (3 attempts, 0.1s stagger). 5x stress runs: 70/70.

2. Audit log directory: /home/runner/.hermes/ doesn't exist in CI. mkdir(parents=True) in the a2a_server fixture. Fixes 12x FileNotFoundError noise.

625 passed, 15 warnings

View on PyPI

v3.3.5 — Extract Shared Core + SSE Unification (1 bug fix)

Choose a tag to compare

@github-actions github-actions released this 28 Jun 04:56

v3.3.5 — Dead Code Removal + Safe Consolidation + SSE Unification

167 INSERTIONS, 329 DELETIONS — NET -162 LINES (-1.9%). 29 files (-3). 625/625 tests.


Phase 4 — Extract _enqueue_and_await_task() (~60 lines)

_handle_task_send (195 lines) and _rest_send_message (99 lines) shared 70% — sanitize, idempotency, collision, enqueue, webhook, wait, filter. Extracted into shared core. Both callers keep their own preamble (configuration, worker_at bypass, return_immediately) and epilogue (RPC response format, SSE/push artifact delivery, REST inline dict formatting).

Phase 5 — Extract _stream_task_sse() (~70 lines + bug fix)

_handle_send_subscribe and _rest_subscribe_to_task were structurally identical — same poll loop, same 0.5s interval, same 300s timeout, same terminal detection. Extracted into unified _stream_task_sse(task_id, extra_headers, http_method).

Bug fixed: JSON-RPC version didn't check for client disconnect during terminal state transmit — wrote SSE events to dead socket silently. REST version checked correctly. The unified core backports the disconnect check from REST.

Full changelog: v3.3.5 on GitHub

Previous releases:

  • v3.3.4 — CI flake fix (TCP readiness probes)
  • v3.3.3 — Cross-model security audit (4 HIGH fixes)

v3.3.4 — Deterministic CI (TCP Readiness Probes)

Choose a tag to compare

@github-actions github-actions released this 28 Jun 04:11

v3.3.4 — Deterministic CI (TCP Readiness Probes)

Fix: Flaky test_concurrent_requests_respect_limitConnectionResetError under CI load caused by 20 concurrent threads hitting the server before it finished binding. Replaced blind time.sleep(0.1) with _wait_for_server() — polls TCP until the port accepts a connection.

Stress test: 5 consecutive runs, 14×5 = 70 tests, zero flakes. 625/625 full suite.

=== run 1 === 14 passed in 9.12s
=== run 2 === 14 passed in 9.29s
=== run 3 === 14 passed in 8.63s
=== run 4 === 14 passed in 9.02s
=== run 5 === 14 passed in 9.00s

Previous: v3.3.3 — cross-model security audit.

v3.3.3 — Cross-Model Security Audit (4 HIGH fixes)

Choose a tag to compare

@github-actions github-actions released this 27 Jun 22:22

v3.3.3 — Cross-Model Security Audit

Three free Devin CLI models (swe-1.6, glm-5-2, kimi-k2.7) reviewed the same codebase with the same checklist. Different blind spots, richer union.

HIGH — Fixed

# File Finding Found by
1 a2a_direct.py:65-67 No SSRF guard on call() — arbitrary urlopen() without URL validation. webhook/push paths had guards; direct A2A didn't. Fixed: validate_target_url() before every call(). swe ✅ kimi ✅
2 tool_handlers.py:171-202 No SSRF guard on webhook reachability check_validate_webhook_reachable() opened arbitrary URLs. Fixed: validate_target_url() with allow_loopback=True before outbound I/O. swe ✅ kimi ✅
3 test_telegram_float.py:62 Env var chain leak — test didn't cover A2A_V2_BOT_TOKEN, causing live token to appear in pytest diff. Fixed: test now covers all 4 tiers. Rotate the leaked token. swe ✅ glm ✅ kimi ✅
4 server.py:806-858 Auth bypass on GET endpoints/tasks, /tasks/{id}, /extendedAgentCard skipped _check_auth() even when A2A_REQUIRE_AUTH=true. Fixed: all task/card GET routes now respect auth. Escalated to HIGH by Linda. kimi ✅

LOW — Fixed

# File Fix
5 identity.py:68,406 Silent except Exception: passlogger.warning()
6 rate_limiter.py:186 Cleanup loop failure → logged instead of swallowed
7 server.py 4 dead imports removed. Webhook host validation error → logged.
8 telegram_float.py:36-38 Docstring env chain updated to reflect A2A_V2_BOT_TOKEN

Cross-Model Reviewer Performance

Model Findings Missed Notes
glm-5-2 3 6 false negatives ✅ Best coder, ❌ NEVER for review. Claimed "no auth gaps" when GET bypass exists. Confident + wrong.
swe-1.6 9 auth bypass Speed king. Solid mechanical sweep — caught both SSRF gaps + all silent exceptions.
kimi-k2.7 10 Slow but caught the auth bypass both others missed. Different training = different blind spots.

Rule codified: glm-5-2 codes. swe-1.6 + kimi-k2.7 review. Coding model ≠ review model.

Tests

625 passed in 88.37s

Attribution: Cross-model sweep by Britney (orchestration) + Linda (gate, escalation of #4). Dispatch via Devin CLI harness v1.9.0.

v3.3.2

Choose a tag to compare

@github-actions github-actions released this 23 Jul 19:19
v3.3.2 — final release, DEPRECATED

v3.3.1 — SSRF Consolidation & Security Fixes

Choose a tag to compare

@github-actions github-actions released this 03 Jun 12:23

v3.3.1 — SSRF Consolidation & Security Fixes

Security

  • ARCH-03: sender_name now uses A2A_AGENT_NAME instead of hardcoded "britney"
  • NEW-01: REST POST /tasks/{id}:cancel now requires auth (was bypassing _check_auth())

SSRF Consolidation

  • 4 SSRF guard functions consolidated to 2 in security.py: validate_host and validate_target_url
  • Webhook delivery path now blocks private CIDRs (10.x, 172.16-31.x, 192.168.x)
  • All 11 call sites use one shared threat model via _is_private_ip

Commits

  • b9d0ea2: ARCH-03 sender_name uses caller identity + NEW-01 auth gate
  • a70e8a7: SSRF guards consolidated into security.py
  • ef69933: CancelTask REST tests fix

Full review cycle: a2a-v3.3-full-20260603

v3.3.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 17:33
v3.3.0 — Transport module extraction (LOW-08)

Transport module extraction: 3 leaf-level modules (telegram_float,
a2a_direct, webhook_delivery) extracted from server.py. 227 lines
of god-module code split into 3 focused files. +20 new tests
across 3 new test files. Pytest 615/615.

Review trail: a2a-review-20260602
Audit chain: 8 commits, each with discipline references
  - 8a226e9 (Task 3, telegram_float extraction)
  - 5534b5f (Task 4, a2a_direct extraction)
  - 1796c11 (Task 5, webhook_delivery extraction)
  - 69009a6 (Task 6, module-internal tests)
  - bd2d9dd (Task 7, preflight clean)
  - d92776d (release prep: CHANGELOG)
  - c5a5ba5 (release prep: unambiguous-fake test fixtures)

See CHANGELOG.md for the full v3.3.0 entry.