hitl/wire: rename 'always' decision-type to 'approve_always'

Renames the SurfSense HITL extension decision-type from "always" to
"approve_always" so it sits in the same verb-first family as "approve",
"reject", and "edit". The Python constant is now SURFSENSE_DECISION_APPROVE_ALWAYS;
the wire value, the permission-domain decision_type, and the FE union members
all match (no wire/internal mismatch).

Both the multi_agent_chat permission middleware and the legacy new_chat one
accept the new wire value; the FE types.ts union is updated accordingly.

The "context.always" payload key is intentionally left untouched - it's the
patterns-to-promote field, semantically distinct from the decision type.
This commit is contained in:
CREDO23 2026-05-15 14:47:32 +02:00
parent 6671c91841
commit c8b756ae8f
16 changed files with 85 additions and 75 deletions

View file

@ -11,7 +11,7 @@ from .payload import (
LC_DECISION_APPROVE,
LC_DECISION_EDIT,
LC_DECISION_REJECT,
SURFSENSE_DECISION_ALWAYS,
SURFSENSE_DECISION_APPROVE_ALWAYS,
build_lc_hitl_payload,
)
@ -19,7 +19,7 @@ __all__ = [
"LC_DECISION_APPROVE",
"LC_DECISION_EDIT",
"LC_DECISION_REJECT",
"SURFSENSE_DECISION_ALWAYS",
"SURFSENSE_DECISION_APPROVE_ALWAYS",
"ParsedLcDecision",
"build_lc_hitl_payload",
"parse_lc_envelope",

View file

@ -28,8 +28,8 @@ class ParsedLcDecision:
Attributes:
decision_type: Lower-cased decision identifier ``"approve"``,
``"reject"``, ``"edit"``, ``"always"``, or any custom value the
FE may emit. Callers map this to their own domain semantics.
``"reject"``, ``"edit"``, ``"approve_always"``, or any custom value
the FE may emit. Callers map this to their own domain semantics.
edited_args: Populated only on ``"edit"`` replies that actually carry
args; ``None`` otherwise so callers can use truthiness directly.
message: Free-form user feedback (typically attached to ``"reject"``).
@ -48,9 +48,9 @@ def parse_lc_envelope(envelope: Any) -> ParsedLcDecision:
- ``{"decisions": [{"type": "approve" | "reject" | "edit", ...}]}`` the
langchain HITL standard envelope.
- A bare scalar string (``"once"``, ``"always"``, ``"reject"``) used by
the legacy SurfSense permission wire. We tolerate it so the parser can
sit behind both call sites without a second adapter.
- A bare scalar string (``"once"``, ``"approve_always"``, ``"reject"``)
used by the legacy SurfSense permission wire. We tolerate it so the
parser can sit behind both call sites without a second adapter.
Edit args are read from the standard ``edited_action.args`` first, then
fall back to a flat ``args`` field for legacy compatibility both shapes

View file

@ -17,10 +17,11 @@ LC_DECISION_APPROVE = "approve"
LC_DECISION_REJECT = "reject"
LC_DECISION_EDIT = "edit"
# ``always`` is a SurfSense extension surfaced by ``PermissionMiddleware`` so a
# single click can promote the matched pattern to a runtime allow rule. The FE
# renders an extra button when it appears in ``allowed_decisions``.
SURFSENSE_DECISION_ALWAYS = "always"
# ``approve_always`` is a SurfSense extension surfaced by ``PermissionMiddleware``
# so a single click can promote the matched pattern to a runtime allow rule and
# (for MCP tools) save it to the user's trusted-tools list. The FE renders an
# extra button when it appears in ``allowed_decisions``.
SURFSENSE_DECISION_APPROVE_ALWAYS = "approve_always"
def build_lc_hitl_payload(
@ -41,8 +42,8 @@ def build_lc_hitl_payload(
an empty dict so the FE always has a stable shape to render.
allowed_decisions: Subset of
``[LC_DECISION_APPROVE, LC_DECISION_REJECT, LC_DECISION_EDIT,
SURFSENSE_DECISION_ALWAYS]``. Other values are passed through but
the FE may not render a control for them.
SURFSENSE_DECISION_APPROVE_ALWAYS]``. Other values are passed through
but the FE may not render a control for them.
interrupt_type: SurfSense card discriminator (``"gmail_email_send"``,
``"permission_ask"``, etc.); the FE keys off this to mount the
right card.
@ -80,6 +81,6 @@ __all__ = [
"LC_DECISION_APPROVE",
"LC_DECISION_EDIT",
"LC_DECISION_REJECT",
"SURFSENSE_DECISION_ALWAYS",
"SURFSENSE_DECISION_APPROVE_ALWAYS",
"build_lc_hitl_payload",
]