@yeaft/webchat-agent 1.0.641 → 1.0.643

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.
@@ -30,7 +30,7 @@ import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, g
30
30
  import { loadConfig } from '../yeaft/config.js';
31
31
  import { discoverLlmModels } from '../llm-model-discovery.js';
32
32
  import { fetchModelsDev } from '../yeaft/llm/models-dev.js';
33
- import { handleYeaftSessionSend, handleYeaftAskUserAnswer, handleYeaftSubAgentPrompt, handleYeaftTaskCancel, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, refreshLiveSessionConfig, handleYeaftLoadHistory, handleYeaftLoadHistoryOutline, handleYeaftSearchHistory, handleYeaftLoadHistoryWindow, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftProjectContextSync, handleYeaftProjectMutation, handleYeaftCreateSession, handleYeaftCopySession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, handleYeaftPluginCatalog, handleYeaftManagedSkill, ensureSessionLoaded, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager, broadcastYeaftVpSnapshotEager, preloadYeaftSkillSlashCommands } from '../yeaft/web-bridge.js';
33
+ import { handleYeaftSessionSend, handleYeaftAskUserAnswer, handleYeaftSubAgentPrompt, handleYeaftTaskCancel, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, refreshLiveSessionConfig, handleYeaftLoadHistory, handleYeaftLoadHistoryOutline, handleYeaftSearchHistory, handleYeaftLoadHistoryWindow, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftProjectContextSync, handleYeaftProjectMutation, handleYeaftCreateSession, handleYeaftCopySession, handleYeaftMergeSessions, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, handleYeaftPluginCatalog, handleYeaftManagedSkill, ensureSessionLoaded, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager, broadcastYeaftVpSnapshotEager, preloadYeaftSkillSlashCommands } from '../yeaft/web-bridge.js';
34
34
  import { startYeaftStatusRefresh, forceRefreshYeaftStatus } from '../yeaft/status-cache.js';
35
35
  import { handleWorkCenterRequest } from '../yeaft/work-center/bridge.js';
36
36
  import { handlePersonRequest } from '../yeaft/person/bridge.js';
