chore: uptick

This commit is contained in:
Brooklyn Nicholson 2026-05-02 03:19:39 -05:00
parent 420f68e4e2
commit db884f4646
240 changed files with 25206 additions and 3155 deletions

View file

@ -12,6 +12,14 @@ import time
from pathlib import Path
from typing import Any, Dict, List, Optional, Set
try:
from hermes_constants import get_hermes_home
except ImportError:
import os as _os
def get_hermes_home() -> Path: # type: ignore[misc]
val = (_os.environ.get("HERMES_HOME") or "").strip()
return Path(val) if val else Path.home() / ".hermes"
try:
from fastapi import APIRouter
except Exception: # Allows local unit tests without dashboard dependencies.
@ -135,15 +143,15 @@ ACHIEVEMENTS: List[Dict[str, Any]] = [
def state_path() -> Path:
return Path.home() / ".hermes" / "plugins" / "hermes-achievements" / "state.json"
return get_hermes_home() / "plugins" / "hermes-achievements" / "state.json"
def snapshot_path() -> Path:
return Path.home() / ".hermes" / "plugins" / "hermes-achievements" / "scan_snapshot.json"
return get_hermes_home() / "plugins" / "hermes-achievements" / "scan_snapshot.json"
def checkpoint_path() -> Path:
return Path.home() / ".hermes" / "plugins" / "hermes-achievements" / "scan_checkpoint.json"
return get_hermes_home() / "plugins" / "hermes-achievements" / "scan_checkpoint.json"
def load_state() -> Dict[str, Any]:

View file

@ -231,7 +231,7 @@
String(this.state.error && this.state.error.message || this.state.error)),
h(Button, {
onClick: () => this.setState({ error: null }),
className: "h-7 px-3 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Reload view"),
),
);
@ -599,11 +599,11 @@
h("div", { className: "flex-1" }),
h(Button, {
onClick: props.onNudgeDispatch,
className: "h-8 px-3 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Nudge dispatcher"),
h(Button, {
onClick: props.onRefresh,
className: "h-8 px-3 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Refresh"),
);
}
@ -619,21 +619,21 @@
`${props.count} selected`),
h(Button, {
onClick: function () { props.onApply({ status: "ready" }); },
className: "hermes-kanban-bulk-btn",
size: "sm",
}, "→ ready"),
h(Button, {
onClick: function () {
props.onApply({ status: "done" },
`Mark ${props.count} task(s) as done?`);
},
className: "hermes-kanban-bulk-btn",
size: "sm",
}, "Complete"),
h(Button, {
onClick: function () {
props.onApply({ archive: true },
`Archive ${props.count} task(s)?`);
},
className: "hermes-kanban-bulk-btn",
size: "sm",
}, "Archive"),
h("div", { className: "hermes-kanban-bulk-reassign" },
h(Select, {
@ -654,14 +654,13 @@
setAssignee("");
},
disabled: !assignee,
className: cn("hermes-kanban-bulk-btn",
!assignee ? "opacity-40 cursor-not-allowed" : ""),
size: "sm",
}, "Apply"),
),
h("div", { className: "flex-1" }),
h(Button, {
onClick: props.onClear,
className: "hermes-kanban-bulk-btn",
size: "sm",
}, "Clear"),
);
}
@ -993,11 +992,11 @@
h("div", { className: "flex gap-2" },
h(Button, {
onClick: submit,
className: "h-7 px-2 text-xs border border-border hover:bg-foreground/10 cursor-pointer flex-1",
size: "sm",
}, "Create"),
h(Button, {
onClick: props.onCancel,
className: "h-7 px-2 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Cancel"),
),
);
@ -1125,7 +1124,7 @@
}),
h(Button, {
onClick: handleComment,
className: "h-8 px-3 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Comment"),
) : null,
),
@ -1355,10 +1354,10 @@
className: "h-8 text-sm flex-1",
}),
h(Button, { onClick: save,
className: "h-7 px-2 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Save"),
h(Button, { onClick: props.onCancel,
className: "h-7 px-2 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Cancel"),
);
}
@ -1439,10 +1438,10 @@
editing
? h("div", { className: "flex gap-1" },
h(Button, { onClick: save,
className: "h-6 px-2 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Save"),
h(Button, { onClick: function () { setEditing(false); setV(props.task.body || ""); },
className: "h-6 px-2 text-xs border border-border hover:bg-foreground/10 cursor-pointer",
size: "sm",
}, "Cancel"),
)
: h("button", {
@ -1516,8 +1515,7 @@
props.onAddParent(newParent).then(function () { setNewParent(""); });
},
disabled: !newParent,
className: cn("h-7 px-2 text-xs border border-border cursor-pointer",
!newParent ? "opacity-40 cursor-not-allowed" : "hover:bg-foreground/10"),
size: "sm",
}, "+ parent"),
),
h("div", { className: "hermes-kanban-deps-row" },
@ -1556,8 +1554,7 @@
props.onAddChild(newChild).then(function () { setNewChild(""); });
},
disabled: !newChild,
className: cn("h-7 px-2 text-xs border border-border cursor-pointer",
!newChild ? "opacity-40 cursor-not-allowed" : "hover:bg-foreground/10"),
size: "sm",
}, "+ child"),
),
);
@ -1569,10 +1566,7 @@
return h(Button, {
onClick: function () { if (enabled !== false) props.onPatch(patch, { confirm: confirmMsg }); },
disabled: enabled === false,
className: cn(
"h-7 px-2 text-xs border border-border cursor-pointer",
enabled === false ? "opacity-40 cursor-not-allowed" : "hover:bg-foreground/10",
),
size: "sm",
}, label);
};
return h("div", { className: "hermes-kanban-actions" },

View file

@ -251,6 +251,11 @@
border-radius: var(--radius-sm, 0.25rem);
}
.hermes-kanban-inline-create > .flex.gap-2:last-child > button:first-of-type {
flex: 1;
min-width: 0;
}
/* ---- Drawer (task detail side panel) --------------------------------- */
.hermes-kanban-drawer-shade {
@ -460,14 +465,17 @@
font-size: 0.75rem;
padding-right: 0.25rem;
}
.hermes-kanban-bulk-btn {
.hermes-kanban-bulk > button,
.hermes-kanban-bulk-reassign > button {
height: 1.7rem !important;
padding: 0 0.5rem !important;
font-size: 0.7rem !important;
border: 1px solid var(--color-border);
cursor: pointer;
}
.hermes-kanban-bulk-btn:hover {
.hermes-kanban-bulk > button:hover:not(:disabled),
.hermes-kanban-bulk-reassign > button:hover:not(:disabled) {
background: color-mix(in srgb, var(--color-foreground) 8%, transparent);
}
.hermes-kanban-bulk-reassign {

View file

@ -110,6 +110,17 @@ def _parse_context_tokens(host_val, root_val) -> int | None:
return None
def _parse_int_config(host_val, root_val, default: int) -> int:
"""Parse an integer config: host wins, then root, then default."""
for val in (host_val, root_val):
if val is not None:
try:
return int(val)
except (ValueError, TypeError):
pass
return default
def _parse_dialectic_depth(host_val, root_val) -> int:
"""Parse dialecticDepth: host wins, then root, then 1. Clamped to 1-3."""
for val in (host_val, root_val):
@ -463,10 +474,10 @@ class HonchoClientConfig:
raw.get("dialecticDynamic"),
default=True,
),
dialectic_max_chars=int(
host_block.get("dialecticMaxChars")
or raw.get("dialecticMaxChars")
or 600
dialectic_max_chars=_parse_int_config(
host_block.get("dialecticMaxChars"),
raw.get("dialecticMaxChars"),
default=600,
),
dialectic_depth=_parse_dialectic_depth(
host_block.get("dialecticDepth"),
@ -487,15 +498,15 @@ class HonchoClientConfig:
or raw.get("reasoningLevelCap")
or "high"
),
message_max_chars=int(
host_block.get("messageMaxChars")
or raw.get("messageMaxChars")
or 25000
message_max_chars=_parse_int_config(
host_block.get("messageMaxChars"),
raw.get("messageMaxChars"),
default=25000,
),
dialectic_max_input_chars=int(
host_block.get("dialecticMaxInputChars")
or raw.get("dialecticMaxInputChars")
or 10000
dialectic_max_input_chars=_parse_int_config(
host_block.get("dialecticMaxInputChars"),
raw.get("dialecticMaxInputChars"),
default=10000,
),
recall_mode=_normalize_recall_mode(
host_block.get("recallMode")

View file

@ -160,11 +160,13 @@ class HonchoSessionManager:
Peers are lazy -- no API call until first use.
Observation settings are controlled per-session via SessionPeerConfig.
"""
if peer_id in self._peers_cache:
return self._peers_cache[peer_id]
with self._cache_lock:
if peer_id in self._peers_cache:
return self._peers_cache[peer_id]
peer = self.honcho.peer(peer_id)
self._peers_cache[peer_id] = peer
with self._cache_lock:
self._peers_cache[peer_id] = peer
return peer
def _get_or_create_honcho_session(
@ -176,9 +178,10 @@ class HonchoSessionManager:
Returns:
Tuple of (honcho_session, existing_messages).
"""
if session_id in self._sessions_cache:
logger.debug("Honcho session '%s' retrieved from cache", session_id)
return self._sessions_cache[session_id], []
with self._cache_lock:
if session_id in self._sessions_cache:
logger.debug("Honcho session '%s' retrieved from cache", session_id)
return self._sessions_cache[session_id], []
session = self.honcho.session(session_id)

View file

@ -38,6 +38,7 @@ except ImportError:
try:
from microsoft_teams.apps import App, ActivityContext
from microsoft_teams.common.http.client import ClientOptions
from microsoft_teams.api import MessageActivity, ConversationReference
from microsoft_teams.api.activities.typing import TypingActivityInput
from microsoft_teams.api.activities.invoke.adaptive_card import AdaptiveCardInvokeActivity
@ -57,6 +58,7 @@ try:
TEAMS_SDK_AVAILABLE = True
except ImportError:
TEAMS_SDK_AVAILABLE = False
ClientOptions = None # type: ignore[assignment,misc]
App = None # type: ignore[assignment,misc]
ActivityContext = None # type: ignore[assignment,misc]
MessageActivity = None # type: ignore[assignment,misc]
@ -208,6 +210,7 @@ class TeamsAdapter(BasePlatformAdapter):
client_secret=self._client_secret,
tenant_id=self._tenant_id,
http_server_adapter=_AiohttpBridgeAdapter(aiohttp_app),
client=ClientOptions(headers={"User-Agent": "Hermes"}),
)
# Register message handler before initialize()