@inline-chat/hermes-agent-adapter 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,6 +51,20 @@ Unsupported or intentionally limited:
51
51
  - Live voice sessions or calls. Voice file messages are supported, but realtime audio is not.
52
52
  - Media without a usable Inline CDN/local URL. Those messages still produce text summaries, but Hermes may not receive a local file path.
53
53
 
54
+ ## Release 0.0.22
55
+
56
+ This release includes typed service-notice filtering before agent admission,
57
+ current shared-session setup guidance, and the pinned realtime SDK `0.0.18`.
58
+ Private thread creation with omitted participants includes the connected account.
59
+ Clarification choices use two-column rows within Inline's button limit.
60
+ Hermes keeps its supported agent activity surface; unsupported experimental tool
61
+ timelines remain disabled.
62
+
63
+ ```sh
64
+ npm install -g @inline-chat/hermes-agent-adapter@0.0.22
65
+ inline-hermes install --force
66
+ ```
67
+
54
68
  ## Install
55
69
 
56
70
  ```sh
@@ -156,7 +170,7 @@ uv run ./hermes plugins list --plain --no-bundled
156
170
  Expected local output includes:
157
171
 
158
172
  ```text
159
- enabled user 0.0.21 inline-platform
173
+ enabled user 0.0.22 inline-platform
160
174
  ```
161
175
 
162
176
  ## Update Or Reinstall
@@ -254,26 +268,14 @@ platforms:
254
268
  enabled: true
255
269
  ```
256
270
 
257
- Inline follows Hermes' native work-chat defaults: show typing/presence while a
258
- turn is running, keep tool-call progress out of the room by default, and keep
259
- edit-based token streaming opt-in. If an older Hermes config has global
260
- `display.tool_progress: all`, add the per-platform override below so terminal
261
- and tool progress bubbles are not left in Inline chats:
271
+ Experimental tool timelines are unavailable in this adapter. The old
272
+ `INLINE_EXPERIMENTAL_AGENT_ACTIVITY` setting is ignored and logs a warning when
273
+ enabled. Hermes uses ordinary typing, optional processing reactions, and replies.
262
274
 
263
- ```yaml
264
- display:
265
- platforms:
266
- inline:
267
- tool_progress: off
268
- cleanup_progress: true
269
- streaming: false
270
- interim_assistant_messages: false
271
- ```
272
-
273
- To temporarily show live tool progress, set `tool_progress: new` or
274
- `tool_progress: all` and leave `cleanup_progress: true` so Hermes deletes the
275
- progress message after a successful final reply. Token streaming requires both
276
- top-level `streaming.enabled: true` and
275
+ Inline keeps tool progress and interim assistant messages quiet by default.
276
+ Explicit Hermes display settings still take precedence; if you enable native
277
+ tool progress, Hermes uses its ordinary progress messages. Token streaming remains
278
+ opt-in through both `streaming.enabled: true` and
277
279
  `display.platforms.inline.streaming: true`.
278
280
 
279
281
  Hermes-native sends and scheduled deliveries accept Inline's explicit target
@@ -431,11 +433,37 @@ chat, while `create_chat` creates a new top-level destination. `create_chat`
431
433
  requires a title, defaults to private, accepts optional participant user IDs or
432
434
  a parent space ID, and requires both `space_id` and explicit `is_public: true`
433
435
  for space-wide visibility. It returns the new chat ID so Hermes can link it in
434
- the normal reply.
436
+ the normal reply. Omitted or empty private participants create a conversation
437
+ accessible only to the connected account. Include intended human participants
438
+ explicitly; owning the bot does not grant membership in its private conversations.
435
439
 
436
440
  The plugin id is `inline`, which is intentionally the same id an eventual
437
441
  bundled Hermes adapter should use.
438
442
 
