refactor(demo): migrate the hexgate SDK surface from User to HexgateContext (0.3.0) - #18
Open
guillaume-hexamind wants to merge 1 commit into
Open
refactor(demo): migrate the hexgate SDK surface from User to HexgateContext (0.3.0)#18guillaume-hexamind wants to merge 1 commit into
guillaume-hexamind wants to merge 1 commit into
Conversation
…ontext (0.3.0) hexgate 0.3.0 removes `User` outright — no alias, and `get_current_user` is gone too — so every gated agent in the repo had to move to the per-request `HexgateContext` scope: User(user_id=…, role="operator") -> HexgateContext(user_id=…, user_roles=["operator"]) get_current_user() -> get_current_context() adapter kwarg user=… -> hexgate_context=… Pins bumped to hexgate>=0.3.0 in agent-server, gdocs-agent and hexgate-agent. `user_roles` is a set, and hexgate evaluates every role with the most permissive outcome winning. That is a semantic change, not a rename, so the ITSM tool bodies' own scoping had to union the same way or it would be stricter than the policy that let the call through: - `_actor()` returns `(name, frozenset[str])`; `_roles_label()` renders it for the audit log - `read_change` applies the implementer-only restriction only when `implementer` is the caller's sole role - `list_my_changes` unions visible rows across roles, so a caller who is both requester and implementer sees both sets The HexKit contract still carries one `role` per caller (CONTRACT.md §5), so each wrapper builds a one-element set at the boundary. Widening the contract to a role list is left as a separate change. devops_agent.py's "vendored from" pointer now names examples/devops_google.py — upstream's devops_agent.py is the OpenAI-SDK variant as of 0.3.0. Verified: ruff clean; proxy suite 90/90; all agent modules import under 0.3.0; create_manifest succeeds for all four `make register` targets; the ITSM role-set paths exercised under a live HexgateContext scope; all four gated stream_as paths reach hexgate's key validation rather than a TypeError. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.
Why
hexgate 0.3.0 removes
Useroutright — no back-compat alias, andget_current_userwas dropped too — so every gated agent in this repo fails to import against the current SDK. This migrates the whole surface to the per-requestHexgateContextscope and bumps the pins.User(user_id=…, role="operator")HexgateContext(user_id=…, user_roles=["operator"])get_current_user()get_current_context()user=…hexgate_context=…Pins →
hexgate>=0.3.0inagent-server,gdocs-agent,hexgate-agent.Not just a rename
user_rolesis a set, and hexgate evaluates every role with the most permissive outcome winning. The ITSM tool bodies do their own row-level scoping on top of the policy, so they had to union the same way — otherwise they'd be stricter than the policy that just allowed the call:_actor()returns(name, frozenset[str]); a new_roles_label()renders it for the audit logread_changeapplies the implementer-only read restriction only whenimplementeris the caller's sole rolelist_my_changesunions visible rows across roles, so a caller who is both requester and implementer sees both setsScope
google-adk) —HexgateRunner.run_async(new_message=…, hexgate_context=…)openai) —HexgateRunner().run_streamed(…, hexgate_context=…)langchain) —astream_events(…, hexgate_context=…)demo/hexgate-agent/+demo/gdocs-agent/—async with HexgateContext(...)aroundstream_agentREADME.md, bothdemo-users.yaml, thehexgate-agent+gdocs-agentREADMEs, and thecontext.usercomment inproxy-server/.../routes/chat.pydevops_agent.py's "vendored from" pointer now namesexamples/devops_google.py— upstream'sdevops_agent.pyis the OpenAI-SDK variant as of 0.3.0.Deliberately out of scope
The HexKit contract still carries a single
roleper caller (CONTRACT.md §5), so each wrapper builds a one-element set at the boundary. Widening the contract anddemo-users.yamlto a role list — to demo genuine multi-role callers — is a separate change.Verification
ruff check .clean; proxy suite 90/90create_manifestsucceeds for all fourmake registertargets (frameworks resolvegoogle/openai/langchain)HexgateContextscope: union visibility, implementer-only read, empty-roles fail-closed, audit column rendering"implementer, requester"/Nonestream_aspaths driven with a fake key — each reaches hexgate's key validation rather than aTypeError, confirming the adapter call shapesNot verified: a real gated run end-to-end (
make register+ a live chat), which needs a validHEXGATE_API_KEYagainst the platform. Re-runmake registerafter merge — the new SDK produces new manifests.🤖 Generated with Claude Code