@agent-link/agent 0.1.339 → 0.1.340

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,3 +1,4 @@
1
+ import WebSocket from 'ws';
1
2
  import type { AgentConfig } from './config.js';
2
3
  import { type BackendType } from './backends/types.js';
3
4
  import { type EntraToken } from './entra.js';
@@ -25,7 +26,7 @@ export declare function connect(config: AgentConfig): Promise<string>;
25
26
  /** Get the E2E key for embedding in the session URL. */
26
27
  export declare function getE2EKey(): Uint8Array | null;
27
28
  export declare function disconnect(): void;
28
- export declare function send(msg: Record<string, unknown>): void;
29
+ export declare function send(msg: Record<string, unknown>, expectedSocket?: WebSocket | null): void;
29
30
  export declare function sendAndFlush(msg: Record<string, unknown>, timeoutMs?: number): Promise<void>;
30
31
  export declare function beginShutdown(): void;
31
32
  export declare function getConnectionStatus(): {
@@ -32,7 +32,7 @@ const require = createRequire(import.meta.url);
32
32
  const pkg = require('../package.json');
33
33
  const TEAM_SESSIONS_DIR = path.join(CONFIG_DIR, 'team-sessions');
34
34
  const LOOP_SESSIONS_DIR = path.join(CONFIG_DIR, 'loop-sessions');
35
- import { handleChat as claudeHandleChat, addSendFn, abort as abortClaude, abortAll as abortAllClaude, cancelExecution as claudeCancelExecution, handleUserAnswer, handleToolPermissionResponse, handleBtwQuestion, getConversation, getConversations, getIsCompacting, clearSessionId, evictByClaudeSessionId, rebindConversation, addOutputObserver, removeOutputObserver, addCloseObserver, removeCloseObserver, setOutputObserver, clearOutputObserver, setCloseObserver, clearCloseObserver, restartConversation, createPlaceholderConversation, getPendingQuestions, getPendingToolPermissions, setModel, addOnSessionStarted, getBackendType, setBackendType, isCopilotBackend, isCodexBackend, isPiBackend, isYeaftBackend, addCopilotSendFn, handleCopilotChat, executeCopilotCommand, setCopilotPlanMode, startCopilotPlanImplementation, cancelCopilotExecution, listCopilotSessionsPage, listAllCopilotSessionsPage, readCopilotSessionMessages, readCopilotSessionMode, readCopilotSessionProvider, readCopilotSessionUsage, getCopilotSessionWorkDir, deleteCopilotSession, renameCopilotSession, moveCopilotSession, getCopilotConversation, getCopilotConversations, createCopilotPlaceholder, rebindCopilotConversation, getPendingCopilotDecisions, handleCopilotUserAnswer, cleanupAllCopilotConversations, copilotCapabilities, addCodexSendFn, handleCodexChat, cancelCodexExecution, listCodexSessionsPage, listAllCodexSessionsPage, readCodexSessionMessages, deleteCodexSession, renameCodexSession, moveCodexSession, getCodexConversation, getCodexConversations, createCodexPlaceholder, restartCodexConversation, rebindCodexConversation, cleanupAllCodexConversations, evictByCodexSessionId, codexCapabilities } from './runtime.js';
35
+ import { handleChat as claudeHandleChat, addSendFn, abort as abortClaude, abortAll as abortAllClaude, cancelExecution as claudeCancelExecution, handleUserAnswer, handleToolPermissionResponse, handleBtwQuestion, getConversation, getConversations, getIsCompacting, clearSessionId, evictByClaudeSessionId, rebindConversation, addOutputObserver, removeOutputObserver, addCloseObserver, removeCloseObserver, setOutputObserver, clearOutputObserver, setCloseObserver, clearCloseObserver, restartConversation, createPlaceholderConversation, getPendingQuestions, getPendingToolPermissions, setModel, addOnSessionStarted, getBackendType, setBackendType, isCopilotBackend, isCodexBackend, isPiBackend, isYeaftBackend, addCopilotSendFn, handleCopilotChat, executeCopilotCommand, setCopilotPlanMode, startCopilotPlanImplementation, cancelCopilotExecution, readCopilotSessionMessages, readCopilotSessionMode, readCopilotSessionProvider, readCopilotSessionUsage, getCopilotSessionWorkDir, deleteCopilotSession, renameCopilotSession, moveCopilotSession, getCopilotConversation, getCopilotConversations, createCopilotPlaceholder, rebindCopilotConversation, getPendingCopilotDecisions, handleCopilotUserAnswer, cleanupAllCopilotConversations, copilotCapabilities, addCodexSendFn, handleCodexChat, cancelCodexExecution, listCodexSessionsPage, listAllCodexSessionsPage, readCodexSessionMessages, deleteCodexSession, renameCodexSession, moveCodexSession, getCodexConversation, getCodexConversations, createCodexPlaceholder, restartCodexConversation, rebindCodexConversation, cleanupAllCodexConversations, evictByCodexSessionId, codexCapabilities } from './runtime.js';
36
36
  import { addPiSendFn, cancelPiExecution, cleanupAllPiConversations, createPiPlaceholder, deletePiSession, evictByPiSessionId, getPiConversation, getPiConversations, getPiSessionWorkDir, handlePiChat, listAllPiSessionsPage, listPiSessionsPage, movePiSession, piCapabilities, readPiSessionMessages, rebindPiConversation, renamePiSession, restartPiConversation, } from './pi.js';
37
37
  import { addYeaftSendFn, cancelYeaftExecution, cleanupAllYeaftConversations, createYeaftPlaceholder, deleteYeaftSession, evictByYeaftSessionId, getYeaftConversation, getYeaftConversations, handleYeaftChat, handleYeaftUserAnswer, listAllYeaftSessionsPage, listYeaftSessionsPage, moveYeaftSession, readYeaftSessionMessages, rebindYeaftConversation, renameYeaftSession, restartYeaftConversation, } from './yeaft.js';
38
38
  import { DEFAULT_SESSION_LIST_LIMIT, LEGACY_SESSION_LIST_CAP, listSessions, listSessionsPageAsync, readSessionMessages, deleteSession, renameSession, moveSession, listAllRecentSessionsPage, getSessionCacheStats } from './history.js';
@@ -53,6 +53,7 @@ import { initScheduler, getRunningExecutions, } from './scheduler.js';
53
53
  import { handleWebUpgradeMessage } from './web-upgrade.js';
54
54
  import { refreshRuntimeLaunchSpecDeviceName } from './upgrade-launch-spec.js';
55
55
  import { getAgentRuntimeInfo } from './runtime-info.js';
56
+ import { listCopilotSessionsPageAsync, listAllCopilotSessionsPageAsync } from './runtime.js';
56
57
  let tunnelHandler = null;
57
58
  let terminalManager = null;
58
59
  const RECONNECT_BASE_DELAY = 1000;
@@ -647,10 +648,13 @@ function deduped(key, fn) {
647
648
  });
