@0xmaxma/claude-gateway 1.1.0 → 1.1.2

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,8 +1,9 @@
1
1
  import { EventEmitter } from 'events';
2
- import { AgentConfig, GatewayConfig, Logger, StreamEvent } from '../types';
2
+ import { AgentConfig, GatewayConfig, Logger, ModelConfig, StreamEvent } from '../types';
3
3
  import { type SkillRegistry } from '../skills';
4
4
  import { HistoryDB } from '../history/db';
5
5
  export declare const MAX_IMAGE_SIZE_BYTES: number;
6
+ export declare const DEFAULT_MODELS: ModelConfig[];
6
7
  export declare class AgentRunner extends EventEmitter {
7
8
  private readonly agentConfig;
8
9
  private readonly gatewayConfig;
@@ -25,6 +26,7 @@ export declare class AgentRunner extends EventEmitter {
25
26
  private readonly maxConcurrent;
26
27
  private idleCleanerTimer;
27
28
  private readonly pendingApiSessions;
29
+ private readonly sessionSpawnLocks;
28
30
  private readonly pendingImagePaths;
29
31
  private skillRegistry;
30
32
  private readonly configPath;
@@ -56,6 +58,7 @@ export declare class AgentRunner extends EventEmitter {
56
58
  private resolveMediaPaths;
57
59
  private static buildChannelXml;
58
60
  private getOrSpawnSession;
61
+ private spawnSession;
59
62
  /**
60
63
  * Returns true if the message content is a session management command.
61
64
  */
@@ -150,6 +153,7 @@ export declare class AgentRunner extends EventEmitter {
150
153
  timeoutMs: number;
151
154
  allowTools?: boolean;
152
155
  mediaFiles?: string[];
156
+ model?: string;
153
157
  }): Promise<string>;
154
158
  /**
155
159
  * Send a message to an API session and stream back events via callbacks.
@@ -165,6 +169,7 @@ export declare class AgentRunner extends EventEmitter {
165
169
  timeoutMs: number;
166
170
  allowTools?: boolean;
167
171
  mediaFiles?: string[];
172
+ model?: string;
168
173
  }): Promise<() => void>;
169
174
  /**
170
175
  * Check if a session has a pending API request (for preflight conflict check).
@@ -173,14 +178,21 @@ export declare class AgentRunner extends EventEmitter {
173
178
  getAgentsBaseDir(): string;
174
179
  getAgentDir(): string;
175
180
  getHistoryDb(): HistoryDB;
176
- getAllSessionNames(): Promise<Map<string, string>>;
181
+ getAllSessionMeta(): Promise<Map<string, {
182
+ name: string;
183
+ }>>;
177
184
  listSessionsForChat(chatId: string, channel: 'telegram' | 'discord'): Promise<import('../types').SessionIndex>;
178
185
  executeApiCommand(sessionId: string, chatId: string, command: string): Promise<Record<string, unknown>>;
179
186
  setModel(newModel: string): Promise<void>;
180
187
  listApiSessions(chatId: string): Promise<import('../types').SessionIndex>;
181
188
  createApiSession(chatId: string, prompt?: string, name?: string): Promise<import('../types').SessionMeta>;
182
189
  getApiSessionInfo(chatId: string, sessionId: string): Promise<Record<string, unknown> | null>;
183
- renameApiSession(chatId: string, sessionId: string, sessionName: string): Promise<void>;
190
+ updateApiSession(chatId: string, sessionId: string, updates: {
191
+ sessionName?: string;
192
+ }): Promise<{
193
+ sessionId: string;
194
+ sessionName?: string;
195
+ }>;
184
196
  deleteApiSession(chatId: string, sessionId: string): Promise<void>;
185
197
  /**
186
198
  * Send a message into an existing channel session (cross-channel continuation from UI).
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.AgentRunner = exports.MAX_IMAGE_SIZE_BYTES = void 0;
36
+ exports.AgentRunner = exports.DEFAULT_MODELS = exports.MAX_IMAGE_SIZE_BYTES = void 0;
37
37
  const events_1 = require("events");
38
38
  const fs = __importStar(require("fs"));
39
39
  const fsPromises = __importStar(require("fs/promises"));
@@ -54,7 +54,7 @@ const cleanup_1 = require("../history/cleanup");
54
54
  const DEFAULT_IDLE_TIMEOUT_MINUTES = 30;
55
55
  const DEFAULT_MAX_CONCURRENT = 20;
56
56
  exports.MAX_IMAGE_SIZE_BYTES = 10 * 1024 * 1024;
57
- const DEFAULT_MODELS = [
57
+ exports.DEFAULT_MODELS = [
58
58
  { id: 'claude-opus-4-7', label: 'Opus 4.7', alias: 'opus', contextWindow: 1000000 },
59
59
  { id: 'claude-opus-4-6', label: 'Opus 4.6', alias: 'opus46', contextWindow: 1000000 },
60
60
  { id: 'claude-sonnet-4-6', label: 'Sonnet 4.6', alias: 'sonnet', contextWindow: 1000000 },
@@ -121,6 +121,8 @@ class AgentRunner extends events_1.EventEmitter {
121
121
  this.idleCleanerTimer = null;
122
122
  // Tracks session IDs with an in-flight API request (prevents concurrent turns)
123
123
  this.pendingApiSessions = new Set();
124
+ // Serialises concurrent getOrSpawnSession calls for the same key to prevent double-spawn
125
+ this.sessionSpawnLocks = new Map();
124
126
  // Tracks pending Telegram image paths per chatId (queue) for size accumulation after each turn.
125
127
  this.pendingImagePaths = new Map();
126
128
  // Skill registry for detecting /skill-name commands in user messages
@@ -249,6 +251,7 @@ class AgentRunner extends events_1.EventEmitter {
249
251
  this.imageSizePerChat.delete(chatId);
250
252
  }
251
253
  // Route to session process (map key = chatId, actual sessionId passed separately)
254
+ // Channel sessions use agent-level model (not per-session)
252
255
  const session = await this.getOrSpawnSession(chatId, channelSource, sessionId);
253
256
  let channelXml = AgentRunner.buildChannelXml(params);
254
257
  // Detect skill commands and inject skill content
@@ -319,42 +322,38 @@ class AgentRunner extends events_1.EventEmitter {
319
322
  }
320
323
  if (command === 'set_model') {
321
324
  const newModel = typeof body.payload?.model === 'string' ? body.payload.model : '';
322
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
323
- const valid = availableModels.find(m => m.id === newModel);
324
- if (!valid) {
325
- respond({ success: false, error: 'Unknown model' });
326
- return;
327
- }
328
- // Update in-memory config
329
- this.agentConfig.claude.model = newModel;
330
- // Persist to config.json (atomic write)
331
325
  try {
332
- this.persistModelToConfig(newModel);
326
+ await this.setModel(newModel);
333
327
  }
334
328
  catch (err) {
335
- this.logger.error('Failed to persist model to config', { error: err.message });
329
+ respond({ success: false, error: err.message });
330
+ return;
336
331
  }
337
- // Graceful restart all sessions with notify payload
332
+ // Graceful restart ALL channel sessions via signal files so they pick up the new agent-level model.
333
+ // Signal file approach: chokidar watcher in SessionProcess detects the file, reads the notify
334
+ // payload, finishes in-flight work, then restarts — ensuring no mid-response interruption.
338
335
  const chatId = body.chat_id ?? '';
339
336
  let restarted = false;
340
- for (const [sessionId, session] of this.sessions) {
341
- restarted = true;
342
- const notifyPayload = JSON.stringify({
343
- notify: {
344
- chat_id: chatId,
345
- text: `Model changed to ${newModel} back online!`,
346
- },
347
- });
348
- const signalPath = path.join(this.agentConfig.workspace, '.telegram-state', `restart-${sessionId}`);
349
- try {
350
- fs.mkdirSync(path.dirname(signalPath), { recursive: true });
351
- fs.writeFileSync(signalPath, notifyPayload);
352
- }
353
- catch (err) {
354
- this.logger.error('Failed to write restart signal', {
355
- sessionId,
356
- error: err.message,
337
+ for (const [key, session] of this.sessions) {
338
+ // Only restart channel sessions (not API sessions which use per-session model)
339
+ if (session.source !== 'api') {
340
+ restarted = true;
341
+ const channel = this.channelSourceMap.get(key) ?? 'telegram';
342
+ const stateDir = channel === 'discord' ? '.discord-state' : '.telegram-state';
343
+ const signalPayload = JSON.stringify({
344
+ notify: { chat_id: chatId, text: `✅ Model changed to ${newModel}` },
357
345
  });
346
+ const signalPath = path.join(this.agentConfig.workspace, stateDir, `restart-${key}`);
347
+ try {
348
+ fs.mkdirSync(path.dirname(signalPath), { recursive: true });
349
+ fs.writeFileSync(signalPath, signalPayload);
350
+ }
351
+ catch (err) {
352
+ this.logger.error('Failed to write restart signal for set_model', {
353
+ sessionKey: key,
354
+ error: err.message,
355
+ });
356
+ }
358
357
  }
359
358
  }
360
359
  respond({ success: true, model: newModel, restarted });
@@ -414,8 +413,9 @@ class AgentRunner extends events_1.EventEmitter {
414
413
  if (!meta) {
415
414
  return respond({ success: true, text: 'No active session found.' });
416
415
  }
417
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
418
- const modelConfig = availableModels.find(m => m.id === this.agentConfig.claude.model);
416
+ const effectiveModel = this.agentConfig.claude.model;
417
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
418
+ const modelConfig = availableModels.find(m => m.id === effectiveModel);
419
419
  const contextWindow = modelConfig?.contextWindow ?? 200000;
420
420
  const contextTokens = meta.lastInputTokens ?? 0;
421
421
  const usedPct = Math.round((contextTokens / contextWindow) * 100);
@@ -560,10 +560,51 @@ class AgentRunner extends events_1.EventEmitter {
560
560
  `ts="${meta['ts'] ?? new Date().toISOString()}"${optionalAttrs}>${repliedBlock}${params.content ?? ''}</channel>`);
561
561
  }
562
562
  async getOrSpawnSession(mapKey, // Map lookup key (chatId for telegram/discord, sessionId for API)
563
- source, sessionId) {
563
+ source, sessionId, // actual session UUID (only for channel sessions; equals mapKey for API)
564
+ modelOverride) {
565
+ // Normalize: treat agent-default model as "no override" so default sessions
566
+ // don't restart unnecessarily when the frontend explicitly sends the default model.
567
+ const agentDefaultModel = this.agentConfig.claude.model;
568
+ const effectiveOverride = (modelOverride && modelOverride !== agentDefaultModel)
569
+ ? modelOverride
570
+ : undefined;
571
+ // If a spawn is already in progress for this key, wait for it instead of spawning a second one
572
+ const pending = this.sessionSpawnLocks.get(mapKey);
573
+ if (pending)
574
+ return pending;
564
575
  const existing = this.sessions.get(mapKey);
565
- if (existing)
566
- return existing;
576
+ if (existing) {
577
+ // Restart if model changed (including switching back to the agent default)
578
+ if (existing.modelOverride !== effectiveOverride) {
579
+ this.logger.info('Model changed, restarting session', { mapKey, oldModel: existing.modelOverride, newModel: effectiveOverride ?? agentDefaultModel });
580
+ const respawn = (async () => {
581
+ await existing.stop();
582
+ this.sessions.delete(mapKey);
583
+ return this.spawnSession(mapKey, source, sessionId, effectiveOverride);
584
+ })();
585
+ this.sessionSpawnLocks.set(mapKey, respawn);
586
+ try {
587
+ return await respawn;
588
+ }
589
+ finally {
590
+ this.sessionSpawnLocks.delete(mapKey);
591
+ }
592
+ }
593
+ else {
594
+ return existing;
595
+ }
596
+ }
597
+ // No existing session — acquire lock for the spawn path
598
+ const spawnPromise = this.spawnSession(mapKey, source, sessionId, effectiveOverride);
599
+ this.sessionSpawnLocks.set(mapKey, spawnPromise);
600
+ try {
601
+ return await spawnPromise;
602
+ }
603
+ finally {
604
+ this.sessionSpawnLocks.delete(mapKey);
605
+ }
606
+ }
607
+ async spawnSession(mapKey, source, sessionId, modelOverride) {
567
608
  // Evict oldest idle session if at capacity
568
609
  if (this.sessions.size >= this.maxConcurrent) {
569
610
  const sorted = [...this.sessions.entries()].sort(([, a], [, b]) => a.lastActivityAt - b.lastActivityAt);
@@ -580,6 +621,9 @@ class AgentRunner extends events_1.EventEmitter {
580
621
  const actualSessionId = sessionId ?? mapKey;
581
622
  const chatId = source !== 'api' ? mapKey : undefined;
582
623
  const proc = new process_1.SessionProcess(actualSessionId, source, this.agentConfig, this.gatewayConfig, this.sessionStore, chatId);
624
+ // Apply per-session model override (caller already normalized to undefined when == agent default)
625
+ if (modelOverride)
626
+ proc.modelOverride = modelOverride;
583
627
  await proc.start();
584
628
  // Forward all session output lines so listeners on AgentRunner (GatewayRouter,
585
629
  // CronScheduler, tests) receive them without needing individual session references.
@@ -822,8 +866,9 @@ class AgentRunner extends events_1.EventEmitter {
822
866
  this.writeAutoForward(chatId, 'No active session found.');
823
867
  return;
824
868
  }
825
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
826
- const modelConfig = availableModels.find(m => m.id === this.agentConfig.claude.model);
869
+ const effectiveModel = this.agentConfig.claude.model;
870
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
871
+ const modelConfig = availableModels.find(m => m.id === effectiveModel);
827
872
  const contextWindow = modelConfig?.contextWindow ?? 200000;
828
873
  const contextTokens = meta.lastInputTokens ?? 0;
829
874
  const usedPct = Math.round((contextTokens / contextWindow) * 100);
@@ -916,13 +961,14 @@ class AgentRunner extends events_1.EventEmitter {
916
961
  const index = await this.sessionStore.listSessions(agentId, chatId, ch);
917
962
  const meta = index.sessions.find(s => s.id === sessionId);
918
963
  const name = meta?.name ?? 'Session';
919
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
920
- const modelConfig = availableModels.find(m => m.id === this.agentConfig.claude.model);
964
+ const compactModel = this.agentConfig.claude.model;
965
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
966
+ const modelConfig = availableModels.find(m => m.id === compactModel);
921
967
  const contextWindow = modelConfig?.contextWindow ?? 200000;
922
968
  this.writeAutoForward(chatId, `⏳ Compacting session "${name}"...`);
923
969
  try {
924
970
  const compactor = new compactor_1.SessionCompactor(this.sessionStore);
925
- const result = await compactor.compact(agentId, chatId, sessionId, this.agentConfig.claude.model, contextWindow, ch);
971
+ const result = await compactor.compact(agentId, chatId, sessionId, compactModel, contextWindow, ch);
926
972
  await this.sessionStore.updateSessionMeta(agentId, chatId, sessionId, {
927
973
  loadedAtSpawn: undefined,
928
974
  archivedCount: undefined,
@@ -1172,12 +1218,13 @@ class AgentRunner extends events_1.EventEmitter {
1172
1218
  const err = Object.assign(new Error(`Session ${sessionId} already has a pending request`), { code: 'CONFLICT' });
1173
1219
  throw err;
1174
1220
  }
1175
- const session = await this.getOrSpawnSession(sessionId, 'api');
1176
1221
  // Register session in api-{chatId} index.json on first use
1177
1222
  const internalChatIdForSession = `api-${chatId}`;
1178
1223
  await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatIdForSession, sessionId).catch((err) => {
1179
1224
  this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
1180
1225
  });
1226
+ // Use model from request body if provided, otherwise use agent default
1227
+ const session = await this.getOrSpawnSession(sessionId, 'api', undefined, opts.model);
1181
1228
  // Promote UI-uploaded files from staging to permanent per-session storage
1182
1229
  const finalMediaFiles = opts.mediaFiles?.length
1183
1230
  ? await promoteUiUploads(this.agentsBaseDir, this.agentConfig.id, sessionId, opts.mediaFiles, this.logger)
@@ -1333,12 +1380,13 @@ class AgentRunner extends events_1.EventEmitter {
1333
1380
  const err = Object.assign(new Error(`Session ${sessionId} already has a pending request`), { code: 'CONFLICT' });
1334
1381
  throw err;
1335
1382
  }
1336
- const session = await this.getOrSpawnSession(sessionId, 'api');
1337
1383
  // Register session in api-{chatId} index.json on first use
1338
1384
  const internalChatIdStream = `api-${chatId}`;
1339
1385
  await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatIdStream, sessionId).catch((err) => {
1340
1386
  this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
1341
1387
  });
1388
+ // Use model from request body if provided, otherwise use agent default
1389
+ const session = await this.getOrSpawnSession(sessionId, 'api', undefined, opts.model);
1342
1390
  // Promote UI-uploaded files from staging to permanent per-session storage
1343
1391
  const finalMediaFilesStream = opts.mediaFiles?.length
1344
1392
  ? await promoteUiUploads(this.agentsBaseDir, this.agentConfig.id, sessionId, opts.mediaFiles, this.logger)
@@ -1538,8 +1586,8 @@ class AgentRunner extends events_1.EventEmitter {
1538
1586
  getHistoryDb() {
1539
1587
  return this.historyDb;
1540
1588
  }
1541
- getAllSessionNames() {
1542
- return this.sessionStore.getAllSessionNames(this.agentConfig.id);
1589
+ getAllSessionMeta() {
1590
+ return this.sessionStore.getAllSessionMeta(this.agentConfig.id);
1543
1591
  }
1544
1592
  async listSessionsForChat(chatId, channel) {
1545
1593
  return this.sessionStore.listSessions(this.agentConfig.id, chatId, channel);
@@ -1562,10 +1610,11 @@ class AgentRunner extends events_1.EventEmitter {
1562
1610
  if (command === '/session') {
1563
1611
  const index = await this.sessionStore.listSessions(agentId, internalChatId, 'api').catch(() => null);
1564
1612
  const meta = index?.sessions.find((s) => s.id === sessionId);
1613
+ const effectiveModel = this.agentConfig.claude.model;
1565
1614
  if (!meta)
1566
- return { sessionId, sessionName: null, messageCount: 0, archivedCount: 0, contextUsedPct: 0, model: this.agentConfig.claude.model };
1567
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
1568
- const modelConfig = availableModels.find((m) => m.id === this.agentConfig.claude.model);
1615
+ return { sessionId, sessionName: null, messageCount: 0, archivedCount: 0, contextUsedPct: 0, model: effectiveModel };
1616
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
1617
+ const modelConfig = availableModels.find((m) => m.id === effectiveModel);
1569
1618
  const contextWindow = modelConfig?.contextWindow ?? 200000;
1570
1619
  const contextUsedPct = Math.round(((meta.lastInputTokens ?? 0) / contextWindow) * 100);
1571
1620
  return {
@@ -1574,7 +1623,7 @@ class AgentRunner extends events_1.EventEmitter {
1574
1623
  messageCount: meta.messageCount,
1575
1624
  archivedCount: meta.archivedCount ?? 0,
1576
1625
  contextUsedPct,
1577
- model: this.agentConfig.claude.model,
1626
+ model: effectiveModel,
1578
1627
  };
1579
1628
  }
1580
1629
  if (command === '/clear') {
@@ -1594,11 +1643,12 @@ class AgentRunner extends events_1.EventEmitter {
1594
1643
  }
1595
1644
  if (command === '/compact') {
1596
1645
  const ch = 'api';
1597
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
1598
- const modelConfig = availableModels.find((m) => m.id === this.agentConfig.claude.model);
1646
+ const compactEffectiveModel = this.agentConfig.claude.model;
1647
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
1648
+ const modelConfig = availableModels.find((m) => m.id === compactEffectiveModel);
1599
1649
  const contextWindow = modelConfig?.contextWindow ?? 200000;
1600
1650
  const compactor = new compactor_1.SessionCompactor(this.sessionStore);
1601
- const result = await compactor.compact(agentId, internalChatId, sessionId, this.agentConfig.claude.model, contextWindow, ch);
1651
+ const result = await compactor.compact(agentId, internalChatId, sessionId, compactEffectiveModel, contextWindow, ch);
1602
1652
  await this.sessionStore.updateSessionMeta(agentId, internalChatId, sessionId, {
1603
1653
  loadedAtSpawn: undefined,
1604
1654
  archivedCount: undefined,
@@ -1610,7 +1660,7 @@ class AgentRunner extends events_1.EventEmitter {
1610
1660
  throw new Error(`Unknown command: ${command}`);
1611
1661
  }
1612
1662
  async setModel(newModel) {
1613
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
1663
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
1614
1664
  if (!availableModels.find((m) => m.id === newModel)) {
1615
1665
  throw Object.assign(new Error(`Unknown model: ${newModel}`), { code: 'UNKNOWN_MODEL' });
1616
1666
  }
@@ -1647,8 +1697,9 @@ class AgentRunner extends events_1.EventEmitter {
1647
1697
  const meta = index?.sessions.find((s) => s.id === sessionId);
1648
1698
  if (!meta)
1649
1699
  return null;
1650
- const availableModels = this.gatewayConfig.gateway.models ?? DEFAULT_MODELS;
1651
- const modelConfig = availableModels.find((m) => m.id === this.agentConfig.claude.model);
1700
+ const effectiveModel = this.agentConfig.claude.model;
1701
+ const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
1702
+ const modelConfig = availableModels.find((m) => m.id === effectiveModel);
1652
1703
  const contextWindow = modelConfig?.contextWindow ?? 200000;
1653
1704
  const contextUsedPct = Math.round(((meta.lastInputTokens ?? 0) / contextWindow) * 100);
1654
1705
  return {
@@ -1657,11 +1708,14 @@ class AgentRunner extends events_1.EventEmitter {
1657
1708
  messageCount: meta.messageCount,
1658
1709
  archivedCount: meta.archivedCount ?? 0,
1659
1710
  contextUsedPct,
1660
- model: this.agentConfig.claude.model,
1711
+ model: effectiveModel,
1661
1712
  };
1662
1713
  }
1663
- async renameApiSession(chatId, sessionId, sessionName) {
1664
- await this.sessionStore.updateSessionMeta(this.agentConfig.id, `api-${chatId}`, sessionId, { name: sessionName }, 'api');
1714
+ async updateApiSession(chatId, sessionId, updates) {
1715
+ if (updates.sessionName) {
1716
+ await this.sessionStore.updateSessionMeta(this.agentConfig.id, `api-${chatId}`, sessionId, { name: updates.sessionName }, 'api');
1717
+ }
1718
+ return { sessionId, ...(updates.sessionName ? { sessionName: updates.sessionName } : {}) };
1665
1719
  }
1666
1720
  async deleteApiSession(chatId, sessionId) {
1667
1721
  await this.sessionStore.deleteTelegramSession(this.agentConfig.id, `api-${chatId}`, sessionId, 'api');
@@ -1674,6 +1728,7 @@ class AgentRunner extends events_1.EventEmitter {
1674
1728
  async sendMessageToSession(rawChatId, channel, sessionId, message, senderName, callbacks, opts) {
1675
1729
  // Ensure the session process uses the correct channel source
1676
1730
  this.channelSourceMap.set(rawChatId, channel);
1731
+ // Channel sessions use agent-level model (not per-session)
1677
1732
  const session = await this.getOrSpawnSession(rawChatId, channel, sessionId);
1678
1733
  // Persist user message (Layer 1 session JSON + Layer 2 history DB)
1679
1734
  const uiUserTs = Date.now();