Skip to content

Keep tool calls on the E2EE stream and in message history - #1

Merged
cursor[bot] merged 1 commit into
mainfrom
cursor/e2ee-tool-calls-830a
Oct 27, 2026
Merged

cursor[bot] merged 1 commit into
mainfrom
cursor/e2ee-tool-calls-830a

Conversation

@gsmachado

Copy link
Copy Markdown
Member

Summary

Agents such as Hermes never ran tools on E2EE models. The model wrote a short preamble into delta.content, then emitted the call on delta.tool_calls and finished with finish_reason: "tool_calls". decryptSSEStream skipped any event whose delta.content was missing, so the call disappeared and the caller closed the turn as stop. The next request then showed the model looking at its own cut-off text.

encrypt also rebuilt every message as { role, content } and encrypted every role. An assistant turn that is only a tool call (content: null or "") became ciphertext, which makes the TEE treat that turn as text. Tool results were not kept as confidential bodies next to their call id.

After this change:

  • The stream yields decrypted content, unchanged tool_calls deltas, and the real finish_reason (tool_calls, stop, or length), in upstream order.
  • Assistant and tool messages keep tool_calls, tool_call_id, and name. content: null stays null. An empty string is not encrypted for those roles.
  • Non-empty content is encrypted for every role, including tool-result bodies. user and system content is still always ciphertext, including an empty string, because Venice rejects plaintext in those roles.
  • Tool names, call ids, and arguments stay plaintext. That is the Venice E2EE rule: the enclave chat template reads them as JSON.

decryptStream no longer yields bare strings. This is a breaking change. The package is still 0.2.0 in this PR; publishing is a local npm run release -- minor (0.2.0 → 0.3.0). There is no npm token in this environment and CI does not publish, so that release is a follow-up. prepare builds dist/ so the unpublished commit can be installed from git until then.

Tests

  • npm test — 42 passed, 3 skipped (live integration tests; no VENICE_API_KEY)
  • npm run build — tsc succeeded
Open in Web Open in Cursor 

Venice function calls were dropped because the stream parser skipped events
without delta.content and encrypt rebuilt every message as role plus content.
Yield decrypted content, tool-call deltas, and finish_reason, and keep tool
metadata in the clear while encrypting non-empty bodies, including tool results.

Co-authored-by: guil <guil@axlabs.com>
@cursor
cursor Bot merged commit 7b4e652 into main Oct 27, 2026
2 checks passed
@cursor
cursor Bot deleted the cursor/e2ee-tool-calls-830a branch October 27, 2026 23:48
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