Skip to content

Preserve recent Inkbox context across fresh Hermes sessions - #62

Open
shreyaskommuri wants to merge 6 commits into
inkbox-ai:mainfrom
shreyaskommuri:feat/webhook-conversation-context
Open

Preserve recent Inkbox context across fresh Hermes sessions#62
shreyaskommuri wants to merge 6 commits into
inkbox-ai:mainfrom
shreyaskommuri:feat/webhook-conversation-context

Conversation

@shreyaskommuri

@shreyaskommuri shreyaskommuri commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds bounded recent Inkbox context to inbound email, SMS, and iMessage turns in Hermes so a fresh Hermes session can recover recent channel continuity without introducing another memory store.

Inkbox can include recent email, text, and call history in data.context. The plugin requests that history on its owned webhook subscriptions, accepts only server-declared thread/conversation/contact scopes, renders selected fields inside strict local bounds, removes the triggering message, and appends the result as explicitly untrusted background data.

Background

This work originated in inkbox-ai/claude-code-plugin#39. That implementation worked technically, but review identified a product-boundary mismatch: Claude Code's /clear experience is intended to start completely fresh, whereas Hermes is treated as a persistent assistant even when its model session rotates.

Production hardening

  • Request fixed windows: 5 email items, 8 text items, and 3 call items.
  • Reconcile only subscriptions owned by the exact current or recorded previous Hermes webhook URL.
  • Preserve unrelated webhook consumers.
  • Fail closed unless each context block declares an SDK-supported scope.
  • Allow only thread-scoped triggering email, conversation-scoped triggering texts, and contact-scoped cross-channel history.
  • Bound and allowlist all rendered fields; omit headers and private asset URLs.
  • Neutralize embedded closing delimiters and keep history explicitly framed as untrusted data.
  • Exclude triggering items before limits; exclude every SMS/iMessage burst fragment.
  • Select the chronologically newest context snapshot for out-of-order bursts, including sub-second timestamps.
  • Return a retryable 503 for overlapping in-flight deliveries and roll back both event and transport reservations so failures cannot lose messages.
  • Preserve completed-delivery deduplication.
  • Keep email, SMS, and iMessage slash commands exact and context-free.

Validation

  • Full suite: 262 passed, 24 skipped
  • Focused context + webhook routing: 53 passed
  • Minimum supported Inkbox 0.4.20: 53 passed
  • Ruff: passed
  • Python compilation: passed
  • git diff --check: clean
  • Independent final diff review: no actionable regression

Live fresh-session validation

Validated against real Inkbox email delivery using the configured Hermes identity:

  1. Sent a first message containing a unique phrase and received a Hermes reply.
  2. Deleted stored Hermes session history and restarted the gateway.
  3. Sent a second message in the same Inkbox email thread.
  4. Confirmed the fresh Hermes turn received bounded Inkbox thread history.
  5. Confirmed Hermes recovered the exact phrase and answered correctly.

Temporary runtime and subscription changes were restored afterward.

Remaining validation gap

The configured identity has no SMS number and iMessage is disabled, so those channels are covered by handler, command, replay, scoping, and burst regression tests rather than live delivery.

Request bounded webhook history and render it as explicitly untrusted data so a fresh Hermes session can recover recent channel continuity without adding a separate memory store. Harden replay deduplication, burst handling, and subscription reconciliation around that boundary.

Constraint: Preserve exact command semantics, unrelated webhook consumers, and fixed local safety limits.
Rejected: Reuse Claude Code's session behavior unchanged | Claude PR inkbox-ai#39 established that completely fresh /clear semantics conflict with restored history there.
Confidence: high
Scope-risk: moderate
Directive: Keep trigger exclusion, exact-URL subscription ownership, and untrusted framing when extending the context schema.
Tested: 258 passed, 24 skipped; 17 focused context tests; Ruff; Python compile; git diff --check; live fresh-session email validation against Inkbox.
Not-tested: Live SMS and iMessage unavailable on the configured Hermes identity.
Make overlapping deliveries retry-safe, require server-declared context scope, preserve exact commands, and select the newest burst snapshot without weakening the bounded untrusted-data boundary.

Constraint: Preserve completed-delivery deduplication and compatibility with Inkbox 0.4.20.

Rejected: Acknowledge in-flight duplicates | a later failure would permanently lose the event.

Confidence: high

Scope-risk: moderate

Directive: Retry responses must roll back both transport and event-level dedup reservations.

Tested: 262 passed, 24 skipped; 53 focused tests on Inkbox 0.4.20; Ruff; Python compile; git diff --check; independent diff review.

Not-tested: Live SMS and iMessage remain unavailable on the configured identity.
@shreyaskommuri
shreyaskommuri marked this pull request as ready for review July 14, 2026 21:03
dimavrem22 and others added 4 commits July 16, 2026 14:34
_dedup_begin and _begin_dedup_response duplicated the same
prune/lookup/reserve sequence against _seen_request_ids and
_inflight_request_ids. Extract _dedup_claim as the single source of
truth so the two call sites can't drift out of sync.
Selection was pure recency (last N items). Overfetch a 3x window from
Inkbox (still capped at the SDK's 50-per-class max) and, within that
window, prefer items whose subject/snippet/text/transcript overlaps
the triggering message over ones that don't — so an older but
on-topic item can survive against a run of newer small talk.

Degrades to exactly the old last-N behavior whenever there's no
overlap signal (empty trigger text, or no shared tokens), since
position is the sole tiebreaker at that point — verified by every
pre-existing webhook-context test passing unchanged.

Cross-channel sections (email:/texts:/calls:) are left as separate
blocks rather than merged into one interleaved timeline: that format
is what the scope/security tests already pin down, and grouping by
kind keeps provenance legible for the "untrusted background data"
framing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants