fix: resolve session ids in session tools

This commit is contained in:
Peter Steinberger
2026-01-24 11:09:06 +00:00
parent 1bbbb10abf
commit ab000398be
13 changed files with 604 additions and 130 deletions

View File

@@ -38,6 +38,7 @@ export const SessionsPreviewParamsSchema = Type.Object(
export const SessionsResolveParamsSchema = Type.Object(
{
key: Type.Optional(NonEmptyString),
sessionId: Type.Optional(NonEmptyString),
label: Type.Optional(SessionLabelString),
agentId: Type.Optional(NonEmptyString),
spawnedBy: Type.Optional(NonEmptyString),

View File

@@ -142,6 +142,12 @@ describe("gateway server sessions", () => {
expect(resolvedByKey.ok).toBe(true);
expect(resolvedByKey.payload?.key).toBe("agent:main:main");
const resolvedBySessionId = await rpcReq<{ ok: true; key: string }>(ws, "sessions.resolve", {
sessionId: "sess-group",
});
expect(resolvedBySessionId.ok).toBe(true);
expect(resolvedBySessionId.payload?.key).toBe("agent:main:discord:group:dev");
const list1 = await rpcReq<{
path: string;
defaults?: { model?: string | null; modelProvider?: string | null };

View File

@@ -23,17 +23,23 @@ export function resolveSessionKeyFromResolveParams(params: {
const key = typeof p.key === "string" ? p.key.trim() : "";
const hasKey = key.length > 0;
const sessionId = typeof p.sessionId === "string" ? p.sessionId.trim() : "";
const hasSessionId = sessionId.length > 0;
const hasLabel = typeof p.label === "string" && p.label.trim().length > 0;
if (hasKey && hasLabel) {
const selectionCount = [hasKey, hasSessionId, hasLabel].filter(Boolean).length;
if (selectionCount > 1) {
return {
ok: false,
error: errorShape(ErrorCodes.INVALID_REQUEST, "Provide either key or label (not both)"),
error: errorShape(
ErrorCodes.INVALID_REQUEST,
"Provide either key, sessionId, or label (not multiple)",
),
};
}
if (!hasKey && !hasLabel) {
if (selectionCount === 0) {
return {
ok: false,
error: errorShape(ErrorCodes.INVALID_REQUEST, "Either key or label is required"),
error: errorShape(ErrorCodes.INVALID_REQUEST, "Either key, sessionId, or label is required"),
};
}
@@ -50,6 +56,43 @@ export function resolveSessionKeyFromResolveParams(params: {
return { ok: true, key: target.canonicalKey };
}
if (hasSessionId) {
const { storePath, store } = loadCombinedSessionStoreForGateway(cfg);
const list = listSessionsFromStore({
cfg,
storePath,
store,
opts: {
includeGlobal: p.includeGlobal === true,
includeUnknown: p.includeUnknown === true,
spawnedBy: p.spawnedBy,
agentId: p.agentId,
search: sessionId,
limit: 8,
},
});
const matches = list.sessions.filter(
(session) => session.sessionId === sessionId || session.key === sessionId,
);
if (matches.length === 0) {
return {
ok: false,
error: errorShape(ErrorCodes.INVALID_REQUEST, `No session found: ${sessionId}`),
};
}
if (matches.length > 1) {
const keys = matches.map((session) => session.key).join(", ");
return {
ok: false,
error: errorShape(
ErrorCodes.INVALID_REQUEST,
`Multiple sessions found for sessionId: ${sessionId} (${keys})`,
),
};
}
return { ok: true, key: String(matches[0]?.key ?? "") };
}
const parsedLabel = parseSessionLabel(p.label);
if (!parsedLabel.ok) {
return {