From adc57d0c9da93d3a0d9c1722d92630e84e495e7f Mon Sep 17 00:00:00 2001 From: alex-w-99 Date: Wed, 22 Jul 2026 06:06:43 +0000 Subject: [PATCH] Align contacts with organization-wide access --- .github/workflows/live-channels.yml | 2 +- .github/workflows/live-external-events.yml | 2 +- .github/workflows/live-voice.yml | 2 +- .github/workflows/tests.yml | 4 ++-- README.md | 8 ++++---- pyproject.toml | 2 +- setup_wizard.py | 2 +- skills/inkbox-contact-lookup/SKILL.md | 10 ++++----- skills/inkbox-identity-access/SKILL.md | 24 +++++++++------------- tests/test_contact_tools.py | 8 ++++---- tests/test_setup_wizard.py | 8 ++++---- tools.py | 8 ++++---- 12 files changed, 38 insertions(+), 42 deletions(-) diff --git a/.github/workflows/live-channels.yml b/.github/workflows/live-channels.yml index 2bd1cba..1bd1a48 100644 --- a/.github/workflows/live-channels.yml +++ b/.github/workflows/live-channels.yml @@ -68,7 +68,7 @@ jobs: ln -sfn "$GITHUB_WORKSPACE" "$HERMES_HOME/plugins/inkbox" hermes plugins enable inkbox "$HERMES_HOME/bin/uv" pip install --python "$HERMES_HOME/hermes-agent/venv/bin/python3" \ - 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' + 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' - name: Configure AUT identity + model (${{ matrix.mode }}) env: diff --git a/.github/workflows/live-external-events.yml b/.github/workflows/live-external-events.yml index c3658ff..261bbb9 100644 --- a/.github/workflows/live-external-events.yml +++ b/.github/workflows/live-external-events.yml @@ -58,7 +58,7 @@ jobs: ln -sfn "$GITHUB_WORKSPACE" "$HERMES_HOME/plugins/inkbox" hermes plugins enable inkbox "$HERMES_HOME/bin/uv" pip install --python "$HERMES_HOME/hermes-agent/venv/bin/python3" \ - 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' + 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' - name: Configure AUT identity + model env: diff --git a/.github/workflows/live-voice.yml b/.github/workflows/live-voice.yml index 1dd7276..2f6f421 100644 --- a/.github/workflows/live-voice.yml +++ b/.github/workflows/live-voice.yml @@ -77,7 +77,7 @@ jobs: ln -sfn "$GITHUB_WORKSPACE" "$HERMES_HOME/plugins/inkbox" hermes plugins enable inkbox "$HERMES_HOME/bin/uv" pip install --python "$HERMES_HOME/hermes-agent/venv/bin/python3" \ - 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' fastapi uvicorn + 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' fastapi uvicorn - name: Configure AUT identity + model + speech path (${{ matrix.scenario }}) env: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4aa848f..896c3fc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,7 +39,7 @@ jobs: run: | uv venv --python ${{ matrix.python-version }} uv pip install \ - "inkbox @ git+https://github.com/inkbox-ai/inkbox.git@8f4b37c56cd153a2acc6cfabe27dbbeb43510f00#subdirectory=sdk/python" \ + "inkbox @ git+https://github.com/inkbox-ai/inkbox.git@199bbd27c8dab2f70e379de52ca9cc910b0e141d#subdirectory=sdk/python" \ 'aiohttp>=3.9' 'segno>=1.5' 'pytest>=8' 'ruff>=0.11.0' - name: Lint @@ -67,7 +67,7 @@ jobs: run: | uv venv --python 3.12 uv pip install \ - "inkbox @ git+https://github.com/inkbox-ai/inkbox.git@8f4b37c56cd153a2acc6cfabe27dbbeb43510f00#subdirectory=sdk/python" \ + "inkbox @ git+https://github.com/inkbox-ai/inkbox.git@199bbd27c8dab2f70e379de52ca9cc910b0e141d#subdirectory=sdk/python" \ 'aiohttp>=3.9' 'segno>=1.5' 'pytest>=8' 'ruff>=0.11.0' uv pip install "hermes-agent @ git+https://github.com/NousResearch/hermes-agent.git@main" diff --git a/README.md b/README.md index 92eaca1..bc2399b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ hermes gateway restart `hermes inkbox setup` walks the active Hermes install through Inkbox configuration: -1. Installs or upgrades `inkbox>=0.5.0,<1.0.0` and `aiohttp>=3.9` in the Hermes Python environment when needed. +1. Installs or upgrades `inkbox>=0.5.1,<1.0.0` and `aiohttp>=3.9` in the Hermes Python environment when needed. 2. Authenticates to Inkbox, or starts self-signup if you do not have an API key yet. 3. Resolves or creates the Inkbox agent identity for this Hermes gateway. 4. Optionally provisions a local US phone number so SMS and voice are available. @@ -96,13 +96,13 @@ The setup wizard installs dependencies into the Python environment that runs Her If the wizard prints a missing-SDK warning, use the exact command it prints. It will look like this: ```bash -/path/to/hermes/venv/bin/python3 -m pip install 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' +/path/to/hermes/venv/bin/python3 -m pip install 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' ``` When `uv` is available, the wizard prefers: ```bash -uv pip install --python /path/to/hermes/venv/bin/python3 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' +uv pip install --python /path/to/hermes/venv/bin/python3 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' ``` Do not use plain `pip install inkbox aiohttp` unless the wizard tells you to; plain `pip` may point at pyenv, Homebrew, system Python, or another virtualenv. @@ -328,7 +328,7 @@ The plugin registers all `skills/*/SKILL.md` files with Hermes. | `inkbox-imessage-responder` | Sending, replying to, or triaging iMessage | | `inkbox-outbound-calling` | Placing calls to numbers or contacts | | `inkbox-call-review` | Current-call/post-call context; historical call reads are not exposed in Hermes | -| `inkbox-contact-lookup` | Resolving, creating, or updating contacts visible to the configured identity | +| `inkbox-contact-lookup` | Resolving, creating, or updating organization-wide contacts | | `inkbox-contact-rules` | Explaining server-side contact rules; rule edit tools are not exposed in Hermes | | `inkbox-identity-access` | Explaining identity access; grant/revoke tools are not exposed in Hermes | | `inkbox-notes-memory` | Explaining note limitations; Inkbox note tools are not exposed in Hermes | diff --git a/pyproject.toml b/pyproject.toml index de0e6c6..6204397 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ description = "Inkbox platform plugin for Hermes Agent" requires-python = ">=3.11" dependencies = [ "aiohttp>=3.9", - "inkbox>=0.5.0,<1.0.0", + "inkbox>=0.5.1,<1.0.0", "segno>=1.5", ] diff --git a/setup_wizard.py b/setup_wizard.py index 475c308..a7976aa 100644 --- a/setup_wizard.py +++ b/setup_wizard.py @@ -58,7 +58,7 @@ def print_warning(message: str) -> None: masked_secret_prompt = None -INKBOX_MIN_VERSION = "0.5.0" +INKBOX_MIN_VERSION = "0.5.1" INKBOX_REQUIREMENTS = (f"inkbox>={INKBOX_MIN_VERSION},<1.0.0", "aiohttp>=3.9", "segno>=1.5") _BRACKETED_PASTE_PATTERN = re.compile(r"\x1b\[\s*200~|\x1b\[\s*201~") _AVATAR_PATH = Path(__file__).resolve().parent / "assets" / "hermes_with_iphone.png" diff --git a/skills/inkbox-contact-lookup/SKILL.md b/skills/inkbox-contact-lookup/SKILL.md index be1e317..8427901 100644 --- a/skills/inkbox-contact-lookup/SKILL.md +++ b/skills/inkbox-contact-lookup/SKILL.md @@ -1,12 +1,12 @@ --- name: inkbox-contact-lookup -description: Use when the user asks "who is X", "what's the email for Y", "find a contact named Z", "save this contact", or any question that needs contact context. Hermes can read and write Inkbox contacts visible to this identity, but does not expose contact admin tools. +description: Use when the user asks "who is X", "what's the email for Y", "find a contact named Z", "save this contact", or any question that needs contact context. Contacts are shared across the Inkbox organization. user-invocable: false --- # Inkbox contact lookup -Hermes is the Inkbox social-assistant tier. It receives contact context on inbound email, SMS, iMessage, and calls when Inkbox resolves the sender, and it can read or update contacts visible to the configured identity. +Hermes receives contact context on inbound email, SMS, iMessage, and calls when Inkbox resolves the sender, and it can read or update the organization's shared contacts. ## Hermes tool availability @@ -32,9 +32,9 @@ Hermes is the Inkbox social-assistant tier. It receives contact context on inbou ## Access semantics -- Contact context is **filtered server-side** by per-identity grants. If Inkbox does not include a resolved contact marker, this identity may not have access or the sender may be unknown. -- Hermes contact tools operate only on contacts visible/writable to the configured identity. -- Grant management is handled by the `inkbox-identity-access` skill when the user asks to share contacts across Inkbox identities. +- Every identity in the organization can read contacts. Creating, updating, or deleting a contact affects the shared address book. +- If Inkbox does not include a resolved contact marker, the sender may be unknown or ambiguous. +- Contacts do not have per-identity access grants. ## What this skill does NOT cover diff --git a/skills/inkbox-identity-access/SKILL.md b/skills/inkbox-identity-access/SKILL.md index 6444f3a..399d546 100644 --- a/skills/inkbox-identity-access/SKILL.md +++ b/skills/inkbox-identity-access/SKILL.md @@ -1,31 +1,27 @@ --- name: inkbox-identity-access -description: Use when the user asks which Inkbox agent identities can see a contact or note, or asks to grant/revoke cross-identity access to contacts or notes. Hermes does not expose identity-access tools; explain the limitation. +description: Use when the user asks which Inkbox agent identities can see a contact or note, or asks to grant/revoke cross-identity note access. Contacts are organization-wide; Hermes does not expose note-access tools. user-invocable: false --- # Inkbox identity access -Use this skill when discussing per-identity visibility for Inkbox contacts and notes. +Use this skill when explaining organization-wide contact visibility or per-identity note access. ## Hermes tool availability -- Hermes does not register `inkbox_list_contact_access`, `inkbox_grant_contact_access`, `inkbox_revoke_contact_access`, `inkbox_list_note_access`, `inkbox_grant_note_access`, or `inkbox_revoke_note_access`. -- This plugin cannot grant or revoke cross-identity access directly. -- Direct the user to Inkbox Console or an admin-capable host/plugin tier when they need access changes. +- Hermes does not register `inkbox_list_note_access`, `inkbox_grant_note_access`, or `inkbox_revoke_note_access`. +- Contacts do not have per-identity access controls. +- Direct the user to Inkbox Console or a host with note-access tools when they need note access changes. ## Workflow 1. Clarify whether the request is about contact visibility or note visibility. -2. If the user needs an actual access change, state that Hermes cannot perform it directly and summarize the requested change for Console/admin execution. -3. For contacts, explain the concepts: - - Grant a specific identity with `identityId`. - - Use `wildcard: true` only when the user wants every active identity to see the contact. - - Revoke by `identityId`. -4. For notes, explain the concepts: - - Grant and revoke only by explicit `identityId`; notes do not support wildcard grants. -5. If the user gives an agent handle instead of an identity UUID, explain that Console/admin tooling may need the identity id. +2. For contacts, explain that every identity in the organization can see them and access cannot be granted or revoked per identity. +3. For notes, explain that grants use an explicit `identityId` and that Hermes cannot change them directly. +4. Summarize the requested note access change for execution in Inkbox Console or a host with note-access tools. +5. If the user gives an agent handle instead of an identity UUID, explain that note access tooling may need the identity id. ## Safety -Access changes affect what other Inkbox agent identities can see. Confirm the target identity and object before granting broad or wildcard contact access. +Note access changes affect what other Inkbox agent identities can see. Confirm the target identity and note before requesting a change. diff --git a/tests/test_contact_tools.py b/tests/test_contact_tools.py index 937a521..a6663c5 100644 --- a/tests/test_contact_tools.py +++ b/tests/test_contact_tools.py @@ -145,10 +145,10 @@ def test_lookup_contact_requires_one_filter(monkeypatch): assert "exactly one" in too_many["error"] -def test_contact_schemas_preserve_identity_scoped_semantics(): - assert "visible to this configured identity" in tools.LOOKUP_CONTACT_SCHEMA["description"] - assert "visible to this configured identity" in tools.LIST_CONTACTS_SCHEMA["description"] - assert "contact access rules" in tools.CREATE_CONTACT_SCHEMA["description"] +def test_contact_schemas_describe_organization_wide_semantics(): + assert "organization-wide" in tools.LOOKUP_CONTACT_SCHEMA["description"] + assert "organization-wide" in tools.LIST_CONTACTS_SCHEMA["description"] + assert "organization-wide" in tools.CREATE_CONTACT_SCHEMA["description"] def test_contact_write_tools_validate_required_inputs(monkeypatch): diff --git a/tests/test_setup_wizard.py b/tests/test_setup_wizard.py index 51b58f8..55e9c93 100644 --- a/tests/test_setup_wizard.py +++ b/tests/test_setup_wizard.py @@ -26,7 +26,7 @@ def test_install_command_prefers_uv_when_available(monkeypatch): "install", "--python", "/tmp/hermes/venv/bin/python", - "inkbox>=0.5.0,<1.0.0", + "inkbox>=0.5.1,<1.0.0", "aiohttp>=3.9", "segno>=1.5", ]] @@ -37,10 +37,10 @@ def test_install_command_falls_back_to_pip_and_ensurepip(monkeypatch): monkeypatch.setattr(setup_wizard.shutil, "which", lambda _name: None) assert setup_wizard._install_commands() == [ - [["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.0,<1.0.0", "aiohttp>=3.9", "segno>=1.5"]], + [["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.1,<1.0.0", "aiohttp>=3.9", "segno>=1.5"]], [ ["/tmp/hermes/venv/bin/python", "-m", "ensurepip", "--upgrade"], - ["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.0,<1.0.0", "aiohttp>=3.9", "segno>=1.5"], + ["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.1,<1.0.0", "aiohttp>=3.9", "segno>=1.5"], ], ] @@ -59,7 +59,7 @@ def fail_import(): out = capsys.readouterr().out assert "/tmp/hermes/venv/bin/python" in out assert "uv pip install --python" in out - assert "inkbox>=0.5.0,<1.0.0" in out + assert "inkbox>=0.5.1,<1.0.0" in out assert "aiohttp>=3.9" in out diff --git a/tools.py b/tools.py index 6900e25..7962743 100644 --- a/tools.py +++ b/tools.py @@ -918,7 +918,7 @@ def inkbox_place_call(args: dict, **kwargs) -> str: def _place(): if not hasattr(identity, "place_call"): - raise RuntimeError("Inkbox SDK identity has no place_call method (upgrade inkbox to >=0.5.0)") + raise RuntimeError("Inkbox SDK identity has no place_call method (upgrade inkbox to >=0.5.1)") try: return identity.place_call( to_number=to_number, @@ -965,7 +965,7 @@ def _place(): LOOKUP_CONTACT_SCHEMA = { "name": "inkbox_lookup_contact", - "description": "Reverse-lookup Inkbox contacts by exactly one email/phone filter. Returns contacts visible to this configured identity.", + "description": "Reverse-lookup organization-wide Inkbox contacts by exactly one email/phone filter.", "parameters": { "type": "object", "properties": { @@ -980,7 +980,7 @@ def _place(): LIST_CONTACTS_SCHEMA = { "name": "inkbox_list_contacts", - "description": "Search/list Inkbox contacts visible to this configured identity. Use for name-based queries like 'who is Alex?'.", + "description": "Search/list organization-wide Inkbox contacts. Use for name-based queries like 'who is Alex?'.", "parameters": { "type": "object", "properties": { @@ -1047,7 +1047,7 @@ def _place(): CREATE_CONTACT_SCHEMA = { "name": "inkbox_create_contact", - "description": "Create an Inkbox address-book contact visible according to Inkbox contact access rules.", + "description": "Create an organization-wide Inkbox address-book contact.", "parameters": { "type": "object", "properties": dict(_CONTACT_WRITE_PROPERTIES),