@signetai/connector-hermes-agent 0.226.14 → 0.226.16

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAuB,MAAM,wBAAwB,CAAC;AAoDtH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAiuBD,qBAAa,oBAAqB,SAAQ,aAAa;IACtD,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,SAAS,kBAAkB;IAEpC,YAAY,IAAI,MAAM;IAItB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAwB;gBAEpC,MAAM,CAAC,EAAE,qBAAqB;IAK1C,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,aAAa;IAKrB,aAAa,IAAI,MAAM;IAIjB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,aAAa,CAAC;IA6MvF,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IA4D3C,WAAW,IAAI,OAAO;IAQhB,QAAQ,IAAI,OAAO,CAAC,kBAAkB,CAAC;CAS7C;AAED,wBAAsB,yBAAyB,CAAC,IAAI,CAAC,EAAE;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuG9B;AAED,wBAAgB,eAAe,IAAI,oBAAoB,CAEtD;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAuB,MAAM,wBAAwB,CAAC;AAqCtH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAwsBD,qBAAa,oBAAqB,SAAQ,aAAa;IACtD,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,SAAS,kBAAkB;IAEpC,YAAY,IAAI,MAAM;IAItB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAwB;gBAEpC,MAAM,CAAC,EAAE,qBAAqB;IAK1C,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,aAAa;IAKrB,aAAa,IAAI,MAAM;IAIjB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,aAAa,CAAC;IA6LvF,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IA2D3C,WAAW,IAAI,OAAO;IAQhB,QAAQ,IAAI,OAAO,CAAC,kBAAkB,CAAC;CAS7C;AAED,wBAAsB,yBAAyB,CAAC,IAAI,CAAC,EAAE;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuG9B;AAED,wBAAgB,eAAe,IAAI,oBAAoB,CAEtD;AAED,eAAe,oBAAoB,CAAC"}
@@ -58,10 +58,6 @@ def _strip_internal_memory_context(value: str) -> str:
58
58
  return _INTERNAL_MEMORY_CLOSE_RE.sub("", _INTERNAL_MEMORY_BLOCK_RE.sub("", value))
59
59
 
60
60
 