@@ -793,6 +793,9 @@ export async function handleMessage(msg) {
793
793
  case 'yeaft_copy_session':
794
794
  handleYeaftCopySession(msg);
795
795
  break;
796
+ case 'yeaft_merge_sessions':
797
+ handleYeaftMergeSessions(msg);
798
+ break;
796
799
  case 'yeaft_rename_group':
797
800
  case 'unify_rename_group':
798
801
  case 'yeaft_rename_session':
package/index.js CHANGED
@@ -178,7 +178,7 @@ async function detectCapabilities() {
178
178
  // agent build can speak plaintext WS frames. New servers see this and
179
179
  // flip `agent.encryptOutbound = false`, stopping outbound encryption
180
180
  // to this peer. Old servers ignore the unknown capability token.
181
- const capabilities = ['background_tasks', 'file_editor', 'ping_session', 'plaintext-ok', 'workbench_session_routes', 'workbench_request_correlation', 'workbench_terminal_cleanup_fence', 'workbench_file_content_chunks', 'workbench_video_stream', 'session_history_search', 'session_history_outline', 'session_history_window_prefetch', 'session_fork_from_turn', 'file_reference_resolution', 'response_image_preview', 'yeaft_plugins', 'yeaft_managed_skills', 'settings_request_correlation', 'work_center_feature_settings'];
181
+ const capabilities = ['background_tasks', 'file_editor', 'ping_session', 'plaintext-ok', 'workbench_session_routes', 'workbench_request_correlation', 'workbench_terminal_cleanup_fence', 'workbench_file_content_chunks', 'workbench_video_stream', 'session_history_search', 'session_history_outline', 'session_history_window_prefetch', 'session_fork_from_turn', 'session_fork_while_running', 'session_merge', 'file_reference_resolution', 'response_image_preview', 'yeaft_plugins', 'yeaft_managed_skills', 'settings_request_correlation', 'work_center_feature_settings'];
182
182
  capabilities.push('digital_person', getAgentUpgradeCapability());
183
183
  if (ctx.CONFIG?.workCenterEnabled === true) {
184
184
  capabilities.push('work_center', 'work_center_message_v2', 'work_center_workbench');
@@ -91,12 +91,14 @@ function syncYeaftSessionMetadata(agentId, agent, event) {
91
91
  }
92
92
  return { ...event, sessions: decorateYeaftSessionsWithPinned(agentId, event.sessions) };
93
93
  }
94
- // A fork is a new Session on the same Agent, not a new Project. Resolve
94
+ // A fork/merge is a new Session on the same Agent, not a new Project. Resolve
95
95
  // membership here (never from browser/Agent project metadata) before the
96
96
  // successful acknowledgement can focus the new Session in the browser.
97
- if (event.ok && ownerId && op === 'copy' && event.sourceSessionId && event.session?.id) {
97
+ if (event.ok && ownerId && (op === 'copy' || op === 'merge') && event.sourceSessionId && event.session?.id) {
98
98
  try {
99
- if (event.sourceSessionId === event.session.id) throw new Error('Fork must have a new Session identity');
99
+ if (event.sourceSessionId === event.session.id || event.otherSessionId === event.session.id) {
100
+ throw new Error('Fork/merge must have a new Session identity');
101
+ }
100
102
  transaction(() => {
101
103
  // Replayed acknowledgements must not undo a later user Project move.
102
104
  if (yeaftSessionDb.getForAgent(ownerId, agentId, event.session.id)) return;
@@ -104,13 +106,13 @@ function syncYeaftSessionMetadata(agentId, agent, event) {
104
106
  yeaftProjectDb.inheritSessionProject(ownerId, agentId, event.sourceSessionId, event.session.id);
105
107
  })();
106
108
  } catch (e) {
107
- console.warn('[Server] Fork Project inheritance failed:', e?.message || e);
109
+ console.warn('[Server] Session Project inheritance failed:', e?.message || e);
108
110
  return {
109
111
  ...event,
110
112
  ok: false,
111
113
  error: {
112
114
  code: 'project_inheritance_failed',
113
- message: `Fork ${event.session.id} was created, but its Project could not be saved.`,
115
+ message: `${op === 'merge' ? 'Merged Session' : 'Fork'} ${event.session.id} was created, but its Project could not be saved.`,
114
116
  },
115
117
  };
116
118
  }
@@ -1624,6 +1624,53 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
1624
1624
  break;
1625
1625
  }
1626
1626
 
1627
+ case 'yeaft_merge_sessions':
1628
+ case 'unify_merge_sessions': {
1629
+ const mergeAgentId = msg.agentId || client.currentAgent || null;
1630
+ const reject = async (code, message) => sendToWebClient(client, {
1631
+ type: 'session_crud_result', op: 'merge', ok: false,
1632
+ requestId: msg.requestId ?? null,
1633
+ agentId: mergeAgentId,
1634
+ sourceSessionId: msg.sessionId ?? null,
1635
+ otherSessionId: msg.otherSessionId ?? null,
1636
+ error: { code, message },
1637
+ });
1638
+ // Use the shared ACL directly: checkAgentAccess emits an uncorrelated
1639
+ // error, which would leave the browser's pending merge waiting forever.
1640
+ const accessError = resolveAgentAccessError(mergeAgentId, client.userId, client.role);
1641
+ if (accessError) {
1642
+ await reject(accessError === 'Agent access denied' ? 'agent_access_denied' : 'agent_unavailable', accessError);
1643
+ break;
1644
+ }
1645
+ if (!agents.get(mergeAgentId)?.capabilities?.includes('session_merge')) {
1646
+ await reject('session_merge_unsupported', 'The selected Agent does not support merging Sessions.');
1647
+ break;
1648
+ }
1649
+ if (typeof msg.sessionId !== 'string' || !msg.sessionId.trim()
1650
+ || typeof msg.otherSessionId !== 'string' || !msg.otherSessionId.trim()
1651
+ || msg.sessionId === msg.otherSessionId) {
1652
+ await reject('invalid_merge_source', 'Select two different Sessions on the same Agent.');
1653
+ break;
1654
+ }
1655
+ if (!CONFIG.skipAuth && (!yeaftSessionDb.getForAgent(client.userId, mergeAgentId, msg.sessionId)
1656
+ || !yeaftSessionDb.getForAgent(client.userId, mergeAgentId, msg.otherSessionId))) {
1657
+ await reject('agent_access_denied', 'Both Sessions must belong to the selected Agent and current user.');
1658
+ break;
1659
+ }
1660
+ // Session ids are scoped to this one Agent; no cross-Agent lookup or
1661
+ // fallback is allowed even if another Agent has an identically named id.
1662
+ let dispatched = false;
1663
+ try {
1664
+ dispatched = await forwardToAgent(mergeAgentId, {
1665
+ type: 'yeaft_merge_sessions', requestId: msg.requestId,
1666
+ sessionId: msg.sessionId, otherSessionId: msg.otherSessionId,
1667
+ ...(msg.name !== undefined ? { name: msg.name } : {}),
1668
+ });
1669
+ } catch { /* Report a correlated dispatch failure below. */ }
1670
+ if (!dispatched) await reject('agent_unavailable', 'Agent is unavailable; Sessions were not merged.');
1671
+ break;
1672
+ }
1673
+
1627
1674
  case 'yeaft_merge_thread':
1628
1675
  case 'unify_merge_thread': {
1629
1676
  const mergeAgentId = msg.agentId || client.currentAgent;
@@ -1 +1 @@
1
- {"version":"1.0.641"}
1
+ {"version":"1.0.643"}