evolcore 0.0.27 → 0.0.29-test.0
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 +38 -15
- package/bin/ec-safe-output.js +270 -54
- package/dist/agents/baseagent-availability.js +37 -1
- package/dist/agents/baseagent.js +29 -14
- package/dist/agents/claude-runner.js +171 -13
- package/dist/agents/codex/app-server-client.js +13 -2
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex/diagnostics.js +4 -3
- package/dist/agents/codex-runner.js +444 -106
- package/dist/agents/gemini-runner.js +35 -17
- package/dist/aun/group/history.js +130 -90
- package/dist/aun/group/operations.js +1 -3
- package/dist/aun/menu/client.js +1 -0
- package/dist/aun/menu/transport.js +5 -3
- package/dist/aun/msg/managed-operation.js +70 -0
- package/dist/aun/msg/p2p.js +1 -3
- package/dist/aun/msg/upload.js +2 -2
- package/dist/aun/outbox.js +1 -37
- package/dist/channels/aun.js +262 -86
- package/dist/channels/daemon.js +18 -1
- package/dist/channels/feishu.js +1 -2
- package/dist/cli/agent-command.js +23 -3
- package/dist/cli/agent-create.js +68 -2
- package/dist/cli/agent.js +12 -2
- package/dist/cli/aun-commands.js +87 -13
- package/dist/cli/cli-argv.js +26 -0
- package/dist/cli/daemon-commands.js +116 -149
- package/dist/cli/data-command.js +4 -4
- package/dist/cli/diag.js +1 -1
- package/dist/cli/handoff-command.js +2 -0
- package/dist/cli/index.js +18 -1
- package/dist/cli/managed-command-guard.js +10 -0
- package/dist/cli/memory-command.js +441 -0
- package/dist/cli/menu-client.js +4 -0
- package/dist/cli/restart-monitor.js +127 -23
- package/dist/cli/skill-command.js +41 -0
- package/dist/cli/task-context.js +2 -23
- package/dist/cli/trigger-command.js +9 -1
- package/dist/cli/watch-msg-diag.js +209 -0
- package/dist/config/config-field-policy.js +52 -3
- package/dist/config/config-manager.js +17 -4
- package/dist/config/contact-book-store.js +2 -2
- package/dist/config/mention-mode.js +7 -2
- package/dist/config/merge.js +28 -9
- package/dist/config/resolved-config-op.js +1 -1
- package/dist/config/runtime-env.js +137 -0
- package/dist/config/schema-registry.js +11 -1
- package/dist/config-store.js +10 -10
- package/dist/core/audit/event-key.js +3 -1
- package/dist/core/audit/log-integrity.js +4 -0
- package/dist/core/auth/agent-delegation.js +2 -1
- package/dist/core/auth/auth-gateway.js +13 -6
- package/dist/core/auth/authorization-audit.js +54 -19
- package/dist/core/auth/operation-authorizer.js +17 -0
- package/dist/core/auth/operation-catalog.js +9 -0
- package/dist/core/causation/context.js +5 -1
- package/dist/core/command/agent-control.js +1 -2
- package/dist/core/command/command-handler.js +80 -24
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/memory-slash.js +270 -0
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +331 -79
- package/dist/core/command/menu-protocol.js +45 -4
- package/dist/core/command/slash-gate.js +10 -10
- package/dist/core/command/slash-handler.js +230 -79
- package/dist/core/data-migration.js +282 -505
- package/dist/core/event-catalog.js +26 -0
- package/dist/core/evolagent-registry.js +6 -0
- package/dist/core/evolagent.js +0 -10
- package/dist/core/handoff/store.js +1 -20
- package/dist/core/inference/text-inference.js +57 -1
- package/dist/core/memory/consolidation-context.js +505 -0
- package/dist/core/memory/consolidation-ops-records.js +124 -0
- package/dist/core/memory/consolidation-trigger.js +394 -0
- package/dist/core/memory/index-manager.js +308 -0
- package/dist/core/memory/launch-consolidation.js +395 -0
- package/dist/core/memory/memory-admin.js +234 -0
- package/dist/core/memory/memory-document.js +100 -0
- package/dist/core/memory/memory-session-policy.js +41 -0
- package/dist/core/memory/memory-signature.js +257 -0
- package/dist/core/memory/memory-writer.js +432 -0
- package/dist/core/memory/staleness.js +117 -0
- package/dist/core/message/auto-mention-gate.js +454 -0
- package/dist/core/message/im-renderer.js +90 -20
- package/dist/core/message/message-bridge.js +333 -23
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +114 -27
- package/dist/core/message/pending-hints.js +329 -161
- package/dist/core/message/response-engine.js +596 -90
- package/dist/core/permission/ec-command-parser.js +1044 -87
- package/dist/core/permission/protected-paths.js +376 -126
- package/dist/core/permission/sandbox-runtime.js +40 -12
- package/dist/core/permission/tool-error-code.js +96 -13
- package/dist/core/permission/tool-policy.js +277 -24
- package/dist/core/role/runtime-policy.js +3 -7
- package/dist/core/session/{runner-task-history.js → runner-event-summary.js} +1 -1
- package/dist/core/session/session-fs-store.js +0 -76
- package/dist/core/session/session-idle-monitor.js +355 -0
- package/dist/core/session/session-manager.js +482 -17
- package/dist/core/session/session-mapper.js +33 -16
- package/dist/core/session/session-renew.js +217 -155
- package/dist/core/session/{session-turns.js → session-transcript.js} +35 -6
- package/dist/core/skill/global-watcher.js +282 -0
- package/dist/core/skill/index-generator.js +84 -0
- package/dist/core/skill/startup.js +73 -0
- package/dist/core/skill/switch-resolver.js +115 -0
- package/dist/core/task/task-activity-store.js +219 -0
- package/dist/eck/kit-renderer.js +30 -3
- package/dist/eck/manifest-engine.js +26 -4
- package/dist/index.js +722 -171
- package/dist/ipc.js +564 -2
- package/dist/paths.js +30 -9
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +116 -15
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +1 -0
- package/dist/trigger/manager.js +0 -10
- package/dist/trigger/scheduler.js +11 -0
- package/dist/trigger/validation.js +22 -0
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/avatar-upload.js +59 -18
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/error-dict.json +6 -3
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/logger.js +32 -10
- package/dist/utils/media-cache.js +84 -0
- package/dist/utils/msg-diag.js +97 -0
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/welcome.js +37 -8
- package/dist/utils/windows-shell-trust.js +37 -0
- package/kits/docs/AUTHORING.md +314 -0
- package/kits/docs/GUIDE.md +2 -0
- package/kits/docs/INDEX.md +2 -0
- package/kits/docs/aun/CHEATSHEET.md +4 -0
- package/kits/docs/aun/SDK.md +60 -0
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/context-assembly.md +10 -6
- package/kits/docs/evolcore/INDEX.md +17 -3
- package/kits/docs/evolcore/agent-create.md +24 -0
- package/kits/docs/evolcore/agent.md +5 -2
- package/kits/docs/evolcore/config.md +1 -1
- package/kits/docs/evolcore/ec-capabilities.md +364 -0
- package/kits/docs/evolcore/group.md +34 -18
- package/kits/docs/evolcore/memory-architecture.md +78 -0
- package/kits/docs/evolcore/memory-consolidation-batches.md +133 -0
- package/kits/docs/evolcore/memory-consolidation.md +263 -0
- package/kits/docs/evolcore/memory-tags.md +63 -0
- package/kits/docs/evolcore/memory.md +110 -0
- package/kits/docs/evolcore/menu-client.md +27 -11
- package/kits/{schemas → docs/evolcore}/menu-exec-schema-commands.md +12 -6
- package/kits/docs/evolcore/menu-protocol.md +213 -0
- package/kits/docs/evolcore/msg.md +2 -0
- package/kits/docs/evolcore/trigger.md +7 -5
- package/kits/docs/path-registry.md +6 -8
- package/kits/docs/prompt-loading-architecture.md +5 -3
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +294 -88
- package/kits/eck_manifest.memory.json +257 -0
- package/kits/rules/03-identity.md +8 -8
- package/kits/rules/05-venue.md +4 -2
- package/kits/rules/06-channel.md +1 -1
- package/kits/schemas/_meta.json +276 -47
- package/kits/schemas/agent-config.schema.12.json +38 -2
- package/kits/schemas/agent-config.schema.13.json +591 -0
- package/kits/schemas/daemon.schema.6.json +9 -9
- package/kits/schemas/defaults.schema.5.json +29 -0
- package/kits/schemas/relation-config.schema.8.json +14 -1
- package/kits/schemas/relation-config.schema.9.json +129 -0
- package/kits/schemas/role-config.schema.1.json +3 -3
- package/kits/skills/.switches.json +3 -0
- package/kits/skills/ec-skill/SKILL.md +217 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +128 -0
- package/kits/skills/ec-skill/scripts/deps.mjs +107 -0
- package/kits/skills/ec-skill/scripts/frontmatter.mjs +104 -0
- package/kits/skills/ec-skill/scripts/skill.mjs +629 -0
- package/kits/skills/ec-skill/scripts/template/SKILL.md.tmpl +30 -0
- package/kits/templates/decision/auto-mention.md +25 -0
- package/kits/templates/decision/session-renew.md +22 -0
- package/kits/templates/memory-consolidation/forget.md +104 -0
- package/kits/templates/memory-consolidation/generalize.md +76 -0
- package/kits/templates/memory-consolidation/notes.md +133 -0
- package/kits/templates/memory-consolidation/profile.md +58 -0
- package/kits/templates/memory-consolidation/promote.md +72 -0
- package/kits/templates/memory-consolidation/workflow.md +75 -0
- package/kits/templates/system-fragments/bootstrap.md +14 -5
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/group-history.md +6 -0
- package/kits/templates/system-fragments/identity.md +0 -3
- package/kits/templates/system-fragments/memory.md +79 -0
- package/kits/templates/system-fragments/reply.md +1 -0
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -6
- package/dist/trigger/legacy-session-history.js +0 -19
- package/kits/templates/system-fragments/group-unread-history.md +0 -7
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { memoryHelpEntries } from './memory-slash.js';
|
|
1
2
|
import { getBaseagentSnapshot, loadedBaseagentIds } from '../../agents/baseagent-availability.js';
|
|
2
3
|
import { normalizePeer, writeScope } from '../model/config-scope.js';
|
|
3
4
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
@@ -13,17 +14,19 @@ import os from 'os';
|
|
|
13
14
|
import crypto from 'crypto';
|
|
14
15
|
import { CronExpressionParser } from 'cron-parser';
|
|
15
16
|
import { parseDuration } from '../../trigger/parser.js';
|
|
16
|
-
import {
|
|
17
|
+
import { isLinkedInstall, resolveGlobalPkg } from '../../utils/npm-ops.js';
|
|
18
|
+
import { refreshManagedPackageVersions, VERSION_INFO_PACKAGES } from '../../utils/package-version-info.js';
|
|
17
19
|
import { resolveCliEntry, launchMonitorAndConfirm } from '../../utils/cross-platform.js';
|
|
18
20
|
import { cachedCliVersion } from '../../utils/cross-platform.js';
|
|
19
21
|
import { scanInstances } from '../../utils/instance-registry.js';
|
|
20
|
-
import {
|
|
22
|
+
import { loadDefaults, loadDaemonConfig } from '../../config-store.js';
|
|
21
23
|
import { WEB_PACKAGE_NAME } from '../../product.js';
|
|
22
24
|
import { read as cfgRead, resolveEffective, resolveEffectiveFieldWithSource, routeFieldPath, write as cfgWrite, ConfigTarget, } from '../../config/config-manager.js';
|
|
23
25
|
import { execAgentAction, execAgentQuery, execAgentOptions, execAidAvatar, resolveProjectPath } from './agent-control.js';
|
|
24
26
|
import { gatewayList, gatewayUpdate, gatewayDelete, gatewayTest, gatewayModels, gatewaySetPrice, gatewaySyncEnv } from '../../config/gateway-config.js';
|
|
25
27
|
import { displaySessionTitle } from '../session/session-title.js';
|
|
26
|
-
import {
|
|
28
|
+
import { buildTranscriptTurns } from '../session/session-transcript.js';
|
|
29
|
+
import { buildForkHistorySnapshot, pageForkHistory } from '../session/session-manager.js';
|
|
27
30
|
import { isCapabilityType, listCapabilityOptions, queryCapabilityTypes, resolveCapabilityContext, updateCapabilityPolicy, } from '../capability/capability-manager.js';
|
|
28
31
|
import { normalizeCliArgv, parseCliIntent, parseLegacyCliCommand, validateCliArgv, withDefaultRelationContext } from './cli-intent-parser.js';
|
|
29
32
|
import { auditCommandAuthorization, auditFullAccessEvent, hashArgv } from '../auth/authorization-audit.js';
|
|
@@ -40,18 +43,20 @@ import { SYSTEM_CONTROL_CHANNEL } from '../system-channels.js';
|
|
|
40
43
|
import { logger } from '../../utils/logger.js';
|
|
41
44
|
import { shouldSuppressRealRestart } from '../../utils/restart-safety.js';
|
|
42
45
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../auth/agent-delegation.js';
|
|
43
|
-
import { evolMenuResponseTransportMetadata, menuFailure, menuCommandForName, menuSuccess, normalizeMenuError, validateConfigWriteScope, validateMenuRequest, } from './menu-protocol.js';
|
|
46
|
+
import { evolMenuResponseTransportMetadata, menuFailure, menuCommandForName, menuSuccess, normalizeMenuError, validateTaskActivityQueryArgs, validateConfigWriteScope, validateMenuRequest, } from './menu-protocol.js';
|
|
44
47
|
import { parseMenuClientProtectedHeaders } from './menu-protocol.js';
|
|
48
|
+
import { TaskActivityStore } from '../task/task-activity-store.js';
|
|
45
49
|
import { remoteAccessService, validateAndRenewRemoteAccessToken } from '../auth/remote-access-store.js';
|
|
46
50
|
import { listDiagnosticLogOptions, listRawConfigResources, queryDiagnosticLogs, readRawConfigResource, } from './daemon-diagnostics.js';
|
|
47
51
|
import { roleMenuAction, roleMenuOperation, roleMenuOptions, roleMenuQuery, roleMenuUpdate, } from './role-menu.js';
|
|
48
52
|
import { handleConnectMenu, connectMenuOperation } from './connect-menu.js';
|
|
49
53
|
import { groupMenuAuthorizationArgs, groupMenuIntent, handleGroupMenu, } from './group-menu.js';
|
|
50
|
-
import { getMenuCatalog, execMenuValueBatch, resolveExplicitMenuExecutionContext, validateMenuCatalogArgs, validateMenuValueBatchArgs } from './menu-catalog.js';
|
|
54
|
+
import { getMenuCatalog, execMenuValueBatch, resolveExplicitMenuExecutionContext, resolveMenuCatalogContext, validateMenuCatalogArgs, validateMenuValueBatchArgs } from './menu-catalog.js';
|
|
51
55
|
import { probeSessionActivity } from './slash-gate.js';
|
|
52
56
|
import { dataRootFailure, dataRootResolver } from './data-root-resolver.js';
|
|
53
57
|
import { agentStorageMenuService, isAgentStorageMenuRequest } from './agent-storage-menu.js';
|
|
54
|
-
import {
|
|
58
|
+
import { MAX_AUN_ATTACHMENT_SIZE } from '../../aun/msg/upload.js';
|
|
59
|
+
import { normalizeTopicLabel, normalizeTopicStatus, resolveTopicArchiveFilter, } from '../session/session-mapper.js';
|
|
55
60
|
/**
|
|
56
61
|
* 获取 baseagent CLI 的版本号(claude/gemini/codex)。
|
|
57
62
|
* 失败返回 null(命令不存在或执行失败)。
|
|
@@ -61,8 +66,8 @@ function getBaseagentVersion(cmd) {
|
|
|
61
66
|
}
|
|
62
67
|
const allEfforts = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
63
68
|
const PERMISSION_MODE_KEYS = PUBLIC_PERMISSION_MODES;
|
|
64
|
-
/** menu file: fetch 文件大小上限(与 /file 一致) */
|
|
65
|
-
const FILE_FETCH_MAX_SIZE =
|
|
69
|
+
/** menu file: fetch 文件大小上限(与 /file 和 AUN sendFile 一致) */
|
|
70
|
+
const FILE_FETCH_MAX_SIZE = MAX_AUN_ATTACHMENT_SIZE;
|
|
66
71
|
/** menu file: query 的 sha256 仅对 ≤ 2 MB 文件计算,超过返回 null(见设计文档 §7 决策 2) */
|
|
67
72
|
const FILE_HASH_MAX_SIZE = 2 * 1024 * 1024;
|
|
68
73
|
const FILE_LIST_DEFAULT_LIMIT = 500;
|
|
@@ -183,12 +188,31 @@ function resolveCapabilityTarget(params) {
|
|
|
183
188
|
function getRenameName(args) {
|
|
184
189
|
return (args?.name ?? args?.title ?? args?.value ?? '').toString().trim();
|
|
185
190
|
}
|
|
191
|
+
export function buildTopicForkSourcePayload(session) {
|
|
192
|
+
const source = session.metadata?.forkSource;
|
|
193
|
+
if (!source)
|
|
194
|
+
return undefined;
|
|
195
|
+
return {
|
|
196
|
+
sourceThreadId: source.threadId,
|
|
197
|
+
sourceAssistantMessageId: source.assistantMessageId,
|
|
198
|
+
sourceTurn: source.turn,
|
|
199
|
+
createdAt: source.createdAt,
|
|
200
|
+
historyVersion: source.historyVersion ?? null,
|
|
201
|
+
historyCount: source.historyCount ?? null,
|
|
202
|
+
historyDigest: source.historyDigest ?? null,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
186
205
|
function buildSessionPayload(session, name) {
|
|
187
206
|
const payload = { id: session.id, name };
|
|
188
|
-
if (session.
|
|
189
|
-
payload.
|
|
207
|
+
if (session.label)
|
|
208
|
+
payload.label = session.label;
|
|
209
|
+
if (session.threadId)
|
|
210
|
+
payload.topicStatus = session.topicStatus ?? 'pending';
|
|
190
211
|
if (session.agentSessionId)
|
|
191
212
|
payload.agentSessionId = session.agentSessionId;
|
|
213
|
+
const forkSource = buildTopicForkSourcePayload(session);
|
|
214
|
+
if (forkSource)
|
|
215
|
+
payload.forkSource = forkSource;
|
|
192
216
|
return payload;
|
|
193
217
|
}
|
|
194
218
|
async function findMainSessionTarget(sessionManager, channel, channelId, target, activeSession) {
|
|
@@ -388,6 +412,11 @@ async function getAvailableEfforts(agent, model) {
|
|
|
388
412
|
const baseagent = agent?.baseagent || agent?.name;
|
|
389
413
|
return (TRANSPORT_EFFORTS[baseagent] ?? []);
|
|
390
414
|
}
|
|
415
|
+
function isDaemonControlSubject(subject) {
|
|
416
|
+
return subject.isDaemonOwner === true
|
|
417
|
+
|| subject.processRole === 'daemon-owner'
|
|
418
|
+
|| subject.processRole === 'daemon-service';
|
|
419
|
+
}
|
|
391
420
|
function modelDisplayLabel(agent, model) {
|
|
392
421
|
const full = agent.resolveModelId?.(model);
|
|
393
422
|
return full && full !== model ? `${model} (${full})` : model;
|
|
@@ -641,7 +670,7 @@ function resolveMenuMentionModeTarget(params) {
|
|
|
641
670
|
function readMenuMentionMode(target, fallback = null, fallbackSource = null) {
|
|
642
671
|
try {
|
|
643
672
|
const resolved = resolveEffectiveFieldWithSource(target.fieldPath, target.sel, { cache: true });
|
|
644
|
-
if (resolved.value === 'disabled' || resolved.value === 'mention-only') {
|
|
673
|
+
if (resolved.value === 'disabled' || resolved.value === 'mention-only' || resolved.value === 'auto') {
|
|
645
674
|
return { value: resolved.value, source: toMenuSource(resolved.source) };
|
|
646
675
|
}
|
|
647
676
|
}
|
|
@@ -942,12 +971,14 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
942
971
|
return intent('model.effort.current', modelScope);
|
|
943
972
|
if (cmdBase === '/chatmode')
|
|
944
973
|
return intent('chatmode.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
945
|
-
if (cmdBase === '/
|
|
974
|
+
if (cmdBase === '/mention')
|
|
946
975
|
return intent('mentionmode.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
947
976
|
if (cmdBase === '/perm')
|
|
948
977
|
return intent('permission.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
949
978
|
if (cmdBase === '/activity')
|
|
950
979
|
return intent('activity.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
980
|
+
if (cmdBase === '/task')
|
|
981
|
+
return intent('task.activity.read', 'relation');
|
|
951
982
|
if (cmdBase === '/observable')
|
|
952
983
|
return intent('observable.current', 'agent');
|
|
953
984
|
if (cmdBase === '/capability')
|
|
@@ -962,7 +993,8 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
962
993
|
return intent(fromControlChannel && !args?.aid ? 'agent.list' : 'agent.show', fromControlChannel ? 'control' : 'agent');
|
|
963
994
|
}
|
|
964
995
|
if (cmdBase === '/trigger')
|
|
965
|
-
return intent('
|
|
996
|
+
return intent(args?.view === 'history' ? 'trigger.history'
|
|
997
|
+
: args?.view === 'detail' ? 'trigger.show' : 'trigger.list', 'relation');
|
|
966
998
|
}
|
|
967
999
|
if (verb === 'options') {
|
|
968
1000
|
if (cmdBase === '/system')
|
|
@@ -987,7 +1019,7 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
987
1019
|
return intent('model.effort.current', modelScope);
|
|
988
1020
|
if (cmdBase === '/chatmode')
|
|
989
1021
|
return intent('chatmode.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
990
|
-
if (cmdBase === '/
|
|
1022
|
+
if (cmdBase === '/mention')
|
|
991
1023
|
return intent('mentionmode.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
992
1024
|
if (cmdBase === '/activity')
|
|
993
1025
|
return intent('activity.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
@@ -1003,7 +1035,7 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
1003
1035
|
return intent('model.effort', modelScope, { effort: value });
|
|
1004
1036
|
if (cmdBase === '/chatmode')
|
|
1005
1037
|
return intent('chatmode.update', args?.scope === 'agent' ? 'agent' : 'relation', { value });
|
|
1006
|
-
if (cmdBase === '/
|
|
1038
|
+
if (cmdBase === '/mention')
|
|
1007
1039
|
return intent('mentionmode.update', args?.scope === 'agent' ? 'agent' : 'relation', { value });
|
|
1008
1040
|
if (cmdBase === '/activity')
|
|
1009
1041
|
return intent('activity.update', args?.scope === 'agent' ? 'agent' : 'relation', { value });
|
|
@@ -1141,7 +1173,12 @@ async function authorizeMenuIntent(params) {
|
|
|
1141
1173
|
}
|
|
1142
1174
|
const source = params.source ?? 'menu';
|
|
1143
1175
|
intent.source = source;
|
|
1144
|
-
const decision = await authorizeOperation({
|
|
1176
|
+
const decision = await authorizeOperation({
|
|
1177
|
+
source,
|
|
1178
|
+
intent,
|
|
1179
|
+
subject,
|
|
1180
|
+
auditMetadata: subject.auditMetadata,
|
|
1181
|
+
});
|
|
1145
1182
|
if (!decision.allow) {
|
|
1146
1183
|
logger.warn(`[MenuAuth] denied operation=${intent.operation} scope=${intent.scope} source=${source} selfAid=${subject.selfAid ?? '<none>'} actor=${subject.actorId ?? '<none>'} role=${subject.role} processRole=${subject.processRole} dataScope=${subject.dataScope} daemonOwner=${subject.isDaemonOwner} control=${subject.fromControlChannel} reason=${decision.reason}`);
|
|
1147
1184
|
if (intent.operation.startsWith('role.') || intent.operation.startsWith('connect.')) {
|
|
@@ -1430,7 +1467,7 @@ export function getMenuItems(role, chatType = 'private', scope = 'agent', authSu
|
|
|
1430
1467
|
{ value: 'interactive', label: '交互模式', desc: '仅在收到消息时响应' },
|
|
1431
1468
|
{ value: 'proactive', label: '主动模式', desc: 'Agent 可主动推进任务' },
|
|
1432
1469
|
] } }] : []),
|
|
1433
|
-
...(canSetMentionmode ? [{ cmd: '/
|
|
1470
|
+
...(canSetMentionmode ? [{ cmd: '/mention', label: '切换 @ 处理模式', desc: '控制群聊消息过滤(仅@提及或全部响应)', next: { type: 'select', items: [
|
|
1434
1471
|
{ value: 'mention-only', label: '@ 提及', desc: '仅在被 @ 提及时响应' },
|
|
1435
1472
|
{ value: 'disabled', label: '全部响应', desc: '响应群内所有消息' },
|
|
1436
1473
|
] } }] : []),
|
|
@@ -1495,6 +1532,26 @@ export function getMenuItems(role, chatType = 'private', scope = 'agent', authSu
|
|
|
1495
1532
|
]
|
|
1496
1533
|
});
|
|
1497
1534
|
}
|
|
1535
|
+
// 记忆管理(紧跟权限管理):条目与 evolhelp 同源,无参数的一点即执行,需要 slug 的弹输入框
|
|
1536
|
+
const memoryOwnerAid = authSubject?.selfAid
|
|
1537
|
+
? this?.agentRegistry?.get?.(authSubject.selfAid)?.config?.owners?.[0]
|
|
1538
|
+
: undefined;
|
|
1539
|
+
const memoryEntries = isControlScope ? [] : memoryHelpEntries({
|
|
1540
|
+
chatType: normalizedChatType,
|
|
1541
|
+
role,
|
|
1542
|
+
isAdmin,
|
|
1543
|
+
isOwnerSelf: isOwner && !!memoryOwnerAid && authSubject?.principalId === memoryOwnerAid,
|
|
1544
|
+
});
|
|
1545
|
+
if (memoryEntries.length > 0) {
|
|
1546
|
+
items.push({
|
|
1547
|
+
group: '记忆管理',
|
|
1548
|
+
commands: memoryEntries.map(e => ({
|
|
1549
|
+
cmd: e.command,
|
|
1550
|
+
label: e.description,
|
|
1551
|
+
...(e.args ? { args: e.args, next: { type: 'text' } } : {}),
|
|
1552
|
+
})),
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1498
1555
|
items.push({
|
|
1499
1556
|
group: isAdmin ? '运维' : '其他',
|
|
1500
1557
|
commands: [
|
|
@@ -1696,10 +1753,9 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1696
1753
|
const isAdmin = isManagementRole(role) || subject.isDaemonOwner || subject.processRole === 'daemon-service';
|
|
1697
1754
|
if (!triggerScheduler)
|
|
1698
1755
|
return [];
|
|
1699
|
-
const list = triggerScheduler.list({ all: scope === 'all' })
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
.map((definition) => {
|
|
1756
|
+
const list = triggerScheduler.list({ all: scope === 'all' })
|
|
1757
|
+
.filter((definition) => this.canAccessTriggerDefinition(definition, userId ?? '', channel, isAdmin));
|
|
1758
|
+
return list.map((definition) => {
|
|
1703
1759
|
const view = this.definitionToTriggerView(definition, triggerScheduler);
|
|
1704
1760
|
return {
|
|
1705
1761
|
...view,
|
|
@@ -1723,7 +1779,7 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1723
1779
|
const agent = this.getAgent(channel, source.baseagent);
|
|
1724
1780
|
if (!agent.capabilities?.forkAtTurn || !agent.getSessionMessages || !agent.forkSessionAt)
|
|
1725
1781
|
return [];
|
|
1726
|
-
const turns =
|
|
1782
|
+
const turns = buildTranscriptTurns(await agent.getSessionMessages(source.agentSessionId, source.projectPath));
|
|
1727
1783
|
return turns.map((turn) => ({
|
|
1728
1784
|
value: turn.assistantUuid,
|
|
1729
1785
|
label: `#${turn.index} ${turn.userContent}`,
|
|
@@ -1734,13 +1790,17 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1734
1790
|
userMessageId: turn.userUuid,
|
|
1735
1791
|
userTextHash: turn.userTextHash,
|
|
1736
1792
|
assistantTextHashes: turn.assistantTextHashes,
|
|
1793
|
+
assistantTextAnchors: turn.assistantTextAnchors,
|
|
1794
|
+
toolResultAnchors: turn.toolResultAnchors,
|
|
1795
|
+
forkAtMessage: agent.capabilities.forkAtMessage === true,
|
|
1796
|
+
forkHistoryVersion: 1,
|
|
1737
1797
|
}));
|
|
1738
1798
|
}
|
|
1739
|
-
const
|
|
1740
|
-
let
|
|
1741
|
-
if (
|
|
1799
|
+
const hasLabel = args && (Object.hasOwn(args, 'label') || Object.hasOwn(args, 'lable'));
|
|
1800
|
+
let label;
|
|
1801
|
+
if (hasLabel) {
|
|
1742
1802
|
try {
|
|
1743
|
-
|
|
1803
|
+
label = normalizeTopicLabel(Object.hasOwn(args, 'label') ? args.label : args.lable);
|
|
1744
1804
|
}
|
|
1745
1805
|
catch (error) {
|
|
1746
1806
|
throw { code: 'INVALID_ARGS', message: error.message };
|
|
@@ -1748,15 +1808,23 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1748
1808
|
}
|
|
1749
1809
|
let archiveFilter;
|
|
1750
1810
|
try {
|
|
1751
|
-
|
|
1752
|
-
archiveFilter = resolveTopicArchiveFilter(archived);
|
|
1811
|
+
archiveFilter = resolveTopicArchiveFilter(args?.archived === undefined && args?.topicStatus === 'archived' ? true : args?.archived);
|
|
1753
1812
|
}
|
|
1754
1813
|
catch (error) {
|
|
1755
1814
|
throw { code: 'INVALID_ARGS', message: error.message };
|
|
1756
1815
|
}
|
|
1757
1816
|
const sessions = await this.sessionManager.listSessions(channel, channelId, { archiveFilter });
|
|
1817
|
+
let topicStatus;
|
|
1818
|
+
if (args?.topicStatus !== undefined) {
|
|
1819
|
+
try {
|
|
1820
|
+
topicStatus = normalizeTopicStatus(args.topicStatus);
|
|
1821
|
+
}
|
|
1822
|
+
catch (error) {
|
|
1823
|
+
throw { code: 'INVALID_ARGS', message: error.message };
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1758
1826
|
return sessions
|
|
1759
|
-
.filter((s) => !!s.threadId && (!
|
|
1827
|
+
.filter((s) => !!s.threadId && (!hasLabel || s.label === label) && (!topicStatus || s.topicStatus === topicStatus))
|
|
1760
1828
|
.map((s) => this.buildTopicMenuItem(s));
|
|
1761
1829
|
}
|
|
1762
1830
|
if (cmd === '/s' || cmd === '/session' || cmd === '/del') {
|
|
@@ -1827,7 +1895,7 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1827
1895
|
agent = this.getAgent(channel, target.baseagent);
|
|
1828
1896
|
}
|
|
1829
1897
|
catch (error) {
|
|
1830
|
-
if (subject
|
|
1898
|
+
if (isDaemonControlSubject(subject)) {
|
|
1831
1899
|
return [{ value: target.baseagent, label: target.baseagent, selected: true }];
|
|
1832
1900
|
}
|
|
1833
1901
|
throw error;
|
|
@@ -1898,7 +1966,7 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1898
1966
|
agent = this.getAgent(channel, target.baseagent);
|
|
1899
1967
|
}
|
|
1900
1968
|
catch (error) {
|
|
1901
|
-
if (subject
|
|
1969
|
+
if (isDaemonControlSubject(subject)) {
|
|
1902
1970
|
return ['low', 'medium', 'high', 'auto'].map(e => ({ value: e, label: e === 'auto' ? 'auto (SDK默认)' : e }));
|
|
1903
1971
|
}
|
|
1904
1972
|
throw error;
|
|
@@ -1930,7 +1998,7 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1930
1998
|
{ value: 'proactive', label: '主动模式', selected: currentMode === 'proactive' },
|
|
1931
1999
|
];
|
|
1932
2000
|
}
|
|
1933
|
-
if (cmd === '/
|
|
2001
|
+
if (cmd === '/mention') {
|
|
1934
2002
|
const target = resolveMenuMentionModeTarget.call(this, {
|
|
1935
2003
|
args,
|
|
1936
2004
|
session,
|
|
@@ -1948,6 +2016,7 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1948
2016
|
return [
|
|
1949
2017
|
{ value: 'mention-only', label: '@提及时响应', selected: currentMode === 'mention-only' },
|
|
1950
2018
|
{ value: 'disabled', label: '所有消息响应', selected: currentMode === 'disabled' },
|
|
2019
|
+
{ value: 'auto', label: '根据上下文自动判断', selected: currentMode === 'auto' },
|
|
1951
2020
|
];
|
|
1952
2021
|
}
|
|
1953
2022
|
if (cmd === '/perm') {
|
|
@@ -2061,6 +2130,59 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2061
2130
|
explicitChatType, channel, channelId, userId, fromControlChannel, source,
|
|
2062
2131
|
});
|
|
2063
2132
|
}
|
|
2133
|
+
if (cmdBase === '/task') {
|
|
2134
|
+
const invalid = validateTaskActivityQueryArgs(args);
|
|
2135
|
+
if (invalid)
|
|
2136
|
+
return { error: invalid.message, code: invalid.code };
|
|
2137
|
+
if (fromControlChannel || !session || !subject.selfAid || !subject.actorId || !subject.allowAccess) {
|
|
2138
|
+
return { error: 'Task is not available in this session', code: 'FORBIDDEN' };
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
let boundSubject = subject;
|
|
2142
|
+
if (session.chatType === 'group') {
|
|
2143
|
+
const groupId = session.metadata?.groupId || session.channelId;
|
|
2144
|
+
const context = await resolveMenuCatalogContext({
|
|
2145
|
+
subject,
|
|
2146
|
+
channelType: subject.channelType || channel.split('#')[0],
|
|
2147
|
+
channelScope: 'agent',
|
|
2148
|
+
channelId,
|
|
2149
|
+
request: { kind: 'group_relation', groupId },
|
|
2150
|
+
});
|
|
2151
|
+
if (context.groupId !== groupId)
|
|
2152
|
+
return { error: 'Task is not available in this group', code: 'FORBIDDEN' };
|
|
2153
|
+
boundSubject = context.subject;
|
|
2154
|
+
}
|
|
2155
|
+
const authDenied = await authorizeMenuIntent.call(this, {
|
|
2156
|
+
intent: buildMenuIntent('query', cmdBase, args, undefined, undefined, false),
|
|
2157
|
+
identity, subject: boundSubject, session, explicitChatType, channel, channelId,
|
|
2158
|
+
userId, fromControlChannel, source,
|
|
2159
|
+
});
|
|
2160
|
+
if (authDenied)
|
|
2161
|
+
return authDenied;
|
|
2162
|
+
const store = new TaskActivityStore(subject.selfAid);
|
|
2163
|
+
const meta = store.getMeta(args.taskId);
|
|
2164
|
+
if (!meta)
|
|
2165
|
+
return { error: 'Task not found', code: 'NOT_FOUND' };
|
|
2166
|
+
const groupId = session.metadata?.groupId || session.channelId;
|
|
2167
|
+
if (meta.selfAid !== subject.selfAid || meta.sessionId !== session.id
|
|
2168
|
+
|| meta.channel !== (subject.channelType || channel.split('#')[0])
|
|
2169
|
+
|| meta.chatType !== session.chatType
|
|
2170
|
+
|| (meta.chatType === 'group'
|
|
2171
|
+
? meta.groupId !== groupId || meta.channelId !== groupId
|
|
2172
|
+
: meta.peerId !== subject.actorId || meta.channelId !== subject.actorId)) {
|
|
2173
|
+
return { error: 'Task is not available in this session', code: 'FORBIDDEN' };
|
|
2174
|
+
}
|
|
2175
|
+
return { data: args.view === 'activities'
|
|
2176
|
+
? store.readList(args.taskId, args.offset ?? 0, args.limit ?? 50)
|
|
2177
|
+
: store.readDetail(args.taskId, args.activityId) };
|
|
2178
|
+
}
|
|
2179
|
+
catch (error) {
|
|
2180
|
+
if (error?.code === 'INVALID_CONTEXT') {
|
|
2181
|
+
return { error: 'Task is not available in this group', code: 'FORBIDDEN' };
|
|
2182
|
+
}
|
|
2183
|
+
return menuResultFailure(error);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2064
2186
|
const authDenied = await authorizeMenuIntent.call(this, {
|
|
2065
2187
|
intent: buildMenuIntent('query', cmdBase, args, undefined, undefined, fromControlChannel),
|
|
2066
2188
|
identity,
|
|
@@ -2075,6 +2197,40 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2075
2197
|
});
|
|
2076
2198
|
if (authDenied)
|
|
2077
2199
|
return authDenied;
|
|
2200
|
+
if (cmdBase === '/trigger') {
|
|
2201
|
+
if (args?.view !== 'detail' && args?.view !== 'history') {
|
|
2202
|
+
return { error: 'Unsupported trigger query view', code: 'INVALID_ARGS' };
|
|
2203
|
+
}
|
|
2204
|
+
const triggerId = args?.triggerId;
|
|
2205
|
+
if (typeof triggerId !== 'string' || !triggerId.trim()) {
|
|
2206
|
+
return { error: 'triggerId is required', code: 'INVALID_ARGS' };
|
|
2207
|
+
}
|
|
2208
|
+
const limit = args?.limit ?? 50;
|
|
2209
|
+
if (args.view === 'history' && (!Number.isInteger(limit) || limit < 1 || limit > 200)) {
|
|
2210
|
+
return { error: 'limit must be between 1 and 200', code: 'INVALID_ARGS' };
|
|
2211
|
+
}
|
|
2212
|
+
const scheduler = this.getTriggerSchedulerForChannel?.(channel);
|
|
2213
|
+
if (!scheduler)
|
|
2214
|
+
return { error: 'Trigger is unavailable', code: 'NOT_SUPPORTED' };
|
|
2215
|
+
const role = identity.role;
|
|
2216
|
+
const isAdmin = isManagementRole(role) || subject.isDaemonOwner || subject.processRole === 'daemon-service';
|
|
2217
|
+
const definition = scheduler.list({ all: true }).find((item) => item.id === triggerId);
|
|
2218
|
+
if (!definition || !this.canAccessTriggerDefinition(definition, userId ?? '', channel, isAdmin)) {
|
|
2219
|
+
return { error: 'Trigger not found', code: 'NOT_FOUND' };
|
|
2220
|
+
}
|
|
2221
|
+
if (args.view === 'detail') {
|
|
2222
|
+
const details = scheduler.show(triggerId, { includeScriptPreview: false });
|
|
2223
|
+
return { data: {
|
|
2224
|
+
trigger: this.definitionToTriggerView(definition, scheduler),
|
|
2225
|
+
active: details.active,
|
|
2226
|
+
recentRuns: details.recentRuns,
|
|
2227
|
+
} };
|
|
2228
|
+
}
|
|
2229
|
+
return { data: {
|
|
2230
|
+
triggerId,
|
|
2231
|
+
runs: scheduler.recentRuns(triggerId, limit),
|
|
2232
|
+
} };
|
|
2233
|
+
}
|
|
2078
2234
|
if (cmdBase === '/agent-data-root') {
|
|
2079
2235
|
if (args && Object.keys(args).length > 0) {
|
|
2080
2236
|
return { error: 'agent-data-root does not accept args', code: 'INVALID_ARGUMENT' };
|
|
@@ -2271,6 +2427,69 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2271
2427
|
const topic = await this.sessionManager.getThreadSession(channel, channelId, target);
|
|
2272
2428
|
if (!topic)
|
|
2273
2429
|
return { error: '话题不存在', code: 'NOT_FOUND' };
|
|
2430
|
+
if (args?.view === 'fork-history') {
|
|
2431
|
+
const source = topic.metadata?.forkSource;
|
|
2432
|
+
if (topic.chatType !== 'private' || !source) {
|
|
2433
|
+
return { error: '该话题没有分叉历史', code: 'NOT_SUPPORTED' };
|
|
2434
|
+
}
|
|
2435
|
+
const limit = args?.limit === undefined ? 20 : args.limit;
|
|
2436
|
+
const before = args?.before;
|
|
2437
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 20
|
|
2438
|
+
|| (before !== undefined && (!Number.isInteger(before) || before < 1))) {
|
|
2439
|
+
return { error: '分叉历史分页参数无效', code: 'INVALID_ARGUMENT' };
|
|
2440
|
+
}
|
|
2441
|
+
try {
|
|
2442
|
+
let current = topic;
|
|
2443
|
+
let snapshot = this.sessionManager.readForkHistory(current);
|
|
2444
|
+
if (!snapshot) {
|
|
2445
|
+
const recovered = await this.sessionManager.attachForkHistory(topic.id);
|
|
2446
|
+
if (recovered) {
|
|
2447
|
+
current = recovered;
|
|
2448
|
+
snapshot = this.sessionManager.readForkHistory(current);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
if (!snapshot) {
|
|
2452
|
+
const candidate = async (session) => {
|
|
2453
|
+
if (!session?.agentSessionId || session.channel !== channel || session.channelId !== channelId)
|
|
2454
|
+
return undefined;
|
|
2455
|
+
const agent = this.getAgent(channel, session.baseagent);
|
|
2456
|
+
if (!agent.getSessionMessages)
|
|
2457
|
+
return undefined;
|
|
2458
|
+
try {
|
|
2459
|
+
return buildForkHistorySnapshot(await agent.getSessionMessages(session.agentSessionId, session.projectPath), source.assistantMessageId);
|
|
2460
|
+
}
|
|
2461
|
+
catch {
|
|
2462
|
+
return undefined;
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
const projected = await candidate(topic)
|
|
2466
|
+
?? await candidate(await this.sessionManager.getSessionById(source.sessionId));
|
|
2467
|
+
if (!projected)
|
|
2468
|
+
return { error: '无法从现有会话恢复分叉历史', code: 'INVALID_STATE' };
|
|
2469
|
+
current = await this.sessionManager.attachForkHistory(topic.id, projected) ?? topic;
|
|
2470
|
+
snapshot = this.sessionManager.readForkHistory(current);
|
|
2471
|
+
}
|
|
2472
|
+
if (!snapshot)
|
|
2473
|
+
return { error: '分叉历史未持久化', code: 'INVALID_STATE' };
|
|
2474
|
+
if (before !== undefined && before > snapshot.items.length) {
|
|
2475
|
+
return { error: '分叉历史分页游标无效', code: 'INVALID_ARGUMENT' };
|
|
2476
|
+
}
|
|
2477
|
+
const page = pageForkHistory(snapshot, before, limit);
|
|
2478
|
+
const forkSource = current.metadata?.forkSource;
|
|
2479
|
+
return { data: {
|
|
2480
|
+
threadId: current.threadId,
|
|
2481
|
+
sourceAssistantMessageId: source.assistantMessageId,
|
|
2482
|
+
historyVersion: 1,
|
|
2483
|
+
historyDigest: forkSource?.historyDigest,
|
|
2484
|
+
createdAt: source.createdAt,
|
|
2485
|
+
...page,
|
|
2486
|
+
} };
|
|
2487
|
+
}
|
|
2488
|
+
catch (error) {
|
|
2489
|
+
logger.warn(`[MenuHandler] Fork history read failed: ${error}`);
|
|
2490
|
+
return { error: '分叉历史读取失败,请稍后重试', code: 'INVALID_STATE' };
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2274
2493
|
if (args?.view === 'subtasks') {
|
|
2275
2494
|
return { data: { scope: 'retained-history', tasks: this.sessionManager.getRunnerTaskHistory(topic.id) } };
|
|
2276
2495
|
}
|
|
@@ -2292,7 +2511,8 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2292
2511
|
const data = {
|
|
2293
2512
|
threadId: topic.threadId,
|
|
2294
2513
|
name: topic.name || null,
|
|
2295
|
-
|
|
2514
|
+
label: topic.label || null,
|
|
2515
|
+
topicStatus: topic.topicStatus ?? 'pending',
|
|
2296
2516
|
agentSessionId: topic.agentSessionId || null,
|
|
2297
2517
|
status: isProcessing ? 'processing' : 'idle',
|
|
2298
2518
|
createdAt: topic.createdAt,
|
|
@@ -2414,7 +2634,7 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2414
2634
|
},
|
|
2415
2635
|
};
|
|
2416
2636
|
}
|
|
2417
|
-
if (cmdBase === '/
|
|
2637
|
+
if (cmdBase === '/mention') {
|
|
2418
2638
|
const chatType = session?.chatType ?? explicitChatType ?? 'private';
|
|
2419
2639
|
if (chatType !== 'group') {
|
|
2420
2640
|
return { error: 'mentionMode 仅在群聊会话中有效', code: 'NOT_APPLICABLE' };
|
|
@@ -3085,8 +3305,8 @@ export async function execMenuUpdate(cmd, value, channel, channelId, userId, ove
|
|
|
3085
3305
|
},
|
|
3086
3306
|
};
|
|
3087
3307
|
}
|
|
3088
|
-
if (cmdBase === '/
|
|
3089
|
-
if (arg !== 'mention-only' && arg !== 'disabled' && arg !== 'clear') {
|
|
3308
|
+
if (cmdBase === '/mention') {
|
|
3309
|
+
if (arg !== 'mention-only' && arg !== 'disabled' && arg !== 'auto' && arg !== 'clear') {
|
|
3090
3310
|
return { error: `无效模式: ${arg}`, code: 'INVALID_VALUE' };
|
|
3091
3311
|
}
|
|
3092
3312
|
const chatType = session?.chatType;
|
|
@@ -3520,8 +3740,6 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3520
3740
|
if (!trigger)
|
|
3521
3741
|
return { error: '触发器不存在或无权限', code: 'NOT_FOUND' };
|
|
3522
3742
|
if (action === 'enable' && trigger.execution.permissionMode === 'fullaccess') {
|
|
3523
|
-
if (!isFullAccessEnabled())
|
|
3524
|
-
return { error: 'fullaccess 功能未启用', code: 'NOT_SUPPORTED' };
|
|
3525
3743
|
if (!subject.isDaemonOwner && subject.processRole !== 'daemon-service')
|
|
3526
3744
|
return { error: '只有 daemon-owner 可以启用 fullaccess Trigger', code: 'FORBIDDEN' };
|
|
3527
3745
|
if (subject.canApprovePersistentFullAccess === false) {
|
|
@@ -3618,11 +3836,11 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3618
3836
|
return { error: `不支持的 trigger action: ${action}`, code: 'INVALID_ARGS' };
|
|
3619
3837
|
}
|
|
3620
3838
|
if (cmdBase === '/topic') {
|
|
3621
|
-
const
|
|
3622
|
-
let
|
|
3623
|
-
if (
|
|
3839
|
+
const hasLabel = args && (Object.hasOwn(args, 'label') || Object.hasOwn(args, 'lable'));
|
|
3840
|
+
let label;
|
|
3841
|
+
if (hasLabel && (action === 'fork' || action === 'label')) {
|
|
3624
3842
|
try {
|
|
3625
|
-
|
|
3843
|
+
label = normalizeTopicLabel(Object.hasOwn(args, 'label') ? args.label : args.lable);
|
|
3626
3844
|
}
|
|
3627
3845
|
catch (error) {
|
|
3628
3846
|
return { error: error.message, code: 'INVALID_ARGS' };
|
|
@@ -3651,7 +3869,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3651
3869
|
: null;
|
|
3652
3870
|
if (requestId
|
|
3653
3871
|
&& forkSource?.requestId === requestId
|
|
3654
|
-
&& forkSource.assistantMessageId === sourceAssistantMessageId
|
|
3872
|
+
&& (forkSource.requestedAssistantMessageId ?? forkSource.assistantMessageId) === sourceAssistantMessageId
|
|
3655
3873
|
&& forkSource.threadId === requestedSourceThreadId) {
|
|
3656
3874
|
return {
|
|
3657
3875
|
data: {
|
|
@@ -3703,25 +3921,33 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3703
3921
|
try {
|
|
3704
3922
|
const executeFork = async (current, currentAgent) => {
|
|
3705
3923
|
const messages = await currentAgent.getSessionMessages(current.agentSessionId, current.projectPath);
|
|
3706
|
-
const turns =
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
if (
|
|
3711
|
-
return { error: '
|
|
3712
|
-
const
|
|
3924
|
+
const turns = buildTranscriptTurns(messages);
|
|
3925
|
+
const matchingTurns = turns.filter(turn => turn.userUuid === sourceAssistantMessageId
|
|
3926
|
+
|| turn.assistantUuids?.includes(sourceAssistantMessageId)
|
|
3927
|
+
|| turn.toolResultAnchors.some(anchor => anchor.messageId === sourceAssistantMessageId));
|
|
3928
|
+
if (matchingTurns.length !== 1)
|
|
3929
|
+
return { error: '分叉点已失效或无法唯一定位,请刷新历史后重试', code: 'NOT_FOUND' };
|
|
3930
|
+
const forkTurn = matchingTurns[0];
|
|
3931
|
+
if (!currentAgent.capabilities?.forkAtMessage
|
|
3932
|
+
&& sourceAssistantMessageId !== forkTurn.assistantUuid) {
|
|
3933
|
+
return { error: '当前 Agent 无法在所选消息处精确分叉', code: 'NOT_SUPPORTED' };
|
|
3934
|
+
}
|
|
3935
|
+
const actualSourceMessageId = sourceAssistantMessageId;
|
|
3936
|
+
const historySnapshot = buildForkHistorySnapshot(messages, actualSourceMessageId);
|
|
3937
|
+
const forkedAgentSessionId = await currentAgent.forkSessionAt(current.agentSessionId, current.projectPath, actualSourceMessageId, name || undefined, { sessionId: current.id, permissionMode: subject.permissionMode, role: subject.role });
|
|
3713
3938
|
const topic = await this.sessionManager.createForkedThreadSession(current, forkedAgentSessionId, targetThreadId, {
|
|
3714
3939
|
name: name || undefined,
|
|
3715
|
-
...(
|
|
3940
|
+
...(hasLabel ? { label: label ?? null } : {}),
|
|
3716
3941
|
creatorPeerId: userId,
|
|
3717
|
-
sourceAssistantMessageId:
|
|
3942
|
+
sourceAssistantMessageId: actualSourceMessageId,
|
|
3718
3943
|
sourceTurn: forkTurn.index,
|
|
3944
|
+
historySnapshot,
|
|
3719
3945
|
requestId,
|
|
3720
3946
|
});
|
|
3721
3947
|
await currentAgent.updateSessionMetadata?.(forkedAgentSessionId, {
|
|
3722
3948
|
evolcoreSessionId: topic.id,
|
|
3723
3949
|
sourceSessionId: current.id,
|
|
3724
|
-
sourceAssistantMessageId:
|
|
3950
|
+
sourceAssistantMessageId: actualSourceMessageId,
|
|
3725
3951
|
sourceTurn: forkTurn.index,
|
|
3726
3952
|
}).catch((error) => {
|
|
3727
3953
|
logger.debug(`[MenuHandler] Topic fork metadata sync failed: ${error}`);
|
|
@@ -3732,7 +3958,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3732
3958
|
sourceSessionId: current.id,
|
|
3733
3959
|
name: topic.name,
|
|
3734
3960
|
threadId: topic.threadId,
|
|
3735
|
-
sourceAssistantMessageId:
|
|
3961
|
+
sourceAssistantMessageId: actualSourceMessageId,
|
|
3736
3962
|
sourceTurn: forkTurn.index,
|
|
3737
3963
|
});
|
|
3738
3964
|
return {
|
|
@@ -3744,7 +3970,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3744
3970
|
threadId: topic.threadId,
|
|
3745
3971
|
sourceSessionId: current.id,
|
|
3746
3972
|
sourceThreadId: current.threadId || null,
|
|
3747
|
-
sourceAssistantMessageId:
|
|
3973
|
+
sourceAssistantMessageId: actualSourceMessageId,
|
|
3748
3974
|
sourceTurn: forkTurn.index,
|
|
3749
3975
|
},
|
|
3750
3976
|
},
|
|
@@ -3833,7 +4059,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3833
4059
|
topicForkTargetsInFlight.delete(targetKey);
|
|
3834
4060
|
}
|
|
3835
4061
|
}
|
|
3836
|
-
if (action !== 'delete' && action !== 'rename' && action !== 'label') {
|
|
4062
|
+
if (action !== 'delete' && action !== 'rename' && action !== 'label' && action !== 'status') {
|
|
3837
4063
|
return { error: `不支持的 topic action: ${action}`, code: 'NOT_SUPPORTED' };
|
|
3838
4064
|
}
|
|
3839
4065
|
const target = (args?.target ?? '').toString().trim();
|
|
@@ -3842,8 +4068,17 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3842
4068
|
const renameName = action === 'rename' ? getRenameName(args) : '';
|
|
3843
4069
|
if (action === 'rename' && !renameName)
|
|
3844
4070
|
return { error: '缺少 args.name', code: 'MISSING_VALUE' };
|
|
3845
|
-
if (action === 'label' && !
|
|
3846
|
-
return { error: '缺少 args.
|
|
4071
|
+
if (action === 'label' && !hasLabel)
|
|
4072
|
+
return { error: '缺少 args.label', code: 'MISSING_VALUE' };
|
|
4073
|
+
let topicStatus;
|
|
4074
|
+
if (action === 'status') {
|
|
4075
|
+
try {
|
|
4076
|
+
topicStatus = normalizeTopicStatus(args?.topicStatus);
|
|
4077
|
+
}
|
|
4078
|
+
catch (error) {
|
|
4079
|
+
return { error: error.message, code: 'INVALID_ARGS' };
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
3847
4082
|
const topic = await this.sessionManager.getThreadSession(channel, channelId, target);
|
|
3848
4083
|
if (!topic)
|
|
3849
4084
|
return { error: '话题不存在', code: 'NOT_FOUND' };
|
|
@@ -3853,19 +4088,25 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3853
4088
|
? 'private'
|
|
3854
4089
|
: this.resolveMenuChatType(channel, channelId, explicitChatType);
|
|
3855
4090
|
if (!this.canDeleteTopic(identity.role, chatType, topic, userId)) {
|
|
3856
|
-
return { error: action === 'label' ? '无权限修改话题分类' : action === 'rename' ? '无权限重命名话题' : '无权限删除话题', code: 'FORBIDDEN' };
|
|
4091
|
+
return { error: action === 'label' ? '无权限修改话题分类' : action === 'status' ? '无权限修改话题状态' : action === 'rename' ? '无权限重命名话题' : '无权限删除话题', code: 'FORBIDDEN' };
|
|
3857
4092
|
}
|
|
3858
4093
|
if (action === 'label') {
|
|
3859
|
-
const success = await this.sessionManager.
|
|
4094
|
+
const success = await this.sessionManager.setTopicLabel(topic.id, label ?? null);
|
|
3860
4095
|
if (!success)
|
|
3861
4096
|
return { error: '话题不存在', code: 'NOT_FOUND' };
|
|
3862
4097
|
return {
|
|
3863
4098
|
data: {
|
|
3864
4099
|
action: 'label', success: true,
|
|
3865
|
-
topic: { ...buildSessionPayload(topic, topic.name || ''), threadId: topic.threadId,
|
|
4100
|
+
topic: { ...buildSessionPayload(topic, topic.name || ''), threadId: topic.threadId, label: label ?? null },
|
|
3866
4101
|
},
|
|
3867
4102
|
};
|
|
3868
4103
|
}
|
|
4104
|
+
if (action === 'status') {
|
|
4105
|
+
const success = await this.sessionManager.setTopicStatus(topic.id, topicStatus);
|
|
4106
|
+
if (!success)
|
|
4107
|
+
return { error: '话题不存在', code: 'NOT_FOUND' };
|
|
4108
|
+
return { data: { action: 'status', success: true, topic: { ...buildSessionPayload(topic, topic.name || ''), threadId: topic.threadId, topicStatus } } };
|
|
4109
|
+
}
|
|
3869
4110
|
if (action === 'rename') {
|
|
3870
4111
|
const newName = renameName;
|
|
3871
4112
|
const existing = await this.sessionManager.getSessionByName?.(channel, channelId, newName);
|
|
@@ -4115,27 +4356,23 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
4115
4356
|
}
|
|
4116
4357
|
if (action === 'upgrade') {
|
|
4117
4358
|
const devMode = isLinkedInstall();
|
|
4118
|
-
const
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
checkLatestVersion(WEB_PACKAGE_NAME),
|
|
4130
|
-
]);
|
|
4131
|
-
const cmp = (local, remote) => !!(local && remote && compareVersions(local, remote) < 0);
|
|
4359
|
+
const results = await refreshManagedPackageVersions(VERSION_INFO_PACKAGES, { source: 'menu-upgrade' });
|
|
4360
|
+
const [evolcore, fastaunWeb, web] = [results[0], results[2], results[1]];
|
|
4361
|
+
const item = (result) => ({
|
|
4362
|
+
local: result.entry.currentVersion,
|
|
4363
|
+
remote: result.status === 'ok' ? result.entry.latestVersion ?? null : null,
|
|
4364
|
+
hasUpdate: result.status === 'ok' && result.hasUpdate,
|
|
4365
|
+
status: result.status,
|
|
4366
|
+
checkedAt: result.status === 'ok' ? result.entry.checkedAt ?? null : null,
|
|
4367
|
+
lastCheckedAt: result.entry.checkedAt ?? null,
|
|
4368
|
+
...(result.error ? { error: result.error } : {}),
|
|
4369
|
+
});
|
|
4132
4370
|
return {
|
|
4133
4371
|
data: {
|
|
4134
4372
|
devMode,
|
|
4135
|
-
evolcore:
|
|
4136
|
-
fastaun: {
|
|
4137
|
-
|
|
4138
|
-
ecweb: { remote: ecwebRemote },
|
|
4373
|
+
evolcore: item(evolcore),
|
|
4374
|
+
fastaun: { ...item(fastaunWeb), managedBy: 'evolcore' },
|
|
4375
|
+
ecweb: item(web),
|
|
4139
4376
|
},
|
|
4140
4377
|
};
|
|
4141
4378
|
}
|
|
@@ -4516,6 +4753,14 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
4516
4753
|
ecwebManagement: context.source === 'ecweb',
|
|
4517
4754
|
canApprovePersistentFullAccess: context.canApprovePersistentFullAccess,
|
|
4518
4755
|
trustedProcessRole: context.source === 'ecweb' ? 'daemon-owner' : undefined,
|
|
4756
|
+
auditMetadata: context.source === 'ecweb'
|
|
4757
|
+
? {
|
|
4758
|
+
ecwebRequestId: context.ecwebRequestId,
|
|
4759
|
+
targetAgentAid: targetAid,
|
|
4760
|
+
endpoint: context.endpoint,
|
|
4761
|
+
logicalToolName: context.logicalToolName,
|
|
4762
|
+
}
|
|
4763
|
+
: undefined,
|
|
4519
4764
|
});
|
|
4520
4765
|
const trustedIdentity = trustedSubject.identity;
|
|
4521
4766
|
const cmd = name ? (menuCommandForName(name) ?? payload.cmd) : payload.cmd;
|
|
@@ -4663,6 +4908,10 @@ export async function execMenuForEcweb(payload, trusted) {
|
|
|
4663
4908
|
const userId = (trusted.actorAid && owners.includes(trusted.actorAid))
|
|
4664
4909
|
? trusted.actorAid
|
|
4665
4910
|
: owners[0] ?? (trusted.localDirect ? 'local-direct' : 'ecweb-remote');
|
|
4911
|
+
const ecwebRequestId = trusted.ecwebRequestId
|
|
4912
|
+
?? (id !== undefined && id !== null && String(id) ? String(id) : crypto.randomUUID());
|
|
4913
|
+
const logicalToolName = trusted.logicalToolName
|
|
4914
|
+
?? (typeof name === 'string' && name.trim() ? name.trim() : menuCommandToken(payload?.cmd) ?? payload?.type);
|
|
4666
4915
|
return execMenuForSystemControl.call(this, payload, {
|
|
4667
4916
|
source: 'ecweb',
|
|
4668
4917
|
actorAid: userId,
|
|
@@ -4674,6 +4923,9 @@ export async function execMenuForEcweb(payload, trusted) {
|
|
|
4674
4923
|
// approve persistent fullaccess without owner-bound token metadata.
|
|
4675
4924
|
canApprovePersistentFullAccess: true,
|
|
4676
4925
|
owners,
|
|
4926
|
+
ecwebRequestId,
|
|
4927
|
+
endpoint: trusted.endpoint ?? 'ECWeb menu.exec',
|
|
4928
|
+
logicalToolName,
|
|
4677
4929
|
});
|
|
4678
4930
|
}
|
|
4679
4931
|
/** Control AID entry: daemon-owner and valid ECWeb token modes share the same
|