@agent-link/agent 0.1.337 → 0.1.339
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.
- package/dist/backends/types.d.ts +58 -0
- package/dist/backends/types.js +15 -4
- package/dist/backends/types.js.map +1 -1
- package/dist/connection.js +231 -28
- package/dist/connection.js.map +1 -1
- package/dist/copilot-capabilities-offline.d.ts +254 -0
- package/dist/copilot-capabilities-offline.js +392 -0
- package/dist/copilot-capabilities-offline.js.map +1 -0
- package/dist/copilot-capabilities.d.ts +43 -0
- package/dist/copilot-capabilities.js +128 -0
- package/dist/copilot-capabilities.js.map +1 -0
- package/dist/copilot-capability-service.d.ts +24 -0
- package/dist/copilot-capability-service.js +116 -0
- package/dist/copilot-capability-service.js.map +1 -0
- package/dist/copilot-command-bridge.d.ts +184 -0
- package/dist/copilot-command-bridge.js +1800 -0
- package/dist/copilot-command-bridge.js.map +1 -0
- package/dist/copilot-compaction-barrier.d.ts +36 -0
- package/dist/copilot-compaction-barrier.js +152 -0
- package/dist/copilot-compaction-barrier.js.map +1 -0
- package/dist/copilot-compaction-lifecycle.d.ts +34 -0
- package/dist/copilot-compaction-lifecycle.js +88 -0
- package/dist/copilot-compaction-lifecycle.js.map +1 -0
- package/dist/copilot-compaction-policy.d.ts +5 -0
- package/dist/copilot-compaction-policy.js +7 -0
- package/dist/copilot-compaction-policy.js.map +1 -0
- package/dist/copilot-configuration.d.ts +63 -0
- package/dist/copilot-configuration.js +283 -0
- package/dist/copilot-configuration.js.map +1 -0
- package/dist/copilot-event-scope.d.ts +13 -0
- package/dist/copilot-event-scope.js +26 -0
- package/dist/copilot-event-scope.js.map +1 -0
- package/dist/copilot-fork-metadata.d.ts +9 -0
- package/dist/copilot-fork-metadata.js +86 -0
- package/dist/copilot-fork-metadata.js.map +1 -0
- package/dist/copilot-message-kind.d.ts +21 -0
- package/dist/copilot-message-kind.js +45 -0
- package/dist/copilot-message-kind.js.map +1 -0
- package/dist/copilot-plan-state.d.ts +19 -0
- package/dist/copilot-plan-state.js +180 -0
- package/dist/copilot-plan-state.js.map +1 -0
- package/dist/copilot-request-dispatch.d.ts +10 -0
- package/dist/copilot-request-dispatch.js +31 -0
- package/dist/copilot-request-dispatch.js.map +1 -0
- package/dist/copilot-review-documents.d.ts +17 -0
- package/dist/copilot-review-documents.js +162 -0
- package/dist/copilot-review-documents.js.map +1 -0
- package/dist/copilot-session-activity.d.ts +3 -0
- package/dist/copilot-session-activity.js +94 -0
- package/dist/copilot-session-activity.js.map +1 -0
- package/dist/copilot-sidecar.d.ts +2 -0
- package/dist/copilot-sidecar.js +17 -0
- package/dist/copilot-sidecar.js.map +1 -0
- package/dist/copilot-turn-journal.d.ts +36 -0
- package/dist/copilot-turn-journal.js +246 -0
- package/dist/copilot-turn-journal.js.map +1 -0
- package/dist/copilot-user-requests.d.ts +11 -0
- package/dist/copilot-user-requests.js +84 -0
- package/dist/copilot-user-requests.js.map +1 -0
- package/dist/copilot.d.ts +194 -9
- package/dist/copilot.js +5012 -240
- package/dist/copilot.js.map +1 -1
- package/dist/directory-handlers.js +36 -8
- package/dist/directory-handlers.js.map +1 -1
- package/dist/history-message-transform.d.ts +47 -1
- package/dist/history-message-transform.js +67 -0
- package/dist/history-message-transform.js.map +1 -1
- package/dist/history.d.ts +8 -0
- package/dist/history.js.map +1 -1
- package/dist/provider-command-discovery.d.ts +5 -0
- package/dist/provider-command-discovery.js +49 -1
- package/dist/provider-command-discovery.js.map +1 -1
- package/dist/provider-command-types.d.ts +5 -0
- package/dist/provider-command-types.js.map +1 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/search-sessions.js +2 -1
- package/dist/search-sessions.js.map +1 -1
- package/package.json +3 -1
package/dist/connection.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import WebSocket from 'ws';
|
|
2
|
+
import { setCopilotProvider } from './runtime.js';
|
|
3
|
+
import { dispatchCopilotRequest, resolveCopilotCommandResumeSessionId } from './copilot-request-dispatch.js';
|
|
4
|
+
import { COPILOT_COMPACTION_POLICY } from './copilot-compaction-policy.js';
|
|
2
5
|
import os from 'os';
|
|
3
6
|
import path from 'path';
|
|
4
7
|
import { performance } from 'perf_hooks';
|
|
@@ -29,12 +32,15 @@ const require = createRequire(import.meta.url);
|
|
|
29
32
|
const pkg = require('../package.json');
|
|
30
33
|
const TEAM_SESSIONS_DIR = path.join(CONFIG_DIR, 'team-sessions');
|
|
31
34
|
const LOOP_SESSIONS_DIR = path.join(CONFIG_DIR, 'loop-sessions');
|
|
32
|
-
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, cancelCopilotExecution, listCopilotSessionsPage, listAllCopilotSessionsPage, readCopilotSessionMessages, getCopilotSessionWorkDir, deleteCopilotSession, renameCopilotSession, moveCopilotSession, getCopilotConversation, getCopilotConversations, createCopilotPlaceholder,
|
|
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';
|
|
33
36
|
import { addPiSendFn, cancelPiExecution, cleanupAllPiConversations, createPiPlaceholder, deletePiSession, evictByPiSessionId, getPiConversation, getPiConversations, getPiSessionWorkDir, handlePiChat, listAllPiSessionsPage, listPiSessionsPage, movePiSession, piCapabilities, readPiSessionMessages, rebindPiConversation, renamePiSession, restartPiConversation, } from './pi.js';
|
|
34
37
|
import { addYeaftSendFn, cancelYeaftExecution, cleanupAllYeaftConversations, createYeaftPlaceholder, deleteYeaftSession, evictByYeaftSessionId, getYeaftConversation, getYeaftConversations, handleYeaftChat, handleYeaftUserAnswer, listAllYeaftSessionsPage, listYeaftSessionsPage, moveYeaftSession, readYeaftSessionMessages, rebindYeaftConversation, renameYeaftSession, restartYeaftConversation, } from './yeaft.js';
|
|
35
38
|
import { DEFAULT_SESSION_LIST_LIMIT, LEGACY_SESSION_LIST_CAP, listSessions, listSessionsPageAsync, readSessionMessages, deleteSession, renameSession, moveSession, listAllRecentSessionsPage, getSessionCacheStats } from './history.js';
|
|
36
39
|
import { discoverProviderCommands, providerCommandDiscoverers, } from './provider-command-discovery.js';
|
|
37
40
|
import { providerCommandsMessage } from './provider-command-types.js';
|
|
41
|
+
import { copilotCapabilityService } from './copilot-capability-service.js';
|
|
42
|
+
import { mergeCopilotCapabilities } from './copilot-capabilities.js';
|
|
43
|
+
const copilotCapabilityRequests = new Map();
|
|
38
44
|
import { claudeCapabilities, yeaftCapabilities } from './backends/types.js';
|
|
39
45
|
import { createSessionSearchHandler } from './session-search-handler.js';
|
|
40
46
|
import { formatSessionExport, isSessionExportFormat } from './session-export.js';
|
|
@@ -103,6 +109,9 @@ function capabilitiesForBackend(backend, providerId) {
|
|
|
103
109
|
})();
|
|
104
110
|
if (!providerId)
|
|
105
111
|
return capabilities;
|
|
112
|
+
if (backend === 'copilot' && ['copilot', 'agency-copilot'].includes(providerId)) {
|
|
113
|
+
capabilities.copilotOptions.catalog = mergeCopilotCapabilities(providerId);
|
|
114
|
+
}
|
|
106
115
|
return {
|
|
107
116
|
...capabilities,
|
|
108
117
|
commands: {
|
|
@@ -981,17 +990,48 @@ function handleServerMessage(msg) {
|
|
|
981
990
|
}
|
|
982
991
|
else if (isCopilotBackend()) {
|
|
983
992
|
const copilotMsg = msg;
|
|
984
|
-
handleCopilotChat(chatConvId || '', copilotMsg.prompt, chatDir, {
|
|
993
|
+
void dispatchCopilotRequest({ conversationId: chatConvId || '', providerId: effectiveProviderId }, () => handleCopilotChat(chatConvId || '', copilotMsg.prompt, chatDir, {
|
|
985
994
|
resumeSessionId: chatOptions.resumeSessionId,
|
|
986
995
|
providerId: effectiveProviderId,
|
|
987
996
|
copilotOptions: copilotMsg.copilotOptions,
|
|
988
|
-
|
|
997
|
+
forkSourceSessionId: copilotMsg.forkSourceSessionId,
|
|
998
|
+
}, copilotMsg.files), send, () => getCopilotConversation(chatConvId || '')?.turnActive === true);
|
|
989
999
|
}
|
|
990
1000
|
else {
|
|
991
1001
|
claudeHandleChat(chatConvId, msg.prompt, chatDir, chatOptions, msg.files);
|
|
992
1002
|
}
|
|
993
1003
|
break;
|
|
994
1004
|
}
|
|
1005
|
+
case 'get_copilot_capabilities': {
|
|
1006
|
+
const m = msg;
|
|
1007
|
+
if (typeof m.requestId !== 'string' || !m.requestId || m.requestId.length > 200)
|
|
1008
|
+
break;
|
|
1009
|
+
if (m.cancel) {
|
|
1010
|
+
copilotCapabilityRequests.get(m.requestId)?.abort();
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
if (!['copilot', 'agency-copilot'].includes(m.providerId) || copilotCapabilityRequests.has(m.requestId))
|
|
1014
|
+
break;
|
|
1015
|
+
const scope = { providerId: m.providerId, workDir: path.resolve(m.workDir || state.workDir) };
|
|
1016
|
+
const controller = new AbortController();
|
|
1017
|
+
copilotCapabilityRequests.set(m.requestId, controller);
|
|
1018
|
+
send({ type: 'copilot_capabilities', requestId: m.requestId, providerId: m.providerId,
|
|
1019
|
+
workDir: scope.workDir, loading: true, catalog: copilotCapabilityService.snapshot(scope) });
|
|
1020
|
+
void copilotCapabilityService.query(scope, controller.signal).then(catalog => {
|
|
1021
|
+
if (!controller.signal.aborted)
|
|
1022
|
+
send({ type: 'copilot_capabilities', requestId: m.requestId,
|
|
1023
|
+
providerId: m.providerId, workDir: scope.workDir, loading: false, catalog });
|
|
1024
|
+
}).catch(error => {
|
|
1025
|
+
if (!controller.signal.aborted)
|
|
1026
|
+
send({ type: 'copilot_capabilities', requestId: m.requestId,
|
|
1027
|
+
providerId: m.providerId, workDir: scope.workDir, loading: false,
|
|
1028
|
+
catalog: { ...copilotCapabilityService.snapshot(scope), error: String(error) } });
|
|
1029
|
+
}).finally(() => {
|
|
1030
|
+
if (copilotCapabilityRequests.get(m.requestId) === controller)
|
|
1031
|
+
copilotCapabilityRequests.delete(m.requestId);
|
|
1032
|
+
});
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
995
1035
|
case 'get_provider_commands': {
|
|
996
1036
|
const m = msg;
|
|
997
1037
|
if (typeof m.requestId !== 'string' || !m.requestId.trim()
|
|
@@ -1014,6 +1054,7 @@ function handleServerMessage(msg) {
|
|
|
1014
1054
|
providerId: m.providerId,
|
|
1015
1055
|
conversationId: m.conversationId,
|
|
1016
1056
|
workDir: path.resolve(m.workDir),
|
|
1057
|
+
...(m.copilotOptions ? { copilotOptions: m.copilotOptions } : {}),
|
|
1017
1058
|
};
|
|
1018
1059
|
void discoverProviderCommands(scope)
|
|
1019
1060
|
.then(result => send(providerCommandsMessage(scope, result)))
|
|
@@ -1023,6 +1064,32 @@ function handleServerMessage(msg) {
|
|
|
1023
1064
|
})));
|
|
1024
1065
|
break;
|
|
1025
1066
|
}
|
|
1067
|
+
case 'execute_provider_command': {
|
|
1068
|
+
const m = msg;
|
|
1069
|
+
const conversation = m.conversationId
|
|
1070
|
+
? getCopilotConversation(m.conversationId)
|
|
1071
|
+
: undefined;
|
|
1072
|
+
const providerId = m.providerId || conversation?.providerId || 'copilot';
|
|
1073
|
+
const command = m.command?.trim().toLowerCase();
|
|
1074
|
+
if (!m.conversationId
|
|
1075
|
+
|| getBackendTypeForProvider(providerId) !== 'copilot'
|
|
1076
|
+
|| !['compact', 'plan', 'goal'].includes(command || '')) {
|
|
1077
|
+
send({
|
|
1078
|
+
type: 'error',
|
|
1079
|
+
conversationId: m.conversationId,
|
|
1080
|
+
message: 'Invalid Copilot provider command request',
|
|
1081
|
+
});
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
const workDir = path.resolve(m.workDir || conversation?.workDir || state.workDir);
|
|
1085
|
+
const conversationId = m.conversationId;
|
|
1086
|
+
void dispatchCopilotRequest({ conversationId, providerId }, () => executeCopilotCommand(conversationId, command, typeof m.input === 'string' ? m.input : '', workDir, {
|
|
1087
|
+
providerId,
|
|
1088
|
+
resumeSessionId: resolveCopilotCommandResumeSessionId(m.resumeSessionId, conversation),
|
|
1089
|
+
copilotOptions: m.copilotOptions,
|
|
1090
|
+
}), send, () => getCopilotConversation(conversationId)?.turnActive === true);
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1026
1093
|
case 'cancel_execution':
|
|
1027
1094
|
{
|
|
1028
1095
|
const conversationId = msg.conversationId || '';
|
|
@@ -1418,6 +1485,10 @@ function handleServerMessage(msg) {
|
|
|
1418
1485
|
}
|
|
1419
1486
|
// Route to copilot backend
|
|
1420
1487
|
if (resumeBackend === 'copilot') {
|
|
1488
|
+
const liveOwner = [...getCopilotConversations().values()].find(conv => conv.copilotSessionId === m.claudeSessionId || conv.lastCopilotSessionId === m.claudeSessionId);
|
|
1489
|
+
const resumeProviderId = liveOwner?.providerId || readCopilotSessionProvider(m.claudeSessionId)
|
|
1490
|
+
|| m.providerId
|
|
1491
|
+
|| 'copilot';
|
|
1421
1492
|
// Copilot rewrites workspace.yaml using the cwd of each resume process.
|
|
1422
1493
|
// Recover the persisted cwd before creating a placeholder so a reconnect
|
|
1423
1494
|
// that omits workDir cannot silently move the session to the agent cwd.
|
|
@@ -1426,35 +1497,101 @@ function handleServerMessage(msg) {
|
|
|
1426
1497
|
|| state.workDir;
|
|
1427
1498
|
// Rebind running copilot process to new conversationId (handles page refresh)
|
|
1428
1499
|
if (convId) {
|
|
1500
|
+
const existing = getCopilotConversation(convId);
|
|
1501
|
+
const boundSession = existing?.copilotSessionId || existing?.lastCopilotSessionId;
|
|
1502
|
+
if (existing && (boundSession || existing.turnActive) && boundSession !== m.claudeSessionId) {
|
|
1503
|
+
send({ type: 'error', operation: 'resume_conversation', conversationId: convId,
|
|
1504
|
+
providerId: resumeProviderId, claudeSessionId: m.claudeSessionId,
|
|
1505
|
+
message: 'Copilot conversation/session mismatch. Reopen the intended conversation.' });
|
|
1506
|
+
break;
|
|
1507
|
+
}
|
|
1429
1508
|
rebindCopilotConversation(m.claudeSessionId, convId);
|
|
1430
1509
|
}
|
|
1431
1510
|
// Create a copilot placeholder so follow-up chats auto-resume
|
|
1432
1511
|
if (convId) {
|
|
1433
|
-
createCopilotPlaceholder(convId, { providerId:
|
|
1512
|
+
createCopilotPlaceholder(convId, { providerId: resumeProviderId });
|
|
1434
1513
|
const placeholder = getCopilotConversation(convId);
|
|
1435
1514
|
if (placeholder) {
|
|
1515
|
+
placeholder.providerId = resumeProviderId;
|
|
1436
1516
|
placeholder.copilotSessionId = m.claudeSessionId;
|
|
1437
1517
|
placeholder.workDir = resolvedWorkDir;
|
|
1438
1518
|
}
|
|
1439
1519
|
}
|
|
1440
1520
|
const history = readCopilotSessionMessages(resolvedWorkDir, m.claudeSessionId);
|
|
1521
|
+
const persistedCopilotMode = readCopilotSessionMode(m.claudeSessionId);
|
|
1522
|
+
const persistedCopilotUsage = readCopilotSessionUsage(m.claudeSessionId);
|
|
1441
1523
|
// Check if this session has an active copilot process running
|
|
1442
1524
|
const copilotState = getCopilotConversation(convId || '');
|
|
1443
|
-
|
|
1525
|
+
// A live persistent Runtime can be newer than events.jsonl while the
|
|
1526
|
+
// Provider is flushing its final usage checkpoint. Do not replace its
|
|
1527
|
+
// authoritative in-memory value merely because the page was reopened.
|
|
1528
|
+
const restoredCopilotUsage = copilotState?.lastUsage || persistedCopilotUsage;
|
|
1529
|
+
const isCopilotProcessing = !!copilotState?.turnActive;
|
|
1530
|
+
if (copilotState && !isCopilotProcessing) {
|
|
1531
|
+
copilotState.copilotMode = persistedCopilotMode;
|
|
1532
|
+
copilotState.planMode = persistedCopilotMode === 'plan';
|
|
1533
|
+
copilotState.planModePending = persistedCopilotMode === 'plan';
|
|
1534
|
+
copilotState.lastUsage = restoredCopilotUsage;
|
|
1535
|
+
copilotState.configuration = restoredCopilotUsage?.configuration;
|
|
1536
|
+
copilotState.model = restoredCopilotUsage?.configuration?.requested.model || restoredCopilotUsage?.model || null;
|
|
1537
|
+
const requestedContext = restoredCopilotUsage?.configuration?.requested.context || restoredCopilotUsage?.contextTier;
|
|
1538
|
+
const requestedEffort = restoredCopilotUsage?.configuration?.requested.effort || restoredCopilotUsage?.reasoningEffort;
|
|
1539
|
+
copilotState.contextTier = requestedContext === 'default' || requestedContext === 'long_context'
|
|
1540
|
+
? requestedContext
|
|
1541
|
+
: null;
|
|
1542
|
+
copilotState.reasoningEffort = [
|
|
1543
|
+
'none', 'low', 'medium', 'high', 'xhigh', 'max',
|
|
1544
|
+
].includes(requestedEffort || '')
|
|
1545
|
+
? requestedEffort
|
|
1546
|
+
: null;
|
|
1547
|
+
copilotState.autoCompactionPending = !!restoredCopilotUsage
|
|
1548
|
+
&& Number.isFinite(restoredCopilotUsage.contextTokens)
|
|
1549
|
+
&& Number.isFinite(restoredCopilotUsage.contextWindow)
|
|
1550
|
+
&& Number(restoredCopilotUsage.contextWindow) > 0
|
|
1551
|
+
&& Number(restoredCopilotUsage.contextTokens) / Number(restoredCopilotUsage.contextWindow) >= COPILOT_COMPACTION_POLICY.preRequest;
|
|
1552
|
+
}
|
|
1444
1553
|
console.log(`[AgentLink] → conversation_resumed (${history.length} copilot messages, session ${m.claudeSessionId.slice(0, 8)})`);
|
|
1445
1554
|
send({
|
|
1446
1555
|
type: 'conversation_resumed',
|
|
1447
1556
|
conversationId: convId,
|
|
1448
1557
|
claudeSessionId: m.claudeSessionId,
|
|
1449
1558
|
history,
|
|
1450
|
-
isCompacting: false,
|
|
1559
|
+
isCompacting: copilotState?.isCompacting || false,
|
|
1560
|
+
compactions: [...(copilotState?.compactionRecords?.values() || [])].slice(-8),
|
|
1451
1561
|
isProcessing: isCopilotProcessing,
|
|
1452
|
-
|
|
1562
|
+
turnId: copilotState?.turnId,
|
|
1563
|
+
stateVersion: copilotState?.stateVersion,
|
|
1564
|
+
planMode: copilotState?.planMode ?? (persistedCopilotMode === 'plan'),
|
|
1565
|
+
copilotMode: copilotState?.copilotMode || persistedCopilotMode,
|
|
1453
1566
|
permissionMode: 'normal',
|
|
1454
1567
|
workDir: resolvedWorkDir,
|
|
1568
|
+
providerId: resumeProviderId,
|
|
1569
|
+
...(restoredCopilotUsage ? { usage: restoredCopilotUsage } : {}),
|
|
1455
1570
|
...(typeof m.scrollToMessageIdx === 'number' ? { scrollToMessageIdx: m.scrollToMessageIdx } : {}),
|
|
1456
1571
|
...(m.searchQuery ? { searchQuery: m.searchQuery } : {}),
|
|
1457
1572
|
});
|
|
1573
|
+
// Seed the resolved history Provider's offline capabilities without
|
|
1574
|
+
// creating a metadata Runtime just because history was opened.
|
|
1575
|
+
send({ type: 'backend_info', conversationId: convId, backend: 'copilot', providerId: resumeProviderId,
|
|
1576
|
+
capabilities: capabilitiesForBackend('copilot', resumeProviderId) });
|
|
1577
|
+
if (convId && isCopilotProcessing) {
|
|
1578
|
+
for (const pending of getPendingCopilotDecisions(convId)) {
|
|
1579
|
+
send({
|
|
1580
|
+
type: 'backend_event',
|
|
1581
|
+
conversationId: convId,
|
|
1582
|
+
providerId: pending.providerId,
|
|
1583
|
+
claudeSessionId: pending.sessionId,
|
|
1584
|
+
turnId: copilotState?.turnId,
|
|
1585
|
+
stateVersion: copilotState?.stateVersion,
|
|
1586
|
+
event: {
|
|
1587
|
+
type: 'user_input_requested',
|
|
1588
|
+
session: { backendType: 'copilot', backendSessionId: pending.sessionId },
|
|
1589
|
+
requestId: pending.requestId,
|
|
1590
|
+
request: pending.request,
|
|
1591
|
+
},
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1458
1595
|
break;
|
|
1459
1596
|
}
|
|
1460
1597
|
if (!convId) {
|
|
@@ -1553,10 +1690,22 @@ function handleServerMessage(msg) {
|
|
|
1553
1690
|
}
|
|
1554
1691
|
case 'ask_user_answer': {
|
|
1555
1692
|
const m = msg;
|
|
1556
|
-
|
|
1693
|
+
const copilotConversation = m.conversationId
|
|
1694
|
+
? getCopilotConversation(m.conversationId)
|
|
1695
|
+
: undefined;
|
|
1696
|
+
if (copilotConversation
|
|
1697
|
+
|| (m.providerId && getBackendTypeForProvider(m.providerId) === 'copilot')) {
|
|
1698
|
+
handleCopilotUserAnswer(m.requestId, m.answers, {
|
|
1699
|
+
conversationId: m.conversationId,
|
|
1700
|
+
providerId: m.providerId,
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
else if (isYeaftBackend()) {
|
|
1557
1704
|
handleYeaftUserAnswer(m.requestId, m.answers, { conversationId: m.conversationId });
|
|
1558
|
-
|
|
1705
|
+
}
|
|
1706
|
+
else {
|
|
1559
1707
|
handleUserAnswer(m.requestId, m.answers);
|
|
1708
|
+
}
|
|
1560
1709
|
break;
|
|
1561
1710
|
}
|
|
1562
1711
|
case 'delete_session': {
|
|
@@ -1621,9 +1770,19 @@ function handleServerMessage(msg) {
|
|
|
1621
1770
|
handleListCodexSessionsFn(dir);
|
|
1622
1771
|
}
|
|
1623
1772
|
else if (sessionBackend === 'copilot') {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1773
|
+
void deleteCopilotSession(dir, m.sessionId).then(ok => {
|
|
1774
|
+
console.log(`[AgentLink] delete copilot session ${m.sessionId}: ${ok}`);
|
|
1775
|
+
if (ok)
|
|
1776
|
+
send({ type: 'session_deleted', sessionId: m.sessionId, providerId: m.providerId, workDir: dir });
|
|
1777
|
+
else
|
|
1778
|
+
send({ type: 'error', operation: 'delete_session', sessionId: m.sessionId,
|
|
1779
|
+
message: 'Session not found or could not be deleted.' });
|
|
1780
|
+
handleListCopilotSessionsFn(dir);
|
|
1781
|
+
}).catch(error => {
|
|
1782
|
+
send({ type: 'error', operation: 'delete_session', sessionId: m.sessionId,
|
|
1783
|
+
message: String(error.message || error) });
|
|
1784
|
+
handleListCopilotSessionsFn(dir);
|
|
1785
|
+
});
|
|
1627
1786
|
}
|
|
1628
1787
|
else {
|
|
1629
1788
|
handleDeleteSession(m.sessionId, dir);
|
|
@@ -1856,10 +2015,12 @@ function handleServerMessage(msg) {
|
|
|
1856
2015
|
const sessionId = conv.claudeSessionId ?? conv.copilotSessionId ?? conv.codexSessionId ?? conv.yeaftSessionId ?? conv.piSessionId ?? null;
|
|
1857
2016
|
if (conv.turnActive) {
|
|
1858
2017
|
active.push({
|
|
2018
|
+
providerId: conv.providerId, workDir: conv.workDir,
|
|
1859
2019
|
conversationId: convId,
|
|
1860
2020
|
claudeSessionId: sessionId,
|
|
1861
2021
|
isProcessing: true,
|
|
1862
2022
|
isCompacting: !!conv.isCompacting,
|
|
2023
|
+
...(conv.compactionRecords ? { compactions: [...conv.compactionRecords.values()].slice(-8) } : {}),
|
|
1863
2024
|
turnId: conv.turnId,
|
|
1864
2025
|
stateVersion: conv.stateVersion,
|
|
1865
2026
|
});
|
|
@@ -1868,12 +2029,14 @@ function handleServerMessage(msg) {
|
|
|
1868
2029
|
// Include idle but resumable conversations so other tabs can
|
|
1869
2030
|
// learn the backend session ID for multi-device continuity.
|
|
1870
2031
|
active.push({
|
|
2032
|
+
providerId: conv.providerId, workDir: conv.workDir,
|
|
1871
2033
|
conversationId: convId,
|
|
1872
2034
|
claudeSessionId: sessionId,
|
|
1873
2035
|
isProcessing: false,
|
|
1874
2036
|
isCompacting: false,
|
|
1875
2037
|
turnId: conv.turnId,
|
|
1876
2038
|
stateVersion: conv.stateVersion,
|
|
2039
|
+
...(conv.compactionRecords ? { compactions: [...conv.compactionRecords.values()].slice(-8) } : {}),
|
|
1877
2040
|
});
|
|
1878
2041
|
}
|
|
1879
2042
|
};
|
|
@@ -1917,12 +2080,14 @@ function handleServerMessage(msg) {
|
|
|
1917
2080
|
const status = isProc ? (isComp ? 'compacting' : 'processing') : 'idle';
|
|
1918
2081
|
return {
|
|
1919
2082
|
type: 'turn_status',
|
|
2083
|
+
providerId: conv.providerId, workDir: conv.workDir,
|
|
1920
2084
|
conversationId: convId,
|
|
1921
2085
|
claudeSessionId: conv.claudeSessionId ?? conv.copilotSessionId ?? conv.codexSessionId ?? conv.yeaftSessionId ?? conv.piSessionId ?? null,
|
|
1922
2086
|
turnId: conv.turnId,
|
|
1923
2087
|
status,
|
|
1924
2088
|
isProcessing: isProc,
|
|
1925
2089
|
isCompacting: isComp,
|
|
2090
|
+
...(conv.compactionRecords ? { compactions: [...conv.compactionRecords.values()].slice(-8) } : {}),
|
|
1926
2091
|
stateVersion: conv.stateVersion,
|
|
1927
2092
|
};
|
|
1928
2093
|
};
|
|
@@ -2114,8 +2279,26 @@ function handleServerMessage(msg) {
|
|
|
2114
2279
|
break;
|
|
2115
2280
|
}
|
|
2116
2281
|
case 'set_plan_mode': {
|
|
2117
|
-
const { enabled, conversationId } = msg;
|
|
2282
|
+
const { enabled, conversationId, providerId, workDir, copilotOptions, resumeSessionId } = msg;
|
|
2118
2283
|
console.log(`[AgentLink] set_plan_mode: enabled=${enabled}, conversationId=${conversationId}`);
|
|
2284
|
+
const copilotConversation = conversationId
|
|
2285
|
+
? getCopilotConversation(conversationId)
|
|
2286
|
+
: undefined;
|
|
2287
|
+
const effectiveProviderId = providerId || copilotConversation?.providerId;
|
|
2288
|
+
if (conversationId
|
|
2289
|
+
&& (copilotConversation
|
|
2290
|
+
|| (effectiveProviderId && getBackendTypeForProvider(effectiveProviderId) === 'copilot')
|
|
2291
|
+
|| isCopilotBackend())) {
|
|
2292
|
+
void setCopilotPlanMode(conversationId, enabled, path.resolve(workDir || copilotConversation?.workDir || state.workDir), effectiveProviderId || 'copilot', copilotOptions, resumeSessionId).catch(error => {
|
|
2293
|
+
send({
|
|
2294
|
+
type: 'error',
|
|
2295
|
+
conversationId,
|
|
2296
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2297
|
+
});
|
|
2298
|
+
send({ type: 'plan_mode_changed', enabled: !enabled, conversationId });
|
|
2299
|
+
});
|
|
2300
|
+
break;
|
|
2301
|
+
}
|
|
2119
2302
|
const conv = getConversation(conversationId);
|
|
2120
2303
|
if (conv) {
|
|
2121
2304
|
// Restart with new mode
|
|
@@ -2131,6 +2314,34 @@ function handleServerMessage(msg) {
|
|
|
2131
2314
|
send({ type: 'plan_mode_changed', enabled, conversationId });
|
|
2132
2315
|
break;
|
|
2133
2316
|
}
|
|
2317
|
+
case 'start_plan_implementation': {
|
|
2318
|
+
const { conversationId, planId, providerId, workDir, claudeSessionId, prompt, copilotOptions } = msg;
|
|
2319
|
+
if (!conversationId || !planId) {
|
|
2320
|
+
send({ type: 'error', conversationId, message: 'Invalid Plan implementation request' });
|
|
2321
|
+
break;
|
|
2322
|
+
}
|
|
2323
|
+
void startCopilotPlanImplementation(conversationId, planId, path.resolve(workDir || state.workDir), { providerId, resumeSessionId: claudeSessionId, prompt, copilotOptions }).catch(error => {
|
|
2324
|
+
send({
|
|
2325
|
+
type: 'backend_event',
|
|
2326
|
+
conversationId,
|
|
2327
|
+
providerId,
|
|
2328
|
+
claudeSessionId,
|
|
2329
|
+
event: {
|
|
2330
|
+
type: 'plan_implementation_status',
|
|
2331
|
+
session: { backendType: 'copilot', backendSessionId: claudeSessionId || '' },
|
|
2332
|
+
planId,
|
|
2333
|
+
status: 'failed',
|
|
2334
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2335
|
+
},
|
|
2336
|
+
});
|
|
2337
|
+
send({
|
|
2338
|
+
type: 'error',
|
|
2339
|
+
conversationId,
|
|
2340
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2341
|
+
});
|
|
2342
|
+
});
|
|
2343
|
+
break;
|
|
2344
|
+
}
|
|
2134
2345
|
case 'set_permission_mode': {
|
|
2135
2346
|
const { mode, conversationId } = msg;
|
|
2136
2347
|
console.log(`[AgentLink] set_permission_mode: mode=${mode}, conversationId=${conversationId}`);
|
|
@@ -2189,7 +2400,7 @@ function handleServerMessage(msg) {
|
|
|
2189
2400
|
break;
|
|
2190
2401
|
}
|
|
2191
2402
|
case 'set_provider': {
|
|
2192
|
-
|
|
2403
|
+
let { providerId, conversationId, resumeSessionId, workDir, restoreOnly } = msg;
|
|
2193
2404
|
console.log(`[AgentLink] set_provider: providerId=${providerId}, conversationId=${conversationId}`);
|
|
2194
2405
|
// Detect backend type change
|
|
2195
2406
|
const newBackendType = getBackendTypeForProvider(providerId);
|
|
@@ -2202,6 +2413,9 @@ function handleServerMessage(msg) {
|
|
|
2202
2413
|
// are routed to background via the web's backgroundRouting handler.
|
|
2203
2414
|
setBackendType(newBackendType);
|
|
2204
2415
|
console.log(`[AgentLink] Backend switched: ${oldBackendType} → ${newBackendType}`);
|
|
2416
|
+
if (newBackendType === 'copilot' && conversationId) {
|
|
2417
|
+
providerId = setCopilotProvider(conversationId, providerId, { resumeSessionId, workDir, restoreOnly });
|
|
2418
|
+
}
|
|
2205
2419
|
}
|
|
2206
2420
|
else if (oldBackendType === 'yeaft') {
|
|
2207
2421
|
const existingYeaftConv = conversationId ? getYeaftConversation(conversationId) : undefined;
|
|
@@ -2250,19 +2464,8 @@ function handleServerMessage(msg) {
|
|
|
2250
2464
|
else if (oldBackendType === 'copilot') {
|
|
2251
2465
|
// Same backend (copilot): provider sync during reconnect must not
|
|
2252
2466
|
// restart an active subprocess.
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
existingCopilotConv.providerId = providerId;
|
|
2256
|
-
}
|
|
2257
|
-
else if (conversationId && existingCopilotConv) {
|
|
2258
|
-
const result = restartCopilotConversation(conversationId, { providerId });
|
|
2259
|
-
if (result.wasTurnActive) {
|
|
2260
|
-
send({ type: 'execution_cancelled', conversationId });
|
|
2261
|
-
}
|
|
2262
|
-
}
|
|
2263
|
-
else if (conversationId) {
|
|
2264
|
-
createCopilotPlaceholder(conversationId, { providerId });
|
|
2265
|
-
}
|
|
2467
|
+
if (conversationId)
|
|
2468
|
+
providerId = setCopilotProvider(conversationId, providerId, { resumeSessionId, workDir, restoreOnly });
|
|
2266
2469
|
}
|
|
2267
2470
|
else {
|
|
2268
2471
|
// Same backend (claude): reconnect provider sync must not interrupt
|
|
@@ -2281,7 +2484,7 @@ function handleServerMessage(msg) {
|
|
|
2281
2484
|
createPlaceholderConversation(conversationId, { providerId });
|
|
2282
2485
|
}
|
|
2283
2486
|
}
|
|
2284
|
-
send({ type: 'provider_changed', providerId, conversationId });
|
|
2487
|
+
send({ type: 'provider_changed', providerId, conversationId, ...(restoreOnly ? { restoreOnly: true } : {}) });
|
|
2285
2488
|
// Capabilities are provider-scoped: wrappers and custom providers can
|
|
2286
2489
|
// share a backend while exposing different command discovery behavior.
|
|
2287
2490
|
send({
|