evolcore 0.0.29 → 0.0.30
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 +7 -0
- package/dist/agents/codex-runner.js +61 -14
- package/dist/aun/aid/agentmd.js +224 -19
- package/dist/aun/aid/index.js +2 -1
- package/dist/aun/aid/managed-operation.js +70 -4
- package/dist/aun/group/index.js +1 -0
- package/dist/{core → aun}/group/invite-service.js +4 -4
- package/dist/channels/daemon.js +1 -1
- package/dist/cli/agent-command.js +7 -7
- package/dist/cli/aun-commands.js +97 -37
- package/dist/cli/data-command.js +2 -1
- package/dist/cli/managed-command-guard.js +2 -2
- package/dist/cli/model.js +1 -1
- package/dist/cli/response.js +1 -1
- package/dist/cli/trigger-command.js +52 -29
- package/dist/config/boot-log.js +95 -1
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/peer-role-resolver.js +21 -0
- package/dist/core/agent-ipc-registration.js +409 -0
- package/dist/core/agent-runtime.js +435 -0
- package/dist/core/auth/delegation-authorization.js +58 -0
- package/dist/core/auth/operation-catalog.js +8 -0
- package/dist/core/bootstrap-service.js +65 -1
- package/dist/core/channel-runtime.js +435 -0
- package/dist/core/command/command-handler.js +4 -1
- package/dist/core/daemon-bootstrap.js +151 -0
- package/dist/core/daemon-control.js +205 -0
- package/dist/core/daemon-lifecycle.js +225 -0
- package/dist/core/data-migration.js +4 -1
- package/dist/core/handoff/ipc-registration.js +156 -0
- package/dist/core/ipc-registration.js +457 -0
- package/dist/core/memory/consolidation-trigger.js +8 -0
- package/dist/core/memory/consolidation.js +838 -0
- package/dist/core/message/aun-ipc-sender.js +226 -0
- package/dist/core/message/outbound.js +165 -0
- package/dist/core/permission/approval-gateway.js +13 -0
- package/dist/core/permission/ec-command-parser.js +80 -35
- package/dist/core/permission/sandbox-runtime.js +23 -2
- package/dist/core/permission/tool-error-code.js +1 -0
- package/dist/core/permission/tool-policy.js +61 -24
- package/dist/core/session/session-idle-monitor.js +17 -0
- package/dist/index.js +352 -4841
- package/dist/ipc.js +2 -1
- package/dist/stats/db.js +24 -0
- package/dist/stats/index.js +1 -1
- package/dist/stats/writer.js +25 -1
- package/dist/trigger/application-service.js +157 -0
- package/dist/trigger/authorization.js +371 -0
- package/dist/trigger/ipc-service.js +406 -0
- package/dist/trigger/local-files.js +133 -0
- package/dist/trigger/manager.js +235 -22
- package/dist/trigger/scheduler.js +30 -5
- package/dist/trigger/script-executor.js +176 -39
- package/dist/trigger/script-sandbox.js +458 -0
- package/dist/trigger/system-definitions.js +188 -0
- package/dist/trigger/validation.js +0 -3
- package/dist/utils/aid-bind.js +1 -1
- package/dist/utils/evolcore-version.js +74 -0
- package/dist/utils/logger.js +16 -0
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/model.md +3 -2
- package/kits/docs/evolcore/rpc.md +4 -0
- package/kits/docs/evolcore/trigger.md +15 -1
- package/kits/schemas/relation-config.schema.9.json +1 -1
- package/kits/templates/system-fragments/commands.md +0 -1
- package/package.json +1 -1
- package/dist/core/memory/launch-consolidation.js +0 -395
package/dist/cli/aun-commands.js
CHANGED
|
@@ -98,6 +98,12 @@ function renderAgentmdGet(aid, result, formatJson) {
|
|
|
98
98
|
console.error(`⚠ 签名验证失败: ${verification.reason ?? '未知原因'}`);
|
|
99
99
|
else
|
|
100
100
|
console.error('ℹ️ 未签名');
|
|
101
|
+
console.error(`来源: ${result.source === 'remote' ? '远端' : '本地缓存'}`);
|
|
102
|
+
console.error(`内容 SHA-256: ${result.contentSha256}`);
|
|
103
|
+
if (result.remoteVersion?.etag)
|
|
104
|
+
console.error(`远端 ETag: ${result.remoteVersion.etag}`);
|
|
105
|
+
if (result.remoteVersion?.lastModified)
|
|
106
|
+
console.error(`远端 Last-Modified: ${result.remoteVersion.lastModified}`);
|
|
101
107
|
}
|
|
102
108
|
function failManagedAid(formatJson, code, error) {
|
|
103
109
|
if (formatJson)
|
|
@@ -119,7 +125,10 @@ async function runManagedAid(args, formatJson) {
|
|
|
119
125
|
if (!parsed.ok)
|
|
120
126
|
failManagedAid(formatJson, parsed.code, parsed.reason);
|
|
121
127
|
const runtime = await readBestTaskRuntimeContext();
|
|
122
|
-
const requiresSelfAid = parsed.command.kind === 'show'
|
|
128
|
+
const requiresSelfAid = parsed.command.kind === 'show'
|
|
129
|
+
|| parsed.command.kind === 'agentmd.put'
|
|
130
|
+
|| parsed.command.kind === 'agentmd.set'
|
|
131
|
+
|| parsed.command.kind === 'avatar';
|
|
123
132
|
if (requiresSelfAid && runtime?.selfAid && parsed.command.aid !== runtime.selfAid.replace(/^@/, '')) {
|
|
124
133
|
failManagedAid(formatJson, 'SCOPE_MISMATCH', `托管任务只能操作当前 self AID:${runtime.selfAid}`);
|
|
125
134
|
}
|
|
@@ -155,10 +164,16 @@ async function runManagedAid(args, formatJson) {
|
|
|
155
164
|
return;
|
|
156
165
|
case 'agentmd.put':
|
|
157
166
|
if (formatJson)
|
|
158
|
-
console.log(JSON.stringify({ ok: true,
|
|
167
|
+
console.log(JSON.stringify({ ok: true, ...response.result }, null, 2));
|
|
159
168
|
else
|
|
160
169
|
console.log('✓ agent.md 已发布');
|
|
161
170
|
return;
|
|
171
|
+
case 'agentmd.set':
|
|
172
|
+
if (formatJson)
|
|
173
|
+
console.log(JSON.stringify({ ok: true, ...response.result }, null, 2));
|
|
174
|
+
else
|
|
175
|
+
console.log(`✓ agent.md 字段已更新: ${response.result.field}`);
|
|
176
|
+
return;
|
|
162
177
|
case 'avatar':
|
|
163
178
|
if (formatJson)
|
|
164
179
|
console.log(JSON.stringify({
|
|
@@ -441,6 +456,7 @@ Commands:
|
|
|
441
456
|
lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
|
|
442
457
|
agentmd put <aid> 读本地 agent.md → 签名 → 上传
|
|
443
458
|
agentmd get <aid> 下载 agent.md → 验签 → 本地持久化
|
|
459
|
+
agentmd set <aid> <field> <value> 修改一个字段并签名上传
|
|
444
460
|
avatar <aid> --file <path> | --url <https-url> 上传头像并更新 agent.md
|
|
445
461
|
|
|
446
462
|
Options:
|
|
@@ -458,14 +474,16 @@ Options:
|
|
|
458
474
|
ec aid delete --unrecoverable --yes
|
|
459
475
|
ec aid lookup someone.agentid.pub
|
|
460
476
|
ec aid agentmd put mybot.agentid.pub
|
|
461
|
-
ec aid agentmd get someone.agentid.pub
|
|
477
|
+
ec aid agentmd get someone.agentid.pub
|
|
478
|
+
ec aid agentmd set mybot.agentid.pub description "A helpful agent"`);
|
|
462
479
|
return;
|
|
463
480
|
}
|
|
464
|
-
|
|
481
|
+
const isAgentmdHelp = sub === 'agentmd' && (!args[1] || isHelpFlag(args[1]));
|
|
482
|
+
if (process.env.EVOLCORE_SESSION_ID && !wantsHelp(args) && !isAgentmdHelp) {
|
|
465
483
|
await runManagedAid(args, formatJson);
|
|
466
484
|
return;
|
|
467
485
|
}
|
|
468
|
-
const { aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, agentmdPut, agentmdGet, buildInitialAgentMd, isValidAid } = await import('../aun/aid/index.js');
|
|
486
|
+
const { aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, agentmdPut, agentmdGet, agentmdSet, buildInitialAgentMd, isValidAid } = await import('../aun/aid/index.js');
|
|
469
487
|
if (sub === 'list') {
|
|
470
488
|
if (wantsHelp(args)) {
|
|
471
489
|
console.log(`用法: ec aid list [筛选选项] [--no-verify] [--format json]
|
|
@@ -833,10 +851,50 @@ Options:
|
|
|
833
851
|
const verb = args[1];
|
|
834
852
|
const aid = args[2];
|
|
835
853
|
if (!verb || isHelpFlag(verb) || wantsHelp(args)) {
|
|
836
|
-
console.log(`用法: ec aid agentmd <put|get> <aid> [--format json]
|
|
854
|
+
console.log(`用法: ec aid agentmd <put|get|set> <aid> [field value] [--format json]
|
|
837
855
|
|
|
838
856
|
put <aid> 读本地 agent.md → 用本地私钥签名 → 上传到 PKI
|
|
839
|
-
get <aid> 从 PKI 下载 agent.md → 验签 →
|
|
857
|
+
get <aid> 从 PKI 下载 agent.md → 验签 → 持久化到本地
|
|
858
|
+
set <aid> <field> <value>
|
|
859
|
+
修改 name/type/description/version/tags 中的一个字段,签名后上传
|
|
860
|
+
tags 的 value 必须是 JSON 字符串数组,例如 ["coding","tools","aun"]`);
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (verb === 'set') {
|
|
864
|
+
const field = args[3];
|
|
865
|
+
const value = args[4];
|
|
866
|
+
const editableFields = new Set(['name', 'type', 'description', 'version', 'tags']);
|
|
867
|
+
if (!aid || !field || value === undefined) {
|
|
868
|
+
failManagedAid(formatJson, 'INVALID_ARGUMENT', '用法: ec aid agentmd set <aid> <name|type|description|version|tags> <value>');
|
|
869
|
+
}
|
|
870
|
+
if (!isValidAid(aid)) {
|
|
871
|
+
failManagedAid(formatJson, 'INVALID_AID', `无效 AID 格式: ${aid}`);
|
|
872
|
+
}
|
|
873
|
+
if (!editableFields.has(field)) {
|
|
874
|
+
failManagedAid(formatJson, 'INVALID_ARGUMENT', `agentmd set field must be one of ${[...editableFields].join(', ')}`);
|
|
875
|
+
}
|
|
876
|
+
let parsedValue = value;
|
|
877
|
+
if (field === 'tags') {
|
|
878
|
+
try {
|
|
879
|
+
const parsed = JSON.parse(value);
|
|
880
|
+
if (!Array.isArray(parsed) || parsed.some(item => typeof item !== 'string'))
|
|
881
|
+
throw new Error('not an array of strings');
|
|
882
|
+
parsedValue = parsed;
|
|
883
|
+
}
|
|
884
|
+
catch {
|
|
885
|
+
failManagedAid(formatJson, 'INVALID_ARGUMENT', 'agentmd set tags value must be a JSON array of strings');
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
try {
|
|
889
|
+
const result = await agentmdSet(aid, field, parsedValue, { aunPath });
|
|
890
|
+
if (formatJson)
|
|
891
|
+
console.log(JSON.stringify({ ok: true, aid, ...result }, null, 2));
|
|
892
|
+
else
|
|
893
|
+
console.log(`✓ agent.md 字段 ${field} 已更新并发布`);
|
|
894
|
+
}
|
|
895
|
+
catch (error) {
|
|
896
|
+
failManagedAid(formatJson, String(error?.code ?? 'AID_OPERATION_FAILED'), String(error?.message ?? error));
|
|
897
|
+
}
|
|
840
898
|
return;
|
|
841
899
|
}
|
|
842
900
|
if (verb === 'put') {
|
|
@@ -848,18 +906,21 @@ Options:
|
|
|
848
906
|
console.error(`❌ 无效 AID 格式: ${aid}`);
|
|
849
907
|
process.exit(1);
|
|
850
908
|
}
|
|
851
|
-
const localPath = agentMdPath(aid);
|
|
909
|
+
const localPath = agentMdPath(aid, aunPath);
|
|
852
910
|
if (!fs.existsSync(localPath)) {
|
|
853
911
|
console.error(`❌ 本地无 agent.md: ${aid}`);
|
|
854
912
|
process.exit(1);
|
|
855
913
|
}
|
|
856
914
|
const content = fs.readFileSync(localPath, 'utf-8');
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
915
|
+
try {
|
|
916
|
+
const result = await agentmdPut(content, { aid, aunPath });
|
|
917
|
+
if (formatJson)
|
|
918
|
+
console.log(JSON.stringify({ ok: true, aid, ...result }, null, 2));
|
|
919
|
+
else
|
|
920
|
+
console.log('✓ agent.md 已发布');
|
|
860
921
|
}
|
|
861
|
-
|
|
862
|
-
|
|
922
|
+
catch (error) {
|
|
923
|
+
failManagedAid(formatJson, String(error?.code ?? 'AID_OPERATION_FAILED'), String(error?.message ?? error));
|
|
863
924
|
}
|
|
864
925
|
return;
|
|
865
926
|
}
|
|
@@ -888,7 +949,7 @@ Options:
|
|
|
888
949
|
}
|
|
889
950
|
return;
|
|
890
951
|
}
|
|
891
|
-
console.error(`未知子命令: aid agentmd ${verb ?? ''}\n用法: ec aid agentmd [put|get] <aid>`);
|
|
952
|
+
console.error(`未知子命令: aid agentmd ${verb ?? ''}\n用法: ec aid agentmd [put|get|set] <aid>`);
|
|
892
953
|
process.exit(1);
|
|
893
954
|
}
|
|
894
955
|
if (sub === 'avatar') {
|
|
@@ -1727,6 +1788,21 @@ function printGroupSendAidHint() {
|
|
|
1727
1788
|
console.error(`仅格式示例(.example.invalid 是保留的虚构域,不是真实 AID): ec group send ${GROUP_FROM_AID_FORMAT_EXAMPLE} ${GROUP_AID_FORMAT_EXAMPLE} "hello"`);
|
|
1728
1789
|
console.error('查询真实群 AID: ec group list <发送方AID>');
|
|
1729
1790
|
}
|
|
1791
|
+
function printGroupRulesUsage() {
|
|
1792
|
+
console.log(`用法:
|
|
1793
|
+
ec group rules <from> <group-id> get
|
|
1794
|
+
ec group rules <from> <group-id> set <file>
|
|
1795
|
+
ec group rules <from> <group-id> publish
|
|
1796
|
+
ec group rules <from> <group-id> [--mode open|approval|invite_only|closed] [--question Q] [--max-pending N]
|
|
1797
|
+
|
|
1798
|
+
说明:
|
|
1799
|
+
get 读取当前已发布的群规则文件 /rules.md
|
|
1800
|
+
set 上传本地文件到群空间 /rules.md,发布 rules.content 元数据,并发送 group.rules.updated 通知
|
|
1801
|
+
publish 不上传文件,仅发布当前群空间 /rules.md 的元数据并发送通知
|
|
1802
|
+
|
|
1803
|
+
兼容:
|
|
1804
|
+
不带 get/set/publish 时仍使用旧的入群规则接口。`);
|
|
1805
|
+
}
|
|
1730
1806
|
export async function cmdGroup(args) {
|
|
1731
1807
|
args = canonicalizeEvolcoreCommandArgv(['ec', 'group', ...args]).slice(2);
|
|
1732
1808
|
const sub = args[0];
|
|
@@ -1752,8 +1828,11 @@ export async function cmdGroup(args) {
|
|
|
1752
1828
|
visitor 不开放历史;群权限仍由托管会话校验。`);
|
|
1753
1829
|
return;
|
|
1754
1830
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1831
|
+
if (sub === 'rules' && (wantsHelp(args) || isHelpFlag(args[3]))) {
|
|
1832
|
+
printGroupRulesUsage();
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
if (!sub || isHelpFlag(sub) || wantsHelp(args)) {
|
|
1757
1836
|
console.log(`用法: ec group <command> <from-aid> [args...] [options]
|
|
1758
1837
|
|
|
1759
1838
|
消息:
|
|
@@ -2320,21 +2399,6 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
2320
2399
|
if (sub === 'rules') {
|
|
2321
2400
|
const groupId = requireGroupId();
|
|
2322
2401
|
const action = args[3];
|
|
2323
|
-
const printRulesFileUsage = () => {
|
|
2324
|
-
console.log(`用法:
|
|
2325
|
-
ec group rules <from> <group-id> get
|
|
2326
|
-
ec group rules <from> <group-id> set <file>
|
|
2327
|
-
ec group rules <from> <group-id> publish
|
|
2328
|
-
ec group rules <from> <group-id> [--mode open|approval|invite_only|closed] [--question Q] [--max-pending N]
|
|
2329
|
-
|
|
2330
|
-
说明:
|
|
2331
|
-
get 读取当前已发布的群规则文件 /rules.md
|
|
2332
|
-
set 上传本地文件到群空间 /rules.md,发布 rules.content 元数据,并发送 group.rules.updated 通知
|
|
2333
|
-
publish 不上传文件,仅发布当前群空间 /rules.md 的元数据并发送通知
|
|
2334
|
-
|
|
2335
|
-
兼容:
|
|
2336
|
-
不带 get/set/publish 时仍使用旧的入群规则接口。`);
|
|
2337
|
-
};
|
|
2338
2402
|
const printRulesFileState = (result, verb) => {
|
|
2339
2403
|
if (!result.ok) {
|
|
2340
2404
|
if (formatJson) {
|
|
@@ -2381,10 +2445,6 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
2381
2445
|
process.exit(1);
|
|
2382
2446
|
}
|
|
2383
2447
|
};
|
|
2384
|
-
if (action && isHelpFlag(action)) {
|
|
2385
|
-
printRulesFileUsage();
|
|
2386
|
-
return;
|
|
2387
|
-
}
|
|
2388
2448
|
if (action === 'get') {
|
|
2389
2449
|
const result = await groupRulesFileGet({ from, groupId, ...commonOpts });
|
|
2390
2450
|
printRulesFileState(result, 'get');
|
|
@@ -2394,7 +2454,7 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
2394
2454
|
const filePath = args[4];
|
|
2395
2455
|
if (!filePath || filePath.startsWith('--')) {
|
|
2396
2456
|
console.error('❌ 缺少 <file> 参数');
|
|
2397
|
-
|
|
2457
|
+
printGroupRulesUsage();
|
|
2398
2458
|
process.exit(1);
|
|
2399
2459
|
}
|
|
2400
2460
|
const result = await groupRulesFileSet({ from, groupId, filePath, ...commonOpts });
|
|
@@ -2408,7 +2468,7 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
2408
2468
|
}
|
|
2409
2469
|
if (action && !action.startsWith('--')) {
|
|
2410
2470
|
console.error(`❌ 未知 rules 动作: ${action}`);
|
|
2411
|
-
|
|
2471
|
+
printGroupRulesUsage();
|
|
2412
2472
|
process.exit(1);
|
|
2413
2473
|
}
|
|
2414
2474
|
const wantsUpdate = args.includes('--mode') || args.includes('--question') || args.includes('--max-pending');
|
package/dist/cli/data-command.js
CHANGED
|
@@ -6,6 +6,7 @@ import { scanInstances } from '../utils/instance-registry.js';
|
|
|
6
6
|
import { isProcessRunning, killProcess } from '../utils/cross-platform.js';
|
|
7
7
|
import { ipcQuery } from '../ipc.js';
|
|
8
8
|
import { cmdStart, cmdStop } from './daemon-commands.js';
|
|
9
|
+
import { wantsHelp } from './help.js';
|
|
9
10
|
function printSummary(manifest) {
|
|
10
11
|
const counts = manifest.operations.reduce((result, operation) => {
|
|
11
12
|
result[operation.status] = (result[operation.status] ?? 0) + 1;
|
|
@@ -78,7 +79,7 @@ async function waitForMaintenanceWindow() {
|
|
|
78
79
|
throw new Error(`cannot begin migration while runtime remains active (main=${runtime.mainCount}, restart-monitor=${runtime.monitorPids.length}, ipc=${ipc})`);
|
|
79
80
|
}
|
|
80
81
|
export async function cmdData(args) {
|
|
81
|
-
if (args[0] !== 'migrate' || args
|
|
82
|
+
if (args[0] !== 'migrate' || wantsHelp(args)) {
|
|
82
83
|
console.log('用法: ec data migrate --dry-run | --apply [migration-id] | --verify [migration-id]');
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { wantsHelp } from './help.js';
|
|
1
|
+
import { isHelpFlag, wantsHelp } from './help.js';
|
|
2
2
|
const MANAGED_TASK_COMMANDS = new Set([
|
|
3
3
|
'aid',
|
|
4
4
|
'agent',
|
|
@@ -51,7 +51,7 @@ export class ManagedCommandNotAllowedError extends Error {
|
|
|
51
51
|
* Keep them outside managed tasks so they cannot read or mutate host state.
|
|
52
52
|
*/
|
|
53
53
|
export function assertManagedTopLevelCommandAllowed(command, args, env = process.env) {
|
|
54
|
-
if (!env.EVOLCORE_SESSION_ID || wantsHelp(args.slice(1))
|
|
54
|
+
if (!env.EVOLCORE_SESSION_ID || isHelpFlag(command) || wantsHelp(args.slice(1)))
|
|
55
55
|
return;
|
|
56
56
|
if (!MANAGED_TASK_COMMANDS.has(command))
|
|
57
57
|
throw new ManagedCommandNotAllowedError(command);
|
package/dist/cli/model.js
CHANGED
|
@@ -601,7 +601,7 @@ async function cmdCheck(args, formatJson) {
|
|
|
601
601
|
export async function cmdModel(args) {
|
|
602
602
|
const sub = args[0];
|
|
603
603
|
const formatJson = getArgValue(args, '--format') === 'json';
|
|
604
|
-
if (!sub || isHelpFlag(sub)) {
|
|
604
|
+
if (!sub || isHelpFlag(sub) || wantsHelp(args)) {
|
|
605
605
|
console.log(HELP);
|
|
606
606
|
return;
|
|
607
607
|
}
|
package/dist/cli/response.js
CHANGED
|
@@ -395,7 +395,7 @@ function cmdConfigSet(args, formatJson) {
|
|
|
395
395
|
export async function cmdResponse(args) {
|
|
396
396
|
const sub = args[0];
|
|
397
397
|
const formatJson = getArgValue(args, '--format') === 'json';
|
|
398
|
-
if (!sub || isHelpFlag(sub)) {
|
|
398
|
+
if (!sub || isHelpFlag(sub) || wantsHelp(args)) {
|
|
399
399
|
console.log(HELP);
|
|
400
400
|
return;
|
|
401
401
|
}
|
|
@@ -7,7 +7,8 @@ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
|
7
7
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
8
8
|
import { assertEcSingleLine } from './cli-argv.js';
|
|
9
9
|
import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
|
|
10
|
-
import {
|
|
10
|
+
import { readTriggerLocalFile, resolveTriggerLocalPath } from '../trigger/local-files.js';
|
|
11
|
+
import { normalizeTriggerDefinition, resolveScriptPath, safeRelativePath, } from '../trigger/validation.js';
|
|
11
12
|
export async function cmdTrigger(args) {
|
|
12
13
|
args = canonicalizeEvolcoreCommandArgv(['ec', 'trigger', ...args]).slice(2);
|
|
13
14
|
const sub = args[0];
|
|
@@ -39,11 +40,31 @@ export async function cmdTrigger(args) {
|
|
|
39
40
|
}
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
|
-
if (process.env.EVOLCORE_SESSION_ID
|
|
43
|
-
&& (hasOption(rest, '--file') || hasOption(rest, '--prompt-file') || hasOption(rest, '--script-path') || hasOption(rest, '--script-file'))) {
|
|
44
|
-
throw new Error('Managed tasks cannot read trigger definitions, prompts, or scripts from local files; use inline prompt content');
|
|
45
|
-
}
|
|
46
43
|
try {
|
|
44
|
+
let fileScope;
|
|
45
|
+
if (process.env.EVOLCORE_SESSION_ID
|
|
46
|
+
&& (hasOption(rest, '--file') || hasOption(rest, '--prompt-file') || hasOption(rest, '--script-path') || hasOption(rest, '--script-file'))) {
|
|
47
|
+
if (!['create', 'set', 'update'].includes(sub))
|
|
48
|
+
throw new Error('local file inputs are only valid for Trigger create/update');
|
|
49
|
+
const agentAid = resolveAgentAid(rest);
|
|
50
|
+
const triggerId = sub === 'update'
|
|
51
|
+
? positional(rest, 0, ['--agent', '--format', '--if-revision', '--prompt-file', '--script-file'])
|
|
52
|
+
: undefined;
|
|
53
|
+
const authorization = await request({
|
|
54
|
+
type: 'trigger.authorizeLocalFiles',
|
|
55
|
+
agentAid,
|
|
56
|
+
operation: sub === 'update' ? 'trigger.update' : 'trigger.create',
|
|
57
|
+
...(triggerId ? { triggerId } : {}),
|
|
58
|
+
cwd: process.cwd(),
|
|
59
|
+
});
|
|
60
|
+
if (authorization.fullAccess !== true) {
|
|
61
|
+
if (!authorization.fileScope || typeof authorization.fileScope.projectPath !== 'string'
|
|
62
|
+
|| typeof authorization.fileScope.cwd !== 'string' || authorization.fileScope.selfAid !== agentAid) {
|
|
63
|
+
throw new Error('daemon did not provide a valid Trigger file scope');
|
|
64
|
+
}
|
|
65
|
+
fileScope = authorization.fileScope;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
47
68
|
switch (sub) {
|
|
48
69
|
case 'list':
|
|
49
70
|
await listTriggers(rest, json);
|
|
@@ -56,10 +77,10 @@ export async function cmdTrigger(args) {
|
|
|
56
77
|
return;
|
|
57
78
|
case 'create':
|
|
58
79
|
case 'set':
|
|
59
|
-
await createTrigger(rest, json);
|
|
80
|
+
await createTrigger(rest, json, fileScope);
|
|
60
81
|
return;
|
|
61
82
|
case 'update':
|
|
62
|
-
await updateTrigger(rest, json);
|
|
83
|
+
await updateTrigger(rest, json, fileScope);
|
|
63
84
|
return;
|
|
64
85
|
case 'enable':
|
|
65
86
|
case 'disable':
|
|
@@ -131,6 +152,10 @@ Create 参数模式支持:
|
|
|
131
152
|
通用输出参数:
|
|
132
153
|
--json | --format json
|
|
133
154
|
|
|
155
|
+
托管文件输入:
|
|
156
|
+
当前 Agent owner 经 daemon 鉴权后,可读取项目或本会话 TMPDIR 内的定义、prompt 和脚本(单文件上限 4 MiB)。
|
|
157
|
+
普通脚本必须使用实际可用的进程沙箱;bypass 不授予宿主权限,fullaccess 仍要求独立宿主批准。
|
|
158
|
+
|
|
134
159
|
Update 参数:
|
|
135
160
|
--once | --delay | --at | --cron | --every | --event [--tz]
|
|
136
161
|
--prompt <文本> | --prompt-file <路径> --script-file <路径> --name <名称>
|
|
@@ -240,7 +265,7 @@ async function showHistory(args, json) {
|
|
|
240
265
|
console.log(`${timestamp} ${event.type.padEnd(18)} ${event.triggerId} ${detail}`);
|
|
241
266
|
}
|
|
242
267
|
}
|
|
243
|
-
async function createTrigger(args, json) {
|
|
268
|
+
async function createTrigger(args, json, fileScope) {
|
|
244
269
|
if (!hasOption(args, '--exec')) {
|
|
245
270
|
throw new Error('创建 trigger 必须显式指定 --exec script|trigger-session|target-session');
|
|
246
271
|
}
|
|
@@ -251,7 +276,7 @@ async function createTrigger(args, json) {
|
|
|
251
276
|
throw new Error('--file(完整定义导入)与 --prompt-file(prompt 正文)不能同时指定');
|
|
252
277
|
}
|
|
253
278
|
const file = requireFlag(args, '--file');
|
|
254
|
-
const { definition, files } = loadDefinitionWithFiles(file);
|
|
279
|
+
const { definition, files } = loadDefinitionWithFiles(file, fileScope);
|
|
255
280
|
if (definition.execution.type !== executionType) {
|
|
256
281
|
throw new Error(`--exec ${flagValue(args, '--exec')} 与 trigger.json 的 execution.type=${definition.execution.type} 不一致`);
|
|
257
282
|
}
|
|
@@ -272,7 +297,7 @@ async function createTrigger(args, json) {
|
|
|
272
297
|
throw new Error('--exec script 不接受 --prompt-file;请使用 --script-path 和 --script-runtime');
|
|
273
298
|
}
|
|
274
299
|
const { parseTriggerSetArgv } = await import('../trigger/parser.js');
|
|
275
|
-
const parseResult = parseTriggerSetArgv(withPromptFromFile(triggerCreateArgs(args)), { allowLongPrompt: usesPromptFile });
|
|
300
|
+
const parseResult = parseTriggerSetArgv(withPromptFromFile(triggerCreateArgs(args), fileScope), { allowLongPrompt: usesPromptFile });
|
|
276
301
|
if (!parseResult.ok) {
|
|
277
302
|
throw new Error(parseResult.error);
|
|
278
303
|
}
|
|
@@ -295,7 +320,7 @@ async function createTrigger(args, json) {
|
|
|
295
320
|
throw new Error('--target-session thread 需要 --target-thread-id');
|
|
296
321
|
}
|
|
297
322
|
const script = parsed.scriptPath ? {
|
|
298
|
-
path: parsed.scriptPath,
|
|
323
|
+
path: path.isAbsolute(parsed.scriptPath) ? path.basename(parsed.scriptPath) : safeRelativePath(parsed.scriptPath),
|
|
299
324
|
runtime: parsed.scriptRuntime,
|
|
300
325
|
args: parsed.scriptArgs,
|
|
301
326
|
timeoutMs: parsed.scriptTimeoutMs ?? 30_000,
|
|
@@ -335,10 +360,14 @@ async function createTrigger(args, json) {
|
|
|
335
360
|
reliability: { concurrency: 'forbid', missedPolicy: 'run_once', retry: { maxAttempts: 0, backoffMs: 30_000 } },
|
|
336
361
|
limits: limitsFromParsed(parsed),
|
|
337
362
|
};
|
|
363
|
+
const files = script ? [{
|
|
364
|
+
relativePath: script.path.replace(/\\/g, '/'),
|
|
365
|
+
contentBase64: readTriggerLocalFile(parsed.scriptPath, fileScope).toString('base64'),
|
|
366
|
+
}] : [];
|
|
338
367
|
const res = await request({
|
|
339
368
|
type: 'trigger.create',
|
|
340
369
|
definition,
|
|
341
|
-
files
|
|
370
|
+
files,
|
|
342
371
|
enable: hasFlag(args, '--enable') ? true : undefined,
|
|
343
372
|
}, 30_000);
|
|
344
373
|
if (json)
|
|
@@ -423,14 +452,14 @@ function shellQuoteArg(value) {
|
|
|
423
452
|
return "''";
|
|
424
453
|
return /[\s"'\\]/.test(value) ? `"${value.replace(/(["\\$`])/g, '\\$1')}"` : value;
|
|
425
454
|
}
|
|
426
|
-
async function updateTrigger(args, json) {
|
|
455
|
+
async function updateTrigger(args, json, fileScope) {
|
|
427
456
|
const agentAid = resolveAgentAid(args);
|
|
428
457
|
const triggerId = positional(args, 0, ['--agent', '--format', '--if-revision', '--prompt-file', '--script-file']);
|
|
429
458
|
const usesPromptFile = hasOption(args, '--prompt-file');
|
|
430
459
|
const usesScriptFile = hasOption(args, '--script-file');
|
|
431
460
|
const scriptFilePath = usesScriptFile ? requireFlag(args, '--script-file') : undefined;
|
|
432
461
|
const { parseTriggerUpdateArgv } = await import('../trigger/parser.js');
|
|
433
|
-
const parsed = parseTriggerUpdateArgv(triggerId, withPromptFromFile(triggerUpdateArgs(args)), { allowLongPrompt: usesPromptFile });
|
|
462
|
+
const parsed = parseTriggerUpdateArgv(triggerId, withPromptFromFile(triggerUpdateArgs(args), fileScope), { allowLongPrompt: usesPromptFile });
|
|
434
463
|
if (!parsed.ok)
|
|
435
464
|
throw new Error(parsed.error);
|
|
436
465
|
const scriptFileRequested = parsed.value.scriptFile !== undefined;
|
|
@@ -438,7 +467,7 @@ async function updateTrigger(args, json) {
|
|
|
438
467
|
const patch = scriptFileRequested ? { ...patchFields, scriptFile: true } : patchFields;
|
|
439
468
|
const expectedRevision = flagValue(args, '--if-revision');
|
|
440
469
|
const scriptFileBase64 = scriptFilePath
|
|
441
|
-
?
|
|
470
|
+
? readTriggerLocalFile(scriptFilePath, fileScope).toString('base64')
|
|
442
471
|
: undefined;
|
|
443
472
|
const res = await request({
|
|
444
473
|
type: 'trigger.update',
|
|
@@ -474,7 +503,7 @@ function triggerUpdateArgs(args) {
|
|
|
474
503
|
}
|
|
475
504
|
return out;
|
|
476
505
|
}
|
|
477
|
-
function withPromptFromFile(args) {
|
|
506
|
+
function withPromptFromFile(args, fileScope) {
|
|
478
507
|
const fileIndexes = [];
|
|
479
508
|
const filePaths = [];
|
|
480
509
|
for (let index = 0; index < args.length; index++) {
|
|
@@ -502,18 +531,9 @@ function withPromptFromFile(args) {
|
|
|
502
531
|
if (hasOption(args, '--prompt'))
|
|
503
532
|
throw new Error('--prompt-file 与 --prompt 不能同时指定');
|
|
504
533
|
const filePath = filePaths[0];
|
|
505
|
-
let stat;
|
|
506
|
-
try {
|
|
507
|
-
stat = fs.statSync(filePath);
|
|
508
|
-
}
|
|
509
|
-
catch (err) {
|
|
510
|
-
throw new Error(`无法读取 prompt 文件 ${filePath}: ${err?.message || String(err)}`);
|
|
511
|
-
}
|
|
512
|
-
if (!stat.isFile())
|
|
513
|
-
throw new Error(`prompt 文件必须是普通文件: ${filePath}`);
|
|
514
534
|
let prompt;
|
|
515
535
|
try {
|
|
516
|
-
prompt =
|
|
536
|
+
prompt = readTriggerLocalFile(filePath, fileScope).toString('utf8').replace(/^\uFEFF/, '');
|
|
517
537
|
}
|
|
518
538
|
catch (err) {
|
|
519
539
|
throw new Error(`无法读取 prompt 文件 ${filePath}: ${err?.message || String(err)}`);
|
|
@@ -598,16 +618,19 @@ async function request(cmd, timeoutMs = 10_000) {
|
|
|
598
618
|
throw new Error(res.error || 'trigger command failed');
|
|
599
619
|
return res;
|
|
600
620
|
}
|
|
601
|
-
function loadDefinitionWithFiles(inputPath) {
|
|
621
|
+
function loadDefinitionWithFiles(inputPath, fileScope) {
|
|
622
|
+
inputPath = resolveTriggerLocalPath(inputPath, fileScope);
|
|
602
623
|
const stat = fs.statSync(inputPath);
|
|
603
624
|
const baseDir = stat.isDirectory() ? inputPath : path.dirname(inputPath);
|
|
604
625
|
const jsonPath = stat.isDirectory() ? path.join(inputPath, 'trigger.json') : inputPath;
|
|
605
|
-
const definition = normalizeTriggerDefinition(JSON.parse(
|
|
626
|
+
const definition = normalizeTriggerDefinition(JSON.parse(readTriggerLocalFile(jsonPath, fileScope).toString('utf8')));
|
|
627
|
+
if (fileScope && definition.agentAid !== fileScope.selfAid)
|
|
628
|
+
throw new Error('imported Trigger must belong to the authorized Agent');
|
|
606
629
|
const files = [];
|
|
607
630
|
if (definition.execution.type === 'script') {
|
|
608
631
|
const scriptAbs = resolveScriptPath(baseDir, definition.execution.script.path);
|
|
609
632
|
const relativePath = path.relative(baseDir, scriptAbs).replace(/\\/g, '/');
|
|
610
|
-
files.push({ relativePath, contentBase64:
|
|
633
|
+
files.push({ relativePath, contentBase64: readTriggerLocalFile(scriptAbs, fileScope).toString('base64') });
|
|
611
634
|
}
|
|
612
635
|
return { definition, files };
|
|
613
636
|
}
|
package/dist/config/boot-log.js
CHANGED
|
@@ -12,11 +12,105 @@ import fs from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import { resolvePaths } from '../paths.js';
|
|
14
14
|
import { logger } from '../utils/logger.js';
|
|
15
|
-
import {
|
|
15
|
+
import { autoMigrateIfNeeded } from '../config-store.js';
|
|
16
|
+
import { initConfigManager } from './config-manager.js';
|
|
17
|
+
import { ensureRoleConfigV4OnStartup, ensureRoleConfigV5OnStartup } from './role-migration-startup.js';
|
|
18
|
+
import { ensureAuxiliaryModelMigrationOnStartup } from './schema-migration.js';
|
|
19
|
+
import { ensureContactBookV2OnStartup } from './contact-book-v2-startup.js';
|
|
20
|
+
import { readInstalledEvolcoreVersion, readFastaunVersion } from '../utils/evolcore-version.js';
|
|
21
|
+
import { readCurrent, readWVersion, writeWVersion, materializeVersion, listAllVersions, diffVersions, snapshot, isConfigSnapshotsEnabled, ensureStartupConfigSnapshot, incrementSuccessCount, retentionCleanup, } from './snapshot.js';
|
|
16
22
|
const MAX_LINES = 300;
|
|
17
23
|
const KEEP_MIN = 150;
|
|
18
24
|
const FALLBACK_MAX_TRIES = 20;
|
|
19
25
|
const FALLBACK_MAX_MS = 120_000;
|
|
26
|
+
export async function prepareStartupConfig(recoverRoleMutations) {
|
|
27
|
+
recoverRoleMutations();
|
|
28
|
+
autoMigrateIfNeeded();
|
|
29
|
+
const auxiliaryModelMigration = await ensureAuxiliaryModelMigrationOnStartup();
|
|
30
|
+
if (auxiliaryModelMigration) {
|
|
31
|
+
const message = `✓ Session Renew auxiliary model migration applied automatically: ${auxiliaryModelMigration.changedFiles} file(s)`
|
|
32
|
+
+ (auxiliaryModelMigration.backup ? `; backup: ${auxiliaryModelMigration.backup}` : '');
|
|
33
|
+
logger.info(message);
|
|
34
|
+
console.error(message);
|
|
35
|
+
}
|
|
36
|
+
const migration = await ensureRoleConfigV4OnStartup();
|
|
37
|
+
if (migration) {
|
|
38
|
+
const message = `✓ Role config v4 migration applied automatically: ${migration.changedFiles} file(s)`
|
|
39
|
+
+ (migration.backup ? `; backup: ${migration.backup}` : '');
|
|
40
|
+
logger.info(message);
|
|
41
|
+
console.error(message);
|
|
42
|
+
}
|
|
43
|
+
const domainMigration = await ensureRoleConfigV5OnStartup();
|
|
44
|
+
if (domainMigration) {
|
|
45
|
+
const message = `✓ Standalone role config migration applied automatically: ${domainMigration.changedFiles} file(s)`
|
|
46
|
+
+ (domainMigration.backup ? `; backup: ${domainMigration.backup}` : '');
|
|
47
|
+
logger.info(message);
|
|
48
|
+
console.error(message);
|
|
49
|
+
}
|
|
50
|
+
const contactMigration = await ensureContactBookV2OnStartup();
|
|
51
|
+
if (contactMigration) {
|
|
52
|
+
const message = `✓ Contact book v2 migration applied automatically: ${contactMigration.changedFiles} file(s)`
|
|
53
|
+
+ (contactMigration.backup ? `; backup: ${contactMigration.backup}` : '');
|
|
54
|
+
logger.info(message);
|
|
55
|
+
console.error(message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function initializeStartupConfig(abort) {
|
|
59
|
+
try {
|
|
60
|
+
initConfigManager();
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const message = `❌ 配置 schema 校验失败: ${error instanceof Error ? error.message : String(error)}`;
|
|
64
|
+
logger.error(message);
|
|
65
|
+
abort(message);
|
|
66
|
+
}
|
|
67
|
+
const snapshotsEnabled = isConfigSnapshotsEnabled();
|
|
68
|
+
if (process.env.EVOLCORE_DIAGNOSE === '1') {
|
|
69
|
+
if (!snapshotsEnabled) {
|
|
70
|
+
const message = '配置快照功能已关闭,无法执行版本回落;请设置 configSnapshots=true';
|
|
71
|
+
logger.error(`[diagnose] ${message}`);
|
|
72
|
+
abort(message);
|
|
73
|
+
}
|
|
74
|
+
logger.info('[diagnose] 进入自检模式,逐版本回落尝试...');
|
|
75
|
+
const result = await selfDiagnose();
|
|
76
|
+
if (result.ok) {
|
|
77
|
+
logger.info(`[diagnose] ✓ 回落到 ${result.actualVersion?.delta} 成功,继续启动。`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const message = result.message ?? '✗ 自检失败:未找到可用版本。';
|
|
81
|
+
logger.error(message);
|
|
82
|
+
abort(message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return snapshotsEnabled;
|
|
86
|
+
}
|
|
87
|
+
export function recordStartupConfig(snapshotsEnabled) {
|
|
88
|
+
if (!snapshotsEnabled) {
|
|
89
|
+
logger.info('[config] snapshots disabled by configSnapshots=false');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const isDiagnoseMode = process.env.EVOLCORE_DIAGNOSE === '1';
|
|
94
|
+
const startupVersion = isDiagnoseMode ? readWVersion() : ensureStartupConfigSnapshot();
|
|
95
|
+
if (startupVersion)
|
|
96
|
+
incrementSuccessCount(startupVersion.delta);
|
|
97
|
+
const startMethod = isDiagnoseMode ? 'diagnose'
|
|
98
|
+
: (process.env.EVOLCORE_LAUNCHED_BY === 'start' ? 'manual' : 'auto');
|
|
99
|
+
appendBootLog({
|
|
100
|
+
bootedAt: new Date().toISOString(),
|
|
101
|
+
startMethod,
|
|
102
|
+
selectedVersion: readCurrent(),
|
|
103
|
+
actualVersion: startupVersion,
|
|
104
|
+
fellBack: !!(isDiagnoseMode && startupVersion && readCurrent()?.delta !== startupVersion.delta),
|
|
105
|
+
versions: { evolcore: readInstalledEvolcoreVersion(), '@agentunion/fastaun': readFastaunVersion(), node: process.version },
|
|
106
|
+
platform: `${process.platform}/${process.arch}`,
|
|
107
|
+
});
|
|
108
|
+
retentionCleanup();
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
logger.warn(`[config] startup snapshot/boot-log failed (non-fatal): ${error instanceof Error ? error.message : String(error)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
20
114
|
export function appendBootLog(entry) {
|
|
21
115
|
if (!isConfigSnapshotsEnabled())
|
|
22
116
|
return;
|
|
@@ -62,6 +62,7 @@ export function getManagementCommandPermissions(role) {
|
|
|
62
62
|
'ec.aid.lookup': { allow: true, scopes: ['agent'] },
|
|
63
63
|
'ec.aid.agentmd.get': { allow: true, scopes: ['agent'] },
|
|
64
64
|
'ec.aid.agentmd.put': { allow: true, dangerous: true, scopes: ['agent'], constraints: { targetCurrentAgentOnly: true, requireAgentAdmin: true } },
|
|
65
|
+
'ec.aid.agentmd.set': { allow: true, dangerous: true, scopes: ['agent'], constraints: { targetCurrentAgentOnly: true, requireAgentAdmin: true } },
|
|
65
66
|
'ec.aid.avatar': { allow: true, dangerous: true, scopes: ['agent'], constraints: { targetCurrentAgentOnly: true, requireAgentOwner: true } },
|
|
66
67
|
'ec.fs.mkdir': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
|
|
67
68
|
'ec.fs.upload': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
|
|
@@ -9,6 +9,7 @@ import { isManagementRole } from './builtin-roles.js';
|
|
|
9
9
|
import { getRoleDefinition, getRoleRank, normalizeDefaultRole, roleExists } from './roles.js';
|
|
10
10
|
import { getStoredRoleRegistry, roleRegistryExists } from './role-store.js';
|
|
11
11
|
import { resolvePrincipal } from './contact-book.js';
|
|
12
|
+
import { tryParseChannelKey } from '../core/channel-loader.js';
|
|
12
13
|
import { isValidAid } from '../aun/aid/validation.js';
|
|
13
14
|
import { isExplicitGroupId } from '../aun/group/index.js';
|
|
14
15
|
export function isAuthenticated(userId) {
|
|
@@ -131,6 +132,26 @@ export function resolvePeerRoleDetail(ctx) {
|
|
|
131
132
|
? resultFor(fallbackRole, 'builtin-fallback', actor, ctx.selfAid)
|
|
132
133
|
: resultFor(null, 'none', actor, ctx.selfAid);
|
|
133
134
|
}
|
|
135
|
+
export function createSessionIdentityResolver(agentRegistry) {
|
|
136
|
+
return (channel, userId, chatType, conversationId) => {
|
|
137
|
+
const parsed = tryParseChannelKey(channel);
|
|
138
|
+
const owningAgent = agentRegistry.resolveByChannel(channel);
|
|
139
|
+
const selfAid = owningAgent?.aid ?? parsed?.selfAID;
|
|
140
|
+
if (!selfAid || !userId)
|
|
141
|
+
return { role: 'none', mode: 'interactive' };
|
|
142
|
+
const actualChatType = chatType || 'private';
|
|
143
|
+
const actualConversationId = actualChatType === 'group' ? (conversationId || userId) : userId;
|
|
144
|
+
const detail = resolvePeerRoleDetail({
|
|
145
|
+
selfAid,
|
|
146
|
+
channelKey: channel,
|
|
147
|
+
channelType: parsed?.type || channel,
|
|
148
|
+
chatType: actualChatType,
|
|
149
|
+
actorId: userId,
|
|
150
|
+
conversationId: actualConversationId,
|
|
151
|
+
});
|
|
152
|
+
return roleToSessionIdentity(detail.effectiveRole);
|
|
153
|
+
};
|
|
154
|
+
}
|
|
134
155
|
export function roleToSessionIdentity(role) {
|
|
135
156
|
return { role: role ?? 'none', mode: 'interactive' };
|
|
136
157
|
}
|