mirror of
https://github.com/EKKOLearnAI/hermes-web-ui.git
synced 2026-05-28 06:50:14 +00:00
add web ui openrouter attribution (#1057)
This commit is contained in:
@@ -42,6 +42,11 @@ DEFAULT_HERMES_HOME = "~/.hermes"
|
||||
APPROVAL_TIMEOUT_SECONDS = 120
|
||||
APPROVAL_TIMEOUT_MS = APPROVAL_TIMEOUT_SECONDS * 1000
|
||||
PARENT_WATCHDOG_INTERVAL_SECONDS = 2.0
|
||||
OPENROUTER_ATTRIBUTION_ENV = {
|
||||
"referer": "HERMES_OPENROUTER_APP_REFERER",
|
||||
"title": "HERMES_OPENROUTER_APP_TITLE",
|
||||
"categories": "HERMES_OPENROUTER_APP_CATEGORIES",
|
||||
}
|
||||
|
||||
|
||||
def _bridge_platform() -> str:
|
||||
@@ -349,6 +354,32 @@ def _ensure_agent_imports() -> None:
|
||||
)
|
||||
os.environ.setdefault("HERMES_HOME", str(_hermes_home()))
|
||||
os.environ.setdefault("HERMES_AGENT_BRIDGE_BASE_HOME", str(_hermes_home()))
|
||||
_apply_openrouter_attribution_override()
|
||||
|
||||
|
||||
def _apply_openrouter_attribution_override() -> None:
|
||||
"""Override hermes-agent OpenRouter attribution at bridge runtime only."""
|
||||
referer = os.environ.get(OPENROUTER_ATTRIBUTION_ENV["referer"], "").strip()
|
||||
title = os.environ.get(OPENROUTER_ATTRIBUTION_ENV["title"], "").strip()
|
||||
categories = os.environ.get(OPENROUTER_ATTRIBUTION_ENV["categories"], "").strip()
|
||||
if not (referer or title or categories):
|
||||
return
|
||||
try:
|
||||
from agent import auxiliary_client
|
||||
except Exception:
|
||||
return
|
||||
headers = dict(getattr(auxiliary_client, "_OR_HEADERS_BASE", {}) or {})
|
||||
if referer:
|
||||
headers["HTTP-Referer"] = referer
|
||||
if title:
|
||||
headers.pop("X-Title", None)
|
||||
headers["X-OpenRouter-Title"] = title
|
||||
if categories:
|
||||
headers["X-OpenRouter-Categories"] = categories
|
||||
try:
|
||||
auxiliary_client._OR_HEADERS_BASE = headers
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _load_cfg(profile: str | None = None) -> dict[str, Any]:
|
||||
|
||||
@@ -9,6 +9,11 @@ import { DEFAULT_AGENT_BRIDGE_ENDPOINT } from './client'
|
||||
const DEFAULT_AGENT_BRIDGE_STARTUP_TIMEOUT_MS = 120000
|
||||
const DEFAULT_AGENT_BRIDGE_RESTART_DELAY_MS = 1000
|
||||
const MAX_AGENT_BRIDGE_RESTART_DELAY_MS = 30000
|
||||
const OPENROUTER_WEB_UI_ATTRIBUTION_ENV = {
|
||||
HERMES_OPENROUTER_APP_REFERER: 'https://ekkolearnai.com',
|
||||
HERMES_OPENROUTER_APP_TITLE: 'Hermes Web UI',
|
||||
HERMES_OPENROUTER_APP_CATEGORIES: 'cli-agent,personal-agent',
|
||||
} as const
|
||||
|
||||
export interface AgentBridgeManagerOptions {
|
||||
endpoint?: string
|
||||
@@ -43,6 +48,18 @@ function envPositiveInt(name: string): number | undefined {
|
||||
return Number.isFinite(value) && value > 0 ? value : undefined
|
||||
}
|
||||
|
||||
export function buildAgentBridgeProcessEnv(endpoint: string, hermesHome: string | undefined, agentRoot: string | undefined): NodeJS.ProcessEnv {
|
||||
return {
|
||||
...process.env,
|
||||
HERMES_AGENT_BRIDGE_ENDPOINT: endpoint,
|
||||
HERMES_HOME: hermesHome,
|
||||
HERMES_OPENROUTER_APP_REFERER: process.env.HERMES_OPENROUTER_APP_REFERER || OPENROUTER_WEB_UI_ATTRIBUTION_ENV.HERMES_OPENROUTER_APP_REFERER,
|
||||
HERMES_OPENROUTER_APP_TITLE: process.env.HERMES_OPENROUTER_APP_TITLE || OPENROUTER_WEB_UI_ATTRIBUTION_ENV.HERMES_OPENROUTER_APP_TITLE,
|
||||
HERMES_OPENROUTER_APP_CATEGORIES: process.env.HERMES_OPENROUTER_APP_CATEGORIES || OPENROUTER_WEB_UI_ATTRIBUTION_ENV.HERMES_OPENROUTER_APP_CATEGORIES,
|
||||
...(agentRoot ? { HERMES_AGENT_ROOT: agentRoot } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
function pathCandidates(agentRoot?: string): string[] {
|
||||
if (!agentRoot) return []
|
||||
return process.platform === 'win32'
|
||||
@@ -358,12 +375,7 @@ export class AgentBridgeManager {
|
||||
if (agentRoot) args.push('--agent-root', agentRoot)
|
||||
if (hermesHome) args.push('--hermes-home', hermesHome)
|
||||
|
||||
const env = {
|
||||
...process.env,
|
||||
HERMES_AGENT_BRIDGE_ENDPOINT: this.endpoint,
|
||||
HERMES_HOME: hermesHome,
|
||||
...(agentRoot ? { HERMES_AGENT_ROOT: agentRoot } : {}),
|
||||
}
|
||||
const env = buildAgentBridgeProcessEnv(this.endpoint, hermesHome, agentRoot)
|
||||
|
||||
logger.info('[agent-bridge] starting: %s %s', command.command, args.join(' '))
|
||||
const child = spawn(command.command, args, {
|
||||
|
||||
@@ -93,6 +93,28 @@ describe('agent bridge manager command resolution', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('injects Web UI OpenRouter attribution into the bridge process env by default', async () => {
|
||||
const { buildAgentBridgeProcessEnv } = await import('../../packages/server/src/services/hermes/agent-bridge/manager')
|
||||
const env = buildAgentBridgeProcessEnv('ipc:///tmp/test.sock', '/tmp/hermes-home', '/tmp/hermes-agent')
|
||||
|
||||
expect(env.HERMES_OPENROUTER_APP_REFERER).toBe('https://ekkolearnai.com')
|
||||
expect(env.HERMES_OPENROUTER_APP_TITLE).toBe('Hermes Web UI')
|
||||
expect(env.HERMES_OPENROUTER_APP_CATEGORIES).toBe('cli-agent,personal-agent')
|
||||
})
|
||||
|
||||
it('keeps explicit OpenRouter attribution env values when starting the bridge', async () => {
|
||||
process.env.HERMES_OPENROUTER_APP_REFERER = 'https://example.invalid/app'
|
||||
process.env.HERMES_OPENROUTER_APP_TITLE = 'Custom App'
|
||||
process.env.HERMES_OPENROUTER_APP_CATEGORIES = 'custom-category'
|
||||
|
||||
const { buildAgentBridgeProcessEnv } = await import('../../packages/server/src/services/hermes/agent-bridge/manager')
|
||||
const env = buildAgentBridgeProcessEnv('ipc:///tmp/test.sock', '/tmp/hermes-home', undefined)
|
||||
|
||||
expect(env.HERMES_OPENROUTER_APP_REFERER).toBe('https://example.invalid/app')
|
||||
expect(env.HERMES_OPENROUTER_APP_TITLE).toBe('Custom App')
|
||||
expect(env.HERMES_OPENROUTER_APP_CATEGORIES).toBe('custom-category')
|
||||
})
|
||||
|
||||
it('uses an isolated default bridge endpoint while running under Vitest', async () => {
|
||||
const { DEFAULT_AGENT_BRIDGE_ENDPOINT } = await import('../../packages/server/src/services/hermes/agent-bridge/client')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user