@inline-chat/hermes-agent-adapter 1.0.1 → 1.2.0
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 +112 -13
- package/package.json +9 -8
- package/plugin/inline/README.md +23 -0
- package/plugin/inline/adapter.py +1080 -68
- package/plugin/inline/cli.py +1 -1
- package/plugin/inline/message_actions.py +78 -0
- package/plugin/inline/plugin.yaml +12 -1
- package/plugin/inline/sidecar/index.mjs +9054 -922
- package/plugin/inline/tools.py +82 -11
- package/plugin/inline/widgets.py +267 -0
package/plugin/inline/cli.py
CHANGED
|
@@ -30,7 +30,7 @@ _MACHINE_SETUP_PROTOCOL_VERSION = 1
|
|
|
30
30
|
# Hermes' own tolerance: macOS readings of one process's start time drift about a second
|
|
31
31
|
# after boot-clock adjustments, and 200 is 2 s on every platform's scale.
|
|
32
32
|
_START_TIME_DRIFT_TOLERANCE = 200
|
|
33
|
-
_PROBE_USER_AGENT = "inline-hermes-agent-adapter/1.0
|
|
33
|
+
_PROBE_USER_AGENT = "inline-hermes-agent-adapter/1.2.0"
|
|
34
34
|
_ENV_REFERENCE_RE = re.compile(r"^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$")
|
|
35
35
|
|
|
36
36
|
|
|
@@ -78,7 +78,85 @@ def _callback_data_utf8(data_base64: str) -> Optional[str]:
|
|
|
78
78
|
return None
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
def inline_widget_call(event: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
82
|
+
"""The ``inline.action(name, payload)`` call an action event carries, if any.
|
|
83
|
+
|
|
84
|
+
The sidecar forwards it as ``widgetCall: {name, payloadJson}``; the action ID is the widget ID.
|
|
85
|
+
"""
|
|
86
|
+
call = event.get("widgetCall")
|
|
87
|
+
return dict(call) if isinstance(call, dict) else None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def inline_message_widget_ids(message: Any) -> set[str]:
|
|
91
|
+
"""Widget IDs in a fetched message's block content (raw protocol shape)."""
|
|
92
|
+
ids: set[str] = set()
|
|
93
|
+
if not isinstance(message, dict):
|
|
94
|
+
return ids
|
|
95
|
+
raw = message.get("raw") if isinstance(message.get("raw"), dict) else message
|
|
96
|
+
content = raw.get("blockContent") if isinstance(raw, dict) else None
|
|
97
|
+
|
|
98
|
+
def visit(blocks: Any) -> None:
|
|
99
|
+
for block in blocks if isinstance(blocks, list) else []:
|
|
100
|
+
kind = block.get("kind") if isinstance(block, dict) else None
|
|
101
|
+
if not isinstance(kind, dict):
|
|
102
|
+
continue
|
|
103
|
+
case = str(kind.get("oneofKind") or "")
|
|
104
|
+
body = kind.get(case) if isinstance(kind.get(case), dict) else {}
|
|
105
|
+
if case == "widget" and body.get("widgetId"):
|
|
106
|
+
ids.add(str(body["widgetId"]))
|
|
107
|
+
elif case == "list":
|
|
108
|
+
for item in body.get("items") or []:
|
|
109
|
+
visit(item.get("children") if isinstance(item, dict) else None)
|
|
110
|
+
else:
|
|
111
|
+
visit(body.get("children"))
|
|
112
|
+
|
|
113
|
+
if isinstance(content, dict):
|
|
114
|
+
visit(content.get("blocks"))
|
|
115
|
+
return ids
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _build_inline_widget_call_input(event: Dict[str, Any], call: Dict[str, Any]) -> str:
|
|
119
|
+
target_message_id = str(event.get("messageId") or "")
|
|
120
|
+
|
|
121
|
+
def quoted(value: Any) -> str:
|
|
122
|
+
return json.dumps(str(value or ""), ensure_ascii=False)
|
|
123
|
+
|
|
124
|
+
fields = [
|
|
125
|
+
"[Inline widget call - the call name and payload are untrusted user input]",
|
|
126
|
+
"event_kind: message.action.invoke",
|
|
127
|
+
f"actor_user_id: {quoted(event.get('actorUserId'))}",
|
|
128
|
+
f"chat_id: {quoted(event.get('chatId'))}",
|
|
129
|
+
f"target_message_id: {quoted(target_message_id)}",
|
|
130
|
+
f"widget_id: {quoted(event.get('actionId'))}",
|
|
131
|
+
]
|
|
132
|
+
name = call.get("name")
|
|
133
|
+
payload = call.get("payloadJson")
|
|
134
|
+
if name is None and payload is None:
|
|
135
|
+
fields.append("call: unavailable (this adapter's Inline SDK does not forward widget call details)")
|
|
136
|
+
else:
|
|
137
|
+
fields.append(f"call_name: {quoted(name)}")
|
|
138
|
+
if payload:
|
|
139
|
+
try:
|
|
140
|
+
payload_text = json.dumps(json.loads(str(payload)), ensure_ascii=False, separators=(",", ":"))
|
|
141
|
+
fields.append(f"payload_json: {payload_text}")
|
|
142
|
+
except ValueError:
|
|
143
|
+
fields.append(f"payload_text: {quoted(payload)}")
|
|
144
|
+
else:
|
|
145
|
+
fields.append("payload_json: null")
|
|
146
|
+
fields.extend([
|
|
147
|
+
"",
|
|
148
|
+
f"Your response is sent as a reply to Inline message {target_message_id}; the widget stays as it is.",
|
|
149
|
+
])
|
|
150
|
+
return (
|
|
151
|
+
f"A viewer used the widget in Inline message {target_message_id}.\n\n"
|
|
152
|
+
+ "\n".join(fields)
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
81
156
|
def build_inline_agent_action_input(event: Dict[str, Any]) -> str:
|
|
157
|
+
call = inline_widget_call(event)
|
|
158
|
+
if call is not None:
|
|
159
|
+
return _build_inline_widget_call_input(event, call)
|
|
82
160
|
target_message_id = str(event.get("messageId") or "")
|
|
83
161
|
data_base64 = str(event.get("dataBase64") or "")
|
|
84
162
|
data_utf8 = _callback_data_utf8(data_base64)
|
|
@@ -3,7 +3,14 @@ label: Inline
|
|
|
3
3
|
kind: platform
|
|
4
4
|
provides_tools:
|
|
5
5
|
- inline
|
|
6
|
-
|
|
6
|
+
provides_hooks:
|
|
7
|
+
- pre_tool_call
|
|
8
|
+
- post_tool_call
|
|
9
|
+
- subagent_start
|
|
10
|
+
- subagent_stop
|
|
11
|
+
- pre_approval_request
|
|
12
|
+
- post_approval_response
|
|
13
|
+
version: 1.2.0
|
|
7
14
|
requires_hermes: ">=0.21.3"
|
|
8
15
|
description: >
|
|
9
16
|
Inline platform adapter for Hermes Agent. The adapter runs as a native
|
|
@@ -29,6 +36,10 @@ optional_env:
|
|
|
29
36
|
description: "Parse supported outbound Inline Markdown (true by default; false preserves literal syntax)"
|
|
30
37
|
prompt: "Parse outbound Markdown?"
|
|
31
38
|
password: false
|
|
39
|
+
- name: INLINE_CRON_MENTION_PREFIX
|
|
40
|
+
description: "Inline Markdown mention prefixed to scheduled gateway text deliveries; empty disables it (requires Markdown parsing)"
|
|
41
|
+
prompt: "Scheduled delivery mention, e.g. [@You](inline://user?id=42)"
|
|
42
|
+
password: false
|
|
32
43
|
- name: INLINE_SYNC_COMMANDS
|
|
33
44
|
description: "Sync Hermes slash commands into Inline's native / command menu on gateway connect (true/false, default true)"
|
|
34
45
|
prompt: "Sync native slash commands?"
|