443
+ ## Shared transcripts in groups and threads
444
+
445
+ To share one conversation transcript among admitted participants in a group
446
+ or thread, add these keys at the root of the `config.yaml` used by the Hermes
447
+ gateway process, outside `platforms.inline.extra`:
448
+
449
+ ```yaml
450
+ group_sessions_per_user: false
451
+ thread_sessions_per_user: false
452
+ ```
453
+
454
+ Hermes defaults `group_sessions_per_user` to `true` (groups split by sender)
455
+ and `thread_sessions_per_user` to `false` (threads shared). These settings
456
+ affect every messaging platform governed by that gateway configuration.
457
+ For separate profile gateways, configure each gateway's profile separately.
458
+ With a multiplexed gateway, do not assume a secondary profile's values control
459
+ its sessions; this adapter does not qualify per-profile session-policy overrides.
460
+
461
+ Distinct Hermes profile/gateway namespaces keep separate conversation sessions.
462
+ Swapping a bot token within one profile does not create a new transcript namespace.
463
+ These flags select shared sessions; they do not merge existing histories, import
464
+ all Inline history, grant permissions, or change access, mention, or bot wake rules.
465
+ Restart the gateway through its existing process manager after editing.
466
+
439
467
  ## Error Reporting And Privacy
440
468
 
441
469
  The Inline adapter and its supervised sidecar keep error reporting disabled
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inline-chat/hermes-agent-adapter",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "Hermes Agent platform adapter for Inline, with a native Python plugin and bundled Inline realtime sidecar.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -230,11 +230,12 @@ def _install_inline_display_defaults() -> None:
230
230
  defaults = getattr(_display_config, "_PLATFORM_DEFAULTS", None)
231
231
  if not isinstance(defaults, dict):
232
232
  return
233
+ inline_defaults = dict(_INLINE_DISPLAY_DEFAULTS)
233
234
  current = defaults.get("inline")
234
235
  if isinstance(current, dict):
235
- defaults["inline"] = {**_INLINE_DISPLAY_DEFAULTS, **current}
236
+ defaults["inline"] = {**inline_defaults, **current}
236
237
  else:
237
- defaults["inline"] = dict(_INLINE_DISPLAY_DEFAULTS)
238
+ defaults["inline"] = inline_defaults
238
239
  except Exception:
239
240
  logger.debug("[inline] failed to install display defaults", exc_info=True)
240
241
 
@@ -812,6 +813,8 @@ class InlineAdapter(BasePlatformAdapter):
812
813
  super().__init__(config, Platform("inline"))
813
814
  extra = config.extra or {}
814
815
 
816
+ if _truthy(os.getenv("INLINE_EXPERIMENTAL_AGENT_ACTIVITY")):
817
+ logger.warning("[inline] experimental tool timelines are unavailable; ignoring INLINE_EXPERIMENTAL_AGENT_ACTIVITY and using ordinary typing")
815
818
  self._token = _config_token(config)
816
819
  self._base_url = os.getenv("INLINE_BASE_URL") or extra.get("base_url") or "https://api.inline.chat"
817
820
  self._sidecar_bind = _normalize_sidecar_bind(extra.get("sidecar_bind") or os.getenv("INLINE_SIDECAR_BIND"))
@@ -2444,7 +2447,14 @@ class InlineAdapter(BasePlatformAdapter):
2444
2447
 
2445
2448
  async def _dispatch_message(self, event: Dict[str, Any], *, edit: bool = False) -> None:
2446
2449
  agent_action = event.get("_inlineAgentAction") if isinstance(event.get("_inlineAgentAction"), dict) else None
2447
- msg = event.get("message") or {}
2450
+ msg = event.get("message")
2451
+ if not isinstance(msg, dict):
2452
+ return
2453
+ # History/join recovery and older sidecars can reach this entry directly.
2454
+ # Service fallback text and mentions are never conversational direction.
2455
+ raw = msg.get("raw") if isinstance(msg.get("raw"), dict) else {}
2456
+ if isinstance(msg.get("serviceMessage"), dict) or isinstance(raw.get("serviceMessage"), dict):
2457
+ return
2448
2458
  msg_id = str(msg.get("id") or "")
2449
2459
  chat_id = str(event.get("chatId") or msg.get("chatId") or "")
2450
2460
  if not msg_id or not chat_id:
@@ -5014,7 +5024,7 @@ class InlineAdapter(BasePlatformAdapter):
5014
5024
  "target": self._target_for(chat_id, metadata),
5015
5025
  "text": "\n".join(lines),
5016
5026
  "parseMarkdown": self._parse_markdown,
5017
- "actions": {"rows": [{"actions": actions}]},
5027
+ "actions": {"rows": self._action_rows(actions)},
5018
5028
  })