61
- # ---------------------------------------------------------------------------
62
- # Tool schemas
63
- # ---------------------------------------------------------------------------
64
-
65
61
  MEMORY_SEARCH_SCHEMA = {
66
62
  "name": "memory_search",
67
63
  "description": (
@@ -117,10 +113,6 @@ MEMORY_SEARCH_SCHEMA = {
117
113
  }
118
114
 
119
115
  SESSION_SEARCH_SCHEMA = {
120
- # Hermes reserves `session_search` as a built-in core tool name;
121
- # registering under that name would be silently dropped by
122
- # `MemoryManager.add_provider`. The Signet provider exposes the
123
- # transcript-search tool under the `signet_` namespace instead.
124
116
  "name": "signet_session_search",
125
117
  "description": "Search active or completed Signet session transcripts.",
126
118
  "parameters": {
@@ -336,23 +328,16 @@ def _resolve_agent_workspace(agent_id: str, kwargs: Dict[str, Any]) -> str:
336
328
  return str(Path(str(fallback)).expanduser())
337
329
 
338
330
 
339
- # ---------------------------------------------------------------------------
340
- # MemoryProvider implementation
341
- # ---------------------------------------------------------------------------
342
-
343
331
  class SignetMemoryProvider(MemoryProvider):
344
332
  """Signet persistent memory with hybrid search and knowledge graph."""
345
333
 
346
334
  def __init__(self):
347
- self._client = None # SignetClient
335
+ self._client = None
348
336
  self._agent_id = ""
349
337
  self._session_key = ""
350
338
  self._project = ""
351
339
  self._inject_cache = ""
352
340
  self._inject_lock = threading.Lock()
353
- # Session-start dynamic context is kept separate from the ordinary
354
- # per-turn result. queue_prefetch() clears the latter before starting
355
- # a new recall, but must not erase the first API-only context block.
356
341
  self._session_prefetch_result = ""
357
342
  self._prefetch_result = ""
358
343
  self._notification_result = ""
@@ -367,13 +352,9 @@ class SignetMemoryProvider(MemoryProvider):
367
352
  self._identity: Optional[Dict[str, Any]] = None
368
353
  self._warnings: List[str] = []
369
354
  self._session_initialized = False
370
- # Checkpoint: extract mid-session every N turns
371
355
  _CHECKPOINT_INTERVAL = 30
372
356
  self._checkpoint_interval = _CHECKPOINT_INTERVAL
373
357
  self._last_checkpoint_turn = 0
374
- # Hermes calls on_memory_write once per committed operation, including
375
- # once for each operation in an atomic batch. Keep one FIFO worker so
376
- # replace/remove cannot overtake the add that established their target.
377
358
  self._mirror_queue: Queue = Queue()
378
359
  self._mirror_worker: Optional[threading.Thread] = None
379
360
  self._mirror_state_lock = threading.Lock()
@@ -435,24 +416,17 @@ class SignetMemoryProvider(MemoryProvider):
435
416
 
436
417
  agent_id = os.environ.get("SIGNET_AGENT_ID", "").strip()
437
418
  if agent_id == "hermes-agent":
438
- # The harness name is provenance, never an agent scope. A stale
439
- # value from an older connector install is healed by letting the
440
- # daemon resolve the workspace's configured agent instead.
441
419
  logger.warning(
442
420
  "SIGNET_AGENT_ID='hermes-agent' is the harness name, not an agent scope; "
443
421
  "the daemon's configured agent will be used instead."
444
422
  )
445
423
  agent_id = ""
446
424
  if not agent_id:
447
- # No explicit agent id: the daemon resolves its configured agent
448
- # (its own SIGNET_AGENT_ID, or 'default' for the default workspace).
449
425
  logger.debug("SIGNET_AGENT_ID is not set; the daemon's configured agent scope applies.")
450
426
 
451
427
  self._agent_id = agent_id
452
428
  with self._mirror_state_lock:
453
429
  self._mirror_shutdown = False
454
-
455
- # Skip for cron/flush contexts — no memory injection needed
456
430
  agent_context = kwargs.get("agent_context", "")
457
431
  platform = kwargs.get("platform", "cli")
458
432
  if agent_context in ("cron", "flush") or platform == "cron":
@@ -468,8 +442,6 @@ class SignetMemoryProvider(MemoryProvider):
468
442
 
469
443
  self._session_key = session_id or "hermes-default"
470
444
  self._project = _resolve_agent_workspace(agent_id, kwargs)
471
-
472
- # Call session-start hook — get identity + memories + split context
473
445
  result = self._client.session_start(
474
446
  self._session_key,
475
447
  project=self._project,
@@ -486,7 +458,6 @@ class SignetMemoryProvider(MemoryProvider):
486
458
  self._session_prefetch_result = dynamic_context if isinstance(dynamic_context, str) else ""
487
459
  self._prefetch_result = ""
488
460
  self._notification_result = ""
489
- # Capture identity and warnings for downstream consumers
490
461
  self._identity = result.get("identity")
491
462
  self._warnings = result.get("warnings", [])
492
463
  self._session_initialized = True
@@ -511,12 +482,9 @@ class SignetMemoryProvider(MemoryProvider):
511
482
 
512
483
  with self._inject_lock:
513
484
  if self._inject_cache:
514
- # First call — return the stable prefix and clear the cache.
515
485
  block = self._inject_cache
516
486
  self._inject_cache = ""
517
487
  return block
518
-
519
- # Subsequent calls — minimal header
520
488
  return (
521
489
  "# Signet Memory\n"
522
490
  "Active. Memories are auto-recalled each turn via hybrid search. "
@@ -566,14 +534,8 @@ class SignetMemoryProvider(MemoryProvider):
566
534
  """
567
535
  if not self._client or not query:
568
536
  return
569
-
570
- # Accumulate transcript for checkpoint/session-end
571
537
  with self._transcript_lock:
572
538
  self._transcript_lines.append(f"user: {_strip_internal_memory_context(query)}")
573
-
574
- # Capture mutable state before spawning the thread to avoid
575
- # data races: sync_turn() can update _last_assistant_message
576
- # concurrently, and shutdown() can null _client.
577
539
  client = self._client
578
540
  last_assistant = self._last_assistant_message
579
541
  with self._prefetch_lock:
@@ -593,15 +555,9 @@ class SignetMemoryProvider(MemoryProvider):
593
555
  project=project,
594
556
  )
595
557
  if result:
596
- # Handle daemon restart detection by restoring only the runtime
597
- # claim. The initial system prompt is already part of this
598
- # conversation; injecting session-start context again would mutate
599
- # the cached prefix mid-conversation.
600
558
  if not result.get("sessionKnown", True) and self._session_initialized:
601
559
  logger.debug("Signet daemon restarted mid-session, restoring session claim")
602
560
  with self._prefetch_lock:
603
- # Do not replay a pre-restart session-start block
604
- # into an already-running Hermes conversation.
605
561
  self._session_prefetch_result = ""
606
562
  reinit = client.session_start(
607
563
  session_key, project=project, claim_only=True,
@@ -625,9 +581,6 @@ class SignetMemoryProvider(MemoryProvider):
625
581
  self._notification_result = notification_inject
626
582
  except Exception as e:
627
583
  logger.debug("Signet prefetch failed: %s", e)
628
-
629
- # Join the previous prefetch thread before starting a new one to prevent
630
- # a stale turn-N result from overwriting a turn-N+1 cleared prefetch.
631
584
  prev_thread = self._prefetch_thread
632
585
  if prev_thread and prev_thread.is_alive():
633
586
  prev_thread.join(timeout=2.0)
@@ -641,8 +594,6 @@ class SignetMemoryProvider(MemoryProvider):
641
594
  """Track turn count and trigger periodic checkpoint extraction."""
642
595
  self._turn_count = turn_number
643
596
  self._last_user_message = message
644
-
645
- # Periodic checkpoint extraction for long-running sessions
646
597
  if (
647
598
  self._client
648
599
  and self._turn_count > 0
@@ -657,7 +608,6 @@ class SignetMemoryProvider(MemoryProvider):
657
608
  ) -> None:
658
609
  """Track assistant response and accumulate transcript."""
659
610
  self._last_assistant_message = assistant_content
660
- # Accumulate assistant side of transcript
661
611
  if assistant_content:
662
612
  with self._transcript_lock:
663
613
  self._transcript_lines.append(f"assistant: {_strip_internal_memory_context(assistant_content)}")
@@ -789,10 +739,6 @@ class SignetMemoryProvider(MemoryProvider):
789
739
  )
790
740
  digest = hashlib.sha256(seed.encode("utf-8")).hexdigest()
791
741
  operation_key = f"hermes-memory-write:{digest}"
792
-
793
- # Preserve Hermes's tool-call id as the source id for the common add
794
- # path. Replacements get an operation-specific suffix because every
795
- # operation in a Hermes batch shares one tool-call id.
796
742
  if tool_call_id and action == "add":
797
743
  source_id = tool_call_id
798
744
  elif tool_call_id:
@@ -909,10 +855,6 @@ class SignetMemoryProvider(MemoryProvider):
909
855
  )
910
856
  if not result or not isinstance(result, dict):
911
857
  return result
912
-
913
- # A tool-call id is shared by every operation in a Hermes batch. If an
914
- # earlier add claimed that source id, retry the new operation with its
915
- # content-derived id rather than accepting a false dedupe.
916
858
  returned_content = str(result.get("content", "") or "").strip()
917
859
  if result.get("deduped") is True and returned_content and returned_content != content.strip():
918
860
  fallback_source_id = f"{source_id}:{operation_key[-16:]}"
@@ -976,10 +918,6 @@ class SignetMemoryProvider(MemoryProvider):
976
918
  if not content:
977
919
  logger.warning("Signet Hermes replace mirror skipped: content was empty")
978
920
  return
979
-
980
- # A completed replace is found by its operation tag/source id. This
981
- # makes a retry a no-op even though the old row is no longer in the
982
- # current recall view.
983
921
  completed = self._find_mirrored_entries(
984
922
  content,
985
923
  target,
@@ -999,8 +937,6 @@ class SignetMemoryProvider(MemoryProvider):
999
937
  )
1000
938
  return
1001
939
  if not matches:
1002
- # The old row may already have been superseded by a prior
1003
- # delivery. No current stale row can be reintroduced.
1004
940
  logger.debug("Signet Hermes replace mirror found no active source row")
1005
941
  return
1006
942
 
@@ -1023,10 +959,6 @@ class SignetMemoryProvider(MemoryProvider):
1023
959
  if not result:
1024
960
  logger.warning("Signet Hermes replace mirror returned no response")
1025
961
  return
1026
-
1027
- # A content/source dedupe can return an existing current row before
1028
- # the daemon sees `supersedes`. Link that row explicitly so the old
1029
- # Hermes entry still cannot remain current.
1030
962
  if result.get("deduped") is True:
1031
963
  replacement_id = str(result.get("id", "") or "").strip()
1032
964
  if replacement_id and replacement_id != old_id and hasattr(client, "supersede_memory"):
@@ -1050,9 +982,6 @@ class SignetMemoryProvider(MemoryProvider):
1050
982
  )
1051
983
  return
1052
984
  if not matches:
1053
- # Soft-delete is idempotent from the current-view perspective:
1054
- # a prior delivery already removed this row, or it was never
1055
- # mirrored. In neither case should a stale row be recreated.
1056
985
  return
1057
986
  memory_id = str(matches[0].get("id", "") or "").strip()
1058
987
  if not memory_id:
@@ -1152,9 +1081,6 @@ class SignetMemoryProvider(MemoryProvider):
1152
1081
  self._notification_result = ""
1153
1082
  if not self._client:
1154
1083
  return
1155
-
1156
- # Prefer accumulated transcript (captures tool calls, etc.),
1157
- # fall back to rebuilding from messages argument
1158
1084
  with self._transcript_lock:
1159
1085
  transcript = "\n\n".join(self._transcript_lines)
1160
1086
 
@@ -1169,19 +1095,14 @@ class SignetMemoryProvider(MemoryProvider):
1169
1095
 
1170
1096
  if not transcript:
1171
1097
  return
1172
-
1173
- # Truncate to ~100k chars, snapping to the nearest message boundary so
1174
- # the extraction pipeline never receives a partial user/assistant line.
1175
1098
  if len(transcript) > 100_000:
1176
1099
  cutoff = len(transcript) - 100_000
1177
- # Scan forward from the cutoff to the next message boundary
1178
1100
  boundary = transcript.find("\n\nuser: ", cutoff)
1179
1101
  if boundary == -1:
1180
1102
  boundary = transcript.find("\n\nassistant: ", cutoff)
1181
1103
  if boundary != -1:
1182
- transcript = transcript[boundary + 2:] # skip leading \n\n
1104
+ transcript = transcript[boundary + 2:]
1183
1105
  else:
1184
- # No boundary found after cutoff; drop the leading fragment
1185
1106
  transcript = transcript[cutoff:]
1186
1107
 
1187
1108
  try:
@@ -1503,10 +1424,6 @@ class SignetMemoryProvider(MemoryProvider):
1503
1424
  self._prefetch_thread.join(timeout=5.0)
1504
1425
 
1505
1426
 
1506
- # ---------------------------------------------------------------------------
1507
- # Plugin entry point
1508
- # ---------------------------------------------------------------------------
1509
-
1510
1427
  def register(ctx) -> None:
1511
1428
  """Register Signet as a memory provider plugin."""
1512
1429
  ctx.register_memory_provider(SignetMemoryProvider())
@@ -210,7 +210,6 @@ class SignetClient:
210
210
  "x-signet-agent-id": self._agent_id,
211
211
  "x-signet-actor": "hermes-memory-plugin",
212
212
  }
213
- # Include auth token only for loopback or explicitly trusted origins.
214
213
  token = _sanitize(os.environ.get("SIGNET_API_KEY", "")) or _sanitize(os.environ.get("SIGNET_TOKEN", ""))
215
214
  if token and _should_send_auth_token(self._base_url):
216
215
  h["Authorization"] = f"Bearer {token}"
@@ -313,15 +312,11 @@ class SignetClient:
313
312
  logger.debug("Signet DELETE %s failed: %s", path, e)
314
313
  return None
315
314
 
316
- # -- Health ---------------------------------------------------------------
317
-
318
315
  def is_available(self) -> bool:
319
316
  """Check if the Signet daemon is reachable. No credentials needed."""
320
317
  result = self._get("/health", timeout=2)
321
318
  return result is not None
322
319
 
323
- # -- Hooks ----------------------------------------------------------------
324
-
325
320
  def session_start(
326
321
  self,
327
322
  session_key: str,
@@ -472,8 +467,6 @@ class SignetClient:
472
467
  timeout=_LONG_TIMEOUT_SECS,
473
468
  )
474
469
 
475
- # -- Memory API -----------------------------------------------------------
476
-
477
470
  def remember(
478
471
  self,
479
472
  content: str,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signetai/connector-hermes-agent",
3
- "version": "0.226.14",
3
+ "version": "0.226.16",
4
4
  "description": "Signet connector for Hermes Agent — installs Signet as a pluggable memory provider",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,8 +25,8 @@
25
25
  "typecheck": "tsc --noEmit"
26
26
  },
27
27
  "dependencies": {
28
- "@signetai/connector-base": "0.226.14",
29
- "@signetai/core": "0.226.14"
28
+ "@signetai/connector-base": "0.226.16",
29
+ "@signetai/core": "0.226.16"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",