evolcore 0.0.27 → 0.0.28
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/CHANGELOG.md +26 -15
- package/dist/agents/baseagent.js +10 -5
- package/dist/agents/codex/app-server-client.js +7 -0
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex-runner.js +48 -11
- package/dist/aun/menu/client.js +1 -0
- package/dist/channels/aun.js +23 -7
- package/dist/cli/daemon-commands.js +77 -140
- package/dist/cli/diag.js +1 -1
- package/dist/cli/menu-client.js +4 -0
- package/dist/cli/restart-monitor.js +65 -17
- package/dist/core/command/command-handler.js +29 -1
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/menu-handler.js +16 -19
- package/dist/core/command/menu-protocol.js +3 -0
- package/dist/core/command/slash-handler.js +24 -15
- package/dist/core/message/im-renderer.js +21 -4
- package/dist/core/message/message-bridge.js +47 -3
- package/dist/core/message/response-engine.js +29 -10
- package/dist/core/permission/ec-command-parser.js +15 -7
- package/dist/core/permission/tool-policy.js +1 -1
- package/dist/core/session/session-manager.js +4 -0
- package/dist/index.js +14 -153
- package/dist/product.js +1 -0
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/windows-shell-trust.js +37 -0
- package/kits/docs/channels/aun.md +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,24 +5,35 @@
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.0.28 (2026-09-24)
|
|
9
|
+
|
|
10
|
+
- 增加 npm 版本缓存,改进升级状态展示及启动、重启流程。
|
|
11
|
+
- 改进 AUN 回复投递与消息展示。
|
|
12
|
+
- 加固 Windows CLI 启动和 PowerShell 命令解析,完善 Codex CLI 诊断。
|
|
13
|
+
- 强化 Menu 请求校验与错误处理。
|
|
14
|
+
|
|
8
15
|
## 0.0.27 (2026-09-24)
|
|
9
16
|
|
|
17
|
+
### AUN、群聊与消息
|
|
18
|
+
|
|
10
19
|
- 持久化 AUN 群邀请的 Owner 审核流程,并增加 Base Agent 清单查询入口。
|
|
11
|
-
- 支持 EC Agent
|
|
12
|
-
- 模型类 Trigger
|
|
13
|
-
- 修复 AUN
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
- 支持 EC Agent 的角色级模型与推理强度策略;完善 Claude、Codex、EC Agent 会话的任务历史和中断恢复。
|
|
21
|
+
- 模型类 Trigger 支持单次执行时限;目标会话失联时明确记录为失败。
|
|
22
|
+
- 修复 AUN 撤回消息造成的私聊游标跳跃;手动停止的 Agent 重新加载后可恢复渠道连接。
|
|
23
|
+
- 规范工具活动中的 Shell 命令展示,并在缺少本地证书时跳过控制 AID 名片发布。
|
|
24
|
+
- 优化消息大小处理,提升长消息和复杂内容的发送稳定性。
|
|
25
|
+
- 升级 AUN SDK 至 `0.5.17`,改进消息、群文件和存储上传的兼容性。
|
|
26
|
+
- 改进附件、头像和文件存储处理,提升文件类型识别、上传和公开访问的稳定性。
|
|
27
|
+
- 改进身份信息缓存刷新,确保对端资料更新后及时生效。
|
|
28
|
+
- 支持无连续编号消息的完整拉取信息,并修正消息数量统计。
|
|
29
|
+
- 群命令和托管群文件操作支持标准群 AID 格式。
|
|
30
|
+
- 优化群名称生成和冲突处理,自定义名称保持原样。
|
|
31
|
+
- 改进群组参数校验和成员身份识别,提升群聊操作准确性。
|
|
32
|
+
|
|
33
|
+
### Agent、权限与运行稳定性
|
|
34
|
+
|
|
35
|
+
- 收紧 Codex 分支会话的权限上下文,避免旧会话继承过期授权。
|
|
36
|
+
- 完善 Agent 初始化、会话恢复、权限边界和运行状态处理。
|
|
26
37
|
|
|
27
38
|
## 0.0.26 (2026-09-18)
|
|
28
39
|
|
package/dist/agents/baseagent.js
CHANGED
|
@@ -12,22 +12,26 @@
|
|
|
12
12
|
import fs from 'fs';
|
|
13
13
|
import path from 'path';
|
|
14
14
|
import os from 'os';
|
|
15
|
-
import { commandExists, isWindows, resolveProbePath } from '../utils/cross-platform.js';
|
|
15
|
+
import { buildCliLaunchCommand, commandExists, isWindows, resolvePowerShellShimPath, resolveProbePath, } from '../utils/cross-platform.js';
|
|
16
16
|
import { execFileSync } from 'child_process';
|
|
17
17
|
import { parse as parseToml } from 'smol-toml';
|
|
18
18
|
/** Resolve the installed Codex CLI entrypoint, including npm shims on Windows. */
|
|
19
19
|
export function resolveCodexCliPath() {
|
|
20
20
|
return resolveProbePath('codex');
|
|
21
21
|
}
|
|
22
|
+
/** Return a PS1-only Codex shim for installation diagnostics, never execution. */
|
|
23
|
+
export function resolveCodexPowerShellShimPath() {
|
|
24
|
+
return resolvePowerShellShimPath('codex');
|
|
25
|
+
}
|
|
22
26
|
export function resolveCodexLaunchCommand(args, options = {}) {
|
|
23
27
|
const windows = options.isWindows ?? isWindows;
|
|
24
28
|
const commandPath = options.commandPath !== undefined ? options.commandPath : resolveCodexCliPath();
|
|
25
29
|
if (!commandPath)
|
|
26
30
|
return null;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
return buildCliLaunchCommand(commandPath, args, {
|
|
32
|
+
isWindows: windows,
|
|
33
|
+
comSpec: options.comSpec,
|
|
34
|
+
});
|
|
31
35
|
}
|
|
32
36
|
/** Execute a Codex CLI command using the resolved npm shim/path. */
|
|
33
37
|
export function execCodexCliSync(args, options) {
|
|
@@ -40,6 +44,7 @@ export function execCodexCliSync(args, options) {
|
|
|
40
44
|
return execFileSync(launchCommand.command, launchCommand.args, {
|
|
41
45
|
...(options ?? {}),
|
|
42
46
|
windowsHide: isWindows,
|
|
47
|
+
windowsVerbatimArguments: launchCommand.windowsVerbatimArguments,
|
|
43
48
|
});
|
|
44
49
|
}
|
|
45
50
|
const BASEAGENT_ALIASES = {
|
|
@@ -481,6 +481,12 @@ export class CodexAppServerClient {
|
|
|
481
481
|
const launchCommand = resolveCodexLaunchCommand(args);
|
|
482
482
|
if (!launchCommand)
|
|
483
483
|
throw new Error('Codex CLI not found');
|
|
484
|
+
logger.info(`[CodexAppServer] launch ${JSON.stringify({
|
|
485
|
+
resolvedPath: launchCommand.resolvedPath,
|
|
486
|
+
launcherKind: launchCommand.launcherKind,
|
|
487
|
+
launcherPath: launchCommand.launcherPath,
|
|
488
|
+
codexVersion: this.options.codexVersion ?? null,
|
|
489
|
+
})}`);
|
|
484
490
|
try {
|
|
485
491
|
let command = launchCommand.command;
|
|
486
492
|
let commandArgs = launchCommand.args;
|
|
@@ -509,6 +515,7 @@ export class CodexAppServerClient {
|
|
|
509
515
|
env,
|
|
510
516
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
511
517
|
windowsHide: process.platform === 'win32',
|
|
518
|
+
windowsVerbatimArguments: launchCommand.windowsVerbatimArguments,
|
|
512
519
|
});
|
|
513
520
|
try {
|
|
514
521
|
this.processRegistrationPath = registerCodexAppServerProcess(this.proc.pid);
|
|
@@ -7,7 +7,13 @@ async function cliModels() {
|
|
|
7
7
|
if (!launch)
|
|
8
8
|
return null;
|
|
9
9
|
return new Promise(resolve => {
|
|
10
|
-
execFile(launch.command, launch.args, {
|
|
10
|
+
execFile(launch.command, launch.args, {
|
|
11
|
+
timeout: 3000,
|
|
12
|
+
windowsHide: true,
|
|
13
|
+
windowsVerbatimArguments: launch.windowsVerbatimArguments,
|
|
14
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
15
|
+
encoding: 'utf8',
|
|
16
|
+
}, (error, stdout) => {
|
|
11
17
|
try {
|
|
12
18
|
if (error)
|
|
13
19
|
return resolve(null);
|
|
@@ -7,7 +7,7 @@ import { checkReadonly, checkDangerousCommand, evaluateToolPreflight } from '../
|
|
|
7
7
|
import { normalizeExecutionPermissionMode, normalizePermissionMode, resolvePhaseOneExecutionSandbox } from '../core/permission/mode.js';
|
|
8
8
|
import { assertWindowsCodexFilesystemRuleBudget, buildCodexProtectedFilesystemRules, isSameOrDescendant, resolveProtectedCandidate, } from '../core/permission/protected-paths.js';
|
|
9
9
|
import { CODEX_THREAD_ACTIVE_WRITER, CodexAppServerClient, } from './codex/app-server-client.js';
|
|
10
|
-
import { resolveOpenaiConfig, resolveCodexCliPath } from './baseagent.js';
|
|
10
|
+
import { resolveOpenaiConfig, resolveCodexCliPath, resolveCodexPowerShellShimPath, } from './baseagent.js';
|
|
11
11
|
import { logger } from '../utils/logger.js';
|
|
12
12
|
import { summarizeToolInputForAudit } from '../utils/tool-summary.js';
|
|
13
13
|
import { auditCodexApprovalDecision, auditPermissionLifecycle, auditToolPreflightDenial } from '../core/auth/authorization-audit.js';
|
|
@@ -212,10 +212,13 @@ function compactCodexProbeText(value, maxLength = 600) {
|
|
|
212
212
|
const text = value.replace(/\s+/gu, ' ').trim();
|
|
213
213
|
return text.length <= maxLength ? text : `${text.slice(0, maxLength - 3).trimEnd()}...`;
|
|
214
214
|
}
|
|
215
|
-
function logCodexProbeFailure(args, startedAt, error, timeoutMs) {
|
|
215
|
+
function logCodexProbeFailure(args, startedAt, error, timeoutMs, launch) {
|
|
216
216
|
const detail = error;
|
|
217
217
|
logger.warn(`[CodexProbe] CLI probe failed: ${JSON.stringify({
|
|
218
218
|
command: ['codex', ...args],
|
|
219
|
+
resolvedPath: launch?.resolvedPath ?? null,
|
|
220
|
+
launcherKind: launch?.launcherKind ?? null,
|
|
221
|
+
launcherPath: launch?.launcherPath ?? null,
|
|
219
222
|
path: detail?.path ?? null,
|
|
220
223
|
spawnargs: detail?.spawnargs ?? null,
|
|
221
224
|
elapsedMs: Date.now() - startedAt,
|
|
@@ -229,13 +232,13 @@ function logCodexProbeFailure(args, startedAt, error, timeoutMs) {
|
|
|
229
232
|
stderr: compactCodexProbeText(detail?.stderr),
|
|
230
233
|
})}`);
|
|
231
234
|
}
|
|
232
|
-
function probeCodexCli(args) {
|
|
233
|
-
return probeCliSync('codex', args, { onFailure: logCodexProbeFailure });
|
|
235
|
+
function probeCodexCli(args, executable) {
|
|
236
|
+
return probeCliSync('codex', args, { executable, onFailure: logCodexProbeFailure });
|
|
234
237
|
}
|
|
235
|
-
export function getCodexCliVersion() {
|
|
238
|
+
export function getCodexCliVersion(executable) {
|
|
236
239
|
const startedAt = Date.now();
|
|
237
240
|
try {
|
|
238
|
-
const output = probeCodexCli(['--version']);
|
|
241
|
+
const output = probeCodexCli(['--version'], executable);
|
|
239
242
|
const version = parseCodexCliVersion(output);
|
|
240
243
|
if (!version) {
|
|
241
244
|
logCodexProbeFailure(['--version'], startedAt, {
|
|
@@ -254,9 +257,15 @@ export function getCodexCliVersion() {
|
|
|
254
257
|
export function getCodexAppServerAvailability() {
|
|
255
258
|
const cliPath = resolveCodexCliPath();
|
|
256
259
|
if (!cliPath) {
|
|
257
|
-
|
|
260
|
+
const powershellShim = resolveCodexPowerShellShimPath();
|
|
261
|
+
return {
|
|
262
|
+
available: false,
|
|
263
|
+
reason: powershellShim
|
|
264
|
+
? '检测到 codex.ps1,但当前 Windows 启动路径要求 codex.exe/codex.cmd/codex.bat;请重新安装 @openai/codex 以恢复 npm shim。'
|
|
265
|
+
: '未检测到 Codex CLI。',
|
|
266
|
+
};
|
|
258
267
|
}
|
|
259
|
-
const version = getCodexCliVersion();
|
|
268
|
+
const version = getCodexCliVersion(cliPath);
|
|
260
269
|
if (!version) {
|
|
261
270
|
return { available: false, reason: '无法读取 Codex CLI 版本。' };
|
|
262
271
|
}
|
|
@@ -269,7 +278,7 @@ export function getCodexAppServerAvailability() {
|
|
|
269
278
|
};
|
|
270
279
|
}
|
|
271
280
|
try {
|
|
272
|
-
probeCodexCli(['app-server', '--help']);
|
|
281
|
+
probeCodexCli(['app-server', '--help'], cliPath);
|
|
273
282
|
return { available: true, version };
|
|
274
283
|
}
|
|
275
284
|
catch (error) {
|
|
@@ -284,10 +293,21 @@ export function isCodexAppServerAvailable() {
|
|
|
284
293
|
}
|
|
285
294
|
/** Daemon startup/hot reload use asynchronous probes; sync CLI callers share the cache. */
|
|
286
295
|
export async function getCodexAppServerAvailabilityAsync() {
|
|
296
|
+
const cliPath = resolveCodexCliPath();
|
|
287
297
|
const options = {
|
|
288
298
|
timeouts: [CODEX_CLI_PROBE_TIMEOUT_MS, CODEX_CLI_PROBE_RETRY_TIMEOUT_MS],
|
|
299
|
+
executable: cliPath ?? undefined,
|
|
289
300
|
onFailure: logCodexProbeFailure,
|
|
290
301
|
};
|
|
302
|
+
if (!cliPath) {
|
|
303
|
+
const powershellShim = resolveCodexPowerShellShimPath();
|
|
304
|
+
return {
|
|
305
|
+
available: false,
|
|
306
|
+
reason: powershellShim
|
|
307
|
+
? '检测到 codex.ps1,但当前 Windows 启动路径要求 codex.exe/codex.cmd/codex.bat;请重新安装 @openai/codex 以恢复 npm shim。'
|
|
308
|
+
: '未检测到 Codex CLI。',
|
|
309
|
+
};
|
|
310
|
+
}
|
|
291
311
|
let version;
|
|
292
312
|
try {
|
|
293
313
|
version = parseCodexCliVersion(await probeCli('codex', ['--version'], options)) ?? undefined;
|
|
@@ -348,6 +368,7 @@ export class CodexRunner {
|
|
|
348
368
|
/** Fallback authorization lifecycle ids for app-server requests without an RPC id. */
|
|
349
369
|
approvalLifecycleIds = new WeakMap();
|
|
350
370
|
resolvedConfig;
|
|
371
|
+
codexVersion;
|
|
351
372
|
pendingInterruptTtlMs = 30_000;
|
|
352
373
|
/** Fallback for direct runner callers that do not inject SessionManager. */
|
|
353
374
|
codexSessionFileAdapter = new CodexSessionFileAdapter();
|
|
@@ -389,6 +410,7 @@ export class CodexRunner {
|
|
|
389
410
|
if (this.resolvedConfig.effort)
|
|
390
411
|
this.effort = this.resolvedConfig.effort;
|
|
391
412
|
this.onSessionIdUpdate = callbacks.onSessionIdUpdate;
|
|
413
|
+
this.codexVersion = runtime?.codexVersion;
|
|
392
414
|
}
|
|
393
415
|
getAppServerClient(fullAccess = false) {
|
|
394
416
|
const existing = fullAccess ? this.fullAccessAppServerClient : this.appServerClient;
|
|
@@ -396,6 +418,7 @@ export class CodexRunner {
|
|
|
396
418
|
return existing;
|
|
397
419
|
const client = new CodexAppServerClient({
|
|
398
420
|
apiKey: this.resolvedConfig.apiKey,
|
|
421
|
+
codexVersion: this.codexVersion,
|
|
399
422
|
authType: this.resolvedConfig.authType,
|
|
400
423
|
baseUrl: this.resolvedConfig.baseUrl,
|
|
401
424
|
provider: this.resolvedConfig.provider,
|
|
@@ -3056,6 +3079,9 @@ export class CodexRunner {
|
|
|
3056
3079
|
}
|
|
3057
3080
|
return await denyInfrastructure('ec_command_not_canonical', canonicalEcApproval?.parseFailure
|
|
3058
3081
|
? `EC command approval denied because canonical argv parsing failed (${canonicalEcApproval.parseFailure.issue})`
|
|
3082
|
+
+ (canonicalEcApproval.parseFailure.dialect === 'powershell' && canonicalEcApproval.parseFailure.issue === 'invalid-quote'
|
|
3083
|
+
? '. PowerShell treats smart quotes as delimiters too; escape quotes for PowerShell or use --text-from-file for message text.'
|
|
3084
|
+
: '')
|
|
3059
3085
|
: 'EC command approval denied because no canonical argv could be derived');
|
|
3060
3086
|
}
|
|
3061
3087
|
try {
|
|
@@ -4680,7 +4706,10 @@ export class CodexRunner {
|
|
|
4680
4706
|
const text = typeof item.text === 'string' && item.text ? item.text : buffered;
|
|
4681
4707
|
if (text) {
|
|
4682
4708
|
state.lastAssistantUuid = item.id || state.turnId;
|
|
4683
|
-
yield {
|
|
4709
|
+
yield {
|
|
4710
|
+
type: 'text', text, assistantUuid: state.lastAssistantUuid,
|
|
4711
|
+
...(item.phase === 'commentary' || item.phase === 'final_answer' ? { phase: item.phase } : {}),
|
|
4712
|
+
};
|
|
4684
4713
|
}
|
|
4685
4714
|
if (item.id)
|
|
4686
4715
|
state.agentMessageDeltaText.delete(item.id);
|
|
@@ -5077,6 +5106,14 @@ export class CodexAgentPlugin {
|
|
|
5077
5106
|
},
|
|
5078
5107
|
},
|
|
5079
5108
|
};
|
|
5080
|
-
return {
|
|
5109
|
+
return {
|
|
5110
|
+
evolagentName: agent.name,
|
|
5111
|
+
baseagent: 'codex',
|
|
5112
|
+
agent: new CodexRunner(merged, callbacks, {
|
|
5113
|
+
agentAid: agent.config.aid,
|
|
5114
|
+
agentConfig: agent.config,
|
|
5115
|
+
codexVersion: availability.version,
|
|
5116
|
+
}),
|
|
5117
|
+
};
|
|
5081
5118
|
}
|
|
5082
5119
|
}
|
package/dist/aun/menu/client.js
CHANGED
|
@@ -67,6 +67,7 @@ export class ManagedMenuClient {
|
|
|
67
67
|
let timer;
|
|
68
68
|
try {
|
|
69
69
|
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
70
|
+
options.beforeSend?.();
|
|
70
71
|
const response = new Promise((resolve, reject) => {
|
|
71
72
|
this.pending.set(key, { resolve, reject });
|
|
72
73
|
timer = setTimeout(() => reject(new MenuClientError('TIMEOUT', 'Remote Menu response timed out')), timeout);
|
package/dist/channels/aun.js
CHANGED
|
@@ -715,8 +715,9 @@ export class AUNChannel {
|
|
|
715
715
|
* 统一的 RPC 调用包装:自动记录 OUT 发送、.ok 结果、.error 错误(含 trace + daemon.log 失败日志)。
|
|
716
716
|
* 所有 client.call() 都应通过此方法调用,保证 aun-trace 里每个 OUT 调用都有"发+收/错"成对记录。
|
|
717
717
|
*/
|
|
718
|
-
callClient(method, params, lane = 'normal', onStart) {
|
|
718
|
+
callClient(method, params, lane = 'normal', onStart, onPrepared) {
|
|
719
719
|
params = menuTransportParams(method, params);
|
|
720
|
+
onPrepared?.(params);
|
|
720
721
|
return this.withOutboundSendGate(method, () => (this.client.call(method, params).then(value => value)), lane, onStart);
|
|
721
722
|
}
|
|
722
723
|
withOutboundSendGate(method, run, lane = 'normal', onStart) {
|
|
@@ -784,7 +785,6 @@ export class AUNChannel {
|
|
|
784
785
|
});
|
|
785
786
|
}
|
|
786
787
|
async callAndTrace(method, params, opts) {
|
|
787
|
-
this.trace('OUT', method, params);
|
|
788
788
|
// 计时同时覆盖排队和 SDK 往返;callStartedAt 让日志能区分「本地队列堵塞」
|
|
789
789
|
// 与「网关慢」。两者对 /evolhelp 等命令的回复延迟都有直接影响。
|
|
790
790
|
const rpcStart = Date.now();
|
|
@@ -794,6 +794,11 @@ export class AUNChannel {
|
|
|
794
794
|
try {
|
|
795
795
|
const result = await this.callClient(method, params, opts?.lane ?? 'normal', () => {
|
|
796
796
|
callStartedAt = Date.now();
|
|
797
|
+
}, preparedParams => {
|
|
798
|
+
// Apply Menu compatibility exactly once, then log the same parameters
|
|
799
|
+
// passed to the SDK (TTL and device targeting may both be removed).
|
|
800
|
+
params = preparedParams;
|
|
801
|
+
this.trace('OUT', method, params);
|
|
797
802
|
});
|
|
798
803
|
const durationMs = Date.now() - rpcStart;
|
|
799
804
|
const rpcDurationMs = Date.now() - callStartedAt;
|
|
@@ -844,14 +849,17 @@ export class AUNChannel {
|
|
|
844
849
|
state.maxDurationMs = 0;
|
|
845
850
|
this.rpcWarningStates.set(key, state);
|
|
846
851
|
const summary = suppressed > 0 ? ` suppressed=${suppressed} max_duration=${maxDurationMs}ms` : '';
|
|
852
|
+
const menuTransport = method === 'message.send' && payloadType.startsWith('menu.')
|
|
853
|
+
? ` ttl=${params.ttl ?? 'default'} to_device_id=${JSON.stringify(params.to_device_id ?? null)}`
|
|
854
|
+
: '';
|
|
847
855
|
if (kind === 'failed') {
|
|
848
856
|
const name = error instanceof Error ? error.name : '';
|
|
849
857
|
const message = error instanceof Error ? error.message : String(error ?? '');
|
|
850
858
|
const errorLabel = `${name}${code ? `(${code})` : ''} ${message}`.trim();
|
|
851
|
-
logger.warn(`${this.logPrefix()} rpc ${method} failed after ${durationMs}ms: ${errorLabel} queue_wait=${queueWaitMs}ms rpc=${rpcDurationMs}ms payload=${payloadType}${summary}`);
|
|
859
|
+
logger.warn(`${this.logPrefix()} rpc ${method} failed after ${durationMs}ms: ${errorLabel} queue_wait=${queueWaitMs}ms rpc=${rpcDurationMs}ms payload=${payloadType}${menuTransport}${summary}`);
|
|
852
860
|
return;
|
|
853
861
|
}
|
|
854
|
-
logger.warn(`${this.logPrefix()} rpc ${method} SLOW: duration=${durationMs}ms queue_wait=${queueWaitMs}ms rpc=${rpcDurationMs}ms payload=${payloadType}${summary} (发送管线可能饱和或链路抖动)`);
|
|
862
|
+
logger.warn(`${this.logPrefix()} rpc ${method} SLOW: duration=${durationMs}ms queue_wait=${queueWaitMs}ms rpc=${rpcDurationMs}ms payload=${payloadType}${menuTransport}${summary} (发送管线可能饱和或链路抖动)`);
|
|
855
863
|
}
|
|
856
864
|
observerQueueDropCount = 0;
|
|
857
865
|
observerQueueDropLastWarnAt = 0;
|
|
@@ -4838,7 +4846,12 @@ export class AUNChannel {
|
|
|
4838
4846
|
}
|
|
4839
4847
|
// 从 context.metadata.source 读取 source,默认为 'daemon'
|
|
4840
4848
|
const source = context?.metadata?.source ?? 'daemon';
|
|
4841
|
-
|
|
4849
|
+
// Put the label in the visible body without requiring client title support.
|
|
4850
|
+
// Derive it from the durable context without mutating the stored text.
|
|
4851
|
+
const title = delivery.chatType === 'private' ? context?.title?.trim() : undefined;
|
|
4852
|
+
const wireText = title && finalText.split(/\r?\n/, 1)[0].trim() !== title
|
|
4853
|
+
? `${title}\n\n${finalText}` : finalText;
|
|
4854
|
+
const payload = withAunAttention({ type: 'text', text: wireText }, context?.attention);
|
|
4842
4855
|
if (delivery.chatType === 'group') {
|
|
4843
4856
|
const extracted = this.extractMentionEntriesFromText(finalText);
|
|
4844
4857
|
if (extracted.length > 0)
|
|
@@ -4863,7 +4876,7 @@ export class AUNChannel {
|
|
|
4863
4876
|
registerAunCausation(causationRef, this.config.aid, channelId, causation);
|
|
4864
4877
|
}
|
|
4865
4878
|
// 诊断日志:记录 payload 构造结果(含 task_id / thread_id / chatmode)
|
|
4866
|
-
logger.info(`${this.logPrefix()} deliverTextEntry: channelId=${channelId} thread_id=${payload.thread_id ?? 'none'} task_id=${payload.task_id ?? 'none'} chatmode=${payload.chatmode ?? 'none'} source=${source} textLen=${
|
|
4879
|
+
logger.info(`${this.logPrefix()} deliverTextEntry: channelId=${channelId} thread_id=${payload.thread_id ?? 'none'} task_id=${payload.task_id ?? 'none'} chatmode=${payload.chatmode ?? 'none'} source=${source} textLen=${wireText.length}`);
|
|
4867
4880
|
const isGroup = delivery.chatType === 'group';
|
|
4868
4881
|
const targetAid = channelId;
|
|
4869
4882
|
if (entry.deliveryReceipt) {
|
|
@@ -6239,6 +6252,8 @@ export class AUNChannelPlugin {
|
|
|
6239
6252
|
if (replyCtx) {
|
|
6240
6253
|
replyCtx = { ...replyCtx };
|
|
6241
6254
|
delete replyCtx.attention;
|
|
6255
|
+
// Assign titles per payload below, never inherit a final-reply title.
|
|
6256
|
+
delete replyCtx.title;
|
|
6242
6257
|
}
|
|
6243
6258
|
if (attention !== undefined)
|
|
6244
6259
|
replyCtx = { ...(replyCtx ?? {}), attention };
|
|
@@ -6283,8 +6298,9 @@ export class AUNChannelPlugin {
|
|
|
6283
6298
|
? { forkAnchor: payload.metadata.forkAnchor } : {}),
|
|
6284
6299
|
},
|
|
6285
6300
|
};
|
|
6286
|
-
if (payload.kind === 'result.text' && payload.isFinal)
|
|
6301
|
+
if (payload.kind === 'result.text' && payload.isFinal && delivery.chatType === 'private') {
|
|
6287
6302
|
sendCtx.title = '✅ 最终回复:';
|
|
6303
|
+
}
|
|
6288
6304
|
let result;
|
|
6289
6305
|
try {
|
|
6290
6306
|
result = await channel.sendMessage(channelId, payload.text, sendCtx);
|