evolcore 0.0.38 → 0.0.40
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 +64 -0
- package/README.md +31 -20
- package/bin/ec-safe-output.js +14 -2
- package/dist/agents/baseagent-availability.js +1 -0
- package/dist/agents/claude-runner.js +32 -46
- package/dist/agents/codex-runner.js +54 -30
- package/dist/agents/ecagent-runner.js +18 -7
- package/dist/agents/gemini-runner.js +1 -2
- package/dist/agents/runner-types.js +28 -6
- package/dist/aun/aid/agentmd.js +21 -0
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +23 -98
- package/dist/aun/aid/ownership-operation.js +35 -12
- package/dist/aun/group/invite-service.js +6 -0
- package/dist/aun/msg/p2p.js +8 -12
- package/dist/channels/aun.js +66 -48
- package/dist/channels/dingtalk.js +8 -2
- package/dist/channels/feishu.js +6 -1
- package/dist/channels/wecom.js +7 -3
- package/dist/cli/agent-create.js +30 -6
- package/dist/cli/agent.js +30 -37
- package/dist/cli/aid-bind-command.js +16 -2
- package/dist/cli/aun-commands.js +31 -23
- package/dist/cli/config.js +15 -18
- package/dist/cli/contact.js +9 -12
- package/dist/cli/ctl-command.js +3 -3
- package/dist/cli/daemon-commands.js +242 -17
- package/dist/cli/diag.js +7 -3
- package/dist/cli/fs-command.js +5 -4
- package/dist/cli/handoff-command.js +11 -11
- package/dist/cli/help.js +18 -0
- package/dist/cli/index.js +25 -13
- package/dist/cli/init-channel.js +2 -1
- package/dist/cli/memory-command.js +47 -27
- package/dist/cli/model.js +5 -4
- package/dist/cli/queue-command.js +3 -3
- package/dist/cli/response.js +5 -4
- package/dist/cli/restart-monitor.js +35 -13
- package/dist/cli/skill-command.js +13 -13
- package/dist/cli/task-command.js +3 -3
- package/dist/cli/task-context.js +1 -0
- package/dist/cli/thread-command.js +5 -3
- package/dist/cli/trigger-command.js +3 -3
- package/dist/cli/version.js +6 -2
- package/dist/config/config-field-policy.js +1 -0
- package/dist/contracts/ecweb-service-protocol.js +44 -0
- package/dist/core/agent-runtime.js +6 -0
- package/dist/core/auth/agent-delegation.js +7 -4
- package/dist/core/auth/auth-gateway.js +3 -1
- package/dist/core/auth/authorization-audit.js +5 -1
- package/dist/core/auth/debug-context.js +5 -1
- package/dist/core/auth/operation-catalog.js +17 -1
- package/dist/core/bootstrap-service.js +20 -12
- package/dist/core/command/cli-intent-parser.js +5 -2
- package/dist/core/command/command-handler.js +20 -5
- package/dist/core/command/menu-catalog.js +48 -12
- package/dist/core/command/menu-handler.js +74 -6
- package/dist/core/command/menu-protocol.js +20 -1
- package/dist/core/command/slash-gate.js +17 -3
- package/dist/core/command/slash-handler.js +90 -7
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/interaction-router.js +2 -1
- package/dist/core/ipc-registration.js +26 -7
- package/dist/core/memory/batch-meta.js +2 -0
- package/dist/core/memory/consolidation-context.js +42 -51
- package/dist/core/memory/consolidation-ops-records.js +39 -7
- package/dist/core/memory/consolidation-trigger.js +71 -64
- package/dist/core/memory/consolidation.js +226 -20
- package/dist/core/memory/memory-writer.js +160 -34
- package/dist/core/memory/relation-idle-monitor.js +287 -0
- package/dist/core/memory/relation-sweep.js +206 -0
- package/dist/core/message/aun-ipc-sender.js +5 -0
- package/dist/core/message/message-bridge.js +64 -55
- package/dist/core/message/message-log.js +17 -0
- package/dist/core/message/message-queue.js +6 -0
- package/dist/core/message/outbound.js +70 -0
- package/dist/core/message/peer-mode.js +7 -2
- package/dist/core/message/response-engine.js +341 -73
- package/dist/core/ownership/owner-resolver.js +465 -140
- package/dist/core/permission/ec-command-parser.js +19 -3
- package/dist/core/permission/protected-paths.js +51 -0
- package/dist/core/permission/tool-policy.js +7 -7
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/session/session-manager.js +25 -5
- package/dist/core/system-session/memory.js +3 -18
- package/dist/ecweb/basic-settings-service.js +709 -0
- package/dist/ecweb/providers-service.js +172 -0
- package/dist/index.js +92 -4
- package/dist/ipc.js +78 -11
- package/dist/stats/db.js +33 -0
- package/dist/stats/index.js +2 -2
- package/dist/stats/query.js +246 -0
- package/dist/stats/writer.js +41 -1
- package/dist/trigger/application-service.js +12 -0
- package/dist/trigger/authorization.js +2 -2
- package/dist/trigger/history.js +36 -0
- package/dist/trigger/scheduler.js +3 -0
- package/dist/utils/ecweb-supervisor.js +31 -10
- package/dist/utils/error-utils.js +8 -4
- package/dist/utils/evolcore-version.js +3 -2
- package/dist/utils/host-info.js +52 -0
- package/dist/utils/welcome.js +18 -24
- package/ecagent/dist/harness/agent-harness.js +4 -1
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/agent.md +1 -1
- package/kits/docs/evolcore/aid.md +58 -8
- package/kits/docs/evolcore/config.md +9 -7
- package/kits/docs/evolcore/memory-architecture.md +3 -4
- package/kits/docs/evolcore/memory-consolidation.md +28 -7
- package/kits/docs/evolcore/memory-tags.md +1 -1
- package/kits/docs/evolcore/memory.md +1 -1
- package/kits/docs/evolcore/menu-client.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +6 -0
- package/kits/docs/evolcore/msg.md +1 -1
- package/kits/eck_manifest.json +3 -3
- package/kits/rules/04-relation.md +3 -2
- package/kits/schemas/agent-config.schema.13.json +5 -1
- package/kits/templates/memory-consolidation/generalize.md +32 -4
- package/kits/templates/memory-consolidation/notes.md +2 -2
- package/kits/templates/memory-consolidation/promote.md +10 -2
- package/kits/templates/system-fragments/baseagent.md +5 -0
- package/kits/templates/system-fragments/memory.md +12 -3
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/{rules/07-memory-and-thread.md → templates/system-fragments/thread.md} +17 -80
- package/package.json +3 -3
|
@@ -42,7 +42,7 @@ import { isUnsupportedBaseagentConfigField } from '../../config/config-field-pol
|
|
|
42
42
|
import { splitConfigBatchGetArgv } from '../../cli/cli-argv.js';
|
|
43
43
|
import { chatmodeFieldForPeer, isPrivateChatmodeRoleLocked, resolveChatModeForField } from '../message/peer-mode.js';
|
|
44
44
|
import { PUBLIC_PERMISSION_MODES } from '../permission/mode.js';
|
|
45
|
-
import { resolveRuntimePermissionMode, resolveRuntimeStringField, validateRuntimeStringFieldOverride, } from '../role/runtime-policy.js';
|
|
45
|
+
import { isAgentFullAccessOwner, resolveRuntimePermissionMode, resolveRuntimeStringField, sessionFullAccessStatus, validateRuntimeStringFieldOverride, } from '../role/runtime-policy.js';
|
|
46
46
|
import { isManagementRole } from '../../config/builtin-roles.js';
|
|
47
47
|
import { SYSTEM_CONTROL_CHANNEL } from '../system-channels.js';
|
|
48
48
|
import { logger } from '../../utils/logger.js';
|
|
@@ -2149,6 +2149,21 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2149
2149
|
return menuResultFailure(error);
|
|
2150
2150
|
}
|
|
2151
2151
|
}
|
|
2152
|
+
if (cmdBase === '/session' && args?.view === 'fullaccess') {
|
|
2153
|
+
if (Object.keys(args).some(key => key !== 'view' && key !== 'context')) {
|
|
2154
|
+
return { error: 'session.fullaccess query only accepts args.view', code: 'INVALID_ARGUMENT' };
|
|
2155
|
+
}
|
|
2156
|
+
if (!session || !subject.selfAid)
|
|
2157
|
+
return { error: '当前没有可绑定的 EC 会话', code: 'NO_ACTIVE_SESSION' };
|
|
2158
|
+
if (session.chatType !== 'private')
|
|
2159
|
+
return { error: '/fa 仅支持私聊中的当前 EC 会话', code: 'NOT_SUPPORTED' };
|
|
2160
|
+
const principalId = subject.principalId;
|
|
2161
|
+
if (!principalId || !subject.isDaemonOwner || !isAgentFullAccessOwner(subject.selfAid, principalId)) {
|
|
2162
|
+
return { error: '/fa 需要同一身份同时具备 Agent Owner 和 daemon Owner 权限', code: 'FORBIDDEN' };
|
|
2163
|
+
}
|
|
2164
|
+
const status = sessionFullAccessStatus(session, principalId);
|
|
2165
|
+
return { data: { ...status, sessionId: session.id, scope: isTopicSession(session) ? 'session' : 'agent' } };
|
|
2166
|
+
}
|
|
2152
2167
|
const storageRequest = { type: 'menu.query', cmd, args };
|
|
2153
2168
|
if (isAgentStorageMenuRequest(storageRequest)) {
|
|
2154
2169
|
try {
|
|
@@ -2948,6 +2963,7 @@ export async function execMenuUpdate(cmd, value, channel, channelId, userId, ove
|
|
|
2948
2963
|
if (!cmdBase)
|
|
2949
2964
|
return { error: '缺少命令', code: 'MISSING_CMD' };
|
|
2950
2965
|
const isLoopUpdate = cmdBase === '/session' && args?.resource === 'loop';
|
|
2966
|
+
const isFullAccessUpdate = cmdBase === '/session' && args?.resource === 'fullaccess';
|
|
2951
2967
|
if (isLoopUpdate) {
|
|
2952
2968
|
if (typeof value !== 'boolean' || Object.keys(args ?? {}).some(key => key !== 'resource' && key !== 'idleSeconds' && key !== 'context')) {
|
|
2953
2969
|
return { error: 'session.loop requires a boolean value and only accepts resource / idleSeconds', code: 'INVALID_ARGUMENT' };
|
|
@@ -2959,9 +2975,13 @@ export async function execMenuUpdate(cmd, value, channel, channelId, userId, ove
|
|
|
2959
2975
|
return { error: `idleSeconds 必须是 ${MIN_SESSION_LOOP_SECONDS}-${MAX_SESSION_LOOP_SECONDS} 的整数`, code: 'INVALID_ARGUMENT' };
|
|
2960
2976
|
}
|
|
2961
2977
|
}
|
|
2962
|
-
else if (typeof value !== 'string') {
|
|
2978
|
+
else if (!isFullAccessUpdate && typeof value !== 'string') {
|
|
2963
2979
|
return { error: 'value 必须是字符串', code: 'INVALID_ARGUMENT' };
|
|
2964
2980
|
}
|
|
2981
|
+
if (isFullAccessUpdate && (typeof value !== 'boolean'
|
|
2982
|
+
|| Object.keys(args ?? {}).some(key => key !== 'resource' && key !== 'context'))) {
|
|
2983
|
+
return { error: 'session.fullaccess requires a boolean value and only accepts resource', code: 'INVALID_ARGUMENT' };
|
|
2984
|
+
}
|
|
2965
2985
|
if (cmdBase === '/perm') {
|
|
2966
2986
|
return { error: 'permissionMode 只能通过角色策略编辑器修改', code: 'ROLE_POLICY_MANAGED' };
|
|
2967
2987
|
}
|
|
@@ -3020,6 +3040,53 @@ export async function execMenuUpdate(cmd, value, channel, channelId, userId, ove
|
|
|
3020
3040
|
return menuResultFailure(error);
|
|
3021
3041
|
}
|
|
3022
3042
|
}
|
|
3043
|
+
if (isFullAccessUpdate) {
|
|
3044
|
+
if (!session || !subject.selfAid)
|
|
3045
|
+
return { error: '当前没有可绑定的 EC 会话', code: 'NO_ACTIVE_SESSION' };
|
|
3046
|
+
const route = { channel, channelId, selfAid: subject.selfAid, threadId: transportReplyContext?.threadId };
|
|
3047
|
+
let target;
|
|
3048
|
+
try {
|
|
3049
|
+
target = await resolveCurrentSessionLoopTarget(this.sessionManager, route);
|
|
3050
|
+
if (target.session.id !== session.id)
|
|
3051
|
+
return { error: '当前会话已发生变化,请重新查询', code: 'CONFLICT' };
|
|
3052
|
+
target = await refreshSessionLoopTarget(this.sessionManager, route, target);
|
|
3053
|
+
session = target.session;
|
|
3054
|
+
}
|
|
3055
|
+
catch (error) {
|
|
3056
|
+
return menuResultFailure(error);
|
|
3057
|
+
}
|
|
3058
|
+
const principalId = subject.principalId;
|
|
3059
|
+
if (session.chatType !== 'private' || !principalId || !subject.isDaemonOwner
|
|
3060
|
+
|| !isAgentFullAccessOwner(subject.selfAid, principalId)) {
|
|
3061
|
+
return { error: '/fa 需要私聊中同一身份同时具备 Agent Owner 和 daemon Owner 权限', code: 'FORBIDDEN' };
|
|
3062
|
+
}
|
|
3063
|
+
try {
|
|
3064
|
+
if (isTopicSession(session)) {
|
|
3065
|
+
this.sessionManager.updateSessionFullAccess(session.id, { enabled: value, authorizedBy: principalId });
|
|
3066
|
+
}
|
|
3067
|
+
else {
|
|
3068
|
+
const config = cfgRead(ConfigTarget.Agent, { self: subject.selfAid }, { cache: false });
|
|
3069
|
+
if (!config)
|
|
3070
|
+
return { error: '找不到当前 Agent 配置', code: 'NOT_FOUND' };
|
|
3071
|
+
config.fullaccess = { enabled: value };
|
|
3072
|
+
cfgWrite(ConfigTarget.Agent, config, { self: subject.selfAid });
|
|
3073
|
+
}
|
|
3074
|
+
auditFullAccessEvent({
|
|
3075
|
+
event: value ? 'fullaccess.session-policy.configured' : 'fullaccess.session-policy.deescalated',
|
|
3076
|
+
source: 'session-policy',
|
|
3077
|
+
actorId: principalId,
|
|
3078
|
+
processRole: 'daemon-owner',
|
|
3079
|
+
agentAid: subject.selfAid,
|
|
3080
|
+
sessionId: session.id,
|
|
3081
|
+
authorizedBy: principalId,
|
|
3082
|
+
reason: isTopicSession(session) ? 'topic session fullaccess updated via Menu' : 'Agent main-session fullaccess updated via Menu',
|
|
3083
|
+
});
|
|
3084
|
+
return { data: { enabled: value, sessionId: session.id, scope: isTopicSession(session) ? 'session' : 'agent' } };
|
|
3085
|
+
}
|
|
3086
|
+
catch (error) {
|
|
3087
|
+
return menuResultFailure(error);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3023
3090
|
const arg = value.trim();
|
|
3024
3091
|
if (!arg)
|
|
3025
3092
|
return { error: '缺少 value 参数', code: 'MISSING_VALUE' };
|
|
@@ -4325,6 +4392,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
4325
4392
|
sessionId: sessionKey,
|
|
4326
4393
|
reason: 'stop',
|
|
4327
4394
|
agentName: this.agentRegistry?.resolveByChannel(channel)?.name ?? '<unknown>',
|
|
4395
|
+
agentAid: session.selfAID,
|
|
4328
4396
|
});
|
|
4329
4397
|
await this.processor.interruptSession(sessionKey, 'stop');
|
|
4330
4398
|
return { data: { action: 'stop', success: true } };
|
|
@@ -4691,8 +4759,8 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
4691
4759
|
}
|
|
4692
4760
|
catch (error) {
|
|
4693
4761
|
const failure = ownershipFailure(error);
|
|
4694
|
-
const code = ['INVALID_ARGUMENT', 'INVALID_AID', 'INVALID_OWNER'].includes(failure.code) ? 'INVALID_ARGUMENT'
|
|
4695
|
-
: ['SUBJECT_REQUIRED', 'SUBJECT_UNAVAILABLE'].includes(failure.code) ? 'NOT_FOUND'
|
|
4762
|
+
const code = ['INVALID_ARGUMENT', 'INVALID_AID', 'INVALID_OWNER', 'INVALID_OPERATION'].includes(failure.code) ? 'INVALID_ARGUMENT'
|
|
4763
|
+
: ['SUBJECT_REQUIRED', 'SUBJECT_UNAVAILABLE', 'REQUEST_NOT_FOUND', 'not_found'].includes(failure.code) ? 'NOT_FOUND'
|
|
4696
4764
|
: ['OWNER_ALREADY_BOUND', 'BIND_CONFLICT', 'BIND_UNCERTAIN', 'CONSENSUS_REQUIRED', 'CLIENT_REPLACED', 'conflict', 'owner_locked'].includes(failure.code)
|
|
4697
4765
|
? 'CONFLICT' : 'INTERNAL_ERROR';
|
|
4698
4766
|
rawExecution = { error: failure.error, code, data: failure };
|
|
@@ -5156,7 +5224,7 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
5156
5224
|
}
|
|
5157
5225
|
/** ECWeb 专用入口:只信任 IPC 信封中的服务端认证上下文,不信任 Menu payload 自报身份。 */
|
|
5158
5226
|
export async function execMenuForEcweb(payload, trusted) {
|
|
5159
|
-
await refreshOwnershipForAuthorization(undefined, { maxAgeMs: OWNERSHIP_CACHE_MAX_AGE_MS });
|
|
5227
|
+
await refreshOwnershipForAuthorization(undefined, { maxAgeMs: OWNERSHIP_CACHE_MAX_AGE_MS, allowTransient: true });
|
|
5160
5228
|
const id = payload?.id ?? '';
|
|
5161
5229
|
const name = payload?.name;
|
|
5162
5230
|
const validationError = validateMenuRequest(payload ?? {});
|
|
@@ -5200,7 +5268,7 @@ export async function execMenuForEcweb(payload, trusted) {
|
|
|
5200
5268
|
* process authorization path. The authenticated envelope peerId remains the
|
|
5201
5269
|
* requester; token mode maps to a configured owner as its management actor. */
|
|
5202
5270
|
export async function execMenuForControl(payload, peerId, auth = {}) {
|
|
5203
|
-
await refreshOwnershipForAuthorization(undefined, { maxAgeMs: OWNERSHIP_CACHE_MAX_AGE_MS });
|
|
5271
|
+
await refreshOwnershipForAuthorization(undefined, { maxAgeMs: OWNERSHIP_CACHE_MAX_AGE_MS, allowTransient: true });
|
|
5204
5272
|
const id = payload?.id ?? '';
|
|
5205
5273
|
const name = payload?.name;
|
|
5206
5274
|
const validationError = validateMenuRequest(payload ?? {});
|
|
@@ -367,14 +367,33 @@ export function validateMenuRequest(request) {
|
|
|
367
367
|
return { code: 'INVALID_ARGUMENT', message: 'idleSeconds is not allowed when session.loop is disabled' };
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
|
-
else if (type === 'menu.update'
|
|
370
|
+
else if (type === 'menu.update'
|
|
371
|
+
&& !((request.name === 'session' || request.cmd === '/session')
|
|
372
|
+
&& request.args?.resource === 'fullaccess')
|
|
373
|
+
&& (typeof request.value !== 'string' || request.value.length === 0)) {
|
|
371
374
|
return { code: 'INVALID_ARGUMENT', message: 'Menu request value is required' };
|
|
372
375
|
}
|
|
376
|
+
const isSessionFullAccessUpdate = type === 'menu.update'
|
|
377
|
+
&& (request.name === 'session' || request.cmd === '/session')
|
|
378
|
+
&& request.args?.resource === 'fullaccess';
|
|
379
|
+
if (isSessionFullAccessUpdate) {
|
|
380
|
+
if (typeof request.value !== 'boolean')
|
|
381
|
+
return { code: 'INVALID_ARGUMENT', message: 'session.fullaccess value must be a boolean' };
|
|
382
|
+
const args = request.args;
|
|
383
|
+
const unknown = Object.keys(args ?? {}).find(key => !['resource', 'context'].includes(key));
|
|
384
|
+
if (unknown)
|
|
385
|
+
return { code: 'INVALID_ARGUMENT', message: 'session.fullaccess update does not accept args.' + unknown };
|
|
386
|
+
}
|
|
373
387
|
if (type === 'menu.query' && (request.name === 'session' || request.cmd === '/session')
|
|
374
388
|
&& request.args?.view === 'loop'
|
|
375
389
|
&& Object.keys(request.args).some(key => key !== 'view' && key !== 'context')) {
|
|
376
390
|
return { code: 'INVALID_ARGUMENT', message: 'session.loop query only accepts args.view' };
|
|
377
391
|
}
|
|
392
|
+
if (type === 'menu.query' && (request.name === 'session' || request.cmd === '/session')
|
|
393
|
+
&& request.args?.view === 'fullaccess'
|
|
394
|
+
&& Object.keys(request.args).some(key => key !== 'view' && key !== 'context')) {
|
|
395
|
+
return { code: 'INVALID_ARGUMENT', message: 'session.fullaccess query only accepts args.view' };
|
|
396
|
+
}
|
|
378
397
|
if (type === 'menu.action' && (typeof request.action !== 'string' || request.action.trim().length === 0)) {
|
|
379
398
|
return { code: 'INVALID_ARGUMENT', message: 'Menu request action is required' };
|
|
380
399
|
}
|
|
@@ -43,7 +43,7 @@ export function probeSessionActivity(evidence, probes) {
|
|
|
43
43
|
return evaluateSessionActivity(collected);
|
|
44
44
|
}
|
|
45
45
|
// 支持的命令列表
|
|
46
|
-
const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mention', '/loop', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory', '/skill', '/thread'];
|
|
46
|
+
const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mention', '/loop', '/fa', '/fullaccess', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory', '/skill', '/thread'];
|
|
47
47
|
const deprecatedCommands = ['/clear'];
|
|
48
48
|
commands.push('/diag');
|
|
49
49
|
const exactBoundaryCommands = new Set(['/pause', '/resume', '/stop', '/pair', '/diag']);
|
|
@@ -55,7 +55,14 @@ export function parseFullAccessCommand(content) {
|
|
|
55
55
|
return {
|
|
56
56
|
matched: true,
|
|
57
57
|
command: match[1],
|
|
58
|
-
|
|
58
|
+
action: match[2].trim() === ''
|
|
59
|
+
? 'status'
|
|
60
|
+
: match[2].trim() === 'on'
|
|
61
|
+
? 'on'
|
|
62
|
+
: match[2].trim() === 'off'
|
|
63
|
+
? 'off'
|
|
64
|
+
: 'invalid',
|
|
65
|
+
raw: match[2].trim(),
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
68
|
// 命令别名映射
|
|
@@ -78,6 +85,13 @@ export function guardGroupSlashCommand(content, chatType) {
|
|
|
78
85
|
return undefined;
|
|
79
86
|
const [inputCommand, ...args] = content.trim().split(/\s+/);
|
|
80
87
|
const command = aliases[inputCommand] ?? inputCommand;
|
|
88
|
+
if (command === '/fa' || command === '/fullaccess') {
|
|
89
|
+
return {
|
|
90
|
+
kind: 'command.error',
|
|
91
|
+
text: '❌ 群聊中不支持 /fa,请在私聊会话操作',
|
|
92
|
+
reason: 'GROUP_COMMAND_UNSUPPORTED',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
81
95
|
if (GROUP_READ_ONLY_COMMANDS.has(command)) {
|
|
82
96
|
if (!args.length || (command === '/model' && args.length === 1 && ['current', 'list', 'check'].includes(args[0]))) {
|
|
83
97
|
return undefined;
|
|
@@ -97,7 +111,7 @@ export function guardGroupSlashCommand(content, chatType) {
|
|
|
97
111
|
};
|
|
98
112
|
}
|
|
99
113
|
// 命令快速路径前缀(所有命令都不进入消息队列)
|
|
100
|
-
const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mention', '/loop', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory', '/skill', '/thread'];
|
|
114
|
+
const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mention', '/loop', '/fa', '/fullaccess', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory', '/skill', '/thread'];
|
|
101
115
|
quickCommandPrefixes.push('/diag');
|
|
102
116
|
/**
|
|
103
117
|
* 计算两个字符串的 Levenshtein 距离(编辑距离)
|
|
@@ -10,8 +10,9 @@ import crypto from 'crypto';
|
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import fs from 'fs';
|
|
12
12
|
import { ensureFreshPackageVersionInfo, refreshManagedPackageVersions } from '../../utils/package-version-info.js';
|
|
13
|
+
import { loadDaemonConfig } from '../../config-store.js';
|
|
13
14
|
import { remoteAccessService } from '../auth/remote-access-store.js';
|
|
14
|
-
import { read as cfgRead, resolveEffective, routeFieldPath, write as cfgWrite, } from '../../config/config-manager.js';
|
|
15
|
+
import { read as cfgRead, resolveEffective, routeFieldPath, write as cfgWrite, ConfigTarget, } from '../../config/config-manager.js';
|
|
15
16
|
import { execAgentAction } from './agent-control.js';
|
|
16
17
|
import { handleMemorySlash, memoryHelpEntries } from './memory-slash.js';
|
|
17
18
|
import { handleSkillSlash, skillHelpEntries } from './skill-slash.js';
|
|
@@ -21,11 +22,12 @@ import { getDaemonOwners, ownerResolver, refreshOwnershipForAuthorization, OWNER
|
|
|
21
22
|
import { authorizationNextStep, formatAuthorizationDenial } from '../auth/authorization-denial.js';
|
|
22
23
|
import { resolvePermissionMode, writeScope } from '../model/config-scope.js';
|
|
23
24
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
25
|
+
import { auditFullAccessEvent } from '../auth/authorization-audit.js';
|
|
24
26
|
import { isMainSession, isTopicSession, isTopicThreadId, sessionTopicThreadId } from '../thread/topic-id.js';
|
|
25
27
|
import { modelMatches, getCatalog, assertCatalogSelectable, resolveCatalogModel, CONFIGURABLE_EFFORTS, configurableEfforts } from '../model/model-catalog.js';
|
|
26
28
|
import { formatModelCheck, runModelCheck } from '../model/model-diagnostics.js';
|
|
27
29
|
import { constrainResolvedModelForRole, filterModelsForRole, validateModelSelectionForRole } from '../model/model-permission.js';
|
|
28
|
-
import { resolveRuntimeStringField } from '../role/runtime-policy.js';
|
|
30
|
+
import { isAgentFullAccessOwner, resolveRuntimeStringField, sessionFullAccessStatus, } from '../role/runtime-policy.js';
|
|
29
31
|
import { displaySessionTitle } from '../session/session-title.js';
|
|
30
32
|
import { chatmodeFieldForPeer, isPrivateChatmodeRoleLocked, resolveChatModeForField } from '../message/peer-mode.js';
|
|
31
33
|
import { normalizePermissionMode as normalizePermissionModeContract, PUBLIC_PERMISSION_MODES } from '../permission/mode.js';
|
|
@@ -33,7 +35,7 @@ import { isManagementRole } from '../../config/builtin-roles.js';
|
|
|
33
35
|
import { isSystemControlChannel } from '../system-channels.js';
|
|
34
36
|
import { launchMonitorAndConfirm, resolveMonitorLaunch, cleanupMonitorStage, isProcessRunning } from '../../utils/cross-platform.js';
|
|
35
37
|
import { scanInstances } from '../../utils/instance-registry.js';
|
|
36
|
-
import { guardIdleCommand, guardGroupSlashCommand, guardKnownCommand, guardRoleCommand, guardThreadCommand, isRecognizedSlashCommand, normalizeSlashContent, probeSessionActivity, } from './slash-gate.js';
|
|
38
|
+
import { guardIdleCommand, guardGroupSlashCommand, guardKnownCommand, guardRoleCommand, guardThreadCommand, isRecognizedSlashCommand, normalizeSlashContent, parseFullAccessCommand, probeSessionActivity, } from './slash-gate.js';
|
|
37
39
|
import { MAX_AUN_ATTACHMENT_SIZE } from '../../aun/msg/upload.js';
|
|
38
40
|
import { DEFAULT_SESSION_LOOP_SECONDS, MAX_SESSION_LOOP_SECONDS, MIN_SESSION_LOOP_SECONDS, refreshSessionLoopTarget, resolveCurrentSessionLoopTarget, sessionLoopPayload, validateIdleSeconds, writeSessionLoopConfig, } from '../session/session-idle-monitor.js';
|
|
39
41
|
const allEfforts = CONFIGURABLE_EFFORTS;
|
|
@@ -400,6 +402,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
400
402
|
const narrowedChatType = chatType === 'group' ? 'group' : chatType === 'private' ? 'private' : undefined;
|
|
401
403
|
await refreshOwnershipForAuthorization(selfAID ?? this.agentRegistry?.resolveByChannel(channel)?.aid ?? this.resolveSelfAID(channel), {
|
|
402
404
|
maxAgeMs: OWNERSHIP_CACHE_MAX_AGE_MS,
|
|
405
|
+
allowTransient: true,
|
|
403
406
|
});
|
|
404
407
|
const identityConversationId = narrowedChatType === 'group' ? channelId : userId;
|
|
405
408
|
const resolvedIdentity = overrideIdentity ?? this.sessionManager.resolveIdentity(channel, userId, narrowedChatType, identityConversationId);
|
|
@@ -523,6 +526,10 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
523
526
|
|| normalizedContent === '/reload'
|
|
524
527
|
|| normalizedContent.startsWith('/reload ')
|
|
525
528
|
|| normalizedContent === '/pair'
|
|
529
|
+
|| normalizedContent === '/fa'
|
|
530
|
+
|| normalizedContent === '/fullaccess'
|
|
531
|
+
|| normalizedContent.startsWith('/fa ')
|
|
532
|
+
|| normalizedContent.startsWith('/fullaccess ')
|
|
526
533
|
|| /^\/diag(?:\s|$)/.test(normalizedContent);
|
|
527
534
|
const roleGuard = guardRoleCommand(normalizedContent, activeChatType, isAdmin || (isDaemonOwner && isProcessLevelSlash));
|
|
528
535
|
if (roleGuard)
|
|
@@ -622,6 +629,71 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
622
629
|
return { kind: 'command.error', text: `❌ ${error instanceof Error ? error.message : String(error)}` };
|
|
623
630
|
}
|
|
624
631
|
}
|
|
632
|
+
const fullAccessControl = parseFullAccessCommand(normalizedContent);
|
|
633
|
+
if (fullAccessControl.matched) {
|
|
634
|
+
if (activeChatType === 'group' || source === 'card-trigger') {
|
|
635
|
+
return { kind: 'command.error', text: '❌ /fa 仅支持私聊中的当前 EC 会话' };
|
|
636
|
+
}
|
|
637
|
+
const commandSession = await getExistingSessionForCommand();
|
|
638
|
+
const agentAid = authSubject.selfAid ?? selfAID;
|
|
639
|
+
const principalId = authSubject.principalId;
|
|
640
|
+
if (!commandSession || !agentAid) {
|
|
641
|
+
return { kind: 'command.error', text: '❌ 当前没有可绑定的 EC 会话' };
|
|
642
|
+
}
|
|
643
|
+
if (this.messageQueue.isProcessing(commandSession.id) || this.messageQueue.getQueueLength(commandSession.id) > 0) {
|
|
644
|
+
return { kind: 'command.error', text: '❌ 当前会话有任务执行中,结束后再修改 fullaccess' };
|
|
645
|
+
}
|
|
646
|
+
if (!principalId || !authSubject.isDaemonOwner || !isAgentFullAccessOwner(agentAid, principalId)) {
|
|
647
|
+
return { kind: 'command.error', text: '❌ /fa 需要同一身份同时具备 Agent Owner 和 daemon Owner 权限' };
|
|
648
|
+
}
|
|
649
|
+
if (fullAccessControl.action === 'status') {
|
|
650
|
+
const status = sessionFullAccessStatus(commandSession, principalId);
|
|
651
|
+
const scope = isTopicSession(commandSession) ? 'session' : 'agent';
|
|
652
|
+
return {
|
|
653
|
+
kind: 'command.result',
|
|
654
|
+
text: '当前 fullaccess(' + scope + ',session=' + commandSession.id + '):'
|
|
655
|
+
+ (status.effective ? '开启' : '关闭'),
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
const enabled = fullAccessControl.action === 'on';
|
|
659
|
+
try {
|
|
660
|
+
if (isTopicSession(commandSession)) {
|
|
661
|
+
const latest = await this.sessionManager.getThreadSession(channel, channelId, threadId);
|
|
662
|
+
if (!latest || latest.id !== commandSession.id || !isTopicSession(latest)) {
|
|
663
|
+
return { kind: 'command.error', text: '❌ 当前话题已发生变化,请重新执行 /fa' };
|
|
664
|
+
}
|
|
665
|
+
this.sessionManager.updateSessionFullAccess(latest.id, { enabled, authorizedBy: principalId });
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
const latest = await this.sessionManager.getActiveSession(channel, channelId);
|
|
669
|
+
if (!latest || latest.id !== commandSession.id || !isMainSession(latest)) {
|
|
670
|
+
return { kind: 'command.error', text: '❌ 当前主会话已发生变化,请重新执行 /fa' };
|
|
671
|
+
}
|
|
672
|
+
const config = cfgRead(ConfigTarget.Agent, { self: agentAid }, { cache: false });
|
|
673
|
+
if (!config)
|
|
674
|
+
return { kind: 'command.error', text: '❌ 找不到当前 Agent 配置' };
|
|
675
|
+
config.fullaccess = { enabled };
|
|
676
|
+
cfgWrite(ConfigTarget.Agent, config, { self: agentAid });
|
|
677
|
+
}
|
|
678
|
+
auditFullAccessEvent({
|
|
679
|
+
event: enabled ? 'fullaccess.session-policy.configured' : 'fullaccess.session-policy.deescalated',
|
|
680
|
+
source: 'session-policy',
|
|
681
|
+
actorId: principalId,
|
|
682
|
+
processRole: 'daemon-owner',
|
|
683
|
+
agentAid,
|
|
684
|
+
sessionId: commandSession.id,
|
|
685
|
+
authorizedBy: principalId,
|
|
686
|
+
reason: isTopicSession(commandSession) ? 'topic session fullaccess updated' : 'Agent main-session fullaccess updated',
|
|
687
|
+
});
|
|
688
|
+
return {
|
|
689
|
+
kind: 'command.result',
|
|
690
|
+
text: '✅ 当前 EC 会话 fullaccess 已' + (enabled ? '开启' : '关闭'),
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
return { kind: 'command.error', text: '❌ ' + (error instanceof Error ? error.message : String(error)) };
|
|
695
|
+
}
|
|
696
|
+
}
|
|
625
697
|
const interruptPausedSessionBeforeReplacement = async (commandSession) => {
|
|
626
698
|
if (commandSession && (this.processor?.isPauseRequested?.(commandSession.id) ?? false)) {
|
|
627
699
|
this.eventBus.publish({
|
|
@@ -629,6 +701,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
629
701
|
sessionId: commandSession.id,
|
|
630
702
|
reason: 'stop',
|
|
631
703
|
agentName: this.agentRegistry?.resolveByChannel(channel)?.name ?? '<unknown>',
|
|
704
|
+
agentAid: commandSession.selfAID,
|
|
632
705
|
});
|
|
633
706
|
await this.processor.interruptSession(commandSession.id, 'stop');
|
|
634
707
|
this.processor?.clearPauseSession?.(commandSession.id);
|
|
@@ -775,7 +848,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
775
848
|
const appendProcessCommands = (lines) => {
|
|
776
849
|
if (!isDaemonOwner)
|
|
777
850
|
return;
|
|
778
|
-
lines.push('', '🛠️ 进程级运维:', ' /restart - 重启服务', ' /upgrade - 检查版本更新', ' /reload [aid] - 热重载 Agent 配置', ' /fa
|
|
851
|
+
lines.push('', '🛠️ 进程级运维:', ' /restart - 重启服务', ' /upgrade - 检查版本更新', ' /reload [aid] - 热重载 Agent 配置', ' /fa [on|off] - 查看或切换当前 EC 会话 fullaccess', ' /pair - 获取远程控制配对码', ' /diag <问题描述> - 邀请或追加远程诊断;/diag stop 撤销授权');
|
|
779
852
|
};
|
|
780
853
|
if (!isAdmin && activeChatType === 'group') {
|
|
781
854
|
const lines = [
|
|
@@ -907,7 +980,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
907
980
|
...(isDaemonOwner ? [
|
|
908
981
|
' /restart - 重启服务',
|
|
909
982
|
' /reload [aid] - 热重载 Agent 配置',
|
|
910
|
-
' /fa
|
|
983
|
+
' /fa [on|off] - 查看或切换当前 EC 会话 fullaccess',
|
|
911
984
|
' /pair - 获取远程控制配对码',
|
|
912
985
|
] : []),
|
|
913
986
|
...(!isDaemonOwner && isAdmin ? [
|
|
@@ -1067,7 +1140,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1067
1140
|
cmds.push({ command: '/observable', args: '[true|false]', description: '查看或切换观察者模式', category: '运维', roles: ['owner'] });
|
|
1068
1141
|
}
|
|
1069
1142
|
if (isDaemonOwner) {
|
|
1070
|
-
cmds.push({ command: '/fa', aliases: ['/fullaccess'], args: '
|
|
1143
|
+
cmds.push({ command: '/fa', aliases: ['/fullaccess'], args: '[on|off]', description: '查看或切换当前 EC 会话 fullaccess', category: '权限管理', roles: ['daemon-owner'] });
|
|
1071
1144
|
cmds.push({ command: '/restart', description: '重启服务', category: '运维', roles: ['daemon-owner'] });
|
|
1072
1145
|
cmds.push({ command: '/upgrade', description: '检查版本更新', category: '运维', roles: ['daemon-owner'] });
|
|
1073
1146
|
cmds.push({ command: '/reload', args: '[aid]', description: '热重载 Agent 配置', category: '运维', roles: ['daemon-owner'] });
|
|
@@ -2475,6 +2548,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2475
2548
|
sessionId: sessionKey,
|
|
2476
2549
|
reason: 'stop',
|
|
2477
2550
|
agentName: this.agentRegistry?.resolveByChannel(channel)?.name ?? '<unknown>',
|
|
2551
|
+
agentAid: stopSession.selfAID,
|
|
2478
2552
|
});
|
|
2479
2553
|
await this.processor.interruptSession(sessionKey, 'stop');
|
|
2480
2554
|
return { kind: 'command.result', text: '✓ 已发送中断信号,任务将尽快停止' };
|
|
@@ -3214,7 +3288,16 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3214
3288
|
logger.warn(`[System] Refusing restart without a valid explicit delivery route: channel=${channel} channelId=${channelId}`);
|
|
3215
3289
|
return false;
|
|
3216
3290
|
}
|
|
3291
|
+
let autoUpgrade = true;
|
|
3217
3292
|
if (!suppressRealRestart) {
|
|
3293
|
+
try {
|
|
3294
|
+
autoUpgrade = loadDaemonConfig().upgrade?.autoOnStart !== false;
|
|
3295
|
+
}
|
|
3296
|
+
catch {
|
|
3297
|
+
autoUpgrade = false;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
if (!suppressRealRestart && autoUpgrade) {
|
|
3218
3301
|
await ensureFreshPackageVersionInfo(undefined, {
|
|
3219
3302
|
source: 'slash-restart',
|
|
3220
3303
|
log: message => logger.info(`[System] ${message}`),
|
|
@@ -3251,7 +3334,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3251
3334
|
cleanupMonitorStage(monitorEntry.stageDir);
|
|
3252
3335
|
return { code: 'RESTART_PENDING_CONFIRMATION', reason: '已有重启请求正在处理', requestId: restartInfo.requestId };
|
|
3253
3336
|
}
|
|
3254
|
-
const confirmation = await launchMonitorAndConfirm([...monitorEntry.args, 'restart-monitor'], { EVOLCORE_HOME: resolvePaths().root, ...monitorEntry.env, [RESTART_REQUEST_ID_ENV]: restartInfo.requestId }, pid => scanInstances().restartMonitors.some(m => m.alive && m.record.pid === pid
|
|
3337
|
+
const confirmation = await launchMonitorAndConfirm([...monitorEntry.args, 'restart-monitor', autoUpgrade ? '--apply-package-upgrades' : '--skip-package-upgrades'], { EVOLCORE_HOME: resolvePaths().root, ...monitorEntry.env, [RESTART_REQUEST_ID_ENV]: restartInfo.requestId }, pid => scanInstances().restartMonitors.some(m => m.alive && m.record.pid === pid
|
|
3255
3338
|
&& m.record.requestId === restartInfo.requestId && m.record.phase === 'accepted'), pid => scanInstances().restartMonitors.some(m => m.alive && m.record.pid !== pid
|
|
3256
3339
|
&& m.record.requestId === restartInfo.requestId && m.record.phase === 'accepted'), {
|
|
3257
3340
|
requestId: restartInfo.requestId,
|
|
@@ -318,6 +318,7 @@ const CATALOG = [
|
|
|
318
318
|
{ path: 'durationMs', type: 'number', optional: true },
|
|
319
319
|
{ path: 'terminalReason', type: 'string', optional: true },
|
|
320
320
|
{ path: 'agentName', type: 'string', optional: true },
|
|
321
|
+
{ path: 'agentAid', type: 'string', optional: true },
|
|
321
322
|
{ path: 'numTurns', type: 'number', optional: true },
|
|
322
323
|
{ path: 'encrypted', type: 'boolean', optional: true },
|
|
323
324
|
{ path: 'timestamp', type: 'number', optional: true },
|
|
@@ -354,6 +355,7 @@ const CATALOG = [
|
|
|
354
355
|
{ path: 'generation', type: 'number', optional: true },
|
|
355
356
|
{ path: 'reason', type: 'string', optional: true },
|
|
356
357
|
{ path: 'agentName', type: 'string', optional: true },
|
|
358
|
+
{ path: 'agentAid', type: 'string', optional: true },
|
|
357
359
|
{ path: 'encrypted', type: 'boolean', optional: true },
|
|
358
360
|
],
|
|
359
361
|
},
|
|
@@ -290,7 +290,8 @@ export function renderActionAsText(req) {
|
|
|
290
290
|
lines.push('', '回复:');
|
|
291
291
|
for (const btn of action.buttons) {
|
|
292
292
|
const arg = fb.buttonArgMap?.[btn.key] ?? btn.key;
|
|
293
|
-
|
|
293
|
+
const label = action.recommendedOption === btn.key ? `💡 ${btn.label}` : btn.label;
|
|
294
|
+
lines.push(` /${fb.command} ${arg} ← ${label}`);
|
|
294
295
|
}
|
|
295
296
|
if (fb.acceptFreeText && fb.freeTextHint) {
|
|
296
297
|
lines.push(` ${fb.freeTextHint}`);
|
|
@@ -11,7 +11,6 @@ import { agentDir } from '../paths.js';
|
|
|
11
11
|
import { parsePeerKey } from './relation/peer-identity.js';
|
|
12
12
|
import { resolvePeerRoleDetail } from '../config/peer-role-resolver.js';
|
|
13
13
|
import { buildDebugTaskContext } from './auth/debug-context.js';
|
|
14
|
-
import { computeBuildId } from '../utils/evolcore-version.js';
|
|
15
14
|
import { loadAgent } from '../config-store.js';
|
|
16
15
|
import { executeLocalInitializationCommand, hasSuppliedInitialization } from '../cli/agent-create.js';
|
|
17
16
|
import { remoteAccessService } from './auth/remote-access-store.js';
|
|
@@ -25,7 +24,7 @@ import { createTriggerBaseagentResolver, registerTriggerIpcExecutor } from '../t
|
|
|
25
24
|
import { createThreadOperationExecutor } from './thread/ipc-operation.js';
|
|
26
25
|
import { isLinkedInstall } from '../utils/npm-ops.js';
|
|
27
26
|
import { buildSystemSessionContext, getSystemSessionModule } from './system-session/registry.js';
|
|
28
|
-
export function registerDaemonIpc({ ipcServer, agentRegistry, agentDelegationRegistry, sessionManager, statsCollector, aidStatsCollector, responseEngine, messageQueue, agentMap, commandHandler, channelInstances, eventBus, handoffRuntime, reloadCoordinator, agentApplicationService, agentInitializationService, enqueueConsolidation, completeAgentBootstrap, contactBinds, bindService, diagService, getProcessOwners, getControlAidState, daemonAid, triggerControlToken, triggerSchedulers, daemonTriggerOwner, primaryAgent, triggerAuthorization, }) {
|
|
27
|
+
export function registerDaemonIpc({ ipcServer, agentRegistry, agentDelegationRegistry, sessionManager, statsCollector, aidStatsCollector, responseEngine, messageQueue, agentMap, commandHandler, channelInstances, eventBus, handoffRuntime, reloadCoordinator, agentApplicationService, agentInitializationService, enqueueConsolidation, requestRelationSweep, completeAgentBootstrap, contactBinds, bindService, diagService, getProcessOwners, getControlAidState, daemonAid, triggerControlToken, triggerSchedulers, daemonTriggerOwner, primaryAgent, triggerAuthorization, }) {
|
|
29
28
|
const authorizeManagedAgentOperation = createDelegationAuthorizer({
|
|
30
29
|
agentDelegationRegistry,
|
|
31
30
|
sessionManager,
|
|
@@ -229,7 +228,7 @@ export function registerDaemonIpc({ ipcServer, agentRegistry, agentDelegationReg
|
|
|
229
228
|
});
|
|
230
229
|
registerAunIpcSender({ ipcServer, channelInstances, agentDelegationRegistry, responseEngine, handoffRuntime, triggerSchedulers, sessionManager });
|
|
231
230
|
ipcServer.setAgentReloadExecutor((aid, options) => reloadCoordinator.reload(aid, options));
|
|
232
|
-
registerConsolidationCheckExecutor({ ipcServer, agentRegistry, enqueueConsolidation });
|
|
231
|
+
registerConsolidationCheckExecutor({ ipcServer, agentRegistry, enqueueConsolidation, requestRelationSweep });
|
|
233
232
|
ipcServer.setInitializationExecutor(async (command) => executeLocalInitializationCommand(agentInitializationService, command));
|
|
234
233
|
ipcServer.setAgentApplicationService(agentApplicationService);
|
|
235
234
|
registerQueueIpcProviders({ ipcServer, statsCollector, agentRegistry, messageQueue });
|
|
@@ -288,10 +287,12 @@ export function createIpcStatusProvider(dependencies) {
|
|
|
288
287
|
return {
|
|
289
288
|
pid: process.pid,
|
|
290
289
|
uptime: snapshot.uptimeMs,
|
|
290
|
+
...(dependencies.runMode ? { runMode: dependencies.runMode } : {}),
|
|
291
|
+
...(dependencies.host ? { host: dependencies.host } : {}),
|
|
291
292
|
build: {
|
|
292
293
|
runtimeMode: dependencies.runtimeIsDist ? 'dist' : 'source',
|
|
293
294
|
runtimeId: dependencies.runtimeBuildIdentity.id,
|
|
294
|
-
diskDistId:
|
|
295
|
+
diskDistId: dependencies.diskDistId ?? null,
|
|
295
296
|
entry: dependencies.runtimeBuildIdentity.entry,
|
|
296
297
|
version: dependencies.runtimeBuildIdentity.version,
|
|
297
298
|
},
|
|
@@ -302,9 +303,26 @@ export function createIpcStatusProvider(dependencies) {
|
|
|
302
303
|
runningAgents: agents.filter(agent => agent.status === 'running').length,
|
|
303
304
|
...(runtimeError ? { error: runtimeError } : {}),
|
|
304
305
|
},
|
|
306
|
+
...(dependencies.baseagents ? {
|
|
307
|
+
baseagents: {
|
|
308
|
+
source: 'runtime-cache',
|
|
309
|
+
items: dependencies.baseagents.baseagents.map(baseagent => ({
|
|
310
|
+
...baseagent,
|
|
311
|
+
state: baseagent.loaded === true
|
|
312
|
+
? 'ready'
|
|
313
|
+
: baseagent.detected === true
|
|
314
|
+
? 'available'
|
|
315
|
+
: baseagent.detected === false
|
|
316
|
+
? 'unavailable'
|
|
317
|
+
: 'unknown',
|
|
318
|
+
})),
|
|
319
|
+
},
|
|
320
|
+
} : {}),
|
|
305
321
|
channels,
|
|
306
322
|
channelsByType,
|
|
307
323
|
queue: { pending: dependencies.messageQueue.getGlobalQueueLength(), processing: dependencies.messageQueue.getGlobalProcessingCount() },
|
|
324
|
+
...(dependencies.getTriggerSummary ? { triggers: dependencies.getTriggerSummary() } : {}),
|
|
325
|
+
...(dependencies.getStatusSnapshot ? dependencies.getStatusSnapshot() : {}),
|
|
308
326
|
stats: {
|
|
309
327
|
received: snapshot.lastHour.received,
|
|
310
328
|
sent: snapshot.lastHour.sent,
|
|
@@ -455,6 +473,7 @@ export function registerQueueIpcProviders({ ipcServer, statsCollector, agentRegi
|
|
|
455
473
|
const snapshots = statsCollector.getSnapshots(agents.map(agent => agent.aid));
|
|
456
474
|
return agents.map((agent) => {
|
|
457
475
|
const snapshot = snapshots.get(agent.aid);
|
|
476
|
+
const queueAgentName = agentRegistry.get(agent.aid)?.name ?? agent.aid;
|
|
458
477
|
return {
|
|
459
478
|
aid: agent.aid,
|
|
460
479
|
received: snapshot.lastHour.received,
|
|
@@ -463,9 +482,9 @@ export function registerQueueIpcProviders({ ipcServer, statsCollector, agentRegi
|
|
|
463
482
|
errors: snapshot.lastHour.errors,
|
|
464
483
|
interrupts: snapshot.lastHour.interrupts,
|
|
465
484
|
avgResponseMs: snapshot.lastHour.avgResponseMs,
|
|
466
|
-
processing: messageQueue.getProcessingCountByAgent(
|
|
467
|
-
queued: messageQueue.getQueueLengthByAgent(
|
|
468
|
-
muted: messageQueue.isAgentMuted(
|
|
485
|
+
processing: messageQueue.getProcessingCountByAgent(queueAgentName),
|
|
486
|
+
queued: messageQueue.getQueueLengthByAgent(queueAgentName),
|
|
487
|
+
muted: messageQueue.isAgentMuted(queueAgentName),
|
|
469
488
|
};
|
|
470
489
|
});
|
|
471
490
|
});
|
|
@@ -95,6 +95,8 @@ export function updateBatchMeta(batchDir, updates) {
|
|
|
95
95
|
finishedAt: updates.finishedAt,
|
|
96
96
|
success: updates.success,
|
|
97
97
|
...(updates.agentSessionId ? { agentSessionId: updates.agentSessionId } : {}),
|
|
98
|
+
...(updates.requestedModel ? { requestedModel: updates.requestedModel } : {}),
|
|
99
|
+
...(updates.actualModel ? { actualModel: updates.actualModel } : {}),
|
|
98
100
|
...(updates.failureReason ? { failureReason: updates.failureReason } : {}),
|
|
99
101
|
};
|
|
100
102
|
// 更新 feedback 正文
|