5019
5029
 
5020
5030
  async def send_exec_approval(
@@ -27,7 +27,7 @@ _CLI_INSTALL_URL = "https://inline.chat/cli/install.sh"
27
27
  _MAX_TOKEN_BYTES = 16 * 1024
28
28
  _MAX_PROBE_RESPONSE_BYTES = 64 * 1024
29
29
  _MACHINE_SETUP_PROTOCOL_VERSION = 1
30
- _PROBE_USER_AGENT = "inline-hermes-agent-adapter/0.0.21"
30
+ _PROBE_USER_AGENT = "inline-hermes-agent-adapter/0.0.22"
31
31
  _ENV_REFERENCE_RE = re.compile(r"^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$")
32
32
 
33
33
 
@@ -3,7 +3,7 @@ label: Inline
3
3
  kind: platform
4
4
  provides_tools:
5
5
  - inline
6
- version: 0.0.21
6
+ version: 0.0.22
7
7
  requires_hermes: ">=0.21.3"
8
8
  description: >
9
9
  Inline platform adapter for Hermes Agent. The adapter runs as a native
@@ -5702,6 +5702,13 @@ var botSettingsEventKinds = new Set([
5702
5702
  function inboundEventNeedsSenderResolution(event) {
5703
5703
  return !botSettingsEventKinds.has(event.kind ?? "");
5704
5704
  }
5705
+ function inboundEventIsServiceMessage(event) {
5706
+ if (event.kind !== "message.new" && event.kind !== "message.edit")
5707
+ return false;
5708
+ const message = asOptionalRecord(event.message);
5709
+ const raw = asOptionalRecord(message?.raw);
5710
+ return Boolean(asOptionalRecord(message?.serviceMessage) || asOptionalRecord(raw?.serviceMessage));
5711
+ }
5705
5712
 
5706
5713
  class SidecarError extends Error {
5707
5714
  errorKind;
@@ -5823,6 +5830,7 @@ function normalizeMessage(message) {
5823
5830
  replies: message.replies ?? null,
5824
5831
  actions: message.actions ?? null,
5825
5832
  rev: message.rev ?? null,
5833
+ ...asOptionalRecord(message.serviceMessage) ? { serviceMessage: message.serviceMessage } : {},
5826
5834
  raw: message
5827
5835
  };
5828
5836
  }
@@ -6021,6 +6029,8 @@ function explicitlyMentionsSelf(event, meId) {
6021
6029
  return message?.entities?.entities?.some((e) => e.entity?.oneofKind === "mention" && e.entity.mention?.userId?.toString() === meId) ?? false;
6022
6030
  }
6023
6031
  async function deliverInboundEvent(event, owner) {
6032
+ if (inboundEventIsServiceMessage(event))
6033
+ return;
6024
6034
  const explicitMention = explicitlyMentionsSelf(event, owner.meId);
6025
6035
  while (!owner.signal.aborted) {
6026
6036
  const resolution = explicitMention ? { provenanceVerified: false } : inboundEventNeedsSenderResolution(event) ? await owner.resolveSender(event) : { provenanceVerified: true };
@@ -47555,6 +47565,9 @@ async function endpointCreateChat(res, body) {
47555
47565
  if (isPublic && participantUserIds.length > 0) {
47556
47566
  throw new SidecarError("public create-chat cannot include participantUserIds", "bad_format");
47557
47567
  }
47568
+ if (!isPublic && participantUserIds.length === 0) {
47569
+ participantUserIds.push(readRequiredInlineId({ meId }, "meId"));
47570
+ }
47558
47571
  const result = await client.invokeUncheckedRaw(Method.CREATE_CHAT, {
47559
47572
  oneofKind: "createChat",
47560
47573
  createChat: {
@@ -226,7 +226,7 @@ INLINE_TOOL_SCHEMA = {
226
226
  "type": "array",
227
227
  "items": {"type": "string"},
228
228
  "maxItems": 50,
229
- "description": "User IDs for a private create_chat destination. Omit for a private bot-only thread.",
229
+ "description": "User IDs for a private create_chat destination. Omit or pass [] for a connected-account-only thread. Include intended human participants explicitly; bot ownership does not grant access.",
230
230
  },
231
231
  "is_public": {
232
232
  "type": "boolean",