lithermes-ai 0.8.0 → 0.8.1

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.
@@ -133,6 +133,9 @@ def register(ctx) -> None:
133
133
  ctx.register_hook("pre_llm_call", _pre_llm_call)
134
134
  # Record each delegate_task child (review lanes, reviewer gate) to the ledger.
135
135
  ctx.register_hook("subagent_stop", core.subagent_stop)
136
+ # Force the LITBURN banner onto a bare-`lit` keyword turn's response (that
137
+ # path has no deterministic display channel; slash commands print it directly).
138
+ ctx.register_hook("transform_llm_output", core.transform_llm_output)
136
139
 
137
140
  # Model-facing litgoal tools (durable criteria/evidence/checkpoint/steering/gate).
138
141
  litgoal_tools.register_tools(ctx)
@@ -38,6 +38,12 @@ _SLUG_PATTERN = re.compile(r"[^a-z0-9]+")
38
38
  # for the bare-`lit` keyword path (best-effort — that path only reaches the model).
39
39
  LITBURN_BANNER = "🔥 LITBURN IGNITED 🔥"
40
40
 
41
+ # Session ids whose CURRENT turn triggered the litwork keyword path. The bare
42
+ # `lit` keyword has no deterministic display channel (pre_llm_call only reaches
43
+ # the model), so pre_llm_call flags the turn here and transform_llm_output forces
44
+ # the banner onto that turn's response before the user sees it. Consumed once.
45
+ _PENDING_IGNITE: set[str] = set()
46
+
41
47
 
42
48
  LIT_CONTEXT = "\n".join(
43
49
  [
@@ -258,6 +264,10 @@ def ignite(result: str | dict[str, str]) -> str | dict[str, str]:
258
264
  def pre_llm_call(**kwargs: Any) -> dict[str, str] | None:
259
265
  user_message = str(kwargs.get("user_message") or "")
260
266
  session_id = str(kwargs.get("session_id") or "")
267
+ # Clear any stale ignite flag from an interrupted previous turn so it can't
268
+ # leak the banner onto this turn's response. Re-added below only if THIS turn
269
+ # is a keyword-lit turn — keeping the flag scoped to the current turn.
270
+ _PENDING_IGNITE.discard(session_id)
261
271
  # /litgoal & /lit-plan declare an objective via the bind-goal marker. Bind it
262
272
  # (we have session_id here) and stop — those messages are self-contained.
263
273
  bind_obj = _extract_bind_goal(user_message)
@@ -291,9 +301,31 @@ def pre_llm_call(**kwargs: Any) -> dict[str, str] | None:
291
301
  session_id=session_id,
292
302
  platform=str(kwargs.get("platform") or ""),
293
303
  )
304
+ # Flag this turn so transform_llm_output forces the banner onto the response
305
+ # (the keyword path has no deterministic display channel like slash commands).
306
+ if session_id:
307
+ _PENDING_IGNITE.add(session_id)
294
308
  return {"context": LIT_CONTEXT + run_context}
295
309
 
296
310
 
311
+ def transform_llm_output(**kwargs: Any) -> str | None:
312
+ """Force the LITBURN banner onto a keyword-`lit` turn's response.
313
+
314
+ Hermes replaces the user-visible response with the first non-empty string a
315
+ transform_llm_output hook returns. Returning None leaves the text unchanged.
316
+ We only act on turns pre_llm_call flagged, consume the flag once, and dedup so
317
+ a model that already opened with the banner is not double-bannered.
318
+ """
319
+ session_id = str(kwargs.get("session_id") or "")
320
+ if session_id not in _PENDING_IGNITE:
321
+ return None
322
+ _PENDING_IGNITE.discard(session_id)
323
+ response_text = str(kwargs.get("response_text") or "")
324
+ if response_text.lstrip().startswith(LITBURN_BANNER):
325
+ return None # model already emitted it — leave unchanged
326
+ return f"{LITBURN_BANNER}\n\n{response_text}"
327
+
328
+
297
329
  def subagent_stop(**kwargs: Any) -> None:
298
330
  """Record each delegate_task child (e.g. a review lane) to the LitHermes ledger.
299
331
 
@@ -1,7 +1,7 @@
1
1
  {
2
- "syncedAt": "2026-06-14T03:56:58.019Z",
2
+ "syncedAt": "2026-06-14T05:53:21.695Z",
3
3
  "source": "source-reference",
4
- "sourceHash": "23886fd1b52dc30433f8886ba15ccedbc3d134ba8f0b99b7a90a83d07c0351fe",
4
+ "sourceHash": "f07cf5a5062f904d4eed678ebf24314e773ca3f92e5c2d1f95c981437e0c5a5a",
5
5
  "files": [
6
6
  {
7
7
  "path": "NOTICE.md",
@@ -13,11 +13,11 @@
13
13
  },
14
14
  {
15
15
  "path": "__init__.py",
16
- "sha256": "14951813219a77f7074ff8ca36e26cc46b66b0987f28dbcf1827c9bcfa98d65c"
16
+ "sha256": "9a0b19060eb12799bf76b15b729fcbab4388d74aac9e888b40369b809fd54669"
17
17
  },
18
18
  {
19
19
  "path": "core.py",
20
- "sha256": "da2888e70b560697eaf81fe29d0b92a36e8e0563ab3bcab95c34472533faa937"
20
+ "sha256": "6b9d8b488d5905232d170f78943d2b5f9b9a4bde564e01a816c4fcc45098a7df"
21
21
  },
22
22
  {
23
23
  "path": "litgoal/__init__.py",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  {
51
51
  "path": "plugin.yaml",
52
- "sha256": "4b8a31a093d883cf1714250564955c3d8ca87889887780515a7df15ed317e732"
52
+ "sha256": "e8ab5e17a3812c1caf91d98e2fb3cf72f2c7d4a429723f0887b6eb3abd736648"
53
53
  },
54
54
  {
55
55
  "path": "skills/ai-slop-remover/SKILL.md",
@@ -1,5 +1,5 @@
1
1
  name: lithermes
2
- version: 0.8.0
2
+ version: 0.8.1
3
3
  description: "Hermes-native workflow toolkit: litgoal durable runtime, 5-lane review orchestrator, Litwork commands, skills, and prompt steering."
4
4
  author: "Hermes Agent"
5
5
  kind: standalone
@@ -7,3 +7,4 @@ auto_load: true
7
7
  hooks:
8
8
  - pre_llm_call
9
9
  - subagent_stop
10
+ - transform_llm_output
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lithermes-ai",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "npx/bunx installer for the LitHermes Hermes plugin",
5
5
  "license": "MIT",
6
6
  "repository": {