@bulolo/hermes-link 0.3.0 → 0.3.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 CHANGED
@@ -1,6 +1,31 @@
1
- # @bulolo/hermes-link
1
+ <div align="center">
2
2
 
3
- 本地伴随服务,为 [Hermes Agent](https://github.com/nousresearch/hermes-agent) 提供 API 接入能力,支持公网、局域网直连。
3
+ # hermes-link
4
+
5
+ **Hermes Agent 本地接入层**
6
+
7
+ 为 [Hermes Agent](https://github.com/nousresearch/hermes-agent) 提供完整的客户端 API、多设备鉴权与对话管理,支持局域网 / 公网直连。
8
+
9
+ [![npm](https://img.shields.io/npm/v/@bulolo/hermes-link?color=cb3837&logo=npm)](https://www.npmjs.com/package/@bulolo/hermes-link)
10
+ [![Node](https://img.shields.io/badge/Node.js-%3E%3D20-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
11
+ [![License](https://img.shields.io/badge/License-MIT-blue)](#)
12
+ [![Platform](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey)](#)
13
+
14
+ 简体中文 | [English](./README.en.md)
15
+
16
+ [npm 包](https://www.npmjs.com/package/@bulolo/hermes-link)
17
+
18
+ <p>
19
+ <a href="https://github.com/bulolo/HermesLink">
20
+ <img src="https://img.shields.io/badge/⭐_Star-项目-yellow?style=for-the-badge&logo=github" alt="Star 项目"/>
21
+ </a>
22
+ </p>
23
+
24
+ **如果这个项目对你有帮助,请点击右上角 ⭐ Star 支持一下,这是对开发者最大的鼓励!**
25
+
26
+ </div>
27
+
28
+ ---
4
29
 
5
30
  ## 概述
6
31
 
@@ -9,7 +34,7 @@ Hermes Link 是一个运行在本机的后台 HTTP 服务,默认监听 `http:/
9
34
  所有 API 请求分为两类:
10
35
 
11
36
  - **无需鉴权**:`/pair`、`/api/v1/bootstrap`
12
- - **需要 Bearer Token**:其余接口均需 `Authorization: Bearer hpat_xxx`,通过配对流程获取
37
+ - **需要 Bearer Token**:其余接口均需 `Authorization: Bearer hlat_xxx`,通过配对流程获取
13
38
 
14
39
  ## 为什么需要 HermesLink?
15
40
 
@@ -190,7 +215,7 @@ curl -s -X POST http://localhost:18642/api/v1/auth/device-session \
190
215
 
191
216
  ---
192
217
 
193
- > **Token 有效期**:access_token 15 分钟,refresh_token 90 天。access_token 过期后用 refresh_token 换新,无需重新配对。
218
+ > **Token 有效期**:access_token 2 小时,refresh_token 90 天。access_token 过期后用 refresh_token 换新,无需重新配对。
194
219
 
195
220
  ## 命令一览
196
221
 
@@ -223,15 +248,15 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
223
248
 
224
249
  ## API 参考
225
250
 
226
- 服务默认监听 `http://0.0.0.0:18642`。所有需要鉴权的接口均使用 Bearer Token(`hpat_` 前缀)。
251
+ 服务默认监听 `http://0.0.0.0:18642`。所有需要鉴权的接口均使用 Bearer Token(`hlat_` 前缀)。
227
252
 
228
253
  ### Token 说明
229
254
 
230
255
  | Token | 前缀 | 有效期 | 用途 |
231
256
  |-------|------|--------|------|
232
257
  | Connect Token | 无前缀(base64url)| 5 分钟,一次性 | 兑换 access_token |
233
- | Access Token | `hpat_` | 15 分钟 | 所有 API 请求 |
234
- | Refresh Token | `hprt_` | 90 天 | 刷新 access_token |
258
+ | Access Token | `hlat_` | 2 小时 | 所有 API 请求 |
259
+ | Refresh Token | `hlrt_` | 90 天 | 刷新 access_token |
235
260
 
236
261
  ### 无需鉴权
237
262
 
@@ -242,7 +267,7 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
242
267
 
243
268
  ### 认证 / 设备
244
269
 
245
- 所有以下接口需要 Header:`Authorization: Bearer hpat_xxx`
270
+ 所有以下接口需要 Header:`Authorization: Bearer hlat_xxx`
246
271
 
247
272
  | 方法 | 路径 | 说明 |
248
273
  |------|------|------|
@@ -251,7 +276,7 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
251
276
  | POST | `/api/v1/auth/refresh` | 用 refresh_token 换新 access_token |
252
277
  | POST | `/api/v1/auth/logout` | 撤销 refresh_token |
253
278
 
254
- **POST `/api/v1/auth/device-session`** 的 Authorization 头需放 **connect_token**(不是 hpat_),Body:
279
+ **POST `/api/v1/auth/device-session`** 的 Authorization 头需放 **connect_token**(不是 hlat_),Body:
255
280
 
256
281
  ```json
257
282
  {
@@ -267,15 +292,15 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
267
292
  {
268
293
  "ok": true,
269
294
  "device": { "device_id": "dev_xxx", "label": "我的设备", "platform": "ios" },
270
- "access_token": { "token": "hpat_xxx", "expires_at": "2026-05-08T13:00:00Z" },
271
- "refresh_token": { "token": "hprt_xxx", "expires_at": "2026-08-06T12:00:00Z" }
295
+ "access_token": { "token": "hlat_xxx", "expires_at": "2026-05-08T13:00:00Z" },
296
+ "refresh_token": { "token": "hlrt_xxx", "expires_at": "2026-08-06T12:00:00Z" }
272
297
  }
273
298
  ```
274
299
 
275
300
  **POST `/api/v1/auth/refresh`** Body:
276
301
 
277
302
  ```json
278
- { "refresh_token": "hprt_xxx" }
303
+ { "refresh_token": "hlrt_xxx" }
279
304
  ```
280
305
 
281
306
  ### 配对
@@ -316,38 +341,144 @@ hermeslink config set log-level debug # 日志级别:debug / info / wa
316
341
 
317
342
  ### 对话(Conversations)
318
343
 
344
+ #### 活跃对话
345
+
319
346
  | 方法 | 路径 | 说明 |
320
347
  |------|------|------|
321
- | GET | `/api/v1/conversations` | 列出所有对话(`?limit=20&cursor=xxx`) |
322
- | GET | `/api/v1/conversations/search` | 搜索对话(`?q=关键词`) |
348
+ | GET | `/api/v1/conversations` | 列出活跃对话(`?limit=20&cursor=xxx`) |
349
+ | GET | `/api/v1/conversations/search` | 搜索活跃对话(`?q=关键词`) |
323
350
  | POST | `/api/v1/conversations` | 新建对话 |
324
- | DELETE | `/api/v1/conversations` | 批量删除对话 |
351
+ | DELETE | `/api/v1/conversations` | 批量删除对话(`{"conversation_ids":["conv_xxx"]}`) |
325
352
  | DELETE | `/api/v1/conversations/:id` | 删除单个对话 |
326
- | GET | `/api/v1/conversations/:id/messages` | 获取对话消息列表 |
353
+ | GET | `/api/v1/conversations/:id/messages` | 获取对话消息列表(含 `runtime` 上下文信息) |
327
354
  | POST | `/api/v1/conversations/:id/messages` | 发送消息 |
328
355
  | GET | `/api/v1/conversations/:id/events` | SSE 实时事件流 |
329
356
  | GET | `/api/v1/conversations/events` | 所有对话事件流(SSE) |
330
357
  | PATCH | `/api/v1/conversations/:id/title` | 重命名对话(`{"title":"新标题"}`) |
331
- | PATCH | `/api/v1/conversations/:id/model` | 切换模型 |
358
+ | PATCH | `/api/v1/conversations/:id/model` | 切换模型(`{"model_id":"xxx"}`) |
332
359
  | PATCH | `/api/v1/conversations/:id/profile` | 切换 profile |
333
360
  | POST | `/api/v1/conversations/:id/ack` | 确认已读 |
334
- | POST | `/api/v1/conversations/clear-plans` | 创建批量清理计划 |
335
- | GET | `/api/v1/conversations/clear-plans/:planId` | 查询清理计划状态 |
336
- | POST | `/api/v1/conversations/clear-plans/:planId/execute` | 执行清理计划 |
337
361
  | POST | `/api/v1/conversations/:id/runs/:runId/cancel` | 取消对话内的某次执行 |
338
- | POST | `/api/v1/conversations/:id/approvals/:approvalId/approve` | 审批工具调用(允许) |
362
+ | POST | `/api/v1/conversations/:id/approvals/:approvalId/approve` | 审批工具调用(允许,`{"scope":"once\|session\|always"}`) |
339
363
  | POST | `/api/v1/conversations/:id/approvals/:approvalId/deny` | 审批工具调用(拒绝) |
340
364
  | POST | `/api/v1/conversations/:id/blobs` | 上传附件 |
341
365
  | GET | `/api/v1/conversations/:id/blobs/:blobId` | 下载附件 |
342
366
  | DELETE | `/api/v1/conversations/:id/blobs/:blobId` | 删除附件 |
343
367
 
368
+ #### 归档对话
369
+
370
+ | 方法 | 路径 | 说明 |
371
+ |------|------|------|
372
+ | GET | `/api/v1/conversations/archived` | 列出已归档对话(`?limit=20&cursor=xxx`) |
373
+ | GET | `/api/v1/conversations/archived/search` | 搜索已归档对话(`?q=关键词`) |
374
+ | POST | `/api/v1/conversations/:id/archive` | 归档对话(发送新消息时自动恢复为活跃) |
375
+ | POST | `/api/v1/conversations/:id/unarchive` | 取消归档 |
376
+
377
+ #### 批量清理计划
378
+
379
+ | 方法 | 路径 | 说明 |
380
+ |------|------|------|
381
+ | POST | `/api/v1/conversations/clear-plans` | 创建批量删除计划(`{"target_status":"active\|archived"}`) |
382
+ | GET | `/api/v1/conversations/clear-plans/:planId` | 查询计划状态 |
383
+ | POST | `/api/v1/conversations/clear-plans/:planId/execute` | 执行计划(批量删除) |
384
+
385
+ #### 批量归档计划
386
+
387
+ | 方法 | 路径 | 说明 |
388
+ |------|------|------|
389
+ | POST | `/api/v1/conversations/archive-plans` | 创建批量归档计划(`{"exclude_conversation_ids":[]}`) |
390
+ | GET | `/api/v1/conversations/archive-plans/:planId` | 查询计划状态 |
391
+ | POST | `/api/v1/conversations/archive-plans/:planId/execute` | 执行计划(批量归档) |
392
+
393
+ #### 响应结构说明
394
+
395
+ **ConversationSummary**(对话列表每项):
396
+
397
+ ```json
398
+ {
399
+ "id": "conv_xxx",
400
+ "title": "对话标题",
401
+ "created_at": "2026-05-09T00:00:00.000Z",
402
+ "updated_at": "2026-05-09T00:00:00.000Z",
403
+ "last_event_seq": 12,
404
+ "usage": { "input_tokens": 100, "output_tokens": 200, "total_tokens": 300, "updated_at": "..." },
405
+ "profile": { "uid": "prof_xxx", "name": "default", "display_name": "default", "avatar_url": null },
406
+ "last_message": { "id": "msg_xxx", "role": "assistant", "content_preview": "消息摘要..." }
407
+ }
408
+ ```
409
+
410
+ **GET `/api/v1/conversations/:id/messages`** 响应新增 `runtime` 字段:
411
+
412
+ ```json
413
+ {
414
+ "ok": true,
415
+ "messages": [...],
416
+ "last_event_seq": 12,
417
+ "runtime": {
418
+ "profile": { "name": "default", "display_name": "default", "avatar_url": null },
419
+ "model": { "id": "claude-3-5-sonnet", "provider": "anthropic", "context_window": 200000 },
420
+ "context": { "input_tokens": 100, "output_tokens": 200, "total_tokens": 300, "usage_percent": 0, "source": "estimated" }
421
+ },
422
+ "page": { "limit": 50, "has_more_before": false, "has_more_after": false, "oldest_message_id": "...", "newest_message_id": "..." }
423
+ }
424
+ ```
425
+
426
+ **LinkMessage**(消息对象):
427
+
428
+ ```json
429
+ {
430
+ "id": "msg_xxx",
431
+ "schema_version": 1,
432
+ "conversation_id": "conv_xxx",
433
+ "role": "user|assistant|tool|system",
434
+ "status": "queued|streaming|completed|failed|cancelled",
435
+ "created_at": "...",
436
+ "updated_at": "...",
437
+ "sender": { "id": "app_user", "type": "human|agent|system|tool", "display_name": "Me" },
438
+ "parts": [{ "type": "text", "text": "消息内容" }],
439
+ "attachments": [],
440
+ "blocks": [],
441
+ "agent_events": [],
442
+ "approvals": []
443
+ }
444
+ ```
445
+
446
+ **DELETE `/api/v1/conversations/:id`** 响应新增字段:
447
+
448
+ ```json
449
+ {
450
+ "ok": true,
451
+ "conversation_id": "conv_xxx",
452
+ "hermes_deleted": false,
453
+ "deleted_at": "2026-05-09T00:00:00.000Z"
454
+ }
455
+ ```
456
+
344
457
  ### 统计
345
458
 
346
459
  | 方法 | 路径 | 说明 |
347
460
  |------|------|------|
348
- | GET | `/api/v1/statistics` | 全局使用统计(对话、消息数等) |
461
+ | GET | `/api/v1/statistics` | 全局使用统计(`?profile=xxx&profile_uid=xxx`) |
349
462
  | GET | `/api/v1/statistics/usage` | Token 用量统计(`?days=7&from=2026-05-01&to=2026-05-08&model=xxx&profile=xxx`) |
350
463
 
464
+ **GET `/api/v1/statistics`** 响应:
465
+
466
+ ```json
467
+ {
468
+ "ok": true,
469
+ "statistics": {
470
+ "conversations": { "total": 10, "active": 8, "archived": 1, "deleted": 1 },
471
+ "tokens": { "input_tokens": 5000, "output_tokens": 8000, "total_tokens": 13000 },
472
+ "messages": { "total": 120 },
473
+ "runs": { "total": 50 },
474
+ "models": { "total": 0 },
475
+ "profiles": { "total": 0 },
476
+ "skills": { "total": 0 },
477
+ "tools": { "total": 0 }
478
+ }
479
+ }
480
+ ```
481
+
351
482
  ### 模型(Models)
352
483
 
353
484
  | 方法 | 路径 | 说明 |