fix(gateway): normalize session key to canonical form before store writes
Ensure 'main' alias is always stored as 'agent:main:main' to prevent duplicate entries. Also update loadSessionEntry to check both forms when looking up entries. Fixes duplicate main sessions in session store.
This commit is contained in:
@@ -24,6 +24,7 @@ import { buildConfigSchema } from "../config/schema.js";
|
|||||||
import {
|
import {
|
||||||
loadSessionStore,
|
loadSessionStore,
|
||||||
mergeSessionEntry,
|
mergeSessionEntry,
|
||||||
|
resolveAgentMainSessionKey,
|
||||||
resolveMainSessionKeyFromConfig,
|
resolveMainSessionKeyFromConfig,
|
||||||
type SessionEntry,
|
type SessionEntry,
|
||||||
saveSessionStore,
|
saveSessionStore,
|
||||||
@@ -35,7 +36,10 @@ import {
|
|||||||
} from "../infra/voicewake.js";
|
} from "../infra/voicewake.js";
|
||||||
import { clearCommandLane } from "../process/command-queue.js";
|
import { clearCommandLane } from "../process/command-queue.js";
|
||||||
import { normalizeProviderId } from "../providers/plugins/index.js";
|
import { normalizeProviderId } from "../providers/plugins/index.js";
|
||||||
import { normalizeMainKey } from "../routing/session-key.js";
|
import {
|
||||||
|
normalizeMainKey,
|
||||||
|
resolveAgentIdFromSessionKey,
|
||||||
|
} from "../routing/session-key.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import {
|
import {
|
||||||
abortChatRunById,
|
abortChatRunById,
|
||||||
@@ -918,8 +922,14 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
|||||||
clientRunId,
|
clientRunId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Normalize short main key alias to canonical form before store write
|
||||||
|
const agentId = resolveAgentIdFromSessionKey(p.sessionKey);
|
||||||
|
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||||
|
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
|
||||||
|
const storeKey =
|
||||||
|
p.sessionKey === rawMainKey ? mainSessionKey : p.sessionKey;
|
||||||
if (store) {
|
if (store) {
|
||||||
store[p.sessionKey] = sessionEntry;
|
store[storeKey] = sessionEntry;
|
||||||
if (storePath) {
|
if (storePath) {
|
||||||
await saveSessionStore(storePath, store);
|
await saveSessionStore(storePath, store);
|
||||||
}
|
}
|
||||||
@@ -1032,12 +1042,18 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
|||||||
if (text.length > 20_000) return;
|
if (text.length > 20_000) return;
|
||||||
const sessionKeyRaw =
|
const sessionKeyRaw =
|
||||||
typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
|
typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
|
||||||
const mainKey = normalizeMainKey(loadConfig().session?.mainKey);
|
const cfg = loadConfig();
|
||||||
const sessionKey = sessionKeyRaw.length > 0 ? sessionKeyRaw : mainKey;
|
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
|
||||||
|
const sessionKey = sessionKeyRaw.length > 0 ? sessionKeyRaw : rawMainKey;
|
||||||
const { storePath, store, entry } = loadSessionEntry(sessionKey);
|
const { storePath, store, entry } = loadSessionEntry(sessionKey);
|
||||||
|
// Normalize short main key alias to canonical form before store write
|
||||||
|
const agentId = resolveAgentIdFromSessionKey(sessionKey);
|
||||||
|
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||||
|
const storeKey =
|
||||||
|
sessionKey === rawMainKey ? mainSessionKey : sessionKey;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const sessionId = entry?.sessionId ?? randomUUID();
|
const sessionId = entry?.sessionId ?? randomUUID();
|
||||||
store[sessionKey] = {
|
store[storeKey] = {
|
||||||
sessionId,
|
sessionId,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
thinkingLevel: entry?.thinkingLevel,
|
thinkingLevel: entry?.thinkingLevel,
|
||||||
@@ -1112,9 +1128,19 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
|
|||||||
const sessionKey =
|
const sessionKey =
|
||||||
sessionKeyRaw.length > 0 ? sessionKeyRaw : `node-${nodeId}`;
|
sessionKeyRaw.length > 0 ? sessionKeyRaw : `node-${nodeId}`;
|
||||||
const { storePath, store, entry } = loadSessionEntry(sessionKey);
|
const { storePath, store, entry } = loadSessionEntry(sessionKey);
|
||||||
|
// Normalize short main key alias to canonical form before store write
|
||||||
|
const nodeCfg = loadConfig();
|
||||||
|
const nodeAgentId = resolveAgentIdFromSessionKey(sessionKey);
|
||||||
|
const nodeMainSessionKey = resolveAgentMainSessionKey({
|
||||||
|
cfg: nodeCfg,
|
||||||
|
agentId: nodeAgentId,
|
||||||
|
});
|
||||||
|
const nodeRawMainKey = normalizeMainKey(nodeCfg.session?.mainKey);
|
||||||
|
const nodeStoreKey =
|
||||||
|
sessionKey === nodeRawMainKey ? nodeMainSessionKey : sessionKey;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const sessionId = entry?.sessionId ?? randomUUID();
|
const sessionId = entry?.sessionId ?? randomUUID();
|
||||||
store[sessionKey] = {
|
store[nodeStoreKey] = {
|
||||||
sessionId,
|
sessionId,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
thinkingLevel: entry?.thinkingLevel,
|
thinkingLevel: entry?.thinkingLevel,
|
||||||
|
|||||||
@@ -189,12 +189,6 @@ export const agentHandlers: GatewayRequestHandlers = {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (store) {
|
|
||||||
store[requestedSessionKey] = nextEntry;
|
|
||||||
if (storePath) {
|
|
||||||
await saveSessionStore(storePath, store);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolvedSessionId = sessionId;
|
resolvedSessionId = sessionId;
|
||||||
const agentId = resolveAgentIdFromSessionKey(requestedSessionKey);
|
const agentId = resolveAgentIdFromSessionKey(requestedSessionKey);
|
||||||
const mainSessionKey = resolveAgentMainSessionKey({
|
const mainSessionKey = resolveAgentMainSessionKey({
|
||||||
@@ -202,6 +196,15 @@ export const agentHandlers: GatewayRequestHandlers = {
|
|||||||
agentId,
|
agentId,
|
||||||
});
|
});
|
||||||
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
|
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
|
||||||
|
// Normalize short main key alias to canonical form before store write
|
||||||
|
const storeKey =
|
||||||
|
requestedSessionKey === rawMainKey ? mainSessionKey : requestedSessionKey;
|
||||||
|
if (store) {
|
||||||
|
store[storeKey] = nextEntry;
|
||||||
|
if (storePath) {
|
||||||
|
await saveSessionStore(storePath, store);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
requestedSessionKey === mainSessionKey ||
|
requestedSessionKey === mainSessionKey ||
|
||||||
requestedSessionKey === rawMainKey
|
requestedSessionKey === rawMainKey
|
||||||
|
|||||||
@@ -3,7 +3,15 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { resolveThinkingDefault } from "../../agents/model-selection.js";
|
import { resolveThinkingDefault } from "../../agents/model-selection.js";
|
||||||
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
|
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
|
||||||
import { agentCommand } from "../../commands/agent.js";
|
import { agentCommand } from "../../commands/agent.js";
|
||||||
import { mergeSessionEntry, saveSessionStore } from "../../config/sessions.js";
|
import {
|
||||||
|
mergeSessionEntry,
|
||||||
|
resolveAgentMainSessionKey,
|
||||||
|
saveSessionStore,
|
||||||
|
} from "../../config/sessions.js";
|
||||||
|
import {
|
||||||
|
normalizeMainKey,
|
||||||
|
resolveAgentIdFromSessionKey,
|
||||||
|
} from "../../routing/session-key.js";
|
||||||
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
||||||
import { defaultRuntime } from "../../runtime.js";
|
import { defaultRuntime } from "../../runtime.js";
|
||||||
import { resolveSendPolicy } from "../../sessions/send-policy.js";
|
import { resolveSendPolicy } from "../../sessions/send-policy.js";
|
||||||
@@ -306,8 +314,14 @@ export const chatHandlers: GatewayRequestHandlers = {
|
|||||||
clientRunId,
|
clientRunId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Normalize short main key alias to canonical form before store write
|
||||||
|
const agentId = resolveAgentIdFromSessionKey(p.sessionKey);
|
||||||
|
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||||
|
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
|
||||||
|
const storeKey =
|
||||||
|
p.sessionKey === rawMainKey ? mainSessionKey : p.sessionKey;
|
||||||
if (store) {
|
if (store) {
|
||||||
store[p.sessionKey] = sessionEntry;
|
store[storeKey] = sessionEntry;
|
||||||
if (storePath) {
|
if (storePath) {
|
||||||
await saveSessionStore(storePath, store);
|
await saveSessionStore(storePath, store);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
buildGroupDisplayName,
|
buildGroupDisplayName,
|
||||||
loadSessionStore,
|
loadSessionStore,
|
||||||
resolveAgentIdFromSessionKey,
|
resolveAgentIdFromSessionKey,
|
||||||
|
resolveAgentMainSessionKey,
|
||||||
resolveSessionTranscriptPath,
|
resolveSessionTranscriptPath,
|
||||||
resolveStorePath,
|
resolveStorePath,
|
||||||
type SessionEntry,
|
type SessionEntry,
|
||||||
@@ -172,7 +173,16 @@ export function loadSessionEntry(sessionKey: string) {
|
|||||||
const store = loadSessionStore(storePath);
|
const store = loadSessionStore(storePath);
|
||||||
const parsed = parseAgentSessionKey(sessionKey);
|
const parsed = parseAgentSessionKey(sessionKey);
|
||||||
const legacyKey = parsed?.rest;
|
const legacyKey = parsed?.rest;
|
||||||
const entry = store[sessionKey] ?? (legacyKey ? store[legacyKey] : undefined);
|
// Also try the canonical key if sessionKey is the short mainKey alias
|
||||||
|
const rawMainKey = normalizeMainKey(sessionCfg?.mainKey);
|
||||||
|
const canonicalKey =
|
||||||
|
sessionKey === rawMainKey
|
||||||
|
? resolveAgentMainSessionKey({ cfg, agentId })
|
||||||
|
: undefined;
|
||||||
|
const entry =
|
||||||
|
store[sessionKey] ??
|
||||||
|
(legacyKey ? store[legacyKey] : undefined) ??
|
||||||
|
(canonicalKey ? store[canonicalKey] : undefined);
|
||||||
return { cfg, storePath, store, entry };
|
return { cfg, storePath, store, entry };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user