@yeaft/webchat-agent 1.0.308 → 1.0.309

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, handleYeaftProjectMutation, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, 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, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, handleYeaftMcpList, handleYeaftMcpAdd, handleYeaftMcpRemove, handleYeaftMcpReload, 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
 
@@ -506,6 +506,10 @@ export async function handleMessage(msg) {
506
506
  await handleYeaftSessionSend(msg);
507
507
  break;
508
508
 
509
+ case 'yeaft_project_context_sync':
510
+ handleYeaftProjectContextSync(msg);
511
+ break;
512
+
509
513
  case 'yeaft_project_mutation':
510
514
  handleYeaftProjectMutation(msg);
511
515
  break;
@@ -248,6 +248,7 @@ db.exec(`
248
248
  id TEXT NOT NULL,
249
249
  user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
250
250
  name TEXT NOT NULL,
251
+ instruction TEXT NOT NULL DEFAULT '',
251
252
  sort_order INTEGER NOT NULL,
252
253
  created_at INTEGER NOT NULL,
253
254
  updated_at INTEGER NOT NULL,
@@ -331,6 +332,13 @@ for (const migration of yeaftMigrations) {
331
332
  try { db.exec(migration); } catch (_) { /* column exists */ }
332
333
  }
333
334
 
335
+ const yeaftProjectMigrations = [
336
+ `ALTER TABLE yeaft_projects ADD COLUMN instruction TEXT NOT NULL DEFAULT ''`,
337
+ ];
338
+ for (const migration of yeaftProjectMigrations) {
339
+ try { db.exec(migration); } catch (_) { /* column exists */ }
340
+ }
341
+
334
342
  for (const migration of migrations) {
335
343
  try {
336
344
  db.exec(migration);
@@ -679,8 +687,8 @@ export const stmts = {
679
687
  // Project organization metadata. Projects are server-owned and may contain
680
688
  // Sessions from multiple Agents; sharing still filters by agent_id.
681
689
  insertYeaftProject: db.prepare(`
682
- INSERT INTO yeaft_projects (id, user_id, name, sort_order, created_at, updated_at)
683
- VALUES (?, ?, ?, ?, ?, ?)
690
+ INSERT INTO yeaft_projects (id, user_id, name, instruction, sort_order, created_at, updated_at)
691
+ VALUES (?, ?, ?, ?, ?, ?, ?)
684
692
  `),
685
693
  getYeaftProjectsByUser: db.prepare(`
686
694
  SELECT * FROM yeaft_projects WHERE user_id = ? ORDER BY sort_order ASC, created_at ASC
@@ -691,6 +699,9 @@ export const stmts = {
691
699
  updateYeaftProjectName: db.prepare(`
692
700
  UPDATE yeaft_projects SET name = ?, updated_at = ? WHERE user_id = ? AND id = ?
693
701
  `),
702
+ updateYeaftProjectInstruction: db.prepare(`
703
+ UPDATE yeaft_projects SET instruction = ?, updated_at = ? WHERE user_id = ? AND id = ?
704
+ `),
694
705
  deleteYeaftProject: db.prepare(`
695
706
  DELETE FROM yeaft_projects WHERE user_id = ? AND id = ?
696
707
  `),
@@ -21,6 +21,17 @@ function requireName(value) {
21
21
  return name.slice(0, 120);
22
22
  }
23
23
 
24
+ function normalizeInstruction(value) {
25
+ if (typeof value !== 'string') {
26
+ throw new YeaftProjectDbError('invalid_instruction', 'Project instruction must be a string');
27
+ }
28
+ const instruction = value.trim();
29
+ if (instruction.length > 20_000) {
30
+ throw new YeaftProjectDbError('instruction_too_long', 'Project instruction must not exceed 20000 characters');
31
+ }
32
+ return instruction;
33
+ }
34
+
24
35
  function requireId(value, code, label) {
25
36
  const id = typeof value === 'string' ? value.trim() : '';
26
37
  if (!id) throw new YeaftProjectDbError(code, `${label} is required`);
@@ -32,6 +43,7 @@ function mapProject(row, members = []) {
32
43
  return {
33
44
  id: row.id,
34
45
  name: row.name,
46
+ instruction: typeof row.instruction === 'string' ? row.instruction : '',
35
47
  sortOrder: row.sort_order,
36
48
  createdAt: row.created_at,
37
49
  updatedAt: row.updated_at,
@@ -79,6 +91,7 @@ export const yeaftProjectDb = {
79
91
  const project = {
80
92
  id: `project-${randomUUID().slice(0, 8)}`,
81
93
  name: requireName(name),
94
+ instruction: '',
82
95
  sortOrder: projects.reduce((max, row) => Math.max(max, Number(row.sortOrder) || 0), -1) + 1,
83
96
  createdAt: now,
84
97
  updatedAt: now,
@@ -88,6 +101,7 @@ export const yeaftProjectDb = {
88
101
  project.id,
89
102
  ownerId,
90
103
  project.name,
104
+ project.instruction,
91
105
  project.sortOrder,
92
106
  now,
93
107
  now,
@@ -105,6 +119,16 @@ export const yeaftProjectDb = {
105
119
  stmts.getYeaftProjectMembersByUser.all(ownerId).filter(member => member.project_id === id));
106
120
  },
107
121
 
122
+ updateInstruction(userId, projectId, instruction) {
123
+ const ownerId = requireUserId(userId);
124
+ const id = requireId(projectId, 'invalid_project_id', 'Project id');
125
+ requireProject(ownerId, id);
126
+ const nextInstruction = normalizeInstruction(instruction);
127
+ stmts.updateYeaftProjectInstruction.run(nextInstruction, Date.now(), ownerId, id);
128
+ return mapProject(stmts.getYeaftProjectForUser.get(ownerId, id),
129
+ stmts.getYeaftProjectMembersByUser.all(ownerId).filter(member => member.project_id === id));
130
+ },
131
+
108
132
  delete(userId, projectId) {
109
133
  const ownerId = requireUserId(userId);
110
134
  const id = requireId(projectId, 'invalid_project_id', 'Project id');
@@ -185,7 +209,7 @@ export const yeaftProjectDb = {
185
209
  for (let suffix = 2; usedNames.has(name); suffix += 1) name = `${baseName} ${suffix}`;
186
210
  const projectId = `project-${randomUUID().slice(0, 8)}`;
187
211
  const now = Date.now();
188
- stmts.insertYeaftProject.run(projectId, ownerId, name.slice(0, 120), sortOrder, now, now);
212
+ stmts.insertYeaftProject.run(projectId, ownerId, name.slice(0, 120), '', sortOrder, now, now);
189
213
  sortOrder += 1;
190
214
  usedNames.add(name);
191
215
  for (const rawSessionId of Array.isArray(row.sessionIds) ? row.sessionIds : []) {
@@ -219,6 +243,7 @@ export const yeaftProjectDb = {
219
243
  return {
220
244
  projectId: project.id,
221
245
  projectName: project.name,
246
+ projectInstruction: typeof project.instruction === 'string' ? project.instruction : '',
222
247
  sessionIds: sameAgentMembers,
223
248
  };
224
249
  },
@@ -49,6 +49,33 @@ async function sendVpSnapshotError(client, msg, error) {
49
49
  });
50
50
  }
51
51
 
52
+ export async function syncProjectContextsToAgents(userId) {
53
+ try {
54
+ const sessionsByAgent = groupOnlineYeaftSessions(yeaftSessionDb.getByUser(userId));
55
+ await Promise.all(Object.entries(sessionsByAgent).map(async ([agentId, sessions]) => {
56
+ try {
57
+ const contexts = sessions.map(session => ({
58
+ sessionId: session.id,
59
+ projectContext: yeaftProjectDb.contextForSession(userId, agentId, session.id) || {
60
+ projectId: null,
61
+ projectName: null,
62
+ projectInstruction: '',
63
+ sessionIds: [],
64
+ },
65
+ }));
66
+ await forwardToAgent(agentId, {
67
+ type: 'yeaft_project_context_sync',
68
+ contexts,
69
+ });
70
+ } catch (err) {
71
+ console.warn(`[Yeaft] Project context sync failed for Agent ${agentId}:`, err?.message || err);
72
+ }
73
+ }));
74
+ } catch (err) {
75
+ console.warn('[Yeaft] Project context sync failed:', err?.message || err);
76
+ }
77
+ }
78
+
52
79
  async function broadcastSessionPin(userId, payload) {
53
80
  for (const [, target] of webClients) {
54
81
  if (!target?.authenticated) continue;
@@ -1299,7 +1326,9 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
1299
1326
  let result = null;
1300
1327
  if (op === 'create') result = yeaftProjectDb.create(client.userId, msg.name);
1301
1328
  else if (op === 'rename') result = yeaftProjectDb.rename(client.userId, msg.projectId, msg.name);
1302
- else if (op === 'delete') result = yeaftProjectDb.delete(client.userId, msg.projectId);
1329
+ else if (op === 'update_instruction') {
1330
+ result = yeaftProjectDb.updateInstruction(client.userId, msg.projectId, msg.instruction);
1331
+ } else if (op === 'delete') result = yeaftProjectDb.delete(client.userId, msg.projectId);
1303
1332
  else if (op === 'move_session') {
1304
1333
  const agentId = msg.targetAgentId || msg.agentId;
1305
1334
  const sessionId = typeof msg.sessionId === 'string' ? msg.sessionId.trim() : '';
@@ -1324,6 +1353,7 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
1324
1353
  ? yeaftProjectDb.listForAgent(client.userId, responseAgentId)
1325
1354
  : yeaftProjectDb.list(client.userId);
1326
1355
  await respond({ ok: true, result, projects });
1356
+ await syncProjectContextsToAgents(client.userId);
1327
1357
  await broadcastSessionCatalog(client.userId);
1328
1358
  } catch (err) {
1329
1359
  await respond({
@@ -1474,6 +1504,7 @@ export async function handleClientConversation(clientId, client, msg, checkAgent
1474
1504
  rest.projectContext = projectContext || {
1475
1505
  projectId: null,
1476
1506
  projectName: null,
1507
+ projectInstruction: '',
1477
1508
  sessionIds: [],
1478
1509
  };
1479
1510
  }
@@ -1 +1 @@
1
- {"version":"1.0.308"}
1
+ {"version":"1.0.309"}