mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
fix(photon): use per-user assigned line for agent iMessage number
On shared-number plans, `/lines` has no dedicated entry, so the `assignedPhoneNumber` field on the user object is the source of truth for which number to text the agent. Fall back to the line inventory only when no per-user assignment exists.
This commit is contained in:
parent
314af28e86
commit
84e4b4b9a5
3 changed files with 53 additions and 11 deletions
|
|
@ -751,6 +751,21 @@ def register_user_if_absent(
|
|||
return user, True
|
||||
|
||||
|
||||
def user_assigned_line(user: Optional[Dict[str, Any]]) -> Optional[str]:
|
||||
"""Return the iMessage number a Spectrum user is assigned to text on.
|
||||
|
||||
This is the user's ``assignedPhoneNumber`` (the dashboard's "TEXTS ON"
|
||||
column) — i.e. the number to text to reach the agent, as opposed to the
|
||||
user's own ``phoneNumber``. On shared-number plans there is no dedicated
|
||||
entry in ``/lines``, so this per-user field is the source of truth.
|
||||
Returns ``None`` when unset (e.g. a freshly created, not-yet-assigned user).
|
||||
"""
|
||||
if not user:
|
||||
return None
|
||||
val = user.get("assignedPhoneNumber")
|
||||
return str(val) if val else None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dashboard API: iMessage lines (the assigned number inventory)
|
||||
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ def _cmd_setup(args: argparse.Namespace) -> int:
|
|||
Colors.CYAN,
|
||||
)
|
||||
)
|
||||
agent_number = None
|
||||
if not phone:
|
||||
print(" Skipped user registration (no phone given). Re-run with --phone later.")
|
||||
else:
|
||||
|
|
@ -190,7 +191,7 @@ def _cmd_setup(args: argparse.Namespace) -> int:
|
|||
first_name = args.first_name
|
||||
email = args.email
|
||||
try:
|
||||
_user, created = photon_auth.register_user_if_absent(
|
||||
user, created = photon_auth.register_user_if_absent(
|
||||
token, dashboard_id,
|
||||
phone_number=phone,
|
||||
first_name=first_name,
|
||||
|
|
@ -204,18 +205,26 @@ def _cmd_setup(args: argparse.Namespace) -> int:
|
|||
print(f" user registration failed: {e}", file=sys.stderr)
|
||||
return 1
|
||||
print(" ✓ phone registered" if created else " ✓ phone already registered")
|
||||
# The number to text the agent is the user's assigned iMessage line
|
||||
# (the dashboard's "TEXTS ON" column). On shared-number plans there is
|
||||
# no dedicated entry in /lines, so this per-user field is the source of
|
||||
# truth — and we already have it from the (reused) user object.
|
||||
agent_number = photon_auth.user_assigned_line(user)
|
||||
|
||||
# 5. Surface the assigned iMessage line (the number to text the agent).
|
||||
try:
|
||||
line = photon_auth.get_imessage_line(token, dashboard_id)
|
||||
except Exception as e:
|
||||
line = None
|
||||
print(f" (could not fetch the assigned line: {e})", file=sys.stderr)
|
||||
if line and line.get("phoneNumber"):
|
||||
status = line.get("status") or "active"
|
||||
# 5. Surface the agent's iMessage number (the number to text the agent).
|
||||
if not agent_number:
|
||||
# No per-user assignment — fall back to a dedicated line if the project
|
||||
# has one provisioned in its line inventory.
|
||||
try:
|
||||
line = photon_auth.get_imessage_line(token, dashboard_id)
|
||||
if line:
|
||||
agent_number = line.get("phoneNumber")
|
||||
except Exception as e:
|
||||
print(f" (could not fetch the assigned line: {e})", file=sys.stderr)
|
||||
if agent_number:
|
||||
print()
|
||||
print("┌─ Your agent's iMessage number ───────────────────────────────")
|
||||
print(f"│ 📱 {line['phoneNumber']} ({status})")
|
||||
print(f"│ 📱 {agent_number}")
|
||||
print("│ Text this number from your phone to talk to your agent.")
|
||||
print("└──────────────────────────────────────────────────────────────")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -329,7 +329,11 @@ def test_register_user_if_absent_dedup(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||
posted = {"n": 0}
|
||||
|
||||
def fake_get(url: str, **kwargs: Any) -> _FakeResponse:
|
||||
return _FakeResponse(json_body=[{"id": "u1", "phoneNumber": "+1 (555) 123-4567"}])
|
||||
return _FakeResponse(json_body=[{
|
||||
"id": "u1",
|
||||
"phoneNumber": "+1 (555) 123-4567",
|
||||
"assignedPhoneNumber": "+16282679185",
|
||||
}])
|
||||
|
||||
def fake_post(url: str, **kwargs: Any) -> _FakeResponse:
|
||||
posted["n"] += 1
|
||||
|
|
@ -344,6 +348,20 @@ def test_register_user_if_absent_dedup(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||
assert created is False
|
||||
assert user["id"] == "u1"
|
||||
assert posted["n"] == 0
|
||||
# The reused user carries the assigned iMessage line ("TEXTS ON").
|
||||
assert photon_auth.user_assigned_line(user) == "+16282679185"
|
||||
|
||||
|
||||
def test_user_assigned_line() -> None:
|
||||
assert (
|
||||
photon_auth.user_assigned_line({"assignedPhoneNumber": "+16282679185"})
|
||||
== "+16282679185"
|
||||
)
|
||||
# Own number present but no assignment yet (e.g. freshly created user).
|
||||
assert photon_auth.user_assigned_line({"phoneNumber": "+15551234567"}) is None
|
||||
assert photon_auth.user_assigned_line({"assignedPhoneNumber": ""}) is None
|
||||
assert photon_auth.user_assigned_line({}) is None
|
||||
assert photon_auth.user_assigned_line(None) is None
|
||||
|
||||
|
||||
def test_register_user_if_absent_creates(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue