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
|
@@ -15,6 +15,8 @@ import { sameGroupAid } from '../../aun/group/index.js';
|
|
|
15
15
|
import crypto from 'crypto';
|
|
16
16
|
import path from 'path';
|
|
17
17
|
import fs from 'fs';
|
|
18
|
+
import { parseDocument } from 'yaml';
|
|
19
|
+
import { agentmdGet } from '../../aun/aid/agentmd.js';
|
|
18
20
|
import { parseDuration, parseTriggerSet, parseTriggerUpdate } from '../../trigger/parser.js';
|
|
19
21
|
import { applyTriggerPatch, replaceEditableTriggerDefinition } from '../../trigger/patch.js';
|
|
20
22
|
import { definitionRevision } from '../../trigger/validation.js';
|
|
@@ -25,6 +27,8 @@ import { resolveConfigCommand } from '../../config/resolved-config-op.js';
|
|
|
25
27
|
import { AUTHENTICATED_CONFIG_ROLE_ENV, executeResolvedConfigCommandAsync } from '../../config/config-operation-service.js';
|
|
26
28
|
import { splitConfigBatchGetArgv } from '../../cli/cli-argv.js';
|
|
27
29
|
import { auditCommandAuthorization, auditFullAccessEvent, hashArgv } from '../auth/authorization-audit.js';
|
|
30
|
+
import { ResponseModeRegistry } from '../../response-system/registry.js';
|
|
31
|
+
import { registerBuiltinModes } from '../../response-system/modes/index.js';
|
|
28
32
|
import { executeResolvedContactCommand, resolveContactCommand } from '../../config/contact-operation-service.js';
|
|
29
33
|
import { hasTrustedFullAccessDelegation, trustedExecutionIdentityInput } from '../auth/agent-delegation.js';
|
|
30
34
|
import { executeManagedAidOperation, ManagedAidOperationError, managedAidShowViewForRole, resolveManagedAidOperation, } from '../../aun/aid/managed-operation.js';
|
|
@@ -41,6 +45,7 @@ import { handleSlashCommand } from './slash-handler.js';
|
|
|
41
45
|
import { resolveChatMode } from '../message/peer-mode.js';
|
|
42
46
|
import { execMenuAction as menuExecMenuAction, execMenuForEcweb as menuExecMenuForEcweb, execMenuForControl as menuExecMenuForControl, execMenuQuery as menuExecMenuQuery, execMenuUpdate as menuExecMenuUpdate, getMenuItems as menuGetMenuItems, getSubMenuItems as menuGetSubMenuItems, buildTopicForkSourcePayload, } from './menu-handler.js';
|
|
43
47
|
import { getMenuCatalog, execMenuValueBatch, validateMenuValueBatchArgs } from './menu-catalog.js';
|
|
48
|
+
import { resolveCurrentSessionLoopTarget } from '../session/session-idle-monitor.js';
|
|
44
49
|
export { isProcessLevelOwner } from './menu-handler.js';
|
|
45
50
|
const CLI_EXEC_TIMEOUT_MS = 15_000;
|
|
46
51
|
const CLI_EXEC_MAX_OUTPUT = 128 * 1024;
|
|
@@ -126,6 +131,8 @@ export class CommandHandler {
|
|
|
126
131
|
primaryRunnerKey;
|
|
127
132
|
agentRegistry;
|
|
128
133
|
memoryConsolidationLauncher;
|
|
134
|
+
/** /skill refresh 的 daemon 侧入口:重建指定 agent 的技能索引 */
|
|
135
|
+
skillIndexRefresher;
|
|
129
136
|
agentApplicationService;
|
|
130
137
|
triggerSchedulerResolver;
|
|
131
138
|
triggerSchedulerFallback;
|
|
@@ -141,9 +148,10 @@ export class CommandHandler {
|
|
|
141
148
|
diagService;
|
|
142
149
|
setDiagService(service) { this.diagService = service; }
|
|
143
150
|
async handleMenuClientOperation(argv, sessionId, delegationToken, delegationCommandHash, send) {
|
|
144
|
-
const validation = this.agentDelegationRegistry?.validate(delegationToken, sessionId, delegationCommandHash)
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
const validation = this.agentDelegationRegistry?.validate(delegationToken, sessionId, delegationCommandHash)
|
|
152
|
+
?? { ok: false, code: 'DELEGATION_REQUIRED', reason: 'Task delegation registry is not configured', diagnosticCause: 'missing_token' };
|
|
153
|
+
if (!validation.ok)
|
|
154
|
+
return { ok: false, code: validation.code ?? 'DELEGATION_REQUIRED', error: validation.reason ?? 'Task delegation is required' };
|
|
147
155
|
const grant = validation.grant;
|
|
148
156
|
const session = await this.sessionManager.getSessionById(sessionId);
|
|
149
157
|
if (!session || session.selfAID !== grant.selfAid || argv[0] !== 'request' || argv[1] !== grant.selfAid)
|
|
@@ -537,17 +545,21 @@ export class CommandHandler {
|
|
|
537
545
|
reason: input.reason,
|
|
538
546
|
});
|
|
539
547
|
}
|
|
540
|
-
triggerRoleContext(selfAid, channel, peerId, chatType) {
|
|
548
|
+
triggerRoleContext(selfAid, channel, peerId, chatType, conversationId) {
|
|
541
549
|
const owning = this.getOwningAgent(channel);
|
|
542
550
|
if (!owning || owning.aid !== selfAid)
|
|
543
551
|
return {};
|
|
552
|
+
const resolvedChatType = chatType === 'group' ? 'group' : 'private';
|
|
553
|
+
const resolvedConversationId = resolvedChatType === 'group'
|
|
554
|
+
? conversationId || peerId
|
|
555
|
+
: peerId;
|
|
544
556
|
const role = resolvePeerRoleDetail({
|
|
545
557
|
selfAid,
|
|
546
558
|
channelKey: channel,
|
|
547
559
|
channelType: this.resolveChannelType(channel),
|
|
548
|
-
chatType:
|
|
560
|
+
chatType: resolvedChatType,
|
|
549
561
|
actorId: peerId,
|
|
550
|
-
conversationId:
|
|
562
|
+
conversationId: resolvedConversationId,
|
|
551
563
|
}).effectiveRole;
|
|
552
564
|
return { role: role || 'none', baseagent: owning.baseagent };
|
|
553
565
|
}
|
|
@@ -592,12 +604,18 @@ export class CommandHandler {
|
|
|
592
604
|
const now = Date.now();
|
|
593
605
|
const id = `trig_${now}_${crypto.randomBytes(4).toString('hex')}`;
|
|
594
606
|
const name = parsed.name ?? `trigger-${now.toString(36)}`;
|
|
607
|
+
const originChatType = chatType === 'group' ? 'group' : 'private';
|
|
608
|
+
const originIsGroup = originChatType === 'group';
|
|
609
|
+
const originConversationId = originIsGroup ? channelId : peerId;
|
|
595
610
|
const feedbackChannel = parsed.targetChannel ?? channel;
|
|
611
|
+
const hasExplicitTarget = parsed.targetChannel !== undefined
|
|
612
|
+
|| parsed.targetChannelId !== undefined
|
|
613
|
+
|| parsed.targetChatType !== undefined;
|
|
596
614
|
if (parsed.targetChannel && !this.adapters.has(parsed.targetChannel)) {
|
|
597
615
|
return { error: `目标渠道不存在或未启用:${parsed.targetChannel}` };
|
|
598
616
|
}
|
|
599
617
|
const targetChannelType = this.resolveChannelType(feedbackChannel);
|
|
600
|
-
const feedbackChannelId = parsed.targetChannelId ??
|
|
618
|
+
const feedbackChannelId = parsed.targetChannelId ?? originConversationId;
|
|
601
619
|
const schedulerAid = parsed.agentId
|
|
602
620
|
?? this.getOwningAgent(feedbackChannel)?.aid
|
|
603
621
|
?? tryParseChannelKey(feedbackChannel)?.selfAID
|
|
@@ -609,19 +627,12 @@ export class CommandHandler {
|
|
|
609
627
|
if (targetChannelType === 'aun' && parsed.targetChannelId && !parsed.targetChatType) {
|
|
610
628
|
return { error: 'AUN 目标必须显式指定 --target-chat-type private 或 group' };
|
|
611
629
|
}
|
|
612
|
-
const targetDelivery = targetChannelType === 'aun'
|
|
613
|
-
? parsed.targetChatType === 'group'
|
|
614
|
-
? { chatType: 'group', groupId: feedbackChannelId }
|
|
615
|
-
: parsed.targetChatType === 'private'
|
|
616
|
-
? { chatType: 'private' }
|
|
617
|
-
: { chatType: 'private' }
|
|
618
|
-
: undefined;
|
|
619
630
|
const target = {
|
|
620
631
|
channelKey: feedbackChannel,
|
|
621
632
|
channelId: feedbackChannelId,
|
|
622
633
|
session: parsed.targetSession,
|
|
623
634
|
threadId: parsed.targetSession === 'thread' ? parsed.targetThreadId : undefined,
|
|
624
|
-
chatType:
|
|
635
|
+
chatType: parsed.targetChatType ?? (hasExplicitTarget ? undefined : originChatType),
|
|
625
636
|
};
|
|
626
637
|
if (target.session === 'thread') {
|
|
627
638
|
const adapter = this.adapters.get(feedbackChannel);
|
|
@@ -630,19 +641,20 @@ export class CommandHandler {
|
|
|
630
641
|
if (!target.threadId)
|
|
631
642
|
return { error: '--target-session thread 需要 --target-thread-id' };
|
|
632
643
|
}
|
|
633
|
-
const originIsGroup = chatType === 'group';
|
|
634
644
|
const activeSession = originIsGroup
|
|
635
645
|
? undefined
|
|
636
646
|
: this.sessionManager.getActiveSessionSync(channel, peerId, this.resolveChannelType(channel), schedulerAid);
|
|
637
647
|
const origin = {
|
|
638
648
|
channelKey: channel,
|
|
639
649
|
channelType: this.resolveChannelType(channel),
|
|
640
|
-
channelId:
|
|
641
|
-
session:
|
|
642
|
-
threadId
|
|
650
|
+
channelId: originConversationId,
|
|
651
|
+
session: threadId ? 'thread' : 'main',
|
|
652
|
+
threadId,
|
|
643
653
|
peerId,
|
|
644
654
|
sessionKey: activeSession?.sessionKey,
|
|
645
|
-
delivery:
|
|
655
|
+
delivery: originIsGroup
|
|
656
|
+
? { chatType: 'group', groupId: originConversationId }
|
|
657
|
+
: { chatType: 'private' },
|
|
646
658
|
};
|
|
647
659
|
if (!isAdmin && parsed.feedbackStrategy === 'target' && !sameFeedbackTarget(target, origin)) {
|
|
648
660
|
return { error: '无权限:非 admin 只能把 trigger 投递到来源会话' };
|
|
@@ -664,7 +676,7 @@ export class CommandHandler {
|
|
|
664
676
|
timeoutMs: parsed.scriptTimeoutMs ?? 30_000,
|
|
665
677
|
} : undefined;
|
|
666
678
|
const permissionMode = this.triggerPermissionFromParsed(parsed);
|
|
667
|
-
const triggerRole = this.triggerRoleContext(schedulerAid, channel, peerId,
|
|
679
|
+
const triggerRole = this.triggerRoleContext(schedulerAid, channel, peerId, originChatType, originConversationId);
|
|
668
680
|
const permissionError = this.validateTriggerPermissionModeForRole(permissionMode, isAdmin, triggerRole.role, schedulerAid, isDaemonOwner, canApprovePersistentFullAccess);
|
|
669
681
|
if (permissionError)
|
|
670
682
|
return { error: permissionError };
|
|
@@ -929,10 +941,21 @@ export class CommandHandler {
|
|
|
929
941
|
setStatsCollector(collector) {
|
|
930
942
|
this.statsCollector = collector;
|
|
931
943
|
}
|
|
932
|
-
/**
|
|
944
|
+
/**
|
|
945
|
+
* 注入记忆整理入口(daemon 的统一整理队列),供 /memory consolidate 使用。
|
|
946
|
+
* 已入队时返回带 queued 的占位结果;返回 null 表示拉起失败。
|
|
947
|
+
*/
|
|
933
948
|
setMemoryConsolidationLauncher(launcher) {
|
|
934
949
|
this.memoryConsolidationLauncher = launcher;
|
|
935
950
|
}
|
|
951
|
+
/** 注入 /skill refresh 的索引重建入口(daemon 启动时调用)。 */
|
|
952
|
+
setSkillIndexRefresher(refresher) {
|
|
953
|
+
this.skillIndexRefresher = refresher;
|
|
954
|
+
}
|
|
955
|
+
/** 供 slash-handler 读取。 */
|
|
956
|
+
getSkillIndexRefresher() {
|
|
957
|
+
return this.skillIndexRefresher;
|
|
958
|
+
}
|
|
936
959
|
registerAdapter(adapter) {
|
|
937
960
|
this.adapters.set(adapter.channelName, adapter);
|
|
938
961
|
}
|
|
@@ -1072,7 +1095,7 @@ export class CommandHandler {
|
|
|
1072
1095
|
getMenuItems(role, chatType = 'private', scope = 'agent', authSubject) {
|
|
1073
1096
|
return menuGetMenuItems.call(this, role, chatType, scope, authSubject);
|
|
1074
1097
|
}
|
|
1075
|
-
async getMenuCatalog(channel, channelId, subject, request, channelScope = 'agent', paircodeAllowed) {
|
|
1098
|
+
async getMenuCatalog(channel, channelId, subject, request, channelScope = 'agent', paircodeAllowed, transportReplyContext) {
|
|
1076
1099
|
return await getMenuCatalog({
|
|
1077
1100
|
subject,
|
|
1078
1101
|
channelType: this.resolveChannelType(channel),
|
|
@@ -1080,6 +1103,19 @@ export class CommandHandler {
|
|
|
1080
1103
|
channelId,
|
|
1081
1104
|
request,
|
|
1082
1105
|
...(paircodeAllowed === undefined ? {} : { paircodeAllowed }),
|
|
1106
|
+
resolveLoopTarget: async (context) => {
|
|
1107
|
+
const target = await resolveCurrentSessionLoopTarget(this.sessionManager, {
|
|
1108
|
+
channel,
|
|
1109
|
+
channelId: context.channelId,
|
|
1110
|
+
selfAid: context.self ?? '',
|
|
1111
|
+
...(transportReplyContext?.threadId && context.channelId === channelId
|
|
1112
|
+
? { threadId: transportReplyContext.threadId }
|
|
1113
|
+
: {}),
|
|
1114
|
+
});
|
|
1115
|
+
if (target.peerKey !== context.peerKey)
|
|
1116
|
+
throw { code: 'INVALID_CONTEXT', message: '当前会话关系不匹配' };
|
|
1117
|
+
return { level: target.level, sessionId: target.session.id };
|
|
1118
|
+
},
|
|
1083
1119
|
});
|
|
1084
1120
|
}
|
|
1085
1121
|
async execMenuValueBatch(channel, channelId, subject, args, request, channelScope = 'agent', transportReplyContext) {
|
|
@@ -1573,7 +1609,11 @@ export class CommandHandler {
|
|
|
1573
1609
|
if (!isAdmin && updated.execution.type === 'script') {
|
|
1574
1610
|
return { ok: false, error: '无权限:只有 owner/admin 可以修改 script trigger' };
|
|
1575
1611
|
}
|
|
1576
|
-
const
|
|
1612
|
+
const originChatType = definition.origin?.delivery?.chatType;
|
|
1613
|
+
const originConversationId = originChatType === 'group'
|
|
1614
|
+
? definition.origin?.channelId
|
|
1615
|
+
: definition.origin?.peerId;
|
|
1616
|
+
const triggerRole = this.triggerRoleContext(definition.agentAid, definition.origin?.channelKey || channel, definition.origin?.peerId || peerId, originChatType, originConversationId);
|
|
1577
1617
|
const permissionError = this.validateTriggerPermissionModeForRole(updated.execution.permissionMode, isAdmin, triggerRole.role, definition.agentAid, isDaemonOwner, canApprovePersistentFullAccess);
|
|
1578
1618
|
if (permissionError) {
|
|
1579
1619
|
return {
|
|
@@ -1853,10 +1893,23 @@ export class CommandHandler {
|
|
|
1853
1893
|
const delegation = this.agentDelegationRegistry.validate(delegationToken, sessionId, delegationCommandHash);
|
|
1854
1894
|
if (!delegation.ok)
|
|
1855
1895
|
return { ok: false, code: delegation.code, error: delegation.reason };
|
|
1896
|
+
return this.executeConfigOperation(argv, sessionId, delegation.grant);
|
|
1897
|
+
}
|
|
1898
|
+
async executeConfigOperation(argv, sessionId, grant) {
|
|
1856
1899
|
const session = await this.sessionManager.getSessionById(sessionId);
|
|
1857
1900
|
if (!session)
|
|
1858
1901
|
return { ok: false, code: 'INVALID_SESSION', error: 'Invalid session' };
|
|
1859
|
-
|
|
1902
|
+
if (session.selfAID !== grant.selfAid || grant.sessionId !== sessionId) {
|
|
1903
|
+
return { ok: false, code: 'INVALID_DELEGATION', error: 'Delegation does not match the current session' };
|
|
1904
|
+
}
|
|
1905
|
+
if (argv[0] === 'agent') {
|
|
1906
|
+
const tail = argv.at(-2) === '--format' && argv.at(-1) === 'json' ? argv.slice(0, -2) : argv;
|
|
1907
|
+
const sub = tail[1];
|
|
1908
|
+
if ((sub !== 'get' && sub !== 'set') || tail.length !== (sub === 'get' ? 4 : 5)) {
|
|
1909
|
+
return { ok: false, code: 'INVALID_ARGS', error: 'Expected agent get/set <aid> <key> [value] [--format json]' };
|
|
1910
|
+
}
|
|
1911
|
+
argv = ['config', sub, ...tail.slice(3), '--self', tail[2]];
|
|
1912
|
+
}
|
|
1860
1913
|
let conversationId;
|
|
1861
1914
|
try {
|
|
1862
1915
|
conversationId = parsePeerKey(grant.peerKey).channelId;
|
|
@@ -2549,39 +2602,76 @@ export class CommandHandler {
|
|
|
2549
2602
|
if (sessionSelfAid && sessionSelfAid !== actorAid) {
|
|
2550
2603
|
return { ok: false, code: 'INVALID_DELEGATION', error: 'Delegation self agent does not match the active session' };
|
|
2551
2604
|
}
|
|
2552
|
-
|
|
2553
|
-
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Managed fs operations require the current AUN group relation' };
|
|
2554
|
-
}
|
|
2605
|
+
const isPersonalTarget = parsed.command.targetAid === actorAid;
|
|
2555
2606
|
let currentGroup;
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2607
|
+
if (isPersonalTarget) {
|
|
2608
|
+
if (grant.issuedRole !== 'owner' && !hasTrustedFullAccessDelegation(grant)) {
|
|
2609
|
+
return { ok: false, code: 'NO_PERMISSION', error: 'Managed personal storage requires the current Agent owner relation' };
|
|
2610
|
+
}
|
|
2611
|
+
if (parsed.command.actorAid && parsed.command.actorAid !== actorAid) {
|
|
2612
|
+
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Only the current Agent can access its personal storage' };
|
|
2613
|
+
}
|
|
2561
2614
|
}
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2615
|
+
else {
|
|
2616
|
+
const trustedFullAccess = hasTrustedFullAccessDelegation(grant);
|
|
2617
|
+
if (trustedFullAccess) {
|
|
2618
|
+
let targetType;
|
|
2619
|
+
try {
|
|
2620
|
+
const card = await agentmdGet(parsed.command.targetAid, { withVerification: true, remoteOnly: true });
|
|
2621
|
+
if (card.verification.status !== 'verified') {
|
|
2622
|
+
return { ok: false, code: 'INVALID_TARGET', error: 'Target AID agent.md verification did not succeed' };
|
|
2623
|
+
}
|
|
2624
|
+
const frontmatter = card.content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
|
2625
|
+
const document = frontmatter ? parseDocument(frontmatter) : undefined;
|
|
2626
|
+
targetType = document && document.errors.length === 0
|
|
2627
|
+
? String(document.toJS()?.type ?? '').trim().toLowerCase()
|
|
2628
|
+
: undefined;
|
|
2629
|
+
}
|
|
2630
|
+
catch {
|
|
2631
|
+
return { ok: false, code: 'INVALID_TARGET', error: 'Target AID agent.md could not be verified' };
|
|
2632
|
+
}
|
|
2633
|
+
if (targetType !== 'group') {
|
|
2634
|
+
return { ok: false, code: 'INVALID_TARGET', error: 'Managed group storage requires a verified group AID' };
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
if (!hasTrustedFullAccessDelegation(grant) && (grant.channelType !== 'aun' || grant.chatType !== 'group')) {
|
|
2638
|
+
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Managed group fs operations require the current AUN group relation' };
|
|
2639
|
+
}
|
|
2640
|
+
try {
|
|
2641
|
+
currentGroup = parsePeerKey(grant.peerKey).channelId;
|
|
2642
|
+
}
|
|
2643
|
+
catch {
|
|
2644
|
+
return { ok: false, code: 'INVALID_DELEGATION', error: 'Delegation contains an invalid relation key' };
|
|
2645
|
+
}
|
|
2646
|
+
if (parsed.command.actorAid && parsed.command.actorAid !== actorAid) {
|
|
2647
|
+
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Managed fs cannot switch the execution identity with --as' };
|
|
2648
|
+
}
|
|
2649
|
+
if (!hasTrustedFullAccessDelegation(grant)
|
|
2650
|
+
&& !sameGroupAid(parsed.command.targetAid, currentGroup)) {
|
|
2651
|
+
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Only the current AUN group can be targeted' };
|
|
2652
|
+
}
|
|
2565
2653
|
}
|
|
2566
|
-
parsed.command
|
|
2567
|
-
|
|
2654
|
+
const resolvedCommand = parsed.command;
|
|
2655
|
+
resolvedCommand.storageBackend = isPersonalTarget ? 'personal' : 'group';
|
|
2656
|
+
resolvedCommand.actorAid = hasTrustedFullAccessDelegation(grant) && !isPersonalTarget
|
|
2657
|
+
? (resolvedCommand.actorAid ?? actorAid)
|
|
2568
2658
|
: actorAid;
|
|
2569
2659
|
const subject = buildAuthSubject({
|
|
2570
2660
|
selfAid: grant.selfAid,
|
|
2571
2661
|
actorId: grant.actorId,
|
|
2572
2662
|
channel: grant.channel,
|
|
2573
2663
|
channelType: grant.channelType,
|
|
2574
|
-
channelId: currentGroup,
|
|
2664
|
+
channelId: currentGroup ?? actorAid,
|
|
2575
2665
|
chatType: grant.chatType,
|
|
2576
|
-
conversationId: currentGroup,
|
|
2666
|
+
conversationId: currentGroup ?? actorAid,
|
|
2577
2667
|
processOwners: loadDaemonConfig().owners ?? [],
|
|
2578
2668
|
...trustedExecutionIdentityInput(grant),
|
|
2579
2669
|
});
|
|
2580
2670
|
const intentArgs = {
|
|
2581
2671
|
self: actorAid,
|
|
2582
|
-
targetId:
|
|
2583
|
-
peer: currentGroup,
|
|
2584
|
-
peerKey: formatPeerKey('aun', currentGroup),
|
|
2672
|
+
targetId: parsed.command.targetAid,
|
|
2673
|
+
peer: currentGroup ?? actorAid,
|
|
2674
|
+
peerKey: formatPeerKey('aun', currentGroup ?? actorAid),
|
|
2585
2675
|
path: parsed.command.remotePath,
|
|
2586
2676
|
targetPath: parsed.command.remotePath,
|
|
2587
2677
|
...(parsed.command.remoteSourcePath ? { sourcePath: parsed.command.remoteSourcePath } : {}),
|
|
@@ -2598,7 +2688,7 @@ export class CommandHandler {
|
|
|
2598
2688
|
subject,
|
|
2599
2689
|
intent: {
|
|
2600
2690
|
operation: parsed.command.operationId,
|
|
2601
|
-
scope: 'relation',
|
|
2691
|
+
scope: isPersonalTarget ? 'agent' : 'relation',
|
|
2602
2692
|
source: 'agent-tool',
|
|
2603
2693
|
args: intentArgs,
|
|
2604
2694
|
},
|
|
@@ -2655,7 +2745,7 @@ export class CommandHandler {
|
|
|
2655
2745
|
}
|
|
2656
2746
|
}
|
|
2657
2747
|
try {
|
|
2658
|
-
return { ok: true, result: await executeManagedFsOperation(
|
|
2748
|
+
return { ok: true, result: await executeManagedFsOperation(resolvedCommand) };
|
|
2659
2749
|
}
|
|
2660
2750
|
catch (error) {
|
|
2661
2751
|
return {
|
|
@@ -2668,6 +2758,95 @@ export class CommandHandler {
|
|
|
2668
2758
|
setAgentDelegationRegistry(registry) {
|
|
2669
2759
|
this.agentDelegationRegistry = registry;
|
|
2670
2760
|
}
|
|
2761
|
+
async handleManagedCliOperation(argv, sessionId, grant) {
|
|
2762
|
+
const invalid = (error) => ({ ok: false, code: 'INVALID_ARGUMENT', error });
|
|
2763
|
+
if (argv[0] === 'ctl') {
|
|
2764
|
+
if (!argv[1] || /\s/.test(argv[1]))
|
|
2765
|
+
return invalid('Expected a ctl subcommand');
|
|
2766
|
+
return this.handleCtl('/' + argv.slice(1).join(' '), sessionId, grant);
|
|
2767
|
+
}
|
|
2768
|
+
if (argv[0] !== 'model' && argv[0] !== 'response')
|
|
2769
|
+
return invalid('Expected a model or response command');
|
|
2770
|
+
if (argv.includes('--self') || argv.includes('--peer') || argv.includes('--role')) {
|
|
2771
|
+
return { ok: false, code: 'NOT_ALLOWED', error: 'Managed commands always use the authenticated current relation' };
|
|
2772
|
+
}
|
|
2773
|
+
const args = argv.slice(2);
|
|
2774
|
+
const formatIndex = args.indexOf('--format');
|
|
2775
|
+
if (formatIndex >= 0) {
|
|
2776
|
+
if (args[formatIndex + 1] !== 'json' || args.lastIndexOf('--format') !== formatIndex)
|
|
2777
|
+
return invalid('--format must be json');
|
|
2778
|
+
args.splice(formatIndex, 2);
|
|
2779
|
+
}
|
|
2780
|
+
const sub = argv[1];
|
|
2781
|
+
if (argv[0] === 'model') {
|
|
2782
|
+
let command;
|
|
2783
|
+
if (['list', 'current', 'reset', 'check'].includes(sub) && args.length === 0) {
|
|
2784
|
+
command = `/model ${sub}`;
|
|
2785
|
+
}
|
|
2786
|
+
else if ((sub === 'info' || sub === 'effort') && args.length === 1 && args[0] && !/\s|^--/.test(args[0])) {
|
|
2787
|
+
command = sub === 'info' ? `/model info ${args[0]}` : `/effort ${args[0]}`;
|
|
2788
|
+
}
|
|
2789
|
+
else if (sub === 'use' && args[0] && !/\s|^--/.test(args[0])
|
|
2790
|
+
&& !['list', 'current', 'reset', 'check', 'info'].includes(args[0])
|
|
2791
|
+
&& (args.length === 1 || (args.length === 3 && args[1] === '--effort' && args[2] && !/\s|^--/.test(args[2])))) {
|
|
2792
|
+
command = `/model ${args[0]}${args.length === 3 ? ` ${args[2]}` : ''}`;
|
|
2793
|
+
}
|
|
2794
|
+
else
|
|
2795
|
+
return invalid('Invalid managed model arguments');
|
|
2796
|
+
return this.handleCtl(command, sessionId, grant);
|
|
2797
|
+
}
|
|
2798
|
+
const execute = (fieldArgs) => this.executeConfigOperation(['config', ...fieldArgs], sessionId, grant);
|
|
2799
|
+
const failure = (response) => ({
|
|
2800
|
+
ok: false, code: response.code, error: response.error, data: response.data,
|
|
2801
|
+
});
|
|
2802
|
+
const emit = (data, result) => ({ ok: true, data, result });
|
|
2803
|
+
if (sub === 'set' && args.length === 1) {
|
|
2804
|
+
const registry = new ResponseModeRegistry();
|
|
2805
|
+
registerBuiltinModes(registry);
|
|
2806
|
+
if (!registry.has(args[0]))
|
|
2807
|
+
return { ok: false, code: 'UNKNOWN_MODE', error: `Unknown mode: ${args[0]}` };
|
|
2808
|
+
const result = await execute(['set', 'responseMode', args[0]]);
|
|
2809
|
+
if (!result.ok)
|
|
2810
|
+
return failure(result);
|
|
2811
|
+
return emit({ ok: true, scope: 'relation', mode: args[0] }, `✓ 已设置响应模式为 ${args[0]}(作用域: relation)`);
|
|
2812
|
+
}
|
|
2813
|
+
if (sub === 'reset' && args.length === 0) {
|
|
2814
|
+
const result = await execute(['unset', 'responseMode']);
|
|
2815
|
+
if (!result.ok)
|
|
2816
|
+
return failure(result);
|
|
2817
|
+
return emit({ ok: true, scope: 'relation' }, '✓ 已清除当前关系的响应模式设置');
|
|
2818
|
+
}
|
|
2819
|
+
if (sub === 'current' && args.length === 0) {
|
|
2820
|
+
const modeResult = await execute(['get', 'responseMode']);
|
|
2821
|
+
if (!modeResult.ok)
|
|
2822
|
+
return failure(modeResult);
|
|
2823
|
+
const paramsResult = await execute(['get', 'responseModeParams']);
|
|
2824
|
+
if (!paramsResult.ok)
|
|
2825
|
+
return failure(paramsResult);
|
|
2826
|
+
if (!modeResult.result?.ok || modeResult.result.subcommand !== 'get'
|
|
2827
|
+
|| !paramsResult.result?.ok || paramsResult.result.subcommand !== 'get')
|
|
2828
|
+
return invalid('Unexpected config result');
|
|
2829
|
+
const configuredMode = typeof modeResult.result.value === 'string' ? modeResult.result.value : undefined;
|
|
2830
|
+
const registry = new ResponseModeRegistry();
|
|
2831
|
+
registerBuiltinModes(registry);
|
|
2832
|
+
const mode = configuredMode ?? registry.getPreferredId();
|
|
2833
|
+
return emit({ ok: true, scope: 'relation', responseMode: mode ?? null,
|
|
2834
|
+
source: configuredMode ? 'config' : 'preferred', sourceTarget: modeResult.result.source?.target ?? null,
|
|
2835
|
+
responseModeParams: paramsResult.result.value ?? null }, `当前响应模式: ${mode ?? '(无)'}`);
|
|
2836
|
+
}
|
|
2837
|
+
if (sub === 'config' && (args.length === 0 || (args.length === 1 && !args[0].startsWith('--') && args[0] !== 'set'))) {
|
|
2838
|
+
const result = await execute(['get', 'responseModeParams']);
|
|
2839
|
+
if (!result.ok)
|
|
2840
|
+
return failure(result);
|
|
2841
|
+
if (!result.result?.ok || result.result.subcommand !== 'get')
|
|
2842
|
+
return invalid('Unexpected config result');
|
|
2843
|
+
const params = (result.result.value ?? {});
|
|
2844
|
+
return args.length === 1
|
|
2845
|
+
? emit({ ok: true, mode: args[0], config: params[args[0]] ?? {} }, `${args[0]} 配置: ${JSON.stringify(params[args[0]] ?? {}, null, 2)}`)
|
|
2846
|
+
: emit({ ok: true, responseModeParams: params }, `所有模式配置: ${JSON.stringify(params, null, 2)}`);
|
|
2847
|
+
}
|
|
2848
|
+
return { ok: false, code: 'NOT_ALLOWED', error: `response ${sub} is not available in a managed task` };
|
|
2849
|
+
}
|
|
2671
2850
|
/**
|
|
2672
2851
|
* Agent ctl 入口:通过 IPC 接收 Agent 自主管理指令
|
|
2673
2852
|
* 复用现有 slash cmd 逻辑,权限继承 session 用户角色
|
|
@@ -19,13 +19,17 @@ export async function executeDiagIpc(service, registry, owners, cmd) {
|
|
|
19
19
|
try {
|
|
20
20
|
if (!Array.isArray(cmd.argv) || cmd.argv.some((v) => typeof v !== 'string'))
|
|
21
21
|
throw new Error('Invalid diag argv');
|
|
22
|
-
|
|
22
|
+
if (cmd.argv[0] !== 'diag')
|
|
23
|
+
throw new Error('Expected a diag command');
|
|
24
|
+
return await service.execute(parseDiagArgs(cmd.argv.slice(1)));
|
|
23
25
|
}
|
|
24
26
|
catch (error) {
|
|
25
27
|
return { ok: false, code: error.code ?? 'INVALID_ARGUMENT', message: error.message };
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
export function parseDiagArgs(args) {
|
|
31
|
+
if (args.at(-2) === '--format' && args.at(-1) === 'json')
|
|
32
|
+
args = args.slice(0, -2);
|
|
29
33
|
const words = [];
|
|
30
34
|
let ownerAid;
|
|
31
35
|
let literal = false;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* 不支持跨关系浏览:relation 永远是发起命令的这段关系。
|
|
9
9
|
*/
|
|
10
10
|
import { CONSOLIDATION_MODES, MODE_SCOPE } from '../memory/consolidation-context.js';
|
|
11
|
+
import { formatQueueDetails } from '../memory/consolidation-queue-format.js';
|
|
11
12
|
import { MEMORY_SCOPES, isMemoryScope, memoryOverview, listMemoryFiles, formatMemoryFiles, readMemoryIndex, showMemoryFile, formatPendingNotes, showPendingNote, reindexScope, dropNote, archiveMemoryFile, restoreMemoryFile, } from '../memory/memory-admin.js';
|
|
12
13
|
const USAGE = [
|
|
13
14
|
'用法:',
|
|
@@ -263,8 +264,11 @@ async function consolidate(ctx, target, rawMode, rawScope, needScope, isPayload)
|
|
|
263
264
|
...(scopeOverride ? { scopeOverride } : {}),
|
|
264
265
|
});
|
|
265
266
|
const label = `${mode}${scopeOverride ? `(${scopeOverride})` : ''}`;
|
|
266
|
-
if (!launched
|
|
267
|
-
return
|
|
267
|
+
if (!launched)
|
|
268
|
+
return error(`拉起整理会话失败(${label}),详见 daemon 日志`);
|
|
269
|
+
if (launched.queued) {
|
|
270
|
+
return result(`⏳ 整理请求已入队(${label}),前一个整理会话结束后自动开始\n` +
|
|
271
|
+
formatQueueDetails(launched.queued).join('\n'));
|
|
268
272
|
}
|
|
269
273
|
return result(`✅ 已拉起整理会话(${label})${launched.executionSessionId ? `\n会话: ${launched.executionSessionId}` : ''}\n完成后会在当前对话反馈结果`);
|
|
270
274
|
}
|
|
@@ -7,6 +7,7 @@ import { ConfigTarget, read as readConfig } from '../../config/config-manager.js
|
|
|
7
7
|
import { readRolesConfig } from '../../config/roles.js';
|
|
8
8
|
import { normalizeMenuError } from './menu-protocol.js';
|
|
9
9
|
import { isValidAid } from '../../aun/aid/validation.js';
|
|
10
|
+
import { DEFAULT_SESSION_LOOP_SECONDS, MAX_SESSION_LOOP_SECONDS, MIN_SESSION_LOOP_SECONDS } from '../session/session-idle-monitor.js';
|
|
10
11
|
const DEFAULT_DIRECTORY = { getGroup: groupInfo, getMembers: groupMembers };
|
|
11
12
|
const HOST_BASEAGENTS = ['claude', 'codex', 'ecagent', 'gemini'];
|
|
12
13
|
export function validateMenuValueBatchArgs(args) {
|
|
@@ -65,6 +66,19 @@ const relation = (id, name, label, order, cmd, operation, extra) => ({
|
|
|
65
66
|
...extra,
|
|
66
67
|
});
|
|
67
68
|
const ENTRIES = [
|
|
69
|
+
{
|
|
70
|
+
id: 'session.loop',
|
|
71
|
+
type: 'setting',
|
|
72
|
+
contexts: ['private_relation', 'group_relation'],
|
|
73
|
+
name: 'session',
|
|
74
|
+
label: '当前会话闲置触发',
|
|
75
|
+
section: 'relation_behavior',
|
|
76
|
+
order: 5,
|
|
77
|
+
query: { cmd: '/session', args: { view: 'loop' }, operation: 'session.loop.current', scope: 'relation' },
|
|
78
|
+
update: { cmd: '/session', args: { resource: 'loop' }, operation: 'session.loop.update', scope: 'relation' },
|
|
79
|
+
valueSchema: { type: 'boolean' },
|
|
80
|
+
control: 'toggle-with-number',
|
|
81
|
+
},
|
|
68
82
|
relation('model.relation', 'model', '模型', 10, '/model', 'model.current', { options: { cmd: '/model', operation: 'model.list', scope: 'relation', mode: 'dynamic' }, update: { cmd: '/model', operation: 'model.use', scope: 'relation' }, control: 'select' }),
|
|
69
83
|
relation('effort.relation', 'effort', '推理强度', 20, '/effort', 'model.effort.current', { options: { cmd: '/effort', operation: 'model.effort.current', scope: 'relation', mode: 'dynamic', dependsOn: ['model.relation'] }, update: { cmd: '/effort', operation: 'model.effort', scope: 'relation' }, control: 'select' }),
|
|
70
84
|
relation('chatmode.relation', 'chatmode', '对话模式', 30, '/chatmode', 'chatmode.current', { options: { cmd: '/chatmode', operation: 'chatmode.current', scope: 'relation', mode: 'static', items: [{ value: 'interactive', label: '交互模式' }, { value: 'proactive', label: '主动模式' }] }, update: { cmd: '/chatmode', operation: 'chatmode.update', scope: 'relation' }, control: 'select' }),
|
|
@@ -272,6 +286,9 @@ export function bindMenuExecutionContextArgs(args, context) {
|
|
|
272
286
|
if (!args && context.kind !== 'group_relation')
|
|
273
287
|
return args;
|
|
274
288
|
const { context: _context, ...bound } = args ?? {};
|
|
289
|
+
const isSessionLoop = bound.resource === 'loop' || bound.view === 'loop';
|
|
290
|
+
if (isSessionLoop)
|
|
291
|
+
return bound;
|
|
275
292
|
if (context.kind === 'private_relation' || context.kind === 'group_relation') {
|
|
276
293
|
if (bound.scope !== 'role')
|
|
277
294
|
bound.scope = 'relation';
|
|
@@ -356,6 +373,12 @@ async function operationView(binding, context, options = {}) {
|
|
|
356
373
|
function wireBinding(binding, context) {
|
|
357
374
|
if (!binding || binding.supported === false)
|
|
358
375
|
return undefined;
|
|
376
|
+
if (binding.operation.startsWith('session.loop.'))
|
|
377
|
+
return {
|
|
378
|
+
args: context.kind === 'group_relation'
|
|
379
|
+
? { ...(binding.args ?? {}), context: { kind: context.kind, ...(context.groupId ? { groupId: context.groupId } : {}) } }
|
|
380
|
+
: binding.args ?? {},
|
|
381
|
+
};
|
|
359
382
|
return {
|
|
360
383
|
args: context.kind === 'group_relation'
|
|
361
384
|
? {
|
|
@@ -379,6 +402,27 @@ export async function getMenuCatalog(input) {
|
|
|
379
402
|
operations[key] = view;
|
|
380
403
|
}
|
|
381
404
|
entries.push({ id: entry.id, type: entry.type, name: entry.name, label: entry.label, section: entry.section, order: entry.order, target: { scope: context.kind === 'agent' ? 'agent' : context.kind === 'process' ? 'process' : 'relation', ...(context.self ? { self: context.self } : {}), ...(context.peerKey ? { peerKey: context.peerKey } : {}) }, valueSchema: entry.valueSchema ?? { type: 'object' }, operations, wire: { name: entry.name, operations: { ...(wireBinding(entry.query, context) ? { query: wireBinding(entry.query, context) } : {}), ...(wireBinding(entry.options, context) ? { options: wireBinding(entry.options, context) } : {}), ...(wireBinding(entry.update, context) ? { update: wireBinding(entry.update, context) } : {}), ...(wireBinding(entry.action, context) ? { action: wireBinding(entry.action, context) } : {}) } }, ui: { control: entry.control ?? 'action' } });
|
|
405
|
+
if (entry.id === 'session.loop') {
|
|
406
|
+
const loopEntry = entries[entries.length - 1];
|
|
407
|
+
let target = { level: 'relation-main' };
|
|
408
|
+
if (input.resolveLoopTarget) {
|
|
409
|
+
try {
|
|
410
|
+
target = await input.resolveLoopTarget(context);
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
const reason = normalizeMenuError(error);
|
|
414
|
+
for (const operation of Object.values(operations)) {
|
|
415
|
+
Object.assign(operation, { allowed: false, reason });
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
loopEntry.target = target;
|
|
420
|
+
loopEntry.label = target.level === 'topic-session' ? '当前话题闲置触发' : '关系主会话闲置触发';
|
|
421
|
+
loopEntry.ui = {
|
|
422
|
+
control: entry.control,
|
|
423
|
+
idleSeconds: { type: 'integer', minimum: MIN_SESSION_LOOP_SECONDS, maximum: MAX_SESSION_LOOP_SECONDS, default: DEFAULT_SESSION_LOOP_SECONDS, unit: 'seconds' },
|
|
424
|
+
};
|
|
425
|
+
}
|
|
382
426
|
}
|
|
383
427
|
const policyRevision = hash({ role: context.subject.role, self: context.subject.selfAid, peerKey: context.subject.peerKey, groupMembershipRole: context.groupMembershipRole, baselineRole: context.baselineRole, paircodeAllowed, roles: readRolesConfig(context.subject.selfAid) });
|
|
384
428
|
const data = { $schema_version: 1, kind: 'menu.catalog', complete: true, catalogRevision: hash({ entries, context: context.contextKey, policyRevision }), policyRevision, generatedAt: Date.now(), context: { contextKey: context.contextKey, kind: context.kind, channelScope: context.channelScope, transport: context.transport, chatType: context.chatType, ...(context.self ? { self: context.self } : {}), ...(context.actor ? { actor: context.actor } : {}), ...(context.groupId ? { groupId: context.groupId } : {}), ...(context.peerKey ? { peerKey: context.peerKey } : {}), requesterRole: context.requesterRole, ...(context.groupMembershipRole ? { groupMembershipRole: context.groupMembershipRole } : {}), ...(context.baselineRole !== undefined ? { baselineRole: context.baselineRole } : {}) }, features: { batchValuesV1: true, verifiedExplicitGroupContext: context.kind === 'group_relation' }, entries };
|
|
@@ -420,7 +464,10 @@ export async function execMenuValueBatch(input) {
|
|
|
420
464
|
if (allowed?.supported === false || !(allowed?.allowed))
|
|
421
465
|
return { itemId, entryId, ok: false, error: allowed?.reason ?? { code: 'NOT_SUPPORTED', message: 'operation is not supported or denied' } };
|
|
422
466
|
try {
|
|
423
|
-
const
|
|
467
|
+
const queryArgs = entry.id === 'session.loop'
|
|
468
|
+
? { ...(entry.query.args ?? {}) }
|
|
469
|
+
: bindingArgs(entry.query, context);
|
|
470
|
+
const result = await input.execQuery(entry.query.cmd, context.channelId, queryArgs, context);
|
|
424
471
|
return !('error' in result) ? { itemId, entryId, ok: true, data: result.data } : { itemId, entryId, ok: false, error: { code: normalizeMenuError({ code: result.code, message: result.error, data: result.data }).code, message: result.error, ...(result.data !== undefined ? { data: result.data } : {}) } };
|
|
425
472
|
}
|
|
426
473
|
catch (error) {
|