evolcore 0.0.31 → 0.0.33
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 +35 -0
- package/bin/install-codex-managed-hooks.mjs +124 -37
- package/dist/agents/claude-runner.js +29 -2
- package/dist/agents/codex/app-server-client.js +3 -0
- package/dist/agents/codex/diagnostics.js +76 -44
- package/dist/agents/codex-runner.js +51 -24
- package/dist/agents/ecagent-runner.js +9 -13
- package/dist/agents/gemini-runner.js +4 -0
- package/dist/aun/aid/store.js +0 -81
- package/dist/aun/group/fs-download.js +1 -10
- package/dist/aun/group/operations.js +0 -1
- package/dist/aun/msg/history.js +1 -0
- package/dist/aun/msg/managed-operation.js +130 -32
- package/dist/aun/msg/p2p.js +0 -1
- package/dist/aun/outbox.js +50 -1
- package/dist/aun/service-proxy.js +12 -18
- package/dist/aun/storage/index.js +29 -0
- package/dist/channels/aun.js +38 -137
- package/dist/channels/daemon.js +257 -2
- package/dist/cli/agent-command.js +64 -31
- package/dist/cli/agent-create.js +43 -24
- package/dist/cli/agent.js +16 -70
- package/dist/cli/aun-commands.js +512 -32
- package/dist/cli/contact.js +8 -2
- package/dist/cli/ctl-command.js +1 -2
- package/dist/cli/daemon-commands.js +82 -13
- package/dist/cli/debug-mode.js +154 -0
- package/dist/cli/diag.js +2 -2
- package/dist/cli/handoff-command.js +18 -5
- package/dist/cli/index.js +81 -64
- package/dist/cli/init.js +2 -2
- package/dist/cli/managed-command-guard.js +5 -0
- package/dist/cli/memory-command.js +93 -12
- package/dist/cli/model.js +14 -138
- package/dist/cli/queue-command.js +51 -0
- package/dist/cli/response.js +5 -54
- package/dist/cli/session-command.js +194 -0
- package/dist/cli/skill-command.js +85 -3
- package/dist/cli/stats.js +10 -4
- package/dist/cli/task-command.js +1 -0
- package/dist/cli/task-context.js +16 -0
- package/dist/cli/thread-command.js +620 -0
- package/dist/cli/trigger-command.js +76 -50
- package/dist/config/builtin-roles.js +9 -7
- package/dist/config/config-field-policy.js +2 -3
- package/dist/config/config-manager.js +7 -2
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +15 -0
- package/dist/core/agent-ipc-registration.js +65 -22
- package/dist/core/auth/agent-delegation.js +42 -2
- package/dist/core/auth/debug-context.js +139 -0
- package/dist/core/auth/delegation-authorization.js +1 -0
- package/dist/core/auth/operation-authorizer.js +24 -1
- package/dist/core/auth/operation-catalog.js +44 -3
- package/dist/core/background-session/session-cleanup.js +212 -0
- package/dist/core/background-session/types.js +10 -0
- package/dist/core/bootstrap-messages.js +1 -1
- package/dist/core/bootstrap-service.js +6 -3
- package/dist/core/command/command-handler.js +224 -45
- package/dist/core/command/diag-service.js +5 -1
- package/dist/core/command/memory-slash.js +6 -2
- package/dist/core/command/menu-catalog.js +48 -1
- package/dist/core/command/menu-handler.js +92 -16
- package/dist/core/command/menu-protocol.js +24 -1
- package/dist/core/command/skill-slash.js +322 -0
- package/dist/core/command/slash-gate.js +6 -4
- package/dist/core/command/slash-handler.js +193 -13
- package/dist/core/command/topic-slash.js +528 -0
- package/dist/core/evolagent-registry.js +20 -5
- package/dist/core/handoff/ipc-registration.js +38 -0
- package/dist/core/handoff/runtime.js +5 -11
- package/dist/core/handoff/store.js +5 -0
- package/dist/core/ipc-registration.js +210 -9
- package/dist/core/memory/consolidation-context.js +49 -16
- package/dist/core/memory/consolidation-ops-records.js +35 -0
- package/dist/core/memory/consolidation-queue-format.js +21 -0
- package/dist/core/memory/consolidation.js +174 -180
- package/dist/core/message/aun-ipc-sender.js +207 -8
- package/dist/core/message/im-renderer.js +149 -6
- package/dist/core/message/message-bridge.js +13 -3
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +131 -3
- package/dist/core/message/peer-mode.js +6 -1
- package/dist/core/message/response-engine.js +379 -69
- package/dist/core/message/subtask-tool-projection.js +140 -0
- package/dist/core/model/catalog-service.js +17 -12
- package/dist/core/permission/ec-command-parser.js +126 -7
- package/dist/core/permission/sandbox-runtime.js +14 -1
- package/dist/core/session/session-idle-monitor.js +249 -22
- package/dist/core/session/session-manager.js +54 -9
- package/dist/core/skill/command-parser.js +13 -0
- package/dist/core/skill/index-generator.js +4 -1
- package/dist/core/skill/startup.js +41 -0
- package/dist/core/skill/switch-resolver.js +55 -29
- package/dist/core/task/task-recovery-service.js +2 -0
- package/dist/core/task/task-resume-operation.js +11 -0
- package/dist/core/thread/command-parser.js +125 -0
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +95 -0
- package/dist/core/thread/thread-context-storage.js +131 -0
- package/dist/core/thread/thread-operation.js +258 -0
- package/dist/core/thread/thread-route.js +33 -0
- package/dist/core/thread/thread-service.js +777 -0
- package/dist/core/thread/types.js +1 -0
- package/dist/eck/message-renderer.js +35 -0
- package/dist/index.js +10 -7
- package/dist/ipc.js +234 -17
- package/dist/paths.js +23 -0
- package/dist/response-system/engines/v1/proactive-flow.js +169 -80
- package/dist/trigger/authorization.js +59 -29
- package/dist/trigger/feedback.js +7 -1
- package/dist/trigger/ipc-service.js +49 -35
- package/dist/trigger/parser.js +63 -1
- package/dist/trigger/script-sandbox.js +58 -77
- package/dist/trigger/validation.js +14 -0
- package/dist/utils/error-utils.js +22 -1
- package/kits/docs/AUTHORING.md +1 -1
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/context-assembly.md +1 -0
- package/kits/docs/evolcore/INDEX.md +3 -2
- package/kits/docs/evolcore/agent-create.md +39 -28
- package/kits/docs/evolcore/agent.md +19 -4
- package/kits/docs/evolcore/ec-capabilities.md +4 -0
- package/kits/docs/evolcore/group-collaboration.md +3 -5
- package/kits/docs/evolcore/group.md +3 -4
- package/kits/docs/evolcore/memory-consolidation.md +1 -1
- package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
- package/kits/docs/evolcore/menu-protocol.md +7 -0
- package/kits/docs/evolcore/msg.md +5 -8
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +267 -0
- package/kits/docs/evolcore/trigger.md +2 -2
- package/kits/docs/prompt-loading-architecture.md +1 -0
- package/kits/eck_manifest.json +61 -26
- package/kits/eck_message_manifest.json +169 -10
- package/kits/rules/01-overview.md +0 -9
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +7 -1
- package/kits/rules/07-memory-and-thread.md +202 -0
- package/kits/schemas/relation-config.schema.9.json +18 -3
- package/kits/schemas/role-config.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.2.json +6 -6
- package/kits/schemas/single-session.schema.3.json +6 -6
- package/kits/skills/.switches.json +12 -1
- package/kits/skills/ec-group/SKILL.md +234 -0
- package/kits/skills/ec-skill/SKILL.md +10 -1
- package/kits/skills/ec-skill/scripts/cli.mjs +15 -1
- package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
- package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
- package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
- package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
- package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
- package/kits/skills/thread-ops/SKILL.md +492 -0
- package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
- package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
- package/kits/skills/wechat-article-reader/SKILL.md +97 -0
- package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
- package/kits/templates/bootstrap-welcome.md +7 -7
- package/kits/templates/memory-consolidation/forget.md +5 -0
- package/kits/templates/memory-consolidation/generalize.md +5 -0
- package/kits/templates/memory-consolidation/profile.md +5 -0
- package/kits/templates/memory-consolidation/promote.md +5 -0
- package/kits/templates/message-fragments/item.md +2 -1
- package/kits/templates/message-fragments/thread-context.md +6 -0
- package/kits/templates/message-fragments/trigger-session.md +2 -0
- package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
- package/kits/templates/roles/member.json +2 -0
- package/kits/templates/roles/visitor.json +2 -0
- package/kits/templates/system-fragments/bootstrap.md +66 -72
- package/kits/templates/system-fragments/channel.md +3 -6
- package/kits/templates/system-fragments/commands.md +2 -1
- package/kits/templates/system-fragments/managed-runtime.md +15 -0
- package/kits/templates/system-fragments/reply.md +3 -2
- package/kits/templates/system-fragments/session.md +5 -14
- package/package.json +3 -1
- package/kits/docs/evolcore/group-fs.md +0 -17
- package/kits/docs/venues/aun-group.md +0 -45
- package/kits/docs/venues/group.md +0 -43
|
@@ -13,11 +13,13 @@ import { remoteAccessService } from '../auth/remote-access-store.js';
|
|
|
13
13
|
import { read as cfgRead, resolveEffective, routeFieldPath, write as cfgWrite, } from '../../config/config-manager.js';
|
|
14
14
|
import { execAgentAction } from './agent-control.js';
|
|
15
15
|
import { handleMemorySlash, memoryHelpEntries } from './memory-slash.js';
|
|
16
|
+
import { handleSkillSlash, skillHelpEntries } from './skill-slash.js';
|
|
17
|
+
import { handleTopicSlash, topicHelpEntries, canUseTopicSlash } from './topic-slash.js';
|
|
16
18
|
import { authorizeOperation, buildAuthSubject } from '../auth/auth-gateway.js';
|
|
17
19
|
import { authorizationNextStep, formatAuthorizationDenial } from '../auth/authorization-denial.js';
|
|
18
20
|
import { resolvePermissionMode, writeScope } from '../model/config-scope.js';
|
|
19
21
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
20
|
-
import { modelMatches, getCatalog, assertCatalogSelectable, resolveCatalogModel } from '../model/model-catalog.js';
|
|
22
|
+
import { modelMatches, getCatalog, assertCatalogSelectable, resolveCatalogModel, CONFIGURABLE_EFFORTS, configurableEfforts } from '../model/model-catalog.js';
|
|
21
23
|
import { formatModelCheck, runModelCheck } from '../model/model-diagnostics.js';
|
|
22
24
|
import { constrainResolvedModelForRole, filterModelsForRole, validateModelSelectionForRole } from '../model/model-permission.js';
|
|
23
25
|
import { resolveRuntimeStringField } from '../role/runtime-policy.js';
|
|
@@ -30,7 +32,8 @@ import { launchMonitorAndConfirm, resolveMonitorLaunch, cleanupMonitorStage } fr
|
|
|
30
32
|
import { scanInstances } from '../../utils/instance-registry.js';
|
|
31
33
|
import { guardIdleCommand, guardGroupSlashCommand, guardKnownCommand, guardRoleCommand, guardThreadCommand, isRecognizedSlashCommand, normalizeSlashContent, probeSessionActivity, } from './slash-gate.js';
|
|
32
34
|
import { MAX_AUN_ATTACHMENT_SIZE } from '../../aun/msg/upload.js';
|
|
33
|
-
|
|
35
|
+
import { DEFAULT_SESSION_LOOP_SECONDS, MAX_SESSION_LOOP_SECONDS, MIN_SESSION_LOOP_SECONDS, refreshSessionLoopTarget, resolveCurrentSessionLoopTarget, sessionLoopPayload, validateIdleSeconds, writeSessionLoopConfig, } from '../session/session-idle-monitor.js';
|
|
36
|
+
const allEfforts = CONFIGURABLE_EFFORTS;
|
|
34
37
|
const PERMISSION_MODE_KEYS = PUBLIC_PERMISSION_MODES;
|
|
35
38
|
function defaultSlashChatmode(field) {
|
|
36
39
|
return field === 'private' ? 'interactive' : 'proactive';
|
|
@@ -144,7 +147,8 @@ function resolveSlashRelationTarget(params) {
|
|
|
144
147
|
};
|
|
145
148
|
}
|
|
146
149
|
async function getAvailableEfforts(agent, model) {
|
|
147
|
-
|
|
150
|
+
const dynamic = await agent.getAvailableEfforts?.(model);
|
|
151
|
+
return configurableEfforts(agent?.baseagent || agent?.name, dynamic);
|
|
148
152
|
}
|
|
149
153
|
function modelDisplayLabel(agent, model) {
|
|
150
154
|
const full = agent.resolveModelId?.(model);
|
|
@@ -490,7 +494,9 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
490
494
|
const isDaemonOwner = authSubject.isDaemonOwner;
|
|
491
495
|
const authorizeIntent = (params) => authorizeSlashIntent({
|
|
492
496
|
...params,
|
|
493
|
-
subject:
|
|
497
|
+
subject: params.intent.operation.startsWith('session.loop.')
|
|
498
|
+
? { ...authSubject, sessionId: params.session?.id }
|
|
499
|
+
: authSubject,
|
|
494
500
|
});
|
|
495
501
|
const canAccessSlashOperation = (operation, scope) => {
|
|
496
502
|
const args = scope === 'relation'
|
|
@@ -534,6 +540,79 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
534
540
|
const isCmd = isRecognizedSlashCommand(normalizedContent);
|
|
535
541
|
if (!isCmd)
|
|
536
542
|
return undefined;
|
|
543
|
+
if (normalizedContent === '/loop' || normalizedContent.startsWith('/loop ')) {
|
|
544
|
+
const rawArgs = normalizedContent.slice('/loop'.length).trim();
|
|
545
|
+
const parts = rawArgs ? rawArgs.split(/\s+/) : [];
|
|
546
|
+
if (parts.length > 2 || (parts.length > 0 && !['on', 'off'].includes(parts[0]))) {
|
|
547
|
+
return { kind: 'command.error', text: `❌ 用法: /loop | /loop on [${MIN_SESSION_LOOP_SECONDS}-${MAX_SESSION_LOOP_SECONDS}] | /loop off` };
|
|
548
|
+
}
|
|
549
|
+
const route = {
|
|
550
|
+
channel,
|
|
551
|
+
channelId,
|
|
552
|
+
selfAid: authSubject.selfAid ?? selfAID ?? '',
|
|
553
|
+
...(threadId ? { threadId } : {}),
|
|
554
|
+
};
|
|
555
|
+
let target;
|
|
556
|
+
try {
|
|
557
|
+
if (!route.selfAid)
|
|
558
|
+
throw Object.assign(new Error('当前 agent 身份不可用'), { code: 'MISSING_AID' });
|
|
559
|
+
target = await resolveCurrentSessionLoopTarget(this.sessionManager, route);
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
const code = error?.code;
|
|
563
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
564
|
+
return { kind: 'command.error', text: `❌ ${message}${code ? ` (${code})` : ''}` };
|
|
565
|
+
}
|
|
566
|
+
const operation = parts.length === 0 ? 'session.loop.current' : 'session.loop.update';
|
|
567
|
+
const denied = await authorizeIntent({
|
|
568
|
+
intent: { operation, scope: 'relation', source: 'slash', args: { sessionId: target.session.id, peer: target.peerKey, value: parts[0] } },
|
|
569
|
+
identity,
|
|
570
|
+
session: target.session,
|
|
571
|
+
explicitChatType: target.session.chatType,
|
|
572
|
+
channel,
|
|
573
|
+
channelId,
|
|
574
|
+
userId,
|
|
575
|
+
selfAid: route.selfAid,
|
|
576
|
+
isDaemonOwner,
|
|
577
|
+
});
|
|
578
|
+
if (denied)
|
|
579
|
+
return denied;
|
|
580
|
+
if (parts.length === 0) {
|
|
581
|
+
try {
|
|
582
|
+
const current = await refreshSessionLoopTarget(this.sessionManager, route, target);
|
|
583
|
+
const payload = sessionLoopPayload(current);
|
|
584
|
+
return { kind: 'command.result', text: `当前 idle 触发(${current.level},session=${current.session.id}):${payload.value ? `开启,${payload.idleSeconds} 秒` : '关闭'}` };
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
return { kind: 'command.error', text: `❌ ${error instanceof Error ? error.message : String(error)}` };
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
let next;
|
|
591
|
+
if (parts[0] === 'off') {
|
|
592
|
+
if (parts.length !== 1)
|
|
593
|
+
return { kind: 'command.error', text: '❌ /loop off 不接受秒数' };
|
|
594
|
+
next = { enabled: false };
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
const seconds = parts.length === 2
|
|
598
|
+
? /^[1-9]\d*$/.test(parts[1]) ? validateIdleSeconds(Number(parts[1])) : undefined
|
|
599
|
+
: DEFAULT_SESSION_LOOP_SECONDS;
|
|
600
|
+
if (seconds === undefined)
|
|
601
|
+
return { kind: 'command.error', text: `❌ 秒数必须是 ${MIN_SESSION_LOOP_SECONDS}-${MAX_SESSION_LOOP_SECONDS} 的整数` };
|
|
602
|
+
next = { enabled: true, idleSeconds: seconds };
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
const latest = await refreshSessionLoopTarget(this.sessionManager, route, target);
|
|
606
|
+
const updated = writeSessionLoopConfig(this.sessionManager, latest, next);
|
|
607
|
+
const payload = sessionLoopPayload(updated);
|
|
608
|
+
if (this.shouldSuppressCardTriggerResult(source, channel))
|
|
609
|
+
return null;
|
|
610
|
+
return { kind: 'command.result', text: `✅ idle 触发(${updated.level},session=${updated.session.id})已${payload.value ? `开启(${payload.idleSeconds} 秒)` : '关闭'}` };
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
return { kind: 'command.error', text: `❌ ${error instanceof Error ? error.message : String(error)}` };
|
|
614
|
+
}
|
|
615
|
+
}
|
|
537
616
|
const interruptPausedSessionBeforeReplacement = async (commandSession) => {
|
|
538
617
|
if (commandSession && (this.processor?.isPauseRequested?.(commandSession.id) ?? false)) {
|
|
539
618
|
this.eventBus.publish({
|
|
@@ -642,6 +721,8 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
642
721
|
};
|
|
643
722
|
// /help 命令不需要会话
|
|
644
723
|
if (normalizedContent === '/help') {
|
|
724
|
+
const canReadLoop = canAccessSlashOperation('session.loop.current', 'relation');
|
|
725
|
+
const canUpdateLoop = canAccessSlashOperation('session.loop.update', 'relation');
|
|
645
726
|
if (groupSlash) {
|
|
646
727
|
const lines = [
|
|
647
728
|
'群聊可用命令:',
|
|
@@ -653,6 +734,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
653
734
|
' /baseagent - 查看 Agent 后端',
|
|
654
735
|
' /perm - 查看权限模式',
|
|
655
736
|
' /mention - 查看群聊 @ 处理模式',
|
|
737
|
+
...(canReadLoop ? [` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
656
738
|
' /ask <选项> - 回答待处理问题',
|
|
657
739
|
' /pause - 在下一次工具调用前暂停任务',
|
|
658
740
|
' /resume - 继续已暂停的任务',
|
|
@@ -660,6 +742,9 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
660
742
|
...(isAdmin ? [
|
|
661
743
|
' /compact - 压缩会话上下文',
|
|
662
744
|
...(threadId ? [' /renew - 轮换当前话题的后端会话'] : []),
|
|
745
|
+
' /memory - 查看本群关系记忆',
|
|
746
|
+
' /skill - 查看技能列表',
|
|
747
|
+
' /thread - 查看本群话题',
|
|
663
748
|
] : []),
|
|
664
749
|
'',
|
|
665
750
|
'模型、推理强度、后端与权限在群聊中仅支持查询;@ 模式可由管理员切换。',
|
|
@@ -695,6 +780,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
695
780
|
'',
|
|
696
781
|
'💬 聊天设置:',
|
|
697
782
|
...(canReadChatmode || canSetChatmode ? [` /chatmode${canSetChatmode ? ' [interactive|proactive]' : ''} - 查看${canSetChatmode ? '或切换' : ''}会话模式`] : []),
|
|
783
|
+
...(canReadLoop ? [` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
698
784
|
...(canReadMentionmode || canSetMentionmode ? [` /mention${canSetMentionmode ? ' [mention-only|disabled]' : ''} - 查看${canSetMentionmode ? '或切换' : ''}群聊 @ 处理模式`] : []),
|
|
699
785
|
] : []),
|
|
700
786
|
...(canReadPermission || canAnswerPermission ? [
|
|
@@ -739,6 +825,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
739
825
|
'💬 聊天设置:',
|
|
740
826
|
` /chatmode${canSetChatmode ? ' [interactive|proactive]' : ''} - 查看${canSetChatmode ? '或切换' : ''}会话模式`,
|
|
741
827
|
] : []),
|
|
828
|
+
...(canReadLoop ? ['', ` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
742
829
|
...(canReadPermission || canAnswerPermission ? [
|
|
743
830
|
'',
|
|
744
831
|
'🔐 权限管理:',
|
|
@@ -786,6 +873,12 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
786
873
|
' /activity [all|text|none] - 查看/控制中间输出显示模式',
|
|
787
874
|
...(canReadChatmode || canSetChatmode ? [` /chatmode${canSetChatmode ? ' [interactive|proactive]' : ''} - 查看${canSetChatmode ? '/切换' : ''}会话模式(被动响应或主动推进)`] : []),
|
|
788
875
|
...(canReadMentionmode || canSetMentionmode ? [` /mention${canSetMentionmode ? ' [mention-only|disabled]' : ''} - 查看${canSetMentionmode ? '/切换' : ''}群聊 @ 处理模式`] : []),
|
|
876
|
+
...(canReadLoop ? [` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
877
|
+
'',
|
|
878
|
+
'🧠 上下文:',
|
|
879
|
+
' /memory - 记忆概览与维护',
|
|
880
|
+
' /skill - 技能列表与索引刷新',
|
|
881
|
+
' /thread - 话题列表、更名与 summary',
|
|
789
882
|
'',
|
|
790
883
|
'🔐 权限管理:',
|
|
791
884
|
...(canReadPermission ? [' /perm - 查看当前权限模式'] : []),
|
|
@@ -848,9 +941,19 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
848
941
|
}
|
|
849
942
|
// /evolhelp 命令:返回 JSON 格式的命令列表(供程序解析)
|
|
850
943
|
if (normalizedContent === '/evolhelp') {
|
|
944
|
+
const canReadLoop = canAccessSlashOperation('session.loop.current', 'relation');
|
|
945
|
+
const canUpdateLoop = canAccessSlashOperation('session.loop.update', 'relation');
|
|
946
|
+
const loopHelp = canReadLoop || canUpdateLoop ? [{
|
|
947
|
+
command: '/loop',
|
|
948
|
+
...(canUpdateLoop ? { args: '[on [seconds]|off]' } : {}),
|
|
949
|
+
description: '查看或设置当前主会话/话题的单次闲置触发',
|
|
950
|
+
category: '聊天设置',
|
|
951
|
+
roles: [identity.role],
|
|
952
|
+
}] : [];
|
|
851
953
|
if (groupSlash) {
|
|
852
954
|
const canSetMentionmode = canAccessSlashOperation('mentionmode.update', 'relation');
|
|
853
955
|
const commands = [
|
|
956
|
+
...loopHelp,
|
|
854
957
|
{ command: '/help', description: '显示帮助信息', category: '帮助', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
855
958
|
{ command: '/status', description: '显示会话状态', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
856
959
|
{ command: '/check', description: '检查 EvolAgent 实例健康', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
@@ -867,13 +970,24 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
867
970
|
if (isAdmin) {
|
|
868
971
|
commands.push({ command: '/compact', description: '压缩会话上下文', category: '会话管理', roles: ['admin', 'owner'] }, ...(threadId ? [{ command: '/renew', description: '轮换当前话题 backend', category: '会话管理', roles: ['admin', 'owner'] }] : []));
|
|
869
972
|
}
|
|
870
|
-
//
|
|
973
|
+
// 记忆管理紧跟权限管理;技能 / 话题管理跟随其后
|
|
871
974
|
const groupMemoryEntries = memoryHelpEntries({ chatType: 'group', role: identity.role, isAdmin, isOwnerSelf: false });
|
|
872
975
|
const lastPermIdx = commands.map(c => c.category).lastIndexOf('权限管理');
|
|
873
|
-
|
|
976
|
+
const insertAt = lastPermIdx >= 0 ? lastPermIdx + 1 : commands.length;
|
|
977
|
+
commands.splice(insertAt, 0, ...groupMemoryEntries);
|
|
978
|
+
const groupExtras = [
|
|
979
|
+
...skillHelpEntries({ chatType: 'group', role: identity.role, isAdmin }),
|
|
980
|
+
...topicHelpEntries({
|
|
981
|
+
chatType: 'group',
|
|
982
|
+
role: identity.role,
|
|
983
|
+
isAdmin,
|
|
984
|
+
peerKey: authSubject.peerKey,
|
|
985
|
+
}),
|
|
986
|
+
];
|
|
987
|
+
commands.splice(insertAt + groupMemoryEntries.length, 0, ...groupExtras);
|
|
874
988
|
return { kind: 'command.result', text: JSON.stringify({ commands, categories: [...new Set(commands.map(c => c.category))] }) };
|
|
875
989
|
}
|
|
876
|
-
const cmds = [];
|
|
990
|
+
const cmds = [...loopHelp];
|
|
877
991
|
const canReadModel = canAccessSlashOperation('model.current', 'relation')
|
|
878
992
|
|| canAccessSlashOperation('model.list', 'relation');
|
|
879
993
|
const canUseModel = canAccessSlashOperation('model.use', 'relation');
|
|
@@ -920,6 +1034,16 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
920
1034
|
isAdmin,
|
|
921
1035
|
isOwnerSelf: isOwner && !!memoryOwnerForHelp && (authSubject.principalId ?? userId) === memoryOwnerForHelp,
|
|
922
1036
|
}));
|
|
1037
|
+
// 技能管理 / 话题管理(紧随记忆管理)
|
|
1038
|
+
cmds.push(...skillHelpEntries({ chatType: 'private', role: identity.role, isAdmin }));
|
|
1039
|
+
const topicHelpCtx = {
|
|
1040
|
+
chatType: activeChatType === 'group' ? 'group' : 'private',
|
|
1041
|
+
role: identity.role,
|
|
1042
|
+
isAdmin,
|
|
1043
|
+
peerKey: authSubject.peerKey,
|
|
1044
|
+
};
|
|
1045
|
+
if (canUseTopicSlash(topicHelpCtx))
|
|
1046
|
+
cmds.push(...topicHelpEntries(topicHelpCtx));
|
|
923
1047
|
// 运维
|
|
924
1048
|
cmds.push({ command: '/status', description: '显示会话状态', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] });
|
|
925
1049
|
cmds.push({ command: '/pause', description: '在下一次工具调用前暂停当前任务', category: '运维', roles: ['admin', 'owner'] });
|
|
@@ -3130,11 +3254,23 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3130
3254
|
channelId,
|
|
3131
3255
|
agentName: 'system',
|
|
3132
3256
|
chatmode: 'interactive',
|
|
3133
|
-
replyContext:
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3257
|
+
replyContext: {
|
|
3258
|
+
...(restartReplyContext ?? (chatType === 'group'
|
|
3259
|
+
? { delivery: { chatType: 'group', groupId: channelId } }
|
|
3260
|
+
: chatType === 'private'
|
|
3261
|
+
? { delivery: { chatType: 'private' } }
|
|
3262
|
+
: {})),
|
|
3263
|
+
// This notice describes the process that is about to die. If it
|
|
3264
|
+
// cannot be handed to the gateway before the shutdown tears the
|
|
3265
|
+
// transport down, the replacement process must NOT replay it:
|
|
3266
|
+
// it already sends its own "restart succeeded" confirmation, and
|
|
3267
|
+
// a late copy of the pre-restart notice is confusing rather than
|
|
3268
|
+
// informative.
|
|
3269
|
+
metadata: {
|
|
3270
|
+
...(restartReplyContext?.metadata ?? {}),
|
|
3271
|
+
processScopedDelivery: true,
|
|
3272
|
+
},
|
|
3273
|
+
},
|
|
3138
3274
|
});
|
|
3139
3275
|
await adapter.send(envelope, { kind: 'command.result', text: '🔄 服务正在重启,请稍候...(约 5 秒后恢复)' });
|
|
3140
3276
|
// 等待消息发送完成后再延迟 kill
|
|
@@ -3670,6 +3806,21 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3670
3806
|
logger.debug('[CommandHandler] Backend session rename sync failed:', error);
|
|
3671
3807
|
});
|
|
3672
3808
|
}
|
|
3809
|
+
// P1.2: 若当前是话题会话,同步更新话题索引
|
|
3810
|
+
if (success && session.threadId) {
|
|
3811
|
+
try {
|
|
3812
|
+
const { ThreadService } = await import('../../core/thread/index.js');
|
|
3813
|
+
const selfAid = session.selfAID;
|
|
3814
|
+
const peer = session.channelId;
|
|
3815
|
+
if (selfAid && peer) {
|
|
3816
|
+
const svc = new ThreadService(this.sessionManager);
|
|
3817
|
+
await svc.renameThread({ selfAid, peer, threadId: session.threadId, name: newName });
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
catch (err) {
|
|
3821
|
+
logger.debug('[CommandHandler] Thread index rename sync failed:', err);
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3673
3824
|
if (!success) {
|
|
3674
3825
|
return { kind: 'command.error', text: `❌ 重命名失败` };
|
|
3675
3826
|
}
|
|
@@ -3886,6 +4037,35 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3886
4037
|
return { kind: 'command.error', text: `❌ 修复失败: ${error.message}` };
|
|
3887
4038
|
}
|
|
3888
4039
|
}
|
|
4040
|
+
// /skill 命令:技能查看与索引刷新(写操作请走 ec skill / ec-skill 技能)
|
|
4041
|
+
if (normalizedContent === '/skill' || normalizedContent.startsWith('/skill ')) {
|
|
4042
|
+
return await handleSkillSlash({
|
|
4043
|
+
content: normalizedContent,
|
|
4044
|
+
selfAid: authSubject.selfAid,
|
|
4045
|
+
chatType: activeChatType === 'group' ? 'group' : 'private',
|
|
4046
|
+
role: identity.role,
|
|
4047
|
+
isAdmin,
|
|
4048
|
+
// 注意:getSkillIndexRefresher 是 getter,必须调用取值;只 .bind 会把这个
|
|
4049
|
+
// getter 本身当成 refresher 传下去,导致 /skill refresh 永远返回「未知错误」。
|
|
4050
|
+
refresher: this.getSkillIndexRefresher?.(),
|
|
4051
|
+
// manifest 的 when 判定要用同一个 lifecycle 值,否则 /skill index 会误报未加载
|
|
4052
|
+
lifecycle: this.agentRegistry?.get?.(authSubject.selfAid ?? '')?.lifecycle ?? null,
|
|
4053
|
+
});
|
|
4054
|
+
}
|
|
4055
|
+
// /thread 命令:话题查看与管理
|
|
4056
|
+
if (normalizedContent === '/thread' || normalizedContent.startsWith('/thread ')) {
|
|
4057
|
+
return await handleTopicSlash({
|
|
4058
|
+
content: normalizedContent,
|
|
4059
|
+
selfAid: authSubject.selfAid,
|
|
4060
|
+
peerKey: authSubject.peerKey,
|
|
4061
|
+
chatType: activeChatType === 'group' ? 'group' : 'private',
|
|
4062
|
+
role: identity.role,
|
|
4063
|
+
isAdmin,
|
|
4064
|
+
threadId,
|
|
4065
|
+
sessionId: activeSession?.id,
|
|
4066
|
+
sessionManager: this.sessionManager,
|
|
4067
|
+
});
|
|
4068
|
+
}
|
|
3889
4069
|
// /trigger 命令
|
|
3890
4070
|
if (normalizedContent === '/memory' || normalizedContent.startsWith('/memory ')) {
|
|
3891
4071
|
const memoryAgent = this.agentRegistry?.get?.(authSubject.selfAid ?? '');
|
|
@@ -3928,7 +4108,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3928
4108
|
});
|
|
3929
4109
|
if (triggerAuthDenied)
|
|
3930
4110
|
return triggerAuthDenied;
|
|
3931
|
-
const text = await this.handleTrigger(normalizedContent, channel, channelId, userId ?? '', isAdmin, messageId,
|
|
4111
|
+
const text = await this.handleTrigger(normalizedContent, channel, channelId, userId ?? '', isAdmin, messageId, activeChatType, threadId, isDaemonOwner, authSubject.canApprovePersistentFullAccess);
|
|
3932
4112
|
return { kind: 'command.result', text };
|
|
3933
4113
|
}
|
|
3934
4114
|
return null;
|