diff --git a/README.md b/README.md index a9f938bf..5d317f18 100644 --- a/README.md +++ b/README.md @@ -283,3 +283,34 @@ The BFF layer handles API proxy (with path rewriting), SSE streaming, file uploa ## License [MIT](./LICENSE) + +## Configuration + +### API Server Key for Jobs API + +Web UI requires `API_SERVER_KEY` to authenticate with Hermes Gateway's Jobs API. + +**For default profile**, create `~/.hermes/.env`: +```bash +API_SERVER_KEY="your-api-server-key" +``` + +**For other profiles**, create `~/.hermes/profiles//.env`: +```bash +API_SERVER_KEY="your-api-server-key" +``` + +The API key is configured in `~/.hermes/config.yaml`: +```yaml +platforms: + api_server: + enabled: true + key: "your-api-server-key" # Copy this value to .env + extra: + host: 127.0.0.1 + port: 8642 +``` + +### Why is this needed? + +Web UI's `gateway-manager.ts` reads `API_SERVER_KEY` from `.env` file to authenticate proxy requests to Hermes Gateway's `/api/jobs` endpoint. Without this configuration, the Jobs page will return `Invalid API key` error. diff --git a/packages/server/src/db/hermes/session-store.ts b/packages/server/src/db/hermes/session-store.ts index fff6bd89..9ab92a82 100644 --- a/packages/server/src/db/hermes/session-store.ts +++ b/packages/server/src/db/hermes/session-store.ts @@ -134,11 +134,12 @@ export function createSession(data: { model?: string title?: string workspace?: string + source?: string }): HermesSessionRow { const now = Math.floor(Date.now() / 1000) if (!isSqliteAvailable()) { return { - id: data.id, profile: data.profile || 'default', source: 'api_server', + id: data.id, profile: data.profile || 'default', source: data.source || 'api_server', user_id: null, model: data.model || '', title: data.title || null, started_at: now, ended_at: null, end_reason: null, message_count: 0, tool_call_count: 0, @@ -150,8 +151,8 @@ export function createSession(data: { const db = getDb()! db.prepare( `INSERT INTO ${SESSIONS_TABLE} (id, profile, source, model, title, started_at, last_active, workspace) - VALUES (?, ?, 'api_server', ?, ?, ?, ?, ?)`, - ).run(data.id, data.profile || 'default', data.model || '', data.title || null, now, now, data.workspace || null) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, + ).run(data.id, data.profile || 'default', data.source || 'api_server', data.model || '', data.title || null, now, now, data.workspace || null) return getSession(data.id)! } diff --git a/packages/server/src/services/hermes/session-sync.ts b/packages/server/src/services/hermes/session-sync.ts index db387eb7..77f9f4de 100644 --- a/packages/server/src/services/hermes/session-sync.ts +++ b/packages/server/src/services/hermes/session-sync.ts @@ -63,7 +63,7 @@ async function syncProfileSessions(profile: string): Promise<{ try { // Use listSessionSummaries to get aggregated session chains // This returns only root sessions with aggregated stats from the entire chain - const summaries = await listHermesSessionSummaries('api_server', 10000, profile) + const summaries = await listHermesSessionSummaries(undefined, 10000, profile) logger.info(`[session-sync] profile '${profile}': found ${summaries.length} aggregated session chains`) @@ -77,6 +77,7 @@ async function syncProfileSessions(profile: string): Promise<{ id: newSessionId, profile, model: hermesSession.model, + source: hermesSession.source, title: hermesSession.title || undefined, })