Adding changes to docker compose

This commit is contained in:
2026-04-25 13:15:15 +02:00
parent 14f74c372b
commit f1fe41dac7
10 changed files with 308 additions and 6 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"updated_at": "2026-04-25T09:38:38.117239", "updated_at": "2026-04-25T11:03:49.746150",
"platforms": { "platforms": {
"telegram": [], "telegram": [],
"discord": [], "discord": [],
-1
View File
@@ -1 +0,0 @@
{"pid": 7, "kind": "hermes-gateway", "argv": ["/opt/hermes/.venv/bin/hermes", "gateway", "run"], "start_time": 28571}
+1 -1
View File
@@ -1 +1 @@
{"pid": 7, "kind": "hermes-gateway", "argv": ["/opt/hermes/.venv/bin/hermes", "gateway", "run"], "start_time": 28571, "gateway_state": "stopped", "exit_reason": null, "restart_requested": false, "active_agents": 0, "platforms": {}, "updated_at": "2026-04-25T09:40:22.622059+00:00"} {"pid": 7, "kind": "hermes-gateway", "argv": ["/opt/hermes/.venv/bin/hermes", "gateway", "run"], "start_time": 539712, "gateway_state": "stopped", "exit_reason": null, "restart_requested": false, "active_agents": 0, "platforms": {}, "updated_at": "2026-04-25T11:13:41.592795+00:00"}
+46
View File
@@ -32,3 +32,49 @@
2026-04-25 09:40:22,622 INFO gateway.run: Gateway stopped 2026-04-25 09:40:22,622 INFO gateway.run: Gateway stopped
2026-04-25 09:40:22,622 INFO gateway.run: Cron ticker stopped 2026-04-25 09:40:22,622 INFO gateway.run: Cron ticker stopped
2026-04-25 09:40:22,997 INFO gateway.run: Exiting with code 1 (signal-initiated shutdown without restart request) so systemd Restart=on-failure can revive the gateway. 2026-04-25 09:40:22,997 INFO gateway.run: Exiting with code 1 (signal-initiated shutdown without restart request) so systemd Restart=on-failure can revive the gateway.
2026-04-25 10:48:29,979 INFO hermes_cli.plugins: Plugin 'openai' registered image_gen provider: openai
2026-04-25 10:48:29,981 INFO hermes_cli.plugins: Plugin 'openai-codex' registered image_gen provider: openai-codex
2026-04-25 10:48:30,118 INFO hermes_cli.plugins: Plugin 'xai' registered image_gen provider: xai
2026-04-25 10:48:30,326 INFO hermes_cli.plugins: Plugin discovery complete: 5 found, 4 enabled
2026-04-25 10:48:30,987 INFO hermes_cli.web_server: Mounted plugin API routes: /api/plugins/example/
2026-04-25 10:48:30,988 WARNING hermes_cli.web_server: Binding to 0.0.0.0 with --insecure — the dashboard has no robust authentication. Only use on trusted networks.
2026-04-25 10:48:31,628 INFO gateway.run: Starting Hermes Gateway...
2026-04-25 10:48:31,629 INFO gateway.run: Session storage: /opt/data/sessions
2026-04-25 10:48:31,636 WARNING gateway.run: No user allowlists configured. All unauthorized users will be denied. Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access, or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).
2026-04-25 10:48:31,640 INFO gateway.run: Previous gateway exited cleanly — skipping session suspension
2026-04-25 10:48:31,640 WARNING gateway.run: No messaging platforms enabled.
2026-04-25 10:48:31,641 INFO gateway.run: Gateway will continue running for cron job execution.
2026-04-25 10:48:31,642 INFO gateway.run: 1 hook(s) loaded
2026-04-25 10:48:31,645 INFO gateway.run: Channel directory built: 0 target(s)
2026-04-25 10:48:31,645 INFO gateway.run: Press Ctrl+C to stop
2026-04-25 10:48:31,686 INFO gateway.run: Cron ticker started (interval=60s)
2026-04-25 11:03:44,640 INFO gateway.run: Received SIGTERM/SIGINT — initiating shutdown
2026-04-25 11:03:44,686 WARNING gateway.run: Shutdown diagnostic — other hermes processes running:
root 1 0.0 0.0 2288 1032 ? Ss 10:48 0:00 /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh gateway run
hermes 35 0.0 0.0 6504 3484 ? R 11:03 0:00 ps aux
2026-04-25 11:03:44,695 INFO gateway.run: Stopping gateway...
2026-04-25 11:03:45,314 INFO gateway.run: Gateway stopped
2026-04-25 11:03:45,315 INFO gateway.run: Cron ticker stopped
2026-04-25 11:03:47,883 INFO hermes_cli.plugins: Plugin 'openai' registered image_gen provider: openai
2026-04-25 11:03:47,886 INFO hermes_cli.plugins: Plugin 'openai-codex' registered image_gen provider: openai-codex
2026-04-25 11:03:48,041 INFO hermes_cli.plugins: Plugin 'xai' registered image_gen provider: xai
2026-04-25 11:03:48,333 INFO hermes_cli.plugins: Plugin discovery complete: 5 found, 4 enabled
2026-04-25 11:03:49,226 INFO hermes_cli.web_server: Mounted plugin API routes: /api/plugins/example/
2026-04-25 11:03:49,226 WARNING hermes_cli.web_server: Binding to 0.0.0.0 with --insecure — the dashboard has no robust authentication. Only use on trusted networks.
2026-04-25 11:03:49,730 INFO gateway.run: Starting Hermes Gateway...
2026-04-25 11:03:49,730 INFO gateway.run: Session storage: /opt/data/sessions
2026-04-25 11:03:49,737 WARNING gateway.run: No user allowlists configured. All unauthorized users will be denied. Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access, or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).
2026-04-25 11:03:49,742 INFO gateway.run: Previous gateway exited cleanly — skipping session suspension
2026-04-25 11:03:49,742 WARNING gateway.run: No messaging platforms enabled.
2026-04-25 11:03:49,742 INFO gateway.run: Gateway will continue running for cron job execution.
2026-04-25 11:03:49,743 INFO gateway.run: 1 hook(s) loaded
2026-04-25 11:03:49,747 INFO gateway.run: Channel directory built: 0 target(s)
2026-04-25 11:03:49,747 INFO gateway.run: Press Ctrl+C to stop
2026-04-25 11:03:49,793 INFO gateway.run: Cron ticker started (interval=60s)
2026-04-25 11:13:40,708 INFO gateway.run: Received SIGTERM/SIGINT — initiating shutdown
2026-04-25 11:13:40,720 WARNING gateway.run: Shutdown diagnostic — other hermes processes running:
root 1 0.0 0.0 2288 1108 ? Ss 11:03 0:00 /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh gateway run
hermes 35 0.0 0.0 6504 3488 ? R 11:13 0:00 ps aux
2026-04-25 11:13:40,723 INFO gateway.run: Stopping gateway...
2026-04-25 11:13:41,593 INFO gateway.run: Gateway stopped
2026-04-25 11:13:41,593 INFO gateway.run: Cron ticker stopped
+12
View File
@@ -3,3 +3,15 @@
2026-04-25 09:40:22,113 WARNING gateway.run: Shutdown diagnostic — other hermes processes running: 2026-04-25 09:40:22,113 WARNING gateway.run: Shutdown diagnostic — other hermes processes running:
root 1 0.0 0.0 2288 1104 ? Ss 09:38 0:00 /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh gateway run root 1 0.0 0.0 2288 1104 ? Ss 09:38 0:00 /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh gateway run
hermes 37 0.0 0.0 6504 3488 ? R 09:40 0:00 ps aux hermes 37 0.0 0.0 6504 3488 ? R 09:40 0:00 ps aux
2026-04-25 10:48:30,988 WARNING hermes_cli.web_server: Binding to 0.0.0.0 with --insecure — the dashboard has no robust authentication. Only use on trusted networks.
2026-04-25 10:48:31,636 WARNING gateway.run: No user allowlists configured. All unauthorized users will be denied. Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access, or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).
2026-04-25 10:48:31,640 WARNING gateway.run: No messaging platforms enabled.
2026-04-25 11:03:44,686 WARNING gateway.run: Shutdown diagnostic — other hermes processes running:
root 1 0.0 0.0 2288 1032 ? Ss 10:48 0:00 /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh gateway run
hermes 35 0.0 0.0 6504 3484 ? R 11:03 0:00 ps aux
2026-04-25 11:03:49,226 WARNING hermes_cli.web_server: Binding to 0.0.0.0 with --insecure — the dashboard has no robust authentication. Only use on trusted networks.
2026-04-25 11:03:49,737 WARNING gateway.run: No user allowlists configured. All unauthorized users will be denied. Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access, or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id).
2026-04-25 11:03:49,742 WARNING gateway.run: No messaging platforms enabled.
2026-04-25 11:13:40,720 WARNING gateway.run: Shutdown diagnostic — other hermes processes running:
root 1 0.0 0.0 2288 1108 ? Ss 11:03 0:00 /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh gateway run
hermes 35 0.0 0.0 6504 3488 ? R 11:13 0:00 ps aux
Binary file not shown.
View File
+4 -2
View File
@@ -76,7 +76,8 @@ services:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
gerhard: gerhard:
image: nousresearch/hermes-agent build:
context: ../hermes-agent
container_name: gerhard container_name: gerhard
volumes: volumes:
- ./agents/gerhard-hermes:/opt/data - ./agents/gerhard-hermes:/opt/data
@@ -89,7 +90,8 @@ services:
command: ["gateway", "run"] command: ["gateway", "run"]
gerhard-dashboard: gerhard-dashboard:
image: nousresearch/hermes-agent build:
context: ../hermes-agent
container_name: gerhard-dashboard container_name: gerhard-dashboard
ports: ports:
- "50007:9119" # web dashboard at localhost:50007 - "50007:9119" # web dashboard at localhost:50007
+225
View File
@@ -1327,6 +1327,231 @@ async def ollama_generate_with_agent_id(agent_id: str, request: Request) -> Resp
return await _handle_ollama_generate(request, agent_name=agent_id.lower()) return await _handle_ollama_generate(request, agent_name=agent_id.lower())
# ---------------------------------------------------------------------------
# /scan — gutask integration: scan task / letter text and return recollection
# ---------------------------------------------------------------------------
# Saliency encounter weight per context type.
# Facts stated in tasks are stronger signals than chat overheard in passing.
_CONTEXT_WEIGHT: dict[str, float] = {
"task": 2.0,
"letter": 1.5,
"chat": 1.0,
}
@app.post("/scan")
async def scan_text(request: Request) -> dict:
"""
Scan a block of plain text for domain concepts and return a recollection block.
Called by gutask when an agent reads a task or a letter, so that the agent
sees relevant knowledge-graph context alongside the task/letter content.
Body:
text (str) — the task description, letter body, or any free text
agent (str) — agent name (for logging; optional)
context (str) — "task" | "letter" | "chat" (default: "task")
Returns:
recollection_block (str | null) — the <recollection>…</recollection> block,
or null if nothing salient was found
salient_tokens (list[str]) — concepts that triggered the block
cues_found (int) — number of URD cues extracted from the text
"""
pool = request.app.state.pool
data = await request.json()
text: str = data.get("text", "").strip()
agent_name: str = data.get("agent", "").strip().lower()
context_type: str = data.get("context", "task").strip().lower()
weight: float = _CONTEXT_WEIGHT.get(context_type, 1.0)
if not text:
return {"recollection_block": None, "salient_tokens": [], "cues_found": 0}
read_threshold = float(await get_config(pool, "saliency_read_threshold", "0.5"))
conf_floor = float(await get_config(pool, "recollection_confidence_floor", "0.6"))
recency_days = int(await get_config(pool, "recollection_recency_days", "90"))
# 1. Cue scanner — extract explicit relationship assertions and enqueue them.
cues = list(scan_cues(text))
cues_found = len(cues)
for cue in cues:
await enqueue_cue(cue)
# 2. Token loop — find salient concepts and record weighted encounters.
tokens = tokenize(text)
salient_ids: list[int] = []
for token in tokens:
row = cache.soas_by_token.get(token)
if row is None or row.saliency == 0.0:
continue
# Weight the encounter: task/letter mentions count more than chat.
# We stage fractional deltas; flush_encounter_deltas rounds to int,
# so accumulate weight as repeated single increments for simplicity.
increments = max(1, round(weight))
for _ in range(increments):
cache.record_encounter(row.id)
if row.saliency >= read_threshold:
salient_ids.append(row.id)
if not salient_ids:
log.debug("scan | agent=%s context=%s cues=%d → no salient concepts",
agent_name or "(none)", context_type, cues_found)
return {"recollection_block": None, "salient_tokens": [], "cues_found": cues_found}
# 3. Build recollection block (session boost not applicable here — no system message).
block = build_recollection_block(salient_ids, conf_floor, recency_days)
salient_tokens = [cache.soas_by_id.get(cid, str(cid)) for cid in salient_ids]
log.info(
"scan | agent=%s context=%s cues=%d salient=%s\n%s",
agent_name or "(none)", context_type, cues_found, salient_tokens,
block or "(no block)",
)
return {
"recollection_block": block,
"salient_tokens": salient_tokens,
"cues_found": cues_found,
}
# ---------------------------------------------------------------------------
# /recall/{concept} — gutask recall backend
# ---------------------------------------------------------------------------
@app.get("/recall/{concept:path}")
async def recall_concept(
concept: str,
request: Request,
depth: str = "brief",
) -> dict:
"""
Return what Festinger knows about a concept, formatted for agent display.
depth:
brief — URD edges only (same as recollection block, more readable)
detailed — edges + saliency stats + related concepts in same dimensions
everything — detailed + full write log history
"""
pool = request.app.state.pool
concept = concept.lower().strip()
row = cache.soas_by_token.get(concept)
if row is None:
# Try DB in case cache is stale
async with pool.acquire() as conn:
db_row = await conn.fetchrow(
"SELECT id, token, saliency, novelty, encounter_count, "
"first_seen_context, last_seen FROM soas WHERE token = $1",
concept,
)
if not db_row:
return {"concept": concept, "found": False, "text": f"No knowledge about '{concept}' in Festinger."}
from .cache import SoasRow
row = SoasRow(
id=db_row["id"], token=db_row["token"],
saliency=db_row["saliency"], novelty=db_row["novelty"],
encounter_count=db_row["encounter_count"],
first_seen_context=db_row["first_seen_context"] or "",
last_seen=db_row["last_seen"],
)
edges = cache.urd_by_concept.get(row.id, [])
reverse_edges = cache.urd_by_parent.get(row.id, [])
lines = [f"── {concept} {'' * max(0, 50 - len(concept))}"]
if depth in ("detailed", "everything"):
from .recollection import recency_decay, centrality_bonus, effective_score
decay = recency_decay(row)
score = effective_score(row.id)
last_seen_str = (
row.last_seen.strftime("%Y-%m-%d") if row.last_seen else "never"
)
lines.append(f" saliency: {row.saliency:.2f} encounters: {row.encounter_count}"
f" score: {score:.2f} last seen: {last_seen_str}")
if row.first_seen_context:
lines.append(f" first seen: \"{row.first_seen_context[:80]}\"")
if row.id in cache.pending_conflicts:
lines.append(" ⚠ has pending conflict in resolution queue")
lines.append("")
if edges:
lines.append(" Relationships (outgoing):")
for e in edges:
conf_str = f" conf={e.confidence:.2f}" if e.confidence < 1.0 else ""
lines.append(f" [{e.dim_token}] → {e.parent_token}{conf_str}")
else:
lines.append(" No outgoing relationships stored.")
if reverse_edges:
lines.append("")
lines.append(" Referenced by:")
for e in reverse_edges[:10]:
child_token = cache.soas_by_id.get(e.concept_id, str(e.concept_id))
lines.append(f" [{e.dim_token}] ← {child_token}")
if len(reverse_edges) > 10:
lines.append(f" … and {len(reverse_edges) - 10} more")
if depth in ("detailed", "everything") and edges:
# Siblings: other concepts sharing the same parent in the same dimension
siblings: dict[str, list[str]] = {}
for e in edges:
peer_edges = cache.urd_by_parent.get(e.parent_id, [])
peers = [
cache.soas_by_id.get(pe.concept_id, str(pe.concept_id))
for pe in peer_edges
if pe.concept_id != row.id and pe.dim_id == e.dim_id
][:5]
if peers:
siblings[f"{e.dim_token}/{e.parent_token}"] = peers
if siblings:
lines.append("")
lines.append(" Siblings (same parent/dimension):")
for label, peers in siblings.items():
lines.append(f" {label}: {', '.join(peers)}")
if depth == "everything":
async with pool.acquire() as conn:
log_rows = await conn.fetch(
"""
SELECT op, parent_token, dim_token, is_isa, source, created_at
FROM kg_write_log WHERE concept_id = $1
ORDER BY created_at DESC LIMIT 20
""",
row.id,
)
if log_rows:
lines.append("")
lines.append(" Write history:")
for lr in log_rows:
ts = lr["created_at"].strftime("%Y-%m-%d")
isa = "is-a" if lr["is_isa"] else "is-part-of"
lines.append(
f" {ts} {lr['op']:<10} [{lr['dim_token']}] {isa} {lr['parent_token']}"
f" ({lr['source']})"
)
text = "\n".join(lines)
return {
"concept": concept,
"found": True,
"depth": depth,
"saliency": row.saliency,
"encounter_count": row.encounter_count,
"edges": [
{"dim": e.dim_token, "parent": e.parent_token,
"is_isa": e.is_isa, "confidence": e.confidence}
for e in edges
],
"text": text,
}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# /iknowthat — manual write path # /iknowthat — manual write path
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
+19 -1
View File
@@ -178,7 +178,25 @@ def build_recollection_block(
if not lines: if not lines:
return None return None
return f"<recollection>\n" + "\n".join(lines) + "\n</recollection>" # Footer: list the concepts that have actual URD data so the agent knows
# it can dig deeper via gutask recall.
hit_tokens = [
cache.soas_by_id.get(cid, str(cid))
for _, cid in scored
if query_edges(cid, confidence_floor) or cache.urd_by_parent.get(cid)
][:6]
footer_lines = []
if hit_tokens:
footer_lines.append(
"To recall more: gutask recall <concept> brief|detailed|everything"
)
footer_lines.append(" concepts: " + ", ".join(hit_tokens))
body = "\n".join(lines)
if footer_lines:
body += "\n" + "\n".join(footer_lines)
return "<recollection>\n" + body + "\n</recollection>"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------