@yeaft/webchat-agent 1.0.119 → 1.0.121
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.
|
@@ -8,6 +8,7 @@ const os = require('os');
|
|
|
8
8
|
const PKG = process.argv[2];
|
|
9
9
|
const TARGET = process.argv[3];
|
|
10
10
|
const LOGFILE = process.argv[4];
|
|
11
|
+
const REGISTRY = process.argv[5];
|
|
11
12
|
|
|
12
13
|
function log(msg) {
|
|
13
14
|
const line = '[Upgrade-Worker] ' + msg;
|
|
@@ -75,7 +76,13 @@ try {
|
|
|
75
76
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'yeaft-upgrade-'));
|
|
76
77
|
log('Temp dir: ' + tmpDir);
|
|
77
78
|
|
|
78
|
-
const packOutput = execFileSync('npm', [
|
|
79
|
+
const packOutput = execFileSync('npm', [
|
|
80
|
+
'pack',
|
|
81
|
+
PKG,
|
|
82
|
+
'--pack-destination',
|
|
83
|
+
tmpDir,
|
|
84
|
+
`--registry=${REGISTRY}`,
|
|
85
|
+
], {
|
|
79
86
|
shell: process.platform === 'win32', encoding: 'utf8', cwd: tmpDir, timeout: 120000
|
|
80
87
|
}).trim();
|
|
81
88
|
const tgzName = packOutput.split('\n').pop().trim();
|
package/connection/upgrade.js
CHANGED
|
@@ -39,6 +39,37 @@ const shellOpt = isWin ? { shell: true, windowsHide: true } : {};
|
|
|
39
39
|
const currentPath = process.env.PATH || '/usr/bin:/bin:/usr/sbin:/sbin';
|
|
40
40
|
const safePath = currentPath.includes(nodeBinDir) ? currentPath : `${nodeBinDir}:${currentPath}`;
|
|
41
41
|
const safeEnv = { ...process.env, PATH: safePath };
|
|
42
|
+
export const PUBLIC_NPM_REGISTRY = 'https://registry.npmjs.org/';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build an npm metadata query that bypasses stale local metadata and registry
|
|
46
|
+
* mirrors. Upgrade decisions must use the package actually published to the
|
|
47
|
+
* public registry, not a cached `latest` value from a previous release.
|
|
48
|
+
*/
|
|
49
|
+
export function buildNpmMetadataArgs(packageSpec, field) {
|
|
50
|
+
return [
|
|
51
|
+
'view',
|
|
52
|
+
packageSpec,
|
|
53
|
+
field,
|
|
54
|
+
`--registry=${PUBLIC_NPM_REGISTRY}`,
|
|
55
|
+
'--prefer-online',
|
|
56
|
+
'--prefer-offline=false',
|
|
57
|
+
'--offline=false',
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Return true only when `latestVersion` is semantically newer. */
|
|
62
|
+
export function isUpgradeAvailable(currentVersion, latestVersion) {
|
|
63
|
+
const current = parseSemver(currentVersion);
|
|
64
|
+
const latest = parseSemver(latestVersion);
|
|
65
|
+
if (!current || !latest) return currentVersion !== latestVersion;
|
|
66
|
+
return cmpTuple(latest, current) > 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Build the Windows worker invocation with the same registry used for metadata. */
|
|
70
|
+
export function buildWindowsWorkerCommand(nodePath) {
|
|
71
|
+
return `"${nodePath.replace(/\//g, '\\')}" "%WORKER%" "%PKG%" "%PKG_DIR%" "%LOGFILE%" "${PUBLIC_NPM_REGISTRY}"`;
|
|
72
|
+
}
|
|
42
73
|
|
|
43
74
|
// Shared cleanup logic for restart/upgrade
|
|
44
75
|
function cleanupAndExit(exitCode) {
|
|
@@ -82,7 +113,7 @@ async function fetchRequiredNodeRange(pkgName, version) {
|
|
|
82
113
|
const stdout = await new Promise((resolve, reject) => {
|
|
83
114
|
execFile(
|
|
84
115
|
npmPath,
|
|
85
|
-
|
|
116
|
+
buildNpmMetadataArgs(`${pkgName}@${version}`, 'engines.node'),
|
|
86
117
|
{ stdio: 'pipe', env: safeEnv, ...shellOpt },
|
|
87
118
|
(err, out) => { if (err) reject(err); else resolve(out.toString().trim()); },
|
|
88
119
|
);
|
|
@@ -154,14 +185,15 @@ export async function handleUpgradeAgent() {
|
|
|
154
185
|
console.log('[Agent] Upgrade requested, checking for updates...');
|
|
155
186
|
try {
|
|
156
187
|
const pkgName = ctx.pkgName || '@yeaft/webchat-agent';
|
|
157
|
-
//
|
|
188
|
+
// Force a public-registry refresh so stale Windows npm metadata or a lagging
|
|
189
|
+
// registry mirror cannot report the installed version as the latest one.
|
|
158
190
|
const latestVersion = await new Promise((resolve, reject) => {
|
|
159
|
-
execFile(npmPath,
|
|
191
|
+
execFile(npmPath, buildNpmMetadataArgs(`${pkgName}@latest`, 'version'), { stdio: 'pipe', env: safeEnv, ...shellOpt }, (err, stdout) => {
|
|
160
192
|
if (err) reject(err); else resolve(stdout.toString().trim());
|
|
161
193
|
});
|
|
162
194
|
});
|
|
163
|
-
if (
|
|
164
|
-
console.log(`[Agent]
|
|
195
|
+
if (!isUpgradeAvailable(ctx.agentVersion, latestVersion)) {
|
|
196
|
+
console.log(`[Agent] No newer version than ${ctx.agentVersion} is available (registry: ${latestVersion}), skipping upgrade.`);
|
|
165
197
|
await sendToServer({ type: 'upgrade_agent_ack', success: true, alreadyLatest: true, version: ctx.agentVersion });
|
|
166
198
|
return;
|
|
167
199
|
}
|
|
@@ -270,7 +302,7 @@ async function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, l
|
|
|
270
302
|
'@echo off',
|
|
271
303
|
'setlocal',
|
|
272
304
|
`set PID=${pid}`,
|
|
273
|
-
`set PKG=${pkgName}
|
|
305
|
+
`set PKG=${pkgName}@${latestVersion}`,
|
|
274
306
|
`set INSTALL_DIR=${installDirWin}`,
|
|
275
307
|
`set PKG_DIR=${pkgDir}`,
|
|
276
308
|
`set LOGFILE=${logPath}`,
|
|
@@ -313,7 +345,7 @@ async function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, l
|
|
|
313
345
|
// Use Node.js worker for file-level upgrade (avoids EBUSY on directory rename)
|
|
314
346
|
batLines.push(
|
|
315
347
|
'echo [Upgrade] Running upgrade worker at %time%... >> "%LOGFILE%"',
|
|
316
|
-
|
|
348
|
+
buildWindowsWorkerCommand(process.execPath),
|
|
317
349
|
'if not "%errorlevel%"=="0" (',
|
|
318
350
|
' echo [Upgrade] Worker failed with exit code %errorlevel% at %time% >> "%LOGFILE%"',
|
|
319
351
|
' goto CLEANUP',
|
|
@@ -390,6 +422,7 @@ async function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, l
|
|
|
390
422
|
*
|
|
391
423
|
* @param {object} opts
|
|
392
424
|
* @param {string} opts.pkgName npm package name
|
|
425
|
+
* @param {string} opts.targetVersion exact version selected by the metadata check
|
|
393
426
|
* @param {string} opts.installDir install dir (local install) — used as cwd
|
|
394
427
|
* @param {boolean} opts.isGlobalInstall global vs local npm install
|
|
395
428
|
* @param {number} opts.pid pid of the exiting agent to wait on
|
|
@@ -402,6 +435,7 @@ async function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, l
|
|
|
402
435
|
*/
|
|
403
436
|
export function buildUnixUpgradeScript({
|
|
404
437
|
pkgName,
|
|
438
|
+
targetVersion,
|
|
405
439
|
installDir,
|
|
406
440
|
isGlobalInstall,
|
|
407
441
|
pid,
|
|
@@ -422,7 +456,8 @@ export function buildUnixUpgradeScript({
|
|
|
422
456
|
const shLines = [
|
|
423
457
|
'#!/bin/bash',
|
|
424
458
|
`PID=${pid}`,
|
|
425
|
-
`PKG="${pkgName}
|
|
459
|
+
`PKG="${pkgName}@${targetVersion}"`,
|
|
460
|
+
`REGISTRY="${PUBLIC_NPM_REGISTRY}"`,
|
|
426
461
|
`NPM="${npmPath}"`,
|
|
427
462
|
`LOGFILE="${join(configDir, 'logs', 'upgrade.log')}"`,
|
|
428
463
|
`export PATH="${safePath}"`,
|
|
@@ -477,8 +512,8 @@ export function buildUnixUpgradeScript({
|
|
|
477
512
|
|
|
478
513
|
// npm install (use absolute path via $NPM variable)
|
|
479
514
|
const npmCmd = isGlobalInstall
|
|
480
|
-
? `"$NPM" install -g "$PKG"`
|
|
481
|
-
: `cd "$INSTALL_DIR" && "$NPM" install "$PKG"`;
|
|
515
|
+
? `"$NPM" install -g "$PKG" --registry="$REGISTRY"`
|
|
516
|
+
: `cd "$INSTALL_DIR" && "$NPM" install "$PKG" --registry="$REGISTRY"`;
|
|
482
517
|
|
|
483
518
|
shLines.push(
|
|
484
519
|
'echo "[Upgrade] Installing $PKG..."',
|
|
@@ -535,6 +570,7 @@ async function spawnUnixUpgradeScript(pkgName, installDir, isGlobalInstall, late
|
|
|
535
570
|
|
|
536
571
|
const script = buildUnixUpgradeScript({
|
|
537
572
|
pkgName,
|
|
573
|
+
targetVersion: latestVersion,
|
|
538
574
|
installDir,
|
|
539
575
|
isGlobalInstall,
|
|
540
576
|
pid: process.pid,
|
package/package.json
CHANGED
package/yeaft/engine.js
CHANGED
|
@@ -23,7 +23,7 @@ import { join, resolve as resolvePath } from 'path';
|
|
|
23
23
|
import { buildSystemPrompt, buildWorkerPrompt } from './prompts.js';
|
|
24
24
|
import { getRuntimePlatformInfo } from './runtime-platform.js';
|
|
25
25
|
import { LLMContextError, LLMAbortError, LLMRateLimitError, LLMServerError, LLMStreamIdleTimeoutError } from './llm/adapter.js';
|
|
26
|
-
import { runMemoryPreflow, buildRelevantScopes } from './sessions/pre-flow.js';
|
|
26
|
+
import { runMemoryPreflow, buildRelevantScopes, memoryScopeLabel } from './sessions/pre-flow.js';
|
|
27
27
|
import { readProjectDoc, pickProjectDocFile, DEFAULT_PROJECT_DOC_MAX_BYTES } from './sessions/project-doc.js';
|
|
28
28
|
import { partitionMessages } from './compact/partition.js';
|
|
29
29
|
import { runCompact as runCompactOrchestrator } from './compact/orchestrator.js';
|
|
@@ -905,19 +905,19 @@ export class Engine {
|
|
|
905
905
|
if (snap.resident.length > 0) {
|
|
906
906
|
parts.push(zh ? '### 常驻记忆' : '### Resident');
|
|
907
907
|
for (const r of snap.resident) {
|
|
908
|
-
parts.push(`- **${r.scope}**: ${r.summary}`);
|
|
908
|
+
parts.push(`- **${memoryScopeLabel(r.scope)}**: ${r.summary}`);
|
|
909
909
|
}
|
|
910
910
|
}
|
|
911
911
|
if (snap.recent.length > 0) {
|
|
912
912
|
parts.push(zh ? '### 最近记忆' : '### Recent');
|
|
913
913
|
for (const s of snap.recent) {
|
|
914
|
-
parts.push(`- (${s.scope}) ${(s.body || '').trim()}`);
|
|
914
|
+
parts.push(`- (${memoryScopeLabel(s.scope)}) ${(s.body || '').trim()}`);
|
|
915
915
|
}
|
|
916
916
|
}
|
|
917
917
|
if (snap.onDemand.length > 0) {
|
|
918
918
|
parts.push(zh ? '### 按需记忆' : '### OnDemand');
|
|
919
919
|
for (const s of snap.onDemand) {
|
|
920
|
-
parts.push(`- (${s.scope}) ${(s.body || '').trim()}`);
|
|
920
|
+
parts.push(`- (${memoryScopeLabel(s.scope)}) ${(s.body || '').trim()}`);
|
|
921
921
|
}
|
|
922
922
|
}
|
|
923
923
|
return parts.join('\n');
|
|
@@ -157,6 +157,24 @@ export function selectRespondingVps(input) {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Turn an internal memory scope into the compact label shown to the model.
|
|
162
|
+
* The active-scope prompt already carries the current session id, so repeating
|
|
163
|
+
* the full storage path on every memory entry only wastes context. Internal
|
|
164
|
+
* entries and debug events keep the original scope for ACLs and diagnostics.
|
|
165
|
+
*
|
|
166
|
+
* @param {string} scope
|
|
167
|
+
* @returns {string}
|
|
168
|
+
*/
|
|
169
|
+
export function memoryScopeLabel(scope) {
|
|
170
|
+
const value = typeof scope === 'string' && scope ? scope : 'unknown';
|
|
171
|
+
const sessionTopic = /^(?:sessions|session|group)\/[^/]+\/topic\/(.+)$/.exec(value);
|
|
172
|
+
if (sessionTopic) return `topic: ${sessionTopic[1]}`;
|
|
173
|
+
if (/^(?:sessions|session|group)\/[^/]+$/.test(value)) return 'session';
|
|
174
|
+
if (value.startsWith('topic/')) return `topic: ${value.slice(6)}`;
|
|
175
|
+
return value;
|
|
176
|
+
}
|
|
177
|
+
|
|
160
178
|
/**
|
|
161
179
|
* Build the heading for a single scope's formatted memory block.
|
|
162
180
|
*
|
|
@@ -167,6 +185,8 @@ export function selectRespondingVps(input) {
|
|
|
167
185
|
* @returns {string}
|
|
168
186
|
*/
|
|
169
187
|
function scopeHeading(scope) {
|
|
188
|
+
const label = memoryScopeLabel(scope);
|
|
189
|
+
if (label.startsWith('topic: ')) return `## Memory: Topic ${label.slice(7)}`;
|
|
170
190
|
if (scope === 'user') return '## Memory: User';
|
|
171
191
|
// Nested chat scopes first.
|
|
172
192
|
let m = /^chat\/([^/]+)\/vp\/(.+)$/.exec(scope);
|
|
@@ -180,10 +200,6 @@ function scopeHeading(scope) {
|
|
|
180
200
|
if (m) return `## Memory: Session ${m[1]} (user)`;
|
|
181
201
|
m = /^session\/([^/]+)\/feature\/(.+)$/.exec(scope);
|
|
182
202
|
if (m) return `## Memory: Feature ${m[2]}`;
|
|
183
|
-
m = /^sessions\/([^/]+)\/topic\/(.+)$/.exec(scope);
|
|
184
|
-
if (m) return `## Memory: Topic ${m[2]}`;
|
|
185
|
-
m = /^session\/([^/]+)\/topic\/(.+)$/.exec(scope);
|
|
186
|
-
if (m) return `## Memory: Topic ${m[2]}`;
|
|
187
203
|
// Legacy nested group scopes (un-migrated data).
|
|
188
204
|
m = /^group\/([^/]+)\/vp\/(.+)$/.exec(scope);
|
|
189
205
|
if (m) return `## Memory: VP ${m[2]}`;
|
|
@@ -191,8 +207,6 @@ function scopeHeading(scope) {
|
|
|
191
207
|
if (m) return `## Memory: Session ${m[1]} (user)`;
|
|
192
208
|
m = /^group\/([^/]+)\/feature\/(.+)$/.exec(scope);
|
|
193
209
|
if (m) return `## Memory: Feature ${m[2]}`;
|
|
194
|
-
m = /^group\/([^/]+)\/topic\/(.+)$/.exec(scope);
|
|
195
|
-
if (m) return `## Memory: Topic ${m[2]}`;
|
|
196
210
|
if (scope.startsWith('session/')) return `## Memory: Session ${scope.slice(8)}`;
|
|
197
211
|
if (scope.startsWith('group/')) return `## Memory: Session ${scope.slice(6)}`;
|
|
198
212
|
if (scope.startsWith('vp/')) return `## Memory: VP ${scope.slice(3)}`;
|