evolcore 0.0.39 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/README.md +31 -20
- package/bin/ec-safe-output.js +14 -2
- package/dist/agents/baseagent-availability.js +1 -0
- package/dist/agents/claude-runner.js +32 -46
- package/dist/agents/codex-runner.js +51 -27
- package/dist/agents/ecagent-runner.js +18 -7
- package/dist/agents/gemini-runner.js +1 -2
- package/dist/agents/runner-types.js +28 -6
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +23 -98
- package/dist/aun/aid/ownership-operation.js +1 -3
- package/dist/aun/group/invite-service.js +6 -0
- package/dist/aun/msg/p2p.js +8 -12
- package/dist/channels/aun.js +66 -48
- package/dist/channels/dingtalk.js +8 -2
- package/dist/channels/feishu.js +6 -1
- package/dist/channels/wecom.js +7 -3
- package/dist/cli/agent-create.js +23 -4
- package/dist/cli/aid-bind-command.js +4 -1
- package/dist/cli/daemon-commands.js +242 -17
- package/dist/cli/index.js +25 -13
- package/dist/cli/memory-command.js +33 -14
- package/dist/cli/restart-monitor.js +35 -13
- package/dist/cli/task-context.js +1 -0
- package/dist/config/config-field-policy.js +1 -0
- package/dist/contracts/ecweb-service-protocol.js +44 -0
- package/dist/core/agent-runtime.js +6 -0
- package/dist/core/auth/agent-delegation.js +7 -4
- package/dist/core/auth/auth-gateway.js +3 -1
- package/dist/core/auth/authorization-audit.js +5 -1
- package/dist/core/auth/debug-context.js +5 -1
- package/dist/core/auth/operation-catalog.js +16 -0
- package/dist/core/command/command-handler.js +7 -1
- package/dist/core/command/menu-catalog.js +48 -12
- package/dist/core/command/menu-handler.js +72 -4
- package/dist/core/command/menu-protocol.js +20 -1
- package/dist/core/command/slash-gate.js +17 -3
- package/dist/core/command/slash-handler.js +90 -7
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/interaction-router.js +2 -1
- package/dist/core/ipc-registration.js +26 -7
- package/dist/core/memory/batch-meta.js +2 -0
- package/dist/core/memory/consolidation-context.js +42 -51
- package/dist/core/memory/consolidation-ops-records.js +39 -7
- package/dist/core/memory/consolidation-trigger.js +71 -64
- package/dist/core/memory/consolidation.js +226 -20
- package/dist/core/memory/memory-writer.js +160 -34
- package/dist/core/memory/relation-idle-monitor.js +287 -0
- package/dist/core/memory/relation-sweep.js +206 -0
- package/dist/core/message/aun-ipc-sender.js +5 -0
- package/dist/core/message/message-bridge.js +64 -55
- package/dist/core/message/message-log.js +17 -0
- package/dist/core/message/message-queue.js +6 -0
- package/dist/core/message/outbound.js +70 -0
- package/dist/core/message/peer-mode.js +7 -2
- package/dist/core/message/response-engine.js +341 -73
- package/dist/core/ownership/owner-resolver.js +384 -178
- package/dist/core/permission/ec-command-parser.js +19 -3
- package/dist/core/permission/tool-policy.js +7 -7
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/session/session-manager.js +25 -5
- package/dist/core/system-session/memory.js +3 -18
- package/dist/ecweb/basic-settings-service.js +709 -0
- package/dist/ecweb/providers-service.js +172 -0
- package/dist/index.js +92 -4
- package/dist/ipc.js +78 -11
- package/dist/stats/db.js +33 -0
- package/dist/stats/index.js +2 -2
- package/dist/stats/query.js +246 -0
- package/dist/stats/writer.js +41 -1
- package/dist/trigger/application-service.js +12 -0
- package/dist/trigger/authorization.js +2 -2
- package/dist/trigger/history.js +36 -0
- package/dist/trigger/scheduler.js +3 -0
- package/dist/utils/ecweb-supervisor.js +31 -10
- package/dist/utils/error-utils.js +8 -4
- package/dist/utils/evolcore-version.js +3 -2
- package/dist/utils/host-info.js +52 -0
- package/ecagent/dist/harness/agent-harness.js +4 -1
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/agent.md +1 -1
- package/kits/docs/evolcore/aid.md +29 -12
- package/kits/docs/evolcore/config.md +9 -7
- package/kits/docs/evolcore/memory-architecture.md +3 -4
- package/kits/docs/evolcore/memory-consolidation.md +28 -7
- package/kits/docs/evolcore/memory-tags.md +1 -1
- package/kits/docs/evolcore/memory.md +1 -1
- package/kits/docs/evolcore/menu-client.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +6 -0
- package/kits/docs/evolcore/msg.md +1 -1
- package/kits/eck_manifest.json +3 -3
- package/kits/rules/04-relation.md +3 -2
- package/kits/schemas/agent-config.schema.13.json +5 -1
- package/kits/templates/memory-consolidation/generalize.md +32 -4
- package/kits/templates/memory-consolidation/notes.md +2 -2
- package/kits/templates/memory-consolidation/promote.md +10 -2
- package/kits/templates/system-fragments/baseagent.md +5 -0
- package/kits/templates/system-fragments/memory.md +12 -3
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/{rules/07-memory-and-thread.md → templates/system-fragments/thread.md} +17 -80
- package/package.json +3 -3
|
@@ -185,6 +185,9 @@ const STDOUT_FILTER_SPECS = new Map([
|
|
|
185
185
|
// operand. Once an explicit pattern option appears, a bare operand would be
|
|
186
186
|
// a file to read, so the operand budget drops to zero. `-r`/`-R`/`-f` are
|
|
187
187
|
// absent from both tables, which keeps recursion and pattern files out.
|
|
188
|
+
// `-d recurse` is the same recursion as `-r` and makes grep ignore stdin and
|
|
189
|
+
// read the working directory, so `-d`/`--directories` are absent too, along
|
|
190
|
+
// with `--include`/`--exclude`/`--exclude-dir`, which only act on recursion.
|
|
188
191
|
['grep', {
|
|
189
192
|
flags: new Set([
|
|
190
193
|
'-i', '--ignore-case', '-v', '--invert-match', '-c', '--count',
|
|
@@ -198,7 +201,7 @@ const STDOUT_FILTER_SPECS = new Map([
|
|
|
198
201
|
valueOptions: new Set([
|
|
199
202
|
'-m', '--max-count', '-A', '--after-context', '-B', '--before-context',
|
|
200
203
|
'-C', '--context', '--color', '--colour', '--binary-files', '--label',
|
|
201
|
-
'--group-separator',
|
|
204
|
+
'--group-separator',
|
|
202
205
|
]),
|
|
203
206
|
patternValueOptions: new Set(['-e', '--regexp']),
|
|
204
207
|
maxOperands: 1,
|
|
@@ -2659,11 +2662,24 @@ export function parseStdinOnlyFilterArgv(segment) {
|
|
|
2659
2662
|
}
|
|
2660
2663
|
if (spec.numericShorthand && /^-\d+$/.test(arg))
|
|
2661
2664
|
continue;
|
|
2665
|
+
// getopt treats the rest of a short option token as that option's value,
|
|
2666
|
+
// so `-A2` / `-n30` / `-ePATTERN` are the same as `-A 2` / `-n 30` /
|
|
2667
|
+
// `-e PATTERN`. Only the leading letter is checked; bundles such as `-iA2`
|
|
2668
|
+
// stay rejected.
|
|
2669
|
+
if (!arg.startsWith('--') && arg.length > 2) {
|
|
2670
|
+
const shortOption = arg.slice(0, 2);
|
|
2671
|
+
if (spec.patternValueOptions?.has(shortOption)) {
|
|
2672
|
+
sawPatternValue = true;
|
|
2673
|
+
continue;
|
|
2674
|
+
}
|
|
2675
|
+
if (spec.valueOptions.has(shortOption))
|
|
2676
|
+
continue;
|
|
2677
|
+
}
|
|
2662
2678
|
const option = arg.split('=', 1)[0];
|
|
2663
2679
|
if (spec.patternValueOptions?.has(option)) {
|
|
2664
2680
|
sawPatternValue = true;
|
|
2665
|
-
//
|
|
2666
|
-
//
|
|
2681
|
+
// `--regexp=PATTERN` carries its own value; only the bare form consumes
|
|
2682
|
+
// the next token.
|
|
2667
2683
|
if (!arg.includes('=') && arg.length === option.length)
|
|
2668
2684
|
expectsOptionValue = true;
|
|
2669
2685
|
continue;
|
|
@@ -2354,7 +2354,7 @@ export function evaluateToolPreflight(toolName, input, context) {
|
|
|
2354
2354
|
return {
|
|
2355
2355
|
behavior: 'deny',
|
|
2356
2356
|
input,
|
|
2357
|
-
message: `🔒 临时文件必须位于当前会话的 $TMPDIR 内(当前值:${currentTmpDir ?? '<不可用>'}):${managedPathCheck.reason}
|
|
2357
|
+
message: `🔒 临时文件必须位于当前会话的 $TMPDIR 内(当前值:${currentTmpDir ?? '<不可用>'}):${managedPathCheck.reason}。在 PowerShell 中用 $env:TMPDIR 读取此路径,例如 $tmp = $env:TMPDIR。`,
|
|
2358
2358
|
policyCode: 'temporary_path_outside_tmpdir',
|
|
2359
2359
|
matchedPath: managedPathCheck.paths[0],
|
|
2360
2360
|
};
|
|
@@ -2385,7 +2385,7 @@ export function evaluateToolPreflight(toolName, input, context) {
|
|
|
2385
2385
|
return {
|
|
2386
2386
|
behavior: 'deny',
|
|
2387
2387
|
input,
|
|
2388
|
-
message: `🔒 临时文件必须位于当前会话的 $TMPDIR 内(当前值:${currentTmpDir ?? '<不可用>'}):${tempCheck.reason}
|
|
2388
|
+
message: `🔒 临时文件必须位于当前会话的 $TMPDIR 内(当前值:${currentTmpDir ?? '<不可用>'}):${tempCheck.reason}。在 PowerShell 中用 $env:TMPDIR 读取此路径,例如 $tmp = $env:TMPDIR。`,
|
|
2389
2389
|
policyCode: 'temporary_path_outside_tmpdir',
|
|
2390
2390
|
};
|
|
2391
2391
|
}
|
|
@@ -2420,8 +2420,8 @@ export function evaluateToolPreflight(toolName, input, context) {
|
|
|
2420
2420
|
behavior: 'deny',
|
|
2421
2421
|
input,
|
|
2422
2422
|
message: invalidArgument
|
|
2423
|
-
? 'apply_patch 参数格式错误:需要一个完整补丁文档(以 *** Begin Patch 开头、以 *** End Patch
|
|
2424
|
-
: '文件修改 patch 无法安全解析:' + applyPatch.reason,
|
|
2423
|
+
? 'apply_patch 参数格式错误:需要一个完整补丁文档(以 *** Begin Patch 开头、以 *** End Patch 结尾),普通命令行参数不是补丁;这不是权限不足。如果补丁内容本身完整但仍报此错,通常是 Windows apply_patch.bat 截断了多行参数;请改用 FileChange 工具直接写文件,或绕过 .bat 直接调用 codex.exe --codex-run-as-apply-patch,不要用 here-string 变体重试。'
|
|
2424
|
+
: '文件修改 patch 无法安全解析:' + applyPatch.reason + '。Windows 上通过 PowerShell here-string 传递补丁时,结尾的 *** End Patch 行通常会被截断导致此错误;请改用 FileChange 工具直接写文件,不要继续用 here-string 变体重试。',
|
|
2425
2425
|
policyCode: invalidArgument ? 'apply_patch_invalid_argument' : 'apply_patch_unparseable',
|
|
2426
2426
|
errorDetailCode: invalidArgument ? 'INVALID_ARGUMENT' : 'APPLY_PATCH_UNPARSEABLE',
|
|
2427
2427
|
};
|
|
@@ -2639,10 +2639,10 @@ export function evaluateToolPreflight(toolName, input, context) {
|
|
|
2639
2639
|
return { behavior: 'deny', input, message: '🔒 PowerShell 调用 ec.cmd 会截断物理多行参数;请保持原有 ec ... 调用,由 PowerShell 原生 shim 无损传递。', policyCode: 'ec_shell_lossy_cmd_shim' };
|
|
2640
2640
|
}
|
|
2641
2641
|
const message = shellDialect === 'powershell'
|
|
2642
|
-
? '🔒 EC 命令调用被拒绝:一次 PowerShell/exec_command 只能执行一条完整的 `ec` 命令。请直接调用 `ec ...`,不要拼接探测命令,也不要使用
|
|
2642
|
+
? '🔒 EC 命令调用被拒绝:一次 PowerShell/exec_command 只能执行一条完整的 `ec` 命令。请直接调用 `ec ...`,不要拼接探测命令,也不要使用 `&&`、`||`、`;`、`|`、重定向、变量展开或子表达式追加其它命令。如需先查询再操作,请拆成两条独立命令分两次调用。'
|
|
2643
2643
|
: shellDialect === 'cmd'
|
|
2644
|
-
? '🔒 EC 命令调用被拒绝:一次 cmd.exe/exec_command 只能执行一条完整的 `ec` 命令。请直接调用 `ec ...`,不要拼接其它命令,不要使用 &、|、重定向、变量展开或 ^
|
|
2645
|
-
: '🔒 EC 命令调用被拒绝:一次 Bash
|
|
2644
|
+
? '🔒 EC 命令调用被拒绝:一次 cmd.exe/exec_command 只能执行一条完整的 `ec` 命令。请直接调用 `ec ...`,不要拼接其它命令,不要使用 &、|、重定向、变量展开或 ^ 转义。如需先查询再操作,请拆成两条独立命令分两次调用。'
|
|
2645
|
+
: '🔒 EC 命令调用被拒绝:一次 Bash 调用只能执行一条完整的 `ec` 命令,不要先用 `command -v` 探测,也不要用 `&&`、`||`、`;`、子 shell、`sh -c`/`bash -lc` 拼接其它命令。安全规则只允许在 ec 后接只读 stdin 的过滤管道:head、tail、grep、wc、sort、cut、uniq、tr(不含读文件、递归、跟随类选项)。jq、awk、sed、python 等能读文件或执行代码的工具不在其内;需要用这类工具时,先 `ec ... > $TMPDIR/<新文件>` 存盘,再另起一次调用处理该文件。';
|
|
2646
2646
|
return {
|
|
2647
2647
|
behavior: 'deny',
|
|
2648
2648
|
input,
|
|
@@ -4,6 +4,7 @@ import { ConfigTarget, read } from '../../config/config-manager.js';
|
|
|
4
4
|
import { resolvePrincipal } from '../../config/contact-book.js';
|
|
5
5
|
import { getDaemonOwners, ownerResolver } from '../ownership/owner-resolver.js';
|
|
6
6
|
import { hasTrustedPrincipal } from '../auth/authenticated-actor.js';
|
|
7
|
+
import { isTopicSession } from '../thread/topic-id.js';
|
|
7
8
|
const PERMISSION_MODE_AUTHORITY = {
|
|
8
9
|
readonly: 0,
|
|
9
10
|
auto: 1,
|
|
@@ -159,6 +160,69 @@ export function agentFullAccessStatus(agentAid, principalId) {
|
|
|
159
160
|
const eligible = isAgentFullAccessOwner(agentAid, principalId);
|
|
160
161
|
return { enabled, eligible, effective: enabled && eligible };
|
|
161
162
|
}
|
|
163
|
+
export function sessionFullAccessStatus(session, principalId) {
|
|
164
|
+
const override = session.metadata?.sessionFullAccess;
|
|
165
|
+
const agentStatus = session.selfAID ? agentFullAccessStatus(session.selfAID, principalId) : {
|
|
166
|
+
enabled: false, eligible: false, effective: false,
|
|
167
|
+
};
|
|
168
|
+
if (isTopicSession(session) && !override) {
|
|
169
|
+
return { enabled: false, eligible: agentStatus.eligible, effective: false, inherited: false };
|
|
170
|
+
}
|
|
171
|
+
if (!override || typeof override !== 'object') {
|
|
172
|
+
return { ...agentStatus, inherited: true };
|
|
173
|
+
}
|
|
174
|
+
const eligible = !!session.selfAID && isAgentFullAccessOwner(session.selfAID, principalId);
|
|
175
|
+
return {
|
|
176
|
+
enabled: override.enabled === true,
|
|
177
|
+
eligible,
|
|
178
|
+
effective: override.enabled === true && eligible && principalId === override.authorizedBy,
|
|
179
|
+
inherited: false,
|
|
180
|
+
authorizedBy: override.authorizedBy,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
export function hasSessionFullAccessOverride(session) {
|
|
184
|
+
return !!session.metadata && Object.prototype.hasOwnProperty.call(session.metadata, 'sessionFullAccess');
|
|
185
|
+
}
|
|
186
|
+
export function createSessionFullAccessAuthorization(input) {
|
|
187
|
+
const config = input.session.metadata?.sessionFullAccess;
|
|
188
|
+
if (!config?.enabled
|
|
189
|
+
|| input.session.chatType !== 'private'
|
|
190
|
+
|| (input.source !== undefined && input.source !== 'user')
|
|
191
|
+
|| ['agent', 'ai', 'bot', 'service', 'group'].includes((input.peerType ?? '').toLowerCase())
|
|
192
|
+
|| !hasTrustedPrincipal(input.actor)
|
|
193
|
+
|| input.actor.principalId !== config.authorizedBy
|
|
194
|
+
|| !input.session.selfAID
|
|
195
|
+
|| !isAgentFullAccessOwner(input.session.selfAID, config.authorizedBy))
|
|
196
|
+
return undefined;
|
|
197
|
+
return {
|
|
198
|
+
permissionMode: 'fullaccess',
|
|
199
|
+
processRole: 'fullaccess-run',
|
|
200
|
+
dataScope: 'daemon',
|
|
201
|
+
source: 'session-policy',
|
|
202
|
+
agentAid: input.session.selfAID,
|
|
203
|
+
sessionId: input.session.id,
|
|
204
|
+
authorizedBy: config.authorizedBy,
|
|
205
|
+
policyActor: { ...input.actor },
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
export function assertSessionFullAccessAuthorization(authorization, session) {
|
|
209
|
+
if (authorization.source !== 'session-policy'
|
|
210
|
+
|| !session
|
|
211
|
+
|| authorization.sessionId !== session.id
|
|
212
|
+
|| !authorization.agentAid
|
|
213
|
+
|| !authorization.policyActor
|
|
214
|
+
|| !hasTrustedPrincipal(authorization.policyActor)) {
|
|
215
|
+
throw new Error('session fullaccess authorization is missing or malformed');
|
|
216
|
+
}
|
|
217
|
+
const current = resolvePrincipal(authorization.agentAid, authorization.policyActor.operatorChannelType, authorization.policyActor.operatorId, authorization.policyActor.operatorChannelKey);
|
|
218
|
+
if (!hasTrustedPrincipal({ ...authorization.policyActor, ...current })
|
|
219
|
+
|| current.principalId !== authorization.authorizedBy
|
|
220
|
+
|| session.metadata?.sessionFullAccess?.enabled !== true
|
|
221
|
+
|| session.metadata.sessionFullAccess.authorizedBy !== authorization.authorizedBy
|
|
222
|
+
|| !isAgentFullAccessOwner(authorization.agentAid, authorization.authorizedBy)) {
|
|
223
|
+
throw new Error('session fullaccess authorization is no longer active');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
162
226
|
/** Create a trusted per-call claim for a direct private message. */
|
|
163
227
|
export function createAgentPolicyAuthorization(input) {
|
|
164
228
|
if (input.chatType !== 'private'
|
|
@@ -227,7 +227,7 @@ export function pageForkHistory(snapshot, before = snapshot.items.length, limit
|
|
|
227
227
|
};
|
|
228
228
|
}
|
|
229
229
|
/** Metadata keys owned by ordinary topic/session routing writers. */
|
|
230
|
-
const TOPIC_METADATA_PROTECTED_KEYS = new Set(['turnState', 'resumeAt', 'agentSessions', 'sessionLoop']);
|
|
230
|
+
const TOPIC_METADATA_PROTECTED_KEYS = new Set(['turnState', 'resumeAt', 'agentSessions', 'sessionLoop', 'sessionFullAccess']);
|
|
231
231
|
const TOPIC_BACKEND_SCOPED_KEYS = ['resumeAt', 'agentSessions'];
|
|
232
232
|
function topicMetadataOwnershipError(key) {
|
|
233
233
|
const error = new Error(`topic metadata field is owned by a dedicated updater: ${key}`);
|
|
@@ -659,13 +659,17 @@ export class SessionManager {
|
|
|
659
659
|
* @returns 是否真的写入了 .jsonl(去重命中时返回 false)
|
|
660
660
|
*/
|
|
661
661
|
persistSession(session, intent, opts) {
|
|
662
|
-
if (!opts?.sessionLoopMutation) {
|
|
662
|
+
if (!opts?.sessionLoopMutation && !opts?.sessionFullAccessMutation) {
|
|
663
663
|
const latest = this.readMetaLatest(this.metaPathForSession(session));
|
|
664
664
|
const metadata = { ...(session.metadata ?? {}) };
|
|
665
665
|
if (latest?.metadata?.sessionLoop !== undefined)
|
|
666
666
|
metadata.sessionLoop = latest.metadata.sessionLoop;
|
|
667
667
|
else
|
|
668
668
|
delete metadata.sessionLoop;
|
|
669
|
+
if (latest?.metadata?.sessionFullAccess !== undefined)
|
|
670
|
+
metadata.sessionFullAccess = latest.metadata.sessionFullAccess;
|
|
671
|
+
else
|
|
672
|
+
delete metadata.sessionFullAccess;
|
|
669
673
|
session.metadata = metadata;
|
|
670
674
|
}
|
|
671
675
|
// Topic session snapshots can be written by synchronous legacy paths
|
|
@@ -1400,8 +1404,9 @@ export class SessionManager {
|
|
|
1400
1404
|
if (updates.name !== undefined)
|
|
1401
1405
|
current.name = updates.name;
|
|
1402
1406
|
if (updates.metadata !== undefined) {
|
|
1403
|
-
if (Object.hasOwn(updates.metadata, 'sessionLoop'))
|
|
1404
|
-
throw topicMetadataOwnershipError('sessionLoop');
|
|
1407
|
+
if (Object.hasOwn(updates.metadata, 'sessionLoop') || Object.hasOwn(updates.metadata, 'sessionFullAccess')) {
|
|
1408
|
+
throw topicMetadataOwnershipError(Object.hasOwn(updates.metadata, 'sessionLoop') ? 'sessionLoop' : 'sessionFullAccess');
|
|
1409
|
+
}
|
|
1405
1410
|
if (isTopicSession(current)) {
|
|
1406
1411
|
for (const key of Object.keys(updates.metadata)) {
|
|
1407
1412
|
if (TOPIC_METADATA_PROTECTED_KEYS.has(key))
|
|
@@ -1431,7 +1436,7 @@ export class SessionManager {
|
|
|
1431
1436
|
return;
|
|
1432
1437
|
const { current } = loaded;
|
|
1433
1438
|
for (const key of Object.keys(patch)) {
|
|
1434
|
-
if (key === 'sessionLoop')
|
|
1439
|
+
if (key === 'sessionLoop' || key === 'sessionFullAccess')
|
|
1435
1440
|
throw topicMetadataOwnershipError(key);
|
|
1436
1441
|
if (isTopicSession(current) && TOPIC_METADATA_PROTECTED_KEYS.has(key)) {
|
|
1437
1442
|
throw topicMetadataOwnershipError(key);
|
|
@@ -1462,6 +1467,19 @@ export class SessionManager {
|
|
|
1462
1467
|
return current;
|
|
1463
1468
|
});
|
|
1464
1469
|
}
|
|
1470
|
+
updateSessionFullAccess(sessionId, config) {
|
|
1471
|
+
if (typeof config.enabled !== 'boolean' || !config.authorizedBy.trim()) {
|
|
1472
|
+
throw Object.assign(new Error('invalid session fullaccess configuration'), { code: 'INVALID_ARGUMENT' });
|
|
1473
|
+
}
|
|
1474
|
+
return this.mutateLatestTopicSession(sessionId, current => {
|
|
1475
|
+
if (!isTopicSession(current)) {
|
|
1476
|
+
throw Object.assign(new Error('session fullaccess requires a topic session'), { code: 'INVALID_CONTEXT' });
|
|
1477
|
+
}
|
|
1478
|
+
current.metadata = { ...(current.metadata ?? {}), sessionFullAccess: { ...config } };
|
|
1479
|
+
this.persistSession(current, 'none', { sessionFullAccessMutation: true });
|
|
1480
|
+
return current;
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1465
1483
|
/** Persist only the turn coordinator-owned metadata field. */
|
|
1466
1484
|
async updateTurnState(sessionId, turnState) {
|
|
1467
1485
|
const loaded = this.loadSessionForUpdate(sessionId);
|
|
@@ -1479,6 +1497,7 @@ export class SessionManager {
|
|
|
1479
1497
|
getOrCreateThreadSession(channel, channelId, threadId, defaultProjectPath, metadata, name, baseagent, selfAID, channelType, peerType, chatType, label, topicStatus) {
|
|
1480
1498
|
const topicMetadata = { ...(metadata ?? {}) };
|
|
1481
1499
|
delete topicMetadata.sessionLoop;
|
|
1500
|
+
delete topicMetadata.sessionFullAccess;
|
|
1482
1501
|
// 使用精确路径(channelType + selfAID)
|
|
1483
1502
|
const chatDir = (channelType && selfAID)
|
|
1484
1503
|
? (() => { const d = chatDirPath(this.sessionsDir, channelType, channelId, selfAID, channel); fs.mkdirSync(d, { recursive: true }); fs.mkdirSync(path.join(d, '_threads'), { recursive: true }); return d; })()
|
|
@@ -2319,6 +2338,7 @@ export class SessionManager {
|
|
|
2319
2338
|
delete metadata.resumeAt;
|
|
2320
2339
|
delete metadata.replyContext;
|
|
2321
2340
|
delete metadata.sessionLoop;
|
|
2341
|
+
delete metadata.sessionFullAccess;
|
|
2322
2342
|
metadata.__sessionRenewedAt = Date.now();
|
|
2323
2343
|
const session = {
|
|
2324
2344
|
id: generateSessionId(),
|
|
@@ -11,12 +11,11 @@
|
|
|
11
11
|
* generalize B, A/consolidated, A/MEMORY.md, R/consolidated, M
|
|
12
12
|
* promote B, O/consolidated, O/MEMORY.md, R/consolidated, M
|
|
13
13
|
* profile B, R/consolidated, R/MEMORY.md, M
|
|
14
|
-
* forget B, X/consolidated, X/MEMORY.md(X
|
|
14
|
+
* forget B, X/consolidated, X/MEMORY.md(X=触发层级,一次只审一层),X=relation 时加 M
|
|
15
15
|
*
|
|
16
16
|
* 详见 docs/memory/system-session-plugin-design.md §5-§8
|
|
17
17
|
*/
|
|
18
18
|
import path from 'path';
|
|
19
|
-
import fs from 'fs';
|
|
20
19
|
import { resolveRoot } from '../../paths.js';
|
|
21
20
|
import { parseCodexToolCommand } from '../permission/ec-command-parser.js';
|
|
22
21
|
import { canonicalToolCall } from '../permission/tool-canonical.js';
|
|
@@ -70,22 +69,8 @@ export function memoryReadRoots(ctx) {
|
|
|
70
69
|
add(...consolidated('relation'), messages);
|
|
71
70
|
break;
|
|
72
71
|
case 'forget':
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const relationsRoot = path.join(resolveRoot(), 'agents', ctx.selfAid, 'relations');
|
|
76
|
-
if (fs.existsSync(relationsRoot)) {
|
|
77
|
-
for (const peerKey of fs.readdirSync(relationsRoot)) {
|
|
78
|
-
const consolidatedDir = path.join(relationsRoot, peerKey, 'memory', 'consolidated');
|
|
79
|
-
const indexPath = path.join(relationsRoot, peerKey, 'memory', 'MEMORY.md');
|
|
80
|
-
if (fs.existsSync(consolidatedDir)) {
|
|
81
|
-
add(consolidatedDir, indexPath);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
add(...consolidated('agent'));
|
|
86
|
-
}
|
|
87
|
-
else if (ctx.memoryScope) {
|
|
88
|
-
// relation / owner 级 forget:只给当前层级
|
|
72
|
+
// 一次会话只审一层:关系层由关系整理链逐关系审,agent 层只审 personal/memory 自身
|
|
73
|
+
if (ctx.memoryScope) {
|
|
89
74
|
add(...consolidated(ctx.memoryScope));
|
|
90
75
|
if (ctx.memoryScope === 'relation')
|
|
91
76
|
add(messages);
|