Skip to content

refactor(demo): migrate the hexgate SDK surface from User to HexgateContext (0.3.0) - #18

Open
guillaume-hexamind wants to merge 1 commit into
mainfrom
gp/feat/hexgate_context_version
Open

refactor(demo): migrate the hexgate SDK surface from User to HexgateContext (0.3.0)#18
guillaume-hexamind wants to merge 1 commit into
mainfrom
gp/feat/hexgate_context_version

Conversation

@guillaume-hexamind

Copy link
Copy Markdown
Contributor

Why

hexgate 0.3.0 removes User outright — no back-compat alias, and get_current_user was dropped too — so every gated agent in this repo fails to import against the current SDK. This migrates the whole surface to the per-request HexgateContext scope and bumps the pins.

0.2.x 0.3.0
User(user_id=…, role="operator") HexgateContext(user_id=…, user_roles=["operator"])
get_current_user() get_current_context()
adapter kwarg user=… hexgate_context=…

Pins → hexgate>=0.3.0 in agent-server, gdocs-agent, hexgate-agent.

Not just a rename

user_roles is 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 log
  • read_change applies the implementer-only read 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

Scope

  • devops (google-adk) — HexgateRunner.run_async(new_message=…, hexgate_context=…)
  • healthcare (openai) — HexgateRunner().run_streamed(…, hexgate_context=…)
  • ITSM + HR (langchain) — astream_events(…, hexgate_context=…)
  • demo/hexgate-agent/ + demo/gdocs-agent/async with HexgateContext(...) around stream_agent
  • Docs/comments that named the old API: root README.md, both demo-users.yaml, the hexgate-agent + gdocs-agent READMEs, and the context.user comment in proxy-server/.../routes/chat.py

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.

Deliberately out of scope

The HexKit contract still carries a single role per caller (CONTRACT.md §5), so each wrapper builds a one-element set at the boundary. Widening the contract and demo-users.yaml to a role list — to demo genuine multi-role callers — is a separate change.

Verification

  • ruff check . clean; proxy suite 90/90
  • All agent modules import under 0.3.0
  • create_manifest succeeds for all four make register targets (frameworks resolve google / openai / langchain)
  • ITSM role-set paths exercised under a live HexgateContext scope: union visibility, implementer-only read, empty-roles fail-closed, audit column rendering "implementer, requester" / None
  • All four gated stream_as paths driven with a fake key — each reaches hexgate's key validation rather than a TypeError, confirming the adapter call shapes

Not verified: a real gated run end-to-end (make register + a live chat), which needs a valid HEXGATE_API_KEY against the platform. Re-run make register after merge — the new SDK produces new manifests.

🤖 Generated with Claude Code

…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>
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.

1 participant