@syengup/friday-channel-next 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { sseEmitter } from "./sse/emitter.js";
2
2
  import { getFridayAgentForwardRuntime } from "./agent-forward-runtime.js";
3
- import { toSessionStoreKey } from "./session/session-manager.js";
3
+ import { toSessionStoreKey, agentIdFromSessionKey } from "./session/session-manager.js";
4
4
  import { getOpenClawAgentRunContext } from "./agent-run-context-bridge.js";
5
5
  import { observeAgentEventForActiveRuns } from "./agent/active-runs.js";
6
6
  import { getRunMetadata, ingestAgentEventMetadata } from "./run-metadata.js";
@@ -118,7 +118,6 @@ export function resolveHistorySessionKeyForFridayDevice(deviceId) {
118
118
  return fromMemory;
119
119
  return `agent:main:friday-next-${did}`;
120
120
  }
121
- const DEFAULT_SESSION_STORE_AGENT_ID = "main";
122
121
  function mergeRunMetadataIntoLifecycleEnd(runId, base) {
123
122
  const meta = getRunMetadata(runId);
124
123
  if (!meta)
@@ -151,9 +150,9 @@ function tryReadSessionUsageFromStore(sessionKeyForStore) {
151
150
  try {
152
151
  const cfg = access.getConfig();
153
152
  const storeConfig = cfg?.session?.store;
154
- const storePath = access.resolveStorePath(storeConfig, { agentId: DEFAULT_SESSION_STORE_AGENT_ID });
155
- const store = access.loadSessionStore(storePath, { skipCache: true });
156
153
  const canonical = toSessionStoreKey(sessionKeyForStore);
154
+ const storePath = access.resolveStorePath(storeConfig, { agentId: agentIdFromSessionKey(canonical) });
155
+ const store = access.loadSessionStore(storePath, { skipCache: true });
157
156
  const entry = store[canonical] ?? store[sessionKeyForStore.trim()];
158
157
  if (!entry || typeof entry !== "object")
159
158
  return undefined;
@@ -14,7 +14,7 @@ import { resolveFridayNextConfig } from "../../config.js";
14
14
  import { getHostOpenClawConfigSnapshot } from "../../host-config.js";
15
15
  import { getFridayNextRuntime } from "../../runtime.js";
16
16
  import { getFridayAgentForwardRuntime } from "../../agent-forward-runtime.js";
17
- import { setSessionSettings, splitModelRef, toSessionStoreKey } from "../../session/session-manager.js";
17
+ import { agentIdFromSessionKey, setSessionSettings, splitModelRef, toSessionStoreKey, } from "../../session/session-manager.js";
18
18
  import { sseEmitter } from "../../sse/emitter.js";
19
19
  import { extractBearerToken } from "../middleware/auth.js";
20
20
  import { readJsonBody } from "../middleware/body.js";
@@ -315,6 +315,10 @@ export async function handleMessages(req, res) {
315
315
  log("MESSAGE_RECEIVED", normalizedDeviceId, runId, `textLen=${trimmedText.length} attachments=${attachments.length} sessionKey=${baseSessionKey}`);
316
316
  const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(runtime.config));
317
317
  // Resolve defaults from the OpenClaw agent config so settings are never left empty.
318
+ // The target agent comes from the app-supplied sessionKey (`agent:<id>:<rest>`); prefer that
319
+ // agent's own configured model/thinking over the global defaults so non-main agents are not
320
+ // silently forced onto the global default model.
321
+ const targetAgentId = agentIdFromSessionKey(baseSessionKey);
318
322
  let defaultModel;
319
323
  let defaultThinking;
320
324
  try {
@@ -322,13 +326,24 @@ export async function handleMessages(req, res) {
322
326
  if (forwardRt) {
323
327
  const ocCfg = (forwardRt.getConfig() ?? {});
324
328
  const agents = ocCfg.agents;
329
+ const agentEntry = agents?.list?.find((a) => agentIdFromSessionKey(`agent:${String(a?.id ?? "")}:x`) === targetAgentId);
330
+ const agentModel = agentEntry?.model;
331
+ const perAgentModel = typeof agentModel === "string"
332
+ ? agentModel
333
+ : typeof agentModel?.primary === "string"
334
+ ? agentModel.primary
335
+ : undefined;
336
+ const perAgentThinking = typeof agentEntry?.thinkingDefault === "string"
337
+ ? agentEntry.thinkingDefault
338
+ : undefined;
325
339
  const agentDefaults = agents?.defaults;
326
340
  const model = agentDefaults?.model;
327
- defaultModel = typeof model?.primary === "string" ? model.primary : undefined;
328
- defaultThinking =
329
- typeof agentDefaults?.thinkingDefault === "string"
330
- ? agentDefaults.thinkingDefault
331
- : undefined;
341
+ const globalModel = typeof model?.primary === "string" ? model.primary : undefined;
342
+ const globalThinking = typeof agentDefaults?.thinkingDefault === "string"
343
+ ? agentDefaults.thinkingDefault
344
+ : undefined;
345
+ defaultModel = perAgentModel ?? globalModel;
346
+ defaultThinking = perAgentThinking ?? globalThinking;
332
347
  }
333
348
  }
334
349
  catch {
@@ -3,6 +3,12 @@ export declare function splitModelRef(modelRef: string): {
3
3
  modelId: string;
4
4
  };
5
5
  export declare function toSessionStoreKey(rawSessionKey: string): string;
6
+ /**
7
+ * Extract the agent id from a (possibly raw) session key. The downstream app now owns the
8
+ * full `agent:<id>:<rest>` key, so non-`main` agents must read/write their own session store
9
+ * directory. `agent:<id>:<rest>` → `<id>`; bare/legacy keys (or an unsafe id) → `main`.
10
+ */
11
+ export declare function agentIdFromSessionKey(rawSessionKey: string): string;
6
12
  export declare function ensureSessionLevels(sessionKey: string, reasoningLevel: string, thinkingLevel: string, historyDir?: string): void;
7
13
  export interface FridaySessionSettings {
8
14
  reasoningLevel?: string;
@@ -3,6 +3,8 @@ import os from "node:os";
3
3
  import { readFileSync, writeFileSync } from "node:fs";
4
4
  const FRIDAY_AGENT_ID = "main";
5
5
  const SESSION_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
6
+ /** Path/shell-safe agent id (mirrors OpenClaw's `normalizeAgentId`). Anything else falls back to `main`. */
7
+ const SAFE_AGENT_ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
6
8
  function deriveOpenClawBaseDir(historyDir) {
7
9
  if (historyDir) {
8
10
  const match = historyDir.replace(/[\\/]+$/, "").match(/(.*[\\/]\.openclaw)[\\/]/);
@@ -37,6 +39,16 @@ export function toSessionStoreKey(rawSessionKey) {
37
39
  }
38
40
  return `agent:${FRIDAY_AGENT_ID}:${lowered}`;
39
41
  }
42
+ /**
43
+ * Extract the agent id from a (possibly raw) session key. The downstream app now owns the
44
+ * full `agent:<id>:<rest>` key, so non-`main` agents must read/write their own session store
45
+ * directory. `agent:<id>:<rest>` → `<id>`; bare/legacy keys (or an unsafe id) → `main`.
46
+ */
47
+ export function agentIdFromSessionKey(rawSessionKey) {
48
+ const canonical = toSessionStoreKey(rawSessionKey);
49
+ const id = canonical.match(/^agent:([^:]+):/)?.[1];
50
+ return id && SAFE_AGENT_ID_RE.test(id) ? id : FRIDAY_AGENT_ID;
51
+ }
40
52
  function toSafeSessionId(raw) {
41
53
  const s = raw.trim();
42
54
  if (SESSION_ID_RE.test(s))
@@ -54,8 +66,8 @@ function sessionIdForSessionsFile(fileKey, rawSessionKey) {
54
66
  for (const c of candidates) {
55
67
  if (SESSION_ID_RE.test(c))
56
68
  return c;
57
- if (c.startsWith(`agent:${FRIDAY_AGENT_ID}:`)) {
58
- const tail = c.slice(`agent:${FRIDAY_AGENT_ID}:`.length);
69
+ const tail = c.match(/^agent:[^:]+:(.+)$/)?.[1];
70
+ if (tail) {
59
71
  if (SESSION_ID_RE.test(tail))
60
72
  return tail;
61
73
  return toSafeSessionId(tail);
@@ -63,9 +75,9 @@ function sessionIdForSessionsFile(fileKey, rawSessionKey) {
63
75
  }
64
76
  return toSafeSessionId(rawSessionKey || fileKey);
65
77
  }
66
- function resolveSessionsFilePath(historyDir) {
78
+ function resolveSessionsFilePath(historyDir, agentId) {
67
79
  const base = deriveOpenClawBaseDir(historyDir);
68
- return join(base, "agents/main/sessions/sessions.json");
80
+ return join(base, "agents", agentId, "sessions", "sessions.json");
69
81
  }
70
82
  function readSessionsData(path) {
71
83
  try {
@@ -98,11 +110,11 @@ export function ensureSessionLevels(sessionKey, reasoningLevel, thinkingLevel, h
98
110
  }
99
111
  export function setSessionSettings(sessionKey, settings, historyDir) {
100
112
  try {
101
- const sessionsFile = resolveSessionsFilePath(historyDir);
113
+ const fileKey = toSessionStoreKey(sessionKey);
114
+ const sessionsFile = resolveSessionsFilePath(historyDir, agentIdFromSessionKey(fileKey));
102
115
  const data = readSessionsData(sessionsFile);
103
116
  if (!data)
104
117
  return {};
105
- const fileKey = toSessionStoreKey(sessionKey);
106
118
  upsertSessionEntry(data, fileKey, sessionKey);
107
119
  const fieldKeys = [
108
120
  "reasoningLevel", "thinkingLevel", "modelRef", "providerOverride", "modelOverride",
@@ -137,11 +149,11 @@ function readSettingsFromEntry(entry) {
137
149
  }
138
150
  export function getSessionSettings(sessionKey, historyDir) {
139
151
  try {
140
- const sessionsFile = resolveSessionsFilePath(historyDir);
152
+ const fileKey = toSessionStoreKey(sessionKey);
153
+ const sessionsFile = resolveSessionsFilePath(historyDir, agentIdFromSessionKey(fileKey));
141
154
  const data = readSessionsData(sessionsFile);
142
155
  if (!data)
143
156
  return {};
144
- const fileKey = toSessionStoreKey(sessionKey);
145
157
  const entry = data[fileKey];
146
158
  if (!entry)
147
159
  return {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syengup/friday-channel-next",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "OpenClaw Friday Next Apple channel plugin",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  import { sseEmitter } from "./sse/emitter.js";
2
2
  import { getFridayAgentForwardRuntime } from "./agent-forward-runtime.js";
3
- import { toSessionStoreKey } from "./session/session-manager.js";
3
+ import { toSessionStoreKey, agentIdFromSessionKey } from "./session/session-manager.js";
4
4
  import { getOpenClawAgentRunContext } from "./agent-run-context-bridge.js";
5
5
  import { observeAgentEventForActiveRuns } from "./agent/active-runs.js";
6
6
  import { getRunMetadata, ingestAgentEventMetadata } from "./run-metadata.js";
@@ -138,8 +138,6 @@ export function resolveHistorySessionKeyForFridayDevice(deviceId: string): strin
138
138
  return `agent:main:friday-next-${did}`;
139
139
  }
140
140
 
141
- const DEFAULT_SESSION_STORE_AGENT_ID = "main";
142
-
143
141
  type ForwardAgentEventArgs = {
144
142
  runId: string;
145
143
  seq?: number;
@@ -186,9 +184,9 @@ function tryReadSessionUsageFromStore(sessionKeyForStore: string): FridaySession
186
184
  try {
187
185
  const cfg = access.getConfig() as { session?: { store?: string } } | null | undefined;
188
186
  const storeConfig = cfg?.session?.store;
189
- const storePath = access.resolveStorePath(storeConfig, { agentId: DEFAULT_SESSION_STORE_AGENT_ID });
190
- const store = access.loadSessionStore(storePath, { skipCache: true }) as Record<string, Record<string, unknown>>;
191
187
  const canonical = toSessionStoreKey(sessionKeyForStore);
188
+ const storePath = access.resolveStorePath(storeConfig, { agentId: agentIdFromSessionKey(canonical) });
189
+ const store = access.loadSessionStore(storePath, { skipCache: true }) as Record<string, Record<string, unknown>>;
192
190
  const entry = store[canonical] ?? store[sessionKeyForStore.trim()];
193
191
  if (!entry || typeof entry !== "object") return undefined;
194
192
  return buildSessionUsageSnapshot(entry);
@@ -28,7 +28,12 @@ import { resolveFridayNextConfig } from "../../config.js";
28
28
  import { getHostOpenClawConfigSnapshot } from "../../host-config.js";
29
29
  import { getFridayNextRuntime } from "../../runtime.js";
30
30
  import { getFridayAgentForwardRuntime } from "../../agent-forward-runtime.js";
31
- import { setSessionSettings, splitModelRef, toSessionStoreKey } from "../../session/session-manager.js";
31
+ import {
32
+ agentIdFromSessionKey,
33
+ setSessionSettings,
34
+ splitModelRef,
35
+ toSessionStoreKey,
36
+ } from "../../session/session-manager.js";
32
37
  import { sseEmitter } from "../../sse/emitter.js";
33
38
  import { extractBearerToken } from "../middleware/auth.js";
34
39
  import { readJsonBody } from "../middleware/body.js";
@@ -421,6 +426,10 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
421
426
  const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(runtime.config));
422
427
 
423
428
  // Resolve defaults from the OpenClaw agent config so settings are never left empty.
429
+ // The target agent comes from the app-supplied sessionKey (`agent:<id>:<rest>`); prefer that
430
+ // agent's own configured model/thinking over the global defaults so non-main agents are not
431
+ // silently forced onto the global default model.
432
+ const targetAgentId = agentIdFromSessionKey(baseSessionKey);
424
433
  let defaultModel: string | undefined;
425
434
  let defaultThinking: string | undefined;
426
435
  try {
@@ -428,13 +437,32 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
428
437
  if (forwardRt) {
429
438
  const ocCfg = (forwardRt.getConfig() ?? {}) as Record<string, unknown>;
430
439
  const agents = ocCfg.agents as Record<string, unknown> | undefined;
440
+
441
+ const agentEntry = (agents?.list as Array<Record<string, unknown>> | undefined)?.find(
442
+ (a) => agentIdFromSessionKey(`agent:${String(a?.id ?? "")}:x`) === targetAgentId,
443
+ );
444
+ const agentModel = agentEntry?.model;
445
+ const perAgentModel =
446
+ typeof agentModel === "string"
447
+ ? agentModel
448
+ : typeof (agentModel as Record<string, unknown> | undefined)?.primary === "string"
449
+ ? ((agentModel as Record<string, unknown>).primary as string)
450
+ : undefined;
451
+ const perAgentThinking =
452
+ typeof agentEntry?.thinkingDefault === "string"
453
+ ? (agentEntry.thinkingDefault as string)
454
+ : undefined;
455
+
431
456
  const agentDefaults = agents?.defaults as Record<string, unknown> | undefined;
432
457
  const model = agentDefaults?.model as Record<string, unknown> | undefined;
433
- defaultModel = typeof model?.primary === "string" ? (model.primary as string) : undefined;
434
- defaultThinking =
458
+ const globalModel = typeof model?.primary === "string" ? (model.primary as string) : undefined;
459
+ const globalThinking =
435
460
  typeof agentDefaults?.thinkingDefault === "string"
436
461
  ? (agentDefaults.thinkingDefault as string)
437
462
  : undefined;
463
+
464
+ defaultModel = perAgentModel ?? globalModel;
465
+ defaultThinking = perAgentThinking ?? globalThinking;
438
466
  }
439
467
  } catch {
440
468
  // Config not available (tests) — leave defaults undefined.
@@ -0,0 +1,90 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import {
6
+ agentIdFromSessionKey,
7
+ toSessionStoreKey,
8
+ setSessionSettings,
9
+ getSessionSettings,
10
+ } from "./session-manager.js";
11
+
12
+ describe("agentIdFromSessionKey", () => {
13
+ it("extracts the agent id from a fully-qualified key", () => {
14
+ expect(agentIdFromSessionKey("agent:operator:friday:direct:abc:1")).toBe("operator");
15
+ expect(agentIdFromSessionKey("agent:ha-maestro:main")).toBe("ha-maestro");
16
+ });
17
+
18
+ it("falls back to main for bare / legacy keys", () => {
19
+ expect(agentIdFromSessionKey("main")).toBe("main");
20
+ expect(agentIdFromSessionKey("friday:direct:dev:1")).toBe("main");
21
+ expect(agentIdFromSessionKey("")).toBe("main");
22
+ });
23
+
24
+ it("rejects path-unsafe agent ids (no traversal)", () => {
25
+ expect(agentIdFromSessionKey("agent:../../etc:foo")).toBe("main");
26
+ });
27
+ });
28
+
29
+ describe("per-agent session settings file routing", () => {
30
+ let baseDir: string;
31
+ let historyDir: string;
32
+
33
+ // historyDir must contain a `.openclaw` segment so deriveOpenClawBaseDir resolves the base.
34
+ function seedSessionsFile(agentId: string): string {
35
+ const dir = join(baseDir, ".openclaw", "agents", agentId, "sessions");
36
+ mkdirSync(dir, { recursive: true });
37
+ const file = join(dir, "sessions.json");
38
+ writeFileSync(file, JSON.stringify({}), "utf-8");
39
+ return file;
40
+ }
41
+
42
+ function readEntry(agentId: string, fileKey: string): Record<string, unknown> | undefined {
43
+ const file = join(baseDir, ".openclaw", "agents", agentId, "sessions", "sessions.json");
44
+ const data = JSON.parse(readFileSync(file, "utf-8")) as Record<string, Record<string, unknown>>;
45
+ return data[fileKey];
46
+ }
47
+
48
+ beforeEach(() => {
49
+ baseDir = mkdtempSync(join(tmpdir(), "friday-sm-"));
50
+ historyDir = join(baseDir, ".openclaw", "friday-next", "history");
51
+ });
52
+
53
+ afterEach(() => {
54
+ rmSync(baseDir, { recursive: true, force: true });
55
+ });
56
+
57
+ it("writes settings for a non-main agent into agents/<agentId>/sessions", () => {
58
+ seedSessionsFile("operator");
59
+ const sessionKey = "agent:operator:friday:direct:dev:1";
60
+
61
+ setSessionSettings(sessionKey, { reasoningLevel: "stream", thinkingLevel: "high" }, historyDir);
62
+
63
+ const entry = readEntry("operator", toSessionStoreKey(sessionKey));
64
+ expect(entry?.reasoningLevel).toBe("stream");
65
+ expect(entry?.thinkingLevel).toBe("high");
66
+
67
+ // Round-trips through getSessionSettings from the same per-agent file.
68
+ const read = getSessionSettings(sessionKey, historyDir);
69
+ expect(read.reasoningLevel).toBe("stream");
70
+ expect(read.thinkingLevel).toBe("high");
71
+ });
72
+
73
+ it("does not leak a non-main agent's settings into the main store", () => {
74
+ seedSessionsFile("operator");
75
+ seedSessionsFile("main");
76
+
77
+ setSessionSettings("agent:operator:s1", { modelRef: "openai/gpt-x" }, historyDir);
78
+
79
+ expect(readEntry("operator", "agent:operator:s1")?.modelRef).toBe("openai/gpt-x");
80
+ expect(getSessionSettings("main", historyDir).modelRef).toBeUndefined();
81
+ });
82
+
83
+ it("still routes bare/main keys to agents/main", () => {
84
+ seedSessionsFile("main");
85
+
86
+ setSessionSettings("main", { thinkingLevel: "low" }, historyDir);
87
+
88
+ expect(readEntry("main", "agent:main:main")?.thinkingLevel).toBe("low");
89
+ });
90
+ });
@@ -4,6 +4,8 @@ import { readFileSync, writeFileSync } from "node:fs";
4
4
 
5
5
  const FRIDAY_AGENT_ID = "main";
6
6
  const SESSION_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
7
+ /** Path/shell-safe agent id (mirrors OpenClaw's `normalizeAgentId`). Anything else falls back to `main`. */
8
+ const SAFE_AGENT_ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
7
9
 
8
10
  function deriveOpenClawBaseDir(historyDir?: string): string {
9
11
  if (historyDir) {
@@ -41,6 +43,17 @@ export function toSessionStoreKey(rawSessionKey: string): string {
41
43
  return `agent:${FRIDAY_AGENT_ID}:${lowered}`;
42
44
  }
43
45
 
46
+ /**
47
+ * Extract the agent id from a (possibly raw) session key. The downstream app now owns the
48
+ * full `agent:<id>:<rest>` key, so non-`main` agents must read/write their own session store
49
+ * directory. `agent:<id>:<rest>` → `<id>`; bare/legacy keys (or an unsafe id) → `main`.
50
+ */
51
+ export function agentIdFromSessionKey(rawSessionKey: string): string {
52
+ const canonical = toSessionStoreKey(rawSessionKey);
53
+ const id = canonical.match(/^agent:([^:]+):/)?.[1];
54
+ return id && SAFE_AGENT_ID_RE.test(id) ? id : FRIDAY_AGENT_ID;
55
+ }
56
+
44
57
  function toSafeSessionId(raw: string): string {
45
58
  const s = raw.trim();
46
59
  if (SESSION_ID_RE.test(s)) return s;
@@ -57,8 +70,8 @@ function sessionIdForSessionsFile(fileKey: string, rawSessionKey: string): strin
57
70
  const candidates = [rawSessionKey.trim(), fileKey.trim()];
58
71
  for (const c of candidates) {
59
72
  if (SESSION_ID_RE.test(c)) return c;
60
- if (c.startsWith(`agent:${FRIDAY_AGENT_ID}:`)) {
61
- const tail = c.slice(`agent:${FRIDAY_AGENT_ID}:`.length);
73
+ const tail = c.match(/^agent:[^:]+:(.+)$/)?.[1];
74
+ if (tail) {
62
75
  if (SESSION_ID_RE.test(tail)) return tail;
63
76
  return toSafeSessionId(tail);
64
77
  }
@@ -66,9 +79,9 @@ function sessionIdForSessionsFile(fileKey: string, rawSessionKey: string): strin
66
79
  return toSafeSessionId(rawSessionKey || fileKey);
67
80
  }
68
81
 
69
- function resolveSessionsFilePath(historyDir?: string): string {
82
+ function resolveSessionsFilePath(historyDir: string | undefined, agentId: string): string {
70
83
  const base = deriveOpenClawBaseDir(historyDir);
71
- return join(base, "agents/main/sessions/sessions.json");
84
+ return join(base, "agents", agentId, "sessions", "sessions.json");
72
85
  }
73
86
 
74
87
  function readSessionsData(path: string): Record<string, Record<string, unknown>> | null {
@@ -125,11 +138,11 @@ export function setSessionSettings(
125
138
  historyDir?: string,
126
139
  ): FridaySessionSettings {
127
140
  try {
128
- const sessionsFile = resolveSessionsFilePath(historyDir);
141
+ const fileKey = toSessionStoreKey(sessionKey);
142
+ const sessionsFile = resolveSessionsFilePath(historyDir, agentIdFromSessionKey(fileKey));
129
143
  const data = readSessionsData(sessionsFile);
130
144
  if (!data) return {};
131
145
 
132
- const fileKey = toSessionStoreKey(sessionKey);
133
146
  upsertSessionEntry(data, fileKey, sessionKey);
134
147
 
135
148
  const fieldKeys: (keyof FridaySessionSettings)[] = [
@@ -172,11 +185,11 @@ export function getSessionSettings(
172
185
  historyDir?: string,
173
186
  ): FridaySessionSettings {
174
187
  try {
175
- const sessionsFile = resolveSessionsFilePath(historyDir);
188
+ const fileKey = toSessionStoreKey(sessionKey);
189
+ const sessionsFile = resolveSessionsFilePath(historyDir, agentIdFromSessionKey(fileKey));
176
190
  const data = readSessionsData(sessionsFile);
177
191
  if (!data) return {};
178
192
 
179
- const fileKey = toSessionStoreKey(sessionKey);
180
193
  const entry = data[fileKey];
181
194
  if (!entry) return {};
182
195
  return readSettingsFromEntry(entry);