refactor(memory,langfuse): fold small helpers (read_file line parse, json hint merge, env-file parse, setup prompts)
This commit is contained in:
@@ -316,10 +316,8 @@ class _ProviderCollector:
|
||||
if not self._register_skills:
|
||||
return
|
||||
try:
|
||||
manager_context = self._plugin_context()
|
||||
manager_context.register_skill(*args, **kwargs)
|
||||
skill_name = args[0] if args else kwargs.get("name")
|
||||
qualified_name = f"{self.name}:{skill_name}"
|
||||
self._plugin_context().register_skill(*args, **kwargs)
|
||||
qualified_name = f"{self.name}:{args[0] if args else kwargs.get('name')}"
|
||||
|
||||
from hermes_cli.plugins import get_plugin_manager
|
||||
|
||||
|
||||
@@ -517,9 +517,7 @@ class HindsightMemoryProvider(MemoryProvider):
|
||||
def _int_setting(self, key: str, env_var: str, default: int, env_default=None) -> int:
|
||||
"""Config value if set (explicit 0 preserved), else env var, else default."""
|
||||
value = self._config.get(key)
|
||||
if value is None:
|
||||
value = os.environ.get(env_var, env_default)
|
||||
return _parse_int_setting(value, default)
|
||||
return _parse_int_setting(os.environ.get(env_var, env_default) if value is None else value, default)
|
||||
|
||||
def _new_embedded_client(self):
|
||||
available, reason = _check_local_runtime()
|
||||
@@ -743,9 +741,8 @@ class HindsightMemoryProvider(MemoryProvider):
|
||||
self._session_id = str(session_id or "").strip()
|
||||
self._parent_session_id = str(kwargs.get("parent_session_id", "") or "").strip()
|
||||
# Status channel for the retain indicator (recall reports via recall_status()).
|
||||
status_cb = kwargs.get("status_callback")
|
||||
if callable(status_cb):
|
||||
self._status_callback = status_cb
|
||||
if callable(kwargs.get("status_callback")):
|
||||
self._status_callback = kwargs["status_callback"]
|
||||
# session_id stays in tags so processes for one session remain filterable together.
|
||||
self._document_id = _mint_document_id(self._session_id)
|
||||
_maybe_upgrade_client()
|
||||
@@ -1172,9 +1169,7 @@ class HindsightMemoryProvider(MemoryProvider):
|
||||
# -- tools -------------------------------------------------------------------
|
||||
|
||||
def get_tool_schemas(self) -> List[Dict[str, Any]]:
|
||||
if self._memory_mode == "context":
|
||||
return []
|
||||
return [RETAIN_SCHEMA, RECALL_SCHEMA, REFLECT_SCHEMA]
|
||||
return [] if self._memory_mode == "context" else [RETAIN_SCHEMA, RECALL_SCHEMA, REFLECT_SCHEMA]
|
||||
|
||||
def _tool_retain(self, args: dict) -> str:
|
||||
content = args["content"]
|
||||
|
||||
@@ -82,13 +82,9 @@ def _load_simple_env(path) -> dict[str, str]:
|
||||
on the Hermes .env during post_setup, where a Notepad BOM would stick to the first key."""
|
||||
if not path.exists():
|
||||
return {}
|
||||
values: dict[str, str] = {}
|
||||
for line in path.read_text(encoding="utf-8-sig", errors="replace").splitlines():
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
values[key.strip()] = value.strip()
|
||||
return values
|
||||
pairs = (line.split("=", 1) for line in path.read_text(encoding="utf-8-sig", errors="replace").splitlines()
|
||||
if line and not line.startswith("#") and "=" in line)
|
||||
return {key.strip(): value.strip() for key, value in pairs}
|
||||
|
||||
|
||||
def _embedded_profile_env_path(config: dict[str, Any]) -> Path:
|
||||
@@ -99,11 +95,7 @@ def _embedded_profile_env_path(config: dict[str, Any]) -> Path:
|
||||
def _build_embedded_profile_env(config: dict[str, Any], *, llm_api_key: str | None = None) -> dict[str, str]:
|
||||
"""Build the profile-scoped env that standalone hindsight-embed consumes."""
|
||||
if llm_api_key is None:
|
||||
llm_api_key = (
|
||||
config.get("llmApiKey")
|
||||
or config.get("llm_api_key")
|
||||
or get_secret("HINDSIGHT_LLM_API_KEY", "")
|
||||
)
|
||||
llm_api_key = config.get("llmApiKey") or config.get("llm_api_key") or get_secret("HINDSIGHT_LLM_API_KEY", "")
|
||||
env_values = {
|
||||
"HINDSIGHT_API_LLM_PROVIDER": str(_daemon_llm_provider(config.get("llm_provider", ""))),
|
||||
"HINDSIGHT_API_LLM_API_KEY": str(llm_api_key or ""),
|
||||
@@ -117,9 +109,7 @@ def _build_embedded_profile_env(config: dict[str, Any], *, llm_api_key: str | No
|
||||
if idle_timeout is None:
|
||||
idle_timeout = os.environ.get("HINDSIGHT_IDLE_TIMEOUT")
|
||||
if idle_timeout is not None and idle_timeout != "":
|
||||
env_values["HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT"] = str(
|
||||
_parse_int_setting(idle_timeout, _DEFAULT_IDLE_TIMEOUT)
|
||||
)
|
||||
env_values["HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT"] = str(_parse_int_setting(idle_timeout, _DEFAULT_IDLE_TIMEOUT))
|
||||
return env_values
|
||||
|
||||
|
||||
|
||||
@@ -129,11 +129,8 @@ def run_setup(provider, hermes_home: str, config: dict) -> None:
|
||||
if mode == "cloud":
|
||||
print("\n Get your API key at https://ui.hindsight.vectorize.io\n")
|
||||
existing_key = get_secret("HINDSIGHT_API_KEY", "") or ""
|
||||
if existing_key:
|
||||
masked = f"...{existing_key[-4:]}" if len(existing_key) > 4 else "set"
|
||||
api_key = _secret_prompt(f" API key (current: {masked}, blank to keep): ")
|
||||
else:
|
||||
api_key = _secret_prompt(" API key: ")
|
||||
masked = f"...{existing_key[-4:]}" if len(existing_key) > 4 else "set"
|
||||
api_key = _secret_prompt(f" API key (current: {masked}, blank to keep): " if existing_key else " API key: ")
|
||||
if api_key:
|
||||
env_writes["HINDSIGHT_API_KEY"] = api_key
|
||||
val = input(f" API URL [{_DEFAULT_API_URL}]: ").strip()
|
||||
@@ -150,9 +147,7 @@ def run_setup(provider, hermes_home: str, config: dict) -> None:
|
||||
else: # local_embedded
|
||||
if llm_provider == "openai_compatible":
|
||||
existing_base_url = provider_config.get("llm_base_url", "")
|
||||
prompt = " LLM endpoint URL (e.g. http://192.168.1.10:8080/v1)"
|
||||
if existing_base_url:
|
||||
prompt += f" [{existing_base_url}]"
|
||||
prompt = " LLM endpoint URL (e.g. http://192.168.1.10:8080/v1)" + (f" [{existing_base_url}]" if existing_base_url else "")
|
||||
val = input(prompt + ": ").strip()
|
||||
if val:
|
||||
provider_config["llm_base_url"] = val
|
||||
|
||||
@@ -319,22 +319,17 @@ def _maybe_parse_json_string(value: str) -> Any:
|
||||
|
||||
hint_key = "_hint" if trailing.startswith("[Hint:") else "_trailing_text"
|
||||
if isinstance(parsed, dict):
|
||||
merged = dict(parsed)
|
||||
merged[hint_key if hint_key not in merged else "_trailing_text"] = trailing
|
||||
return merged
|
||||
return {**parsed, (hint_key if hint_key not in parsed else "_trailing_text"): trailing}
|
||||
return {"data": parsed, hint_key: trailing}
|
||||
|
||||
|
||||
def _parse_read_file_lines(content: str) -> list[dict[str, Any]]:
|
||||
if not isinstance(content, str) or not content:
|
||||
return []
|
||||
lines = []
|
||||
for raw_line in content.splitlines():
|
||||
match = _READ_FILE_LINE_RE.match(raw_line)
|
||||
if not match:
|
||||
return []
|
||||
lines.append({"line": int(match.group(1)), "text": match.group(2)})
|
||||
return lines
|
||||
matches = [_READ_FILE_LINE_RE.match(raw_line) for raw_line in content.splitlines()]
|
||||
if not all(matches):
|
||||
return []
|
||||
return [{"line": int(m.group(1)), "text": m.group(2)} for m in matches]
|
||||
|
||||
|
||||
def _normalize_read_file_payload(value: dict[str, Any], *, args: Any = None) -> dict[str, Any]:
|
||||
@@ -391,11 +386,8 @@ def _safe_value(value: Any, *, max_chars: Optional[int] = None, depth: int = 0,
|
||||
return {"type": "bytes", "len": len(value)}
|
||||
recurse = lambda v, d: _safe_value(v, max_chars=max_chars, depth=d, parse_json_strings=parse_json_strings) # noqa: E731
|
||||
if isinstance(value, str):
|
||||
if parse_json_strings:
|
||||
parsed = _maybe_parse_json_string(value)
|
||||
if parsed is not value:
|
||||
return recurse(parsed, depth)
|
||||
return _truncate_text(value, max_chars)
|
||||
parsed = _maybe_parse_json_string(value) if parse_json_strings else value
|
||||
return recurse(parsed, depth) if parsed is not value else _truncate_text(value, max_chars)
|
||||
if isinstance(value, dict):
|
||||
normalized = _normalize_payload(value)
|
||||
if normalized is not value:
|
||||
@@ -485,8 +477,8 @@ def _serialize_tool_calls(tool_calls: Any) -> list[dict[str, Any]]:
|
||||
serialized = []
|
||||
for tool_call in tool_calls or ():
|
||||
fn = getattr(tool_call, "function", None)
|
||||
name = getattr(fn, "name", None) if fn else None
|
||||
safe_arguments = _capture_content(getattr(fn, "arguments", None) if fn else None)
|
||||
name = getattr(fn, "name", None)
|
||||
safe_arguments = _capture_content(getattr(fn, "arguments", None))
|
||||
serialized.append({
|
||||
"id": getattr(tool_call, "id", None),
|
||||
"type": getattr(tool_call, "type", None) or "function",
|
||||
@@ -580,12 +572,9 @@ def _summary_usage_and_cost(usage: dict, *, provider: str, model: str, base_url:
|
||||
from agent.usage_pricing import CanonicalUsage
|
||||
|
||||
canonical = CanonicalUsage(
|
||||
input_tokens=usage.get("input_tokens", 0),
|
||||
output_tokens=usage.get("output_tokens", 0) or usage.get("completion_tokens", 0),
|
||||
cache_read_tokens=usage.get("cache_read_tokens", 0),
|
||||
cache_write_tokens=usage.get("cache_write_tokens", 0),
|
||||
reasoning_tokens=usage.get("reasoning_tokens", 0),
|
||||
request_count=usage.get("request_count", 1),
|
||||
**{attr: usage.get(attr, 0) for attr in ("input_tokens", "cache_read_tokens", "cache_write_tokens", "reasoning_tokens")},
|
||||
)
|
||||
return _canonical_usage_and_cost(canonical, provider=provider, model=model, base_url=base_url)
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user