648
649
  inflightHandlers.set(key, run());
649
650
  }
650
- export function send(msg) {
651
+ export function send(msg, expectedSocket) {
652
+ if (expectedSocket !== undefined && state.ws !== expectedSocket)
653
+ return;
651
654
  if (state.ws && state.ws.readyState === WebSocket.OPEN) {
652
655
  sendQueue = sendQueue.then(async () => {
653
- if (!state.ws || state.ws.readyState !== WebSocket.OPEN)
656
+ if (!state.ws || state.ws.readyState !== WebSocket.OPEN
657
+ || (expectedSocket !== undefined && state.ws !== expectedSocket))
654
658
  return;
655
659
  let payload = msg;
656
660
  // Don't E2E-encrypt messages the server must inspect (it only decrypts
@@ -671,6 +675,8 @@ export function send(msg) {
671
675
  if (state.e2eKey && state.e2eNegotiated && !skipE2E.includes(msg.type)) {
672
676
  payload = await e2eEncrypt(msg, state.e2eKey);
673
677
  }
678
+ if (expectedSocket !== undefined && state.ws !== expectedSocket)
679
+ return;
674
680
  return encryptAndSend(state.ws, payload, state.sessionKey);
675
681
  }).catch((err) => {
676
682
  console.error(`[AgentLink] send() failed for ${msg.type}:`, err.message);
@@ -1241,18 +1247,7 @@ function handleServerMessage(msg) {
1241
1247
  });
1242
1248
  }
1243
1249
  else if (recentBackend === 'copilot') {
1244
- const page = listAllCopilotSessionsPage({ limit: m.limit, cursor: m.cursor });
1245
- console.log(`[AgentLink] → recent_sessions_list (${page.sessions.length} copilot sessions) hasMore=${page.hasMore}`);
1246
- send({
1247
- type: 'recent_sessions_list',
1248
- sessions: page.sessions,
1249
- hasMore: page.hasMore,
1250
- nextCursor: page.nextCursor,
1251
- indexState: page.indexState,
1252
- ...(m.mode ? { mode: m.mode } : {}),
1253
- ...(m.requestId ? { requestId: m.requestId } : {}),
1254
- ...(m.providerId ? { providerId: m.providerId } : {}),
1255
- });
1250
+ void handleListRecentCopilotSessions(m);
1256
1251
  }
1257
1252
  else {
1258
1253
  handleListRecentSessions(m);
@@ -3050,18 +3045,24 @@ async function handleListSessions(dir, options = {}) {
3050
3045
  });
3051
3046
  }
3052
3047
  }
3053
- function handleListCopilotSessionsFn(dir, options = {}) {
3048
+ async function handleListCopilotSessionsFn(dir, options = {}) {
3049
+ const requestSocket = state.ws;
3050
+ const backend = getBackendType();
3051
+ const stillCurrent = () => state.ws === requestSocket && (!!options.providerId || getBackendType() === backend);
3052
+ const startedAt = performance.now();
3054
3053
  try {
3055
3054
  const page = options.legacy
3056
- ? { ...listCopilotSessionsPage(dir, { limit: Number.POSITIVE_INFINITY }), hasMore: false }
3057
- : listCopilotSessionsPage(dir, {
3055
+ ? { ...await listCopilotSessionsPageAsync(dir, { limit: Number.POSITIVE_INFINITY }), hasMore: false }
3056
+ : await listCopilotSessionsPageAsync(dir, {
3058
3057
  limit: options.limit ?? DEFAULT_SESSION_LIST_LIMIT,
3059
3058
  cursor: options.cursor,
3060
3059
  });
3061
3060
  if (options.legacy && page.sessions.length > LEGACY_SESSION_LIST_CAP) {
3062
3061
  page.sessions = page.sessions.slice(0, LEGACY_SESSION_LIST_CAP);
3063
3062
  }
3064
- console.log(`[AgentLink] → sessions_list (${page.sessions.length} copilot sessions for ${dir}) hasMore=${page.hasMore}`);
3063
+ if (!stillCurrent())
3064
+ return;
3065
+ console.log(`[AgentLink] → sessions_list (${page.sessions.length} copilot sessions for ${dir}) hasMore=${page.hasMore} durationMs=${Math.round(performance.now() - startedAt)}`);
3065
3066
  send({
3066
3067
  type: 'sessions_list',
3067
3068
  sessions: page.sessions,
@@ -3072,10 +3073,12 @@ function handleListCopilotSessionsFn(dir, options = {}) {
3072
3073
  ...(options.mode ? { mode: options.mode } : {}),
3073
3074
  ...(options.requestId ? { requestId: options.requestId } : {}),
3074
3075
  ...(options.providerId ? { providerId: options.providerId } : {}),
3075
- });
3076
+ }, requestSocket);
3076
3077
  }
3077
3078
  catch (err) {
3078
3079
  console.error(`[AgentLink] listCopilotSessions failed:`, err);
3080
+ if (!stillCurrent())
3081
+ return;
3079
3082
  send({
3080
3083
  type: 'sessions_list',
3081
3084
  sessions: [],
@@ -3086,7 +3089,32 @@ function handleListCopilotSessionsFn(dir, options = {}) {
3086
3089
  ...(options.mode ? { mode: options.mode } : {}),
3087
3090
  ...(options.requestId ? { requestId: options.requestId } : {}),
3088
3091
  ...(options.providerId ? { providerId: options.providerId } : {}),
3089
- });
3092
+ }, requestSocket);
3093
+ }
3094
+ }
3095
+ async function handleListRecentCopilotSessions(options) {
3096
+ const requestSocket = state.ws;
3097
+ const backend = getBackendType();
3098
+ const stillCurrent = () => state.ws === requestSocket && (!!options.providerId || getBackendType() === backend);
3099
+ const envelope = {
3100
+ type: 'recent_sessions_list',
3101
+ ...(options.mode ? { mode: options.mode } : {}),
3102
+ ...(options.requestId ? { requestId: options.requestId } : {}),
3103
+ ...(options.providerId ? { providerId: options.providerId } : {}),
3104
+ };
3105
+ const startedAt = performance.now();
3106
+ try {
3107
+ const page = await listAllCopilotSessionsPageAsync({ limit: options.limit, cursor: options.cursor });
3108
+ if (!stillCurrent())
3109
+ return;
3110
+ console.log(`[AgentLink] → recent_sessions_list (${page.sessions.length} copilot sessions) hasMore=${page.hasMore} durationMs=${Math.round(performance.now() - startedAt)}`);
3111
+ send({ ...envelope, ...page }, requestSocket);
3112
+ }
3113
+ catch (error) {
3114
+ console.error('[AgentLink] listAllCopilotSessions failed:', error);
3115
+ if (stillCurrent())
3116
+ send({ ...envelope, sessions: [], hasMore: false, indexState: 'ready',
3117
+ error: error instanceof Error ? error.message : String(error) }, requestSocket);
3090
3118
  }
3091
3119
  }
3092
3120
  function handleListCodexSessionsFn(dir, options = {}) {