@inline-chat/hermes-agent-adapter 0.0.5-alpha.0 → 0.0.5-alpha.2
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 +5 -5
- package/package.json +1 -1
- package/plugin/inline/adapter.py +2 -8
- package/plugin/inline/cli.py +103 -10
- package/plugin/inline/plugin.yaml +1 -1
package/README.md
CHANGED
|
@@ -58,11 +58,11 @@ hermes plugins enable inline-platform
|
|
|
58
58
|
hermes gateway setup
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Select Inline in the messaging-platform picker. The
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
Select Inline in the messaging-platform picker. The default path is: go to
|
|
62
|
+
**Inline → Settings → Bots → Create a new bot**, then paste its token. See the
|
|
63
|
+
[Inline bot creation guide](https://inline.chat/docs/creating-a-bot). The
|
|
64
|
+
optional CLI path can install/sign in to the Inline CLI and create the bot from
|
|
65
|
+
the terminal. Both paths securely save the token and configure access.
|
|
66
66
|
|
|
67
67
|
## Coding Agent Setup Prompt
|
|
68
68
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inline-chat/hermes-agent-adapter",
|
|
3
|
-
"version": "0.0.5-alpha.
|
|
3
|
+
"version": "0.0.5-alpha.2",
|
|
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",
|
package/plugin/inline/adapter.py
CHANGED
|
@@ -3001,7 +3001,6 @@ class InlineAdapter(BasePlatformAdapter):
|
|
|
3001
3001
|
) -> SendResult:
|
|
3002
3002
|
target = self._target_for(chat_id, metadata)
|
|
3003
3003
|
reply_to = self._reply_to_for_target(reply_to, target)
|
|
3004
|
-
parse_markdown = self._parse_markdown and not self._expects_edits(metadata)
|
|
3005
3004
|
chunks = self.truncate_message(self.format_message(content), self.MAX_MESSAGE_LENGTH)
|
|
3006
3005
|
message_ids: List[str] = []
|
|
3007
3006
|
raw_responses: List[Any] = []
|
|
@@ -3011,7 +3010,7 @@ class InlineAdapter(BasePlatformAdapter):
|
|
|
3011
3010
|
body: Dict[str, Any] = {
|
|
3012
3011
|
"target": target,
|
|
3013
3012
|
"text": chunk,
|
|
3014
|
-
"parseMarkdown":
|
|
3013
|
+
"parseMarkdown": self._parse_markdown,
|
|
3015
3014
|
}
|
|
3016
3015
|
if reply_to and index == 0:
|
|
3017
3016
|
body["replyToMsgId"] = str(reply_to)
|
|
@@ -3052,7 +3051,6 @@ class InlineAdapter(BasePlatformAdapter):
|
|
|
3052
3051
|
metadata: Optional[Dict[str, Any]] = None,
|
|
3053
3052
|
) -> SendResult:
|
|
3054
3053
|
text = self.format_message(content)
|
|
3055
|
-
parse_markdown = self._parse_markdown if finalize else False
|
|
3056
3054
|
if len(text) > self.MAX_MESSAGE_LENGTH:
|
|
3057
3055
|
if finalize:
|
|
3058
3056
|
return await self._edit_overflow_split(chat_id, message_id, content, metadata=metadata)
|
|
@@ -3062,7 +3060,7 @@ class InlineAdapter(BasePlatformAdapter):
|
|
|
3062
3060
|
"target": target,
|
|
3063
3061
|
"messageId": str(message_id),
|
|
3064
3062
|
"text": text,
|
|
3065
|
-
"parseMarkdown":
|
|
3063
|
+
"parseMarkdown": self._parse_markdown,
|
|
3066
3064
|
}
|
|
3067
3065
|
result = await self._send_sidecar("/edit", body)
|
|
3068
3066
|
if result.success:
|
|
@@ -3480,10 +3478,6 @@ class InlineAdapter(BasePlatformAdapter):
|
|
|
3480
3478
|
def format_message(self, content: str) -> str:
|
|
3481
3479
|
return content if self._parse_markdown else strip_markdown(content)
|
|
3482
3480
|
|
|
3483
|
-
@staticmethod
|
|
3484
|
-
def _expects_edits(metadata: Optional[Dict[str, Any]]) -> bool:
|
|
3485
|
-
return bool((metadata or {}).get("expect_edits"))
|
|
3486
|
-
|
|
3487
3481
|
def _target_for(self, chat_id: str, metadata: Optional[Dict[str, Any]] = None) -> Dict[str, str]:
|
|
3488
3482
|
thread_id = (metadata or {}).get("thread_id")
|
|
3489
3483
|
if thread_id:
|
package/plugin/inline/cli.py
CHANGED
|
@@ -12,12 +12,14 @@ import os
|
|
|
12
12
|
import re
|
|
13
13
|
import shutil
|
|
14
14
|
import subprocess
|
|
15
|
+
import sys
|
|
15
16
|
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
|
|
18
19
|
_SIDECAR_ENTRY = Path(__file__).parent / "sidecar" / "index.mjs"
|
|
19
20
|
_MIN_NODE_MAJOR = 20
|
|
20
21
|
_BOT_USERNAME_RE = re.compile(r"^[A-Za-z0-9_]+bot$", re.IGNORECASE)
|
|
22
|
+
_CLI_INSTALL_URL = "https://inline.chat/cli/install.sh"
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
def gateway_setup() -> None:
|
|
@@ -42,17 +44,18 @@ def gateway_setup() -> None:
|
|
|
42
44
|
|
|
43
45
|
hermes_setup.print_info("How would you like to connect Hermes to Inline?")
|
|
44
46
|
print()
|
|
45
|
-
hermes_setup.print_info(" [1] Create a
|
|
46
|
-
hermes_setup.print_info("
|
|
47
|
+
hermes_setup.print_info(" [1] Create a bot in Inline and paste its token")
|
|
48
|
+
hermes_setup.print_info(" Go to Settings → Bots → Create a new bot.")
|
|
49
|
+
hermes_setup.print_info(" https://inline.chat/docs/creating-a-bot")
|
|
47
50
|
print()
|
|
48
|
-
hermes_setup.print_info(" [2]
|
|
49
|
-
hermes_setup.print_info("
|
|
51
|
+
hermes_setup.print_info(" [2] Create a bot with the Inline CLI")
|
|
52
|
+
hermes_setup.print_info(" Install or sign in to the CLI, then create the bot here.")
|
|
50
53
|
print()
|
|
51
54
|
|
|
52
55
|
choice = hermes_setup.prompt("Choice [1/2]", default="1").strip()
|
|
53
56
|
owner_user_id: str | None = None
|
|
54
57
|
token: str | None = None
|
|
55
|
-
if choice == "
|
|
58
|
+
if choice == "2":
|
|
56
59
|
token, owner_user_id = _create_bot_with_inline_cli(hermes_setup)
|
|
57
60
|
if not token:
|
|
58
61
|
print()
|
|
@@ -70,6 +73,7 @@ def gateway_setup() -> None:
|
|
|
70
73
|
if not owner_user_id:
|
|
71
74
|
owner_user_id = _inline_cli_user_id(shutil.which("inline"))
|
|
72
75
|
_configure_access(hermes_gateway, hermes_setup, owner_user_id)
|
|
76
|
+
hermes_gateway.write_platform_config_field("inline", "enabled", True, raw=True)
|
|
73
77
|
|
|
74
78
|
print()
|
|
75
79
|
hermes_setup.print_success("💬 Inline is configured!")
|
|
@@ -78,11 +82,13 @@ def gateway_setup() -> None:
|
|
|
78
82
|
|
|
79
83
|
|
|
80
84
|
def _create_bot_with_inline_cli(hermes_setup) -> tuple[str | None, str | None]:
|
|
81
|
-
inline_bin =
|
|
85
|
+
inline_bin = _find_inline_cli()
|
|
82
86
|
if not inline_bin:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
inline_bin = _install_inline_cli(hermes_setup)
|
|
88
|
+
if not inline_bin:
|
|
89
|
+
hermes_setup.print_warning("Automatic bot creation is unavailable because the Inline CLI could not be installed.")
|
|
90
|
+
hermes_setup.print_info("Install it from https://inline.chat/docs/cli, or use an existing bot token.")
|
|
91
|
+
return None, None
|
|
86
92
|
|
|
87
93
|
owner_user_id = _inline_cli_user_id(inline_bin)
|
|
88
94
|
if not owner_user_id:
|
|
@@ -126,9 +132,96 @@ def _create_bot_with_inline_cli(hermes_setup) -> tuple[str | None, str | None]:
|
|
|
126
132
|
return None, owner_user_id
|
|
127
133
|
|
|
128
134
|
|
|
135
|
+
def _install_inline_cli(hermes_setup) -> str | None:
|
|
136
|
+
print()
|
|
137
|
+
hermes_setup.print_info("The Inline CLI is needed to create your bot automatically.")
|
|
138
|
+
if not hermes_setup.prompt_yes_no("Install the Inline CLI now?", True):
|
|
139
|
+
hermes_setup.print_info("Inline CLI installation skipped.")
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
brew_bin = shutil.which("brew") if sys.platform == "darwin" else None
|
|
143
|
+
if brew_bin:
|
|
144
|
+
hermes_setup.print_info("Installing the Inline CLI with Homebrew...")
|
|
145
|
+
result = subprocess.run(
|
|
146
|
+
[brew_bin, "install", "--cask", "inline"],
|
|
147
|
+
check=False,
|
|
148
|
+
)
|
|
149
|
+
else:
|
|
150
|
+
curl_bin = shutil.which("curl")
|
|
151
|
+
shell_bin = shutil.which("sh") or "/bin/sh"
|
|
152
|
+
if not curl_bin:
|
|
153
|
+
hermes_setup.print_warning("Automatic installation requires curl.")
|
|
154
|
+
return None
|
|
155
|
+
hermes_setup.print_info("Downloading the official Inline CLI installer...")
|
|
156
|
+
try:
|
|
157
|
+
download = subprocess.run(
|
|
158
|
+
[curl_bin, "-fsSL", _CLI_INSTALL_URL],
|
|
159
|
+
stdout=subprocess.PIPE,
|
|
160
|
+
stderr=subprocess.PIPE,
|
|
161
|
+
timeout=60,
|
|
162
|
+
check=False,
|
|
163
|
+
)
|
|
164
|
+
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
165
|
+
hermes_setup.print_warning(f"Could not download the Inline CLI installer: {exc}")
|
|
166
|
+
return None
|
|
167
|
+
if download.returncode != 0 or not download.stdout:
|
|
168
|
+
hermes_setup.print_warning("Could not download the Inline CLI installer.")
|
|
169
|
+
return None
|
|
170
|
+
try:
|
|
171
|
+
result = subprocess.run(
|
|
172
|
+
[shell_bin, "-s"],
|
|
173
|
+
input=download.stdout,
|
|
174
|
+
timeout=180,
|
|
175
|
+
check=False,
|
|
176
|
+
)
|
|
177
|
+
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
178
|
+
hermes_setup.print_warning(f"Inline CLI installation failed: {exc}")
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
if result.returncode != 0:
|
|
182
|
+
hermes_setup.print_warning("The Inline CLI installer exited unsuccessfully.")
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
inline_bin = _find_inline_cli()
|
|
186
|
+
if not inline_bin:
|
|
187
|
+
hermes_setup.print_warning("The Inline CLI was installed but could not be found on PATH.")
|
|
188
|
+
return None
|
|
189
|
+
try:
|
|
190
|
+
verified = subprocess.run(
|
|
191
|
+
[inline_bin, "--version"],
|
|
192
|
+
stdout=subprocess.PIPE,
|
|
193
|
+
stderr=subprocess.PIPE,
|
|
194
|
+
timeout=10,
|
|
195
|
+
check=False,
|
|
196
|
+
)
|
|
197
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
198
|
+
verified = None
|
|
199
|
+
if verified is None or verified.returncode != 0:
|
|
200
|
+
hermes_setup.print_warning("The installed Inline CLI could not be verified.")
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
hermes_setup.print_success("Inline CLI installed successfully.")
|
|
204
|
+
return inline_bin
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _find_inline_cli() -> str | None:
|
|
208
|
+
discovered = shutil.which("inline")
|
|
209
|
+
if discovered:
|
|
210
|
+
return discovered
|
|
211
|
+
candidates = [
|
|
212
|
+
Path("/opt/homebrew/bin/inline"),
|
|
213
|
+
Path("/usr/local/bin/inline"),
|
|
214
|
+
Path.home() / ".local" / "bin" / "inline",
|
|
215
|
+
]
|
|
216
|
+
for candidate in candidates:
|
|
217
|
+
if candidate.is_file() and os.access(candidate, os.X_OK):
|
|
218
|
+
return str(candidate)
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
|
|
129
222
|
def _prompt_existing_token(hermes_setup) -> str | None:
|
|
130
223
|
print()
|
|
131
|
-
hermes_setup.print_info("
|
|
224
|
+
hermes_setup.print_info("Go to Inline → Settings → Bots → Create a new bot, then copy its token.")
|
|
132
225
|
hermes_setup.print_info("Guide: https://inline.chat/docs/creating-a-bot")
|
|
133
226
|
token = hermes_setup.prompt("Inline bot token", password=True).strip()
|
|
134
227
|
return token or None
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
name: inline-platform
|
|
2
2
|
label: Inline
|
|
3
3
|
kind: platform
|
|
4
|
-
version: 0.0.5-alpha.
|
|
4
|
+
version: 0.0.5-alpha.2
|
|
5
5
|
description: >
|
|
6
6
|
Inline platform adapter for Hermes Agent. The adapter runs as a native
|
|
7
7
|
Hermes Python platform plugin and supervises a local Node sidecar that uses
|