hermes-baiduapp 0.1.0__tar.gz
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.
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
lerna-debug.log*
|
|
8
|
+
|
|
9
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
10
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
11
|
+
|
|
12
|
+
# Runtime data
|
|
13
|
+
pids
|
|
14
|
+
*.pid
|
|
15
|
+
*.seed
|
|
16
|
+
*.pid.lock
|
|
17
|
+
|
|
18
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
19
|
+
lib-cov
|
|
20
|
+
|
|
21
|
+
# Coverage directory used by tools like istanbul
|
|
22
|
+
coverage
|
|
23
|
+
*.lcov
|
|
24
|
+
|
|
25
|
+
# nyc test coverage
|
|
26
|
+
.nyc_output
|
|
27
|
+
|
|
28
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
29
|
+
.grunt
|
|
30
|
+
|
|
31
|
+
# Bower dependency directory (https://bower.io/)
|
|
32
|
+
bower_components
|
|
33
|
+
|
|
34
|
+
# node-waf configuration
|
|
35
|
+
.lock-wscript
|
|
36
|
+
|
|
37
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
38
|
+
build/Release
|
|
39
|
+
|
|
40
|
+
# Dependency directories
|
|
41
|
+
node_modules/
|
|
42
|
+
jspm_packages/
|
|
43
|
+
|
|
44
|
+
# TypeScript v1 declaration files
|
|
45
|
+
typings/
|
|
46
|
+
|
|
47
|
+
# TypeScript cache
|
|
48
|
+
*.tsbuildinfo
|
|
49
|
+
|
|
50
|
+
# Optional npm cache directory
|
|
51
|
+
.npm
|
|
52
|
+
|
|
53
|
+
# Optional eslint cache
|
|
54
|
+
.eslintcache
|
|
55
|
+
|
|
56
|
+
# Microbundle cache
|
|
57
|
+
.rpt2_cache/
|
|
58
|
+
.rts2_cache_cjs/
|
|
59
|
+
.rts2_cache_es/
|
|
60
|
+
.rts2_cache_umd/
|
|
61
|
+
|
|
62
|
+
# Optional REPL history
|
|
63
|
+
.node_repl_history
|
|
64
|
+
|
|
65
|
+
# Output of 'npm pack'
|
|
66
|
+
*.tgz
|
|
67
|
+
|
|
68
|
+
# Yarn Integrity file
|
|
69
|
+
.yarn-integrity
|
|
70
|
+
|
|
71
|
+
# dotenv environment variables file
|
|
72
|
+
.env
|
|
73
|
+
.env.test
|
|
74
|
+
|
|
75
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
76
|
+
.cache
|
|
77
|
+
|
|
78
|
+
# Next.js build output
|
|
79
|
+
.next
|
|
80
|
+
|
|
81
|
+
# Nuxt.js build / generate output
|
|
82
|
+
.nuxt
|
|
83
|
+
dist
|
|
84
|
+
|
|
85
|
+
# Gatsby files
|
|
86
|
+
.cache/
|
|
87
|
+
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
|
88
|
+
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
89
|
+
# public
|
|
90
|
+
|
|
91
|
+
# vuepress build output
|
|
92
|
+
.vuepress/dist
|
|
93
|
+
|
|
94
|
+
# Serverless directories
|
|
95
|
+
.serverless/
|
|
96
|
+
|
|
97
|
+
# FuseBox cache
|
|
98
|
+
.fusebox/
|
|
99
|
+
|
|
100
|
+
# DynamoDB Local files
|
|
101
|
+
.dynamodb/
|
|
102
|
+
|
|
103
|
+
# TernJS port file
|
|
104
|
+
.tern-port
|
|
105
|
+
|
|
106
|
+
# mac
|
|
107
|
+
.DS_Store
|
|
108
|
+
|
|
109
|
+
log/
|
|
110
|
+
|
|
111
|
+
.env
|
|
112
|
+
|
|
113
|
+
node_modules.zip
|
|
114
|
+
|
|
115
|
+
output
|
|
116
|
+
|
|
117
|
+
# ReCode local database
|
|
118
|
+
.recode
|
|
119
|
+
|
|
120
|
+
CLAUDE.md
|
|
121
|
+
.sisyphus
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-baiduapp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Baidu App platform plugin for Hermes Agent (polling mode, no webhook)
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: baidu,chatbot,gateway,hermes,hermes-agent
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# hermes-baiduapp
|
|
11
|
+
|
|
12
|
+
Baidu App platform plugin for [Hermes Agent](https://github.com/NousResearch/hermes-agent).
|
|
13
|
+
|
|
14
|
+
Uses polling mode (`/channel/msg/poll`) to receive messages. No webhook required.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install hermes-baiduapp
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configure
|
|
23
|
+
|
|
24
|
+
Add to `~/.hermes/.env`:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
BAIDU_APP_KEY=your-app-key
|
|
28
|
+
BAIDU_APP_SECRET=your-app-secret
|
|
29
|
+
# Optional:
|
|
30
|
+
BAIDU_API_BASE=https://claw.baidu.com
|
|
31
|
+
GATEWAY_ALLOW_ALL_USERS=true
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then restart the gateway:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
hermes gateway run
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
No changes to `config.yaml` needed — the plugin is auto-discovered via entry_points.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# hermes-baiduapp
|
|
2
|
+
|
|
3
|
+
Baidu App platform plugin for [Hermes Agent](https://github.com/NousResearch/hermes-agent).
|
|
4
|
+
|
|
5
|
+
Uses polling mode (`/channel/msg/poll`) to receive messages. No webhook required.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install hermes-baiduapp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Configure
|
|
14
|
+
|
|
15
|
+
Add to `~/.hermes/.env`:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
BAIDU_APP_KEY=your-app-key
|
|
19
|
+
BAIDU_APP_SECRET=your-app-secret
|
|
20
|
+
# Optional:
|
|
21
|
+
BAIDU_API_BASE=https://claw.baidu.com
|
|
22
|
+
GATEWAY_ALLOW_ALL_USERS=true
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then restart the gateway:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
hermes gateway run
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
No changes to `config.yaml` needed — the plugin is auto-discovered via entry_points.
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import binascii
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import time
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
from urllib.parse import urlencode
|
|
10
|
+
from urllib.request import Request, urlopen
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
import secrets
|
|
14
|
+
except ImportError:
|
|
15
|
+
secrets = None
|
|
16
|
+
|
|
17
|
+
from gateway.config import Platform
|
|
18
|
+
from gateway.platforms.base import BasePlatformAdapter, MessageEvent, MessageType, SendResult
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
DEFAULT_API_BASE = "https://claw.baidu.com"
|
|
24
|
+
DEFAULT_SESSION_ID = "agent:main:main"
|
|
25
|
+
DEFAULT_POLL_INTERVAL = 3.0 # seconds
|
|
26
|
+
DEFAULT_POLL_TIMEOUT = 10.0 # seconds
|
|
27
|
+
PLUGIN_VERSION = "hermes-baiduapp/1.0.0"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _generate_nonce():
|
|
31
|
+
if secrets is not None:
|
|
32
|
+
return secrets.token_hex(8)
|
|
33
|
+
return binascii.hexlify(os.urandom(8)).decode("ascii")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _compute_aksk_token(ak, sk, timestamp, nonce):
|
|
37
|
+
return hashlib.sha1((ak + sk + timestamp + nonce).encode()).hexdigest()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build_authorization_header(ak, sk, timestamp, nonce):
|
|
41
|
+
token = _compute_aksk_token(ak, sk, timestamp, nonce)
|
|
42
|
+
return "Bearer {token}".format(token=token)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _coerce_float(value, default):
|
|
46
|
+
try:
|
|
47
|
+
return float(value)
|
|
48
|
+
except (TypeError, ValueError):
|
|
49
|
+
return default
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _coerce_poll_interval(extra):
|
|
53
|
+
env_ms = os.getenv("BAIDU_POLL_INTERVAL_MS")
|
|
54
|
+
if env_ms:
|
|
55
|
+
interval_ms = _coerce_float(env_ms, DEFAULT_POLL_INTERVAL * 1000)
|
|
56
|
+
return max(interval_ms / 1000.0, 0.1)
|
|
57
|
+
|
|
58
|
+
if "poll_interval" in extra:
|
|
59
|
+
return max(_coerce_float(extra.get("poll_interval"), DEFAULT_POLL_INTERVAL), 0.1)
|
|
60
|
+
|
|
61
|
+
if "poll_interval_ms" in extra:
|
|
62
|
+
interval_ms = _coerce_float(extra.get("poll_interval_ms"), DEFAULT_POLL_INTERVAL * 1000)
|
|
63
|
+
return max(interval_ms / 1000.0, 0.1)
|
|
64
|
+
|
|
65
|
+
return DEFAULT_POLL_INTERVAL
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _extract_text_from_list(items):
|
|
69
|
+
texts = []
|
|
70
|
+
if not isinstance(items, list):
|
|
71
|
+
return ""
|
|
72
|
+
|
|
73
|
+
for item in items:
|
|
74
|
+
if not isinstance(item, dict) or item.get("type") != "text":
|
|
75
|
+
continue
|
|
76
|
+
raw_data = item.get("data")
|
|
77
|
+
data = raw_data if isinstance(raw_data, dict) else {}
|
|
78
|
+
raw_text = data.get("text")
|
|
79
|
+
text_data = raw_text if isinstance(raw_text, dict) else {}
|
|
80
|
+
content = text_data.get("content")
|
|
81
|
+
if isinstance(content, str) and content:
|
|
82
|
+
texts.append(content)
|
|
83
|
+
|
|
84
|
+
return "\n".join(texts).strip()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class BaiduAppAdapter(BasePlatformAdapter):
|
|
88
|
+
"""Polling adapter for the Baidu App V2 channel API."""
|
|
89
|
+
|
|
90
|
+
def __init__(self, config, **kwargs):
|
|
91
|
+
super().__init__(config=config, platform=Platform("baiduapp"))
|
|
92
|
+
|
|
93
|
+
extra = getattr(config, "extra", {}) or {}
|
|
94
|
+
self.app_key = os.getenv("BAIDU_APP_KEY") or extra.get("app_key") or extra.get("appKey") or ""
|
|
95
|
+
self.app_secret = os.getenv("BAIDU_APP_SECRET") or extra.get("app_secret") or extra.get("appSecret") or ""
|
|
96
|
+
self.api_base = (os.getenv("BAIDU_API_BASE") or extra.get("api_base") or extra.get("apiBase") or DEFAULT_API_BASE).rstrip("/")
|
|
97
|
+
self.poll_interval = _coerce_poll_interval(extra)
|
|
98
|
+
self.request_timeout = _coerce_float(extra.get("request_timeout"), DEFAULT_POLL_TIMEOUT)
|
|
99
|
+
self.session_id = extra.get("session_id") or extra.get("sessionId") or DEFAULT_SESSION_ID
|
|
100
|
+
self._poll_task: Optional[asyncio.Task] = None
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def name(self) -> str:
|
|
104
|
+
return "Baidu App"
|
|
105
|
+
|
|
106
|
+
async def connect(self) -> bool:
|
|
107
|
+
if not self.app_key or not self.app_secret:
|
|
108
|
+
logger.error("Baidu App: BAIDU_APP_KEY and BAIDU_APP_SECRET must be configured")
|
|
109
|
+
self._set_fatal_error(
|
|
110
|
+
"config_missing",
|
|
111
|
+
"BAIDU_APP_KEY and BAIDU_APP_SECRET must be configured",
|
|
112
|
+
retryable=False,
|
|
113
|
+
)
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
if self._poll_task is None or self._poll_task.done():
|
|
117
|
+
self._poll_task = asyncio.create_task(self._poll_loop())
|
|
118
|
+
self._mark_connected()
|
|
119
|
+
logger.info("Baidu App: connected using polling interval %.1fs", self.poll_interval)
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
async def disconnect(self) -> None:
|
|
123
|
+
self._mark_disconnected()
|
|
124
|
+
if self._poll_task and not self._poll_task.done():
|
|
125
|
+
self._poll_task.cancel()
|
|
126
|
+
try:
|
|
127
|
+
await self._poll_task
|
|
128
|
+
except asyncio.CancelledError:
|
|
129
|
+
pass
|
|
130
|
+
self._poll_task = None
|
|
131
|
+
|
|
132
|
+
async def send(
|
|
133
|
+
self,
|
|
134
|
+
chat_id: str,
|
|
135
|
+
content: str,
|
|
136
|
+
reply_to: Optional[str] = None,
|
|
137
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
138
|
+
):
|
|
139
|
+
body = {
|
|
140
|
+
"sessionId": self.session_id,
|
|
141
|
+
"list": [{"type": "text", "data": {"text": {"content": content}}}],
|
|
142
|
+
"version": PLUGIN_VERSION,
|
|
143
|
+
"isActive": True,
|
|
144
|
+
}
|
|
145
|
+
try:
|
|
146
|
+
response = await self._post_json("/channel/msg/callback", body)
|
|
147
|
+
except asyncio.CancelledError:
|
|
148
|
+
raise
|
|
149
|
+
except Exception as exc:
|
|
150
|
+
logger.warning("Baidu App: send failed: %s", exc)
|
|
151
|
+
return SendResult(success=False, error=str(exc), retryable=True)
|
|
152
|
+
|
|
153
|
+
if response.get("code") != 0:
|
|
154
|
+
error = response.get("msg") or response.get("message") or "channel callback failed"
|
|
155
|
+
return SendResult(success=False, error=str(error), raw_response=response)
|
|
156
|
+
|
|
157
|
+
raw_data = response.get("data")
|
|
158
|
+
data = raw_data if isinstance(raw_data, dict) else {}
|
|
159
|
+
message_id = data.get("msgId") or data.get("messageId") or str(int(time.time() * 1000))
|
|
160
|
+
return SendResult(success=True, message_id=str(message_id), raw_response=response)
|
|
161
|
+
|
|
162
|
+
async def send_typing(self, chat_id: str, metadata=None) -> None:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
async def get_chat_info(self, chat_id: str) -> Dict[str, Any]:
|
|
166
|
+
return {"name": chat_id, "type": "dm", "chat_id": chat_id}
|
|
167
|
+
|
|
168
|
+
async def _poll_loop(self):
|
|
169
|
+
try:
|
|
170
|
+
while True:
|
|
171
|
+
try:
|
|
172
|
+
await self._poll_once()
|
|
173
|
+
except asyncio.CancelledError:
|
|
174
|
+
raise
|
|
175
|
+
except Exception as exc:
|
|
176
|
+
logger.warning("Baidu App: poll cycle failed: %s", exc)
|
|
177
|
+
await asyncio.sleep(self.poll_interval)
|
|
178
|
+
except asyncio.CancelledError:
|
|
179
|
+
raise
|
|
180
|
+
|
|
181
|
+
async def _poll_once(self):
|
|
182
|
+
body = {"sessionId": self.session_id, "num": 5, "version": PLUGIN_VERSION}
|
|
183
|
+
response = await self._post_json("/channel/msg/poll", body)
|
|
184
|
+
if response.get("code") != 0:
|
|
185
|
+
logger.debug(
|
|
186
|
+
"Baidu App: poll returned non-zero code=%s message=%s",
|
|
187
|
+
response.get("code"),
|
|
188
|
+
response.get("message") or response.get("msg"),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
raw_data = response.get("data")
|
|
192
|
+
data = raw_data if isinstance(raw_data, dict) else {}
|
|
193
|
+
raw_msg_list = data.get("msgList")
|
|
194
|
+
msg_list = raw_msg_list if isinstance(raw_msg_list, list) else []
|
|
195
|
+
for msg in msg_list:
|
|
196
|
+
if isinstance(msg, dict):
|
|
197
|
+
await self._dispatch_poll_message(msg)
|
|
198
|
+
|
|
199
|
+
async def _dispatch_poll_message(self, msg):
|
|
200
|
+
text = _extract_text_from_list(msg.get("list"))
|
|
201
|
+
if not text:
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
message_id = msg.get("msgId") or str(int(time.time() * 1000))
|
|
205
|
+
raw_from = msg.get("from")
|
|
206
|
+
from_info = raw_from if isinstance(raw_from, dict) else {}
|
|
207
|
+
user_id = from_info.get("uid") or "baiduapp-user"
|
|
208
|
+
user_name = from_info.get("name") or str(user_id)
|
|
209
|
+
chat_id = msg.get("sessionId") or self.session_id
|
|
210
|
+
|
|
211
|
+
source = self.build_source(
|
|
212
|
+
chat_id=chat_id,
|
|
213
|
+
chat_name=chat_id,
|
|
214
|
+
chat_type="dm",
|
|
215
|
+
user_id=str(user_id),
|
|
216
|
+
user_name=user_name,
|
|
217
|
+
message_id=str(message_id),
|
|
218
|
+
)
|
|
219
|
+
event = MessageEvent(
|
|
220
|
+
text=text,
|
|
221
|
+
message_type=MessageType.TEXT,
|
|
222
|
+
source=source,
|
|
223
|
+
raw_message=msg,
|
|
224
|
+
message_id=str(message_id),
|
|
225
|
+
)
|
|
226
|
+
await self.handle_message(event)
|
|
227
|
+
|
|
228
|
+
async def _post_json(self, path, body):
|
|
229
|
+
timestamp = str(int(time.time()))
|
|
230
|
+
nonce = _generate_nonce()
|
|
231
|
+
query = urlencode({"ak": self.app_key, "timestamp": timestamp, "nonce": nonce})
|
|
232
|
+
url = "%s%s?%s" % (self.api_base, path, query)
|
|
233
|
+
headers = {
|
|
234
|
+
"Authorization": build_authorization_header(self.app_key, self.app_secret, timestamp, nonce),
|
|
235
|
+
"Content-Type": "application/json",
|
|
236
|
+
}
|
|
237
|
+
payload = json.dumps(body).encode("utf-8")
|
|
238
|
+
loop = asyncio.get_running_loop()
|
|
239
|
+
return await loop.run_in_executor(None, self._post_json_sync, url, headers, payload)
|
|
240
|
+
|
|
241
|
+
def _post_json_sync(self, url, headers, payload):
|
|
242
|
+
request = Request(url, data=payload, headers=headers, method="POST")
|
|
243
|
+
with urlopen(request, timeout=self.request_timeout) as response:
|
|
244
|
+
response_text = response.read().decode("utf-8")
|
|
245
|
+
if not response_text:
|
|
246
|
+
raise ValueError("empty response from Baidu App API")
|
|
247
|
+
try:
|
|
248
|
+
return json.loads(response_text)
|
|
249
|
+
except ValueError as exc:
|
|
250
|
+
raise ValueError("invalid JSON response from Baidu App API") from exc
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def check_requirements():
|
|
254
|
+
return bool(os.getenv("BAIDU_APP_KEY") and os.getenv("BAIDU_APP_SECRET"))
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def validate_config(config) -> bool:
|
|
258
|
+
extra = getattr(config, "extra", {}) or {}
|
|
259
|
+
app_key = os.getenv("BAIDU_APP_KEY") or extra.get("app_key") or extra.get("appKey")
|
|
260
|
+
app_secret = os.getenv("BAIDU_APP_SECRET") or extra.get("app_secret") or extra.get("appSecret")
|
|
261
|
+
return bool(app_key and app_secret)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def is_connected(config) -> bool:
|
|
265
|
+
return validate_config(config)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _env_enablement():
|
|
269
|
+
app_key = os.getenv("BAIDU_APP_KEY", "").strip()
|
|
270
|
+
app_secret = os.getenv("BAIDU_APP_SECRET", "").strip()
|
|
271
|
+
if not (app_key and app_secret):
|
|
272
|
+
return None
|
|
273
|
+
return {
|
|
274
|
+
"app_key": app_key,
|
|
275
|
+
"api_base": os.getenv("BAIDU_API_BASE", DEFAULT_API_BASE).strip(),
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def register(ctx):
|
|
280
|
+
ctx.register_platform(
|
|
281
|
+
name="baiduapp",
|
|
282
|
+
label="Baidu App",
|
|
283
|
+
adapter_factory=lambda cfg: BaiduAppAdapter(cfg),
|
|
284
|
+
check_fn=check_requirements,
|
|
285
|
+
validate_config=validate_config,
|
|
286
|
+
is_connected=is_connected,
|
|
287
|
+
required_env=["BAIDU_APP_KEY", "BAIDU_APP_SECRET"],
|
|
288
|
+
install_hint="Configure BAIDU_APP_KEY and BAIDU_APP_SECRET in ~/.hermes/.env",
|
|
289
|
+
env_enablement_fn=_env_enablement,
|
|
290
|
+
allowed_users_env="BAIDU_ALLOWED_USERS",
|
|
291
|
+
allow_all_env="BAIDU_ALLOW_ALL_USERS",
|
|
292
|
+
platform_hint=(
|
|
293
|
+
"You are chatting via Baidu App. "
|
|
294
|
+
"Use plain text or markdown. "
|
|
295
|
+
"Keep responses concise."
|
|
296
|
+
),
|
|
297
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hermes-baiduapp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Baidu App platform plugin for Hermes Agent (polling mode, no webhook)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
keywords = ["hermes", "hermes-agent", "baidu", "chatbot", "gateway"]
|
|
13
|
+
|
|
14
|
+
[project.entry-points."hermes.plugins"]
|
|
15
|
+
baiduapp = "hermes_baiduapp"
|