evolcore 0.0.35 → 0.0.37
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 +42 -0
- package/README.md +6 -0
- package/bin/install-codex-managed-hooks.mjs +20 -3
- package/dist/agents/baseagent-availability.js +1 -1
- package/dist/agents/baseagent.js +88 -0
- package/dist/agents/claude-runner.js +59 -12
- package/dist/agents/codex/app-server-client.js +18 -1
- package/dist/agents/codex-runner.js +262 -21
- package/dist/agents/ecagent-runner.js +47 -11
- package/dist/agents/gemini-runner.js +36 -12
- package/dist/aun/aid/client.js +4 -3
- package/dist/aun/aid/control-aid.js +270 -8
- package/dist/aun/aid/identity.js +6 -3
- package/dist/aun/aid/ownership-operation.js +58 -0
- package/dist/aun/aid/store.js +1 -0
- package/dist/aun/group/fs-download.js +67 -2
- package/dist/aun/group/history.js +20 -5
- package/dist/aun/group/operations.js +8 -2
- package/dist/aun/menu/client.js +39 -2
- package/dist/aun/menu/transport.js +1 -1
- package/dist/aun/msg/history.js +43 -4
- package/dist/aun/msg/managed-operation.js +30 -53
- package/dist/aun/msg/p2p.js +51 -15
- package/dist/aun/outbox.js +4 -0
- package/dist/channels/aun.js +260 -73
- package/dist/channels/daemon.js +6 -4
- package/dist/channels/feishu.js +3 -0
- package/dist/cli/agent-command.js +161 -223
- package/dist/cli/agent-create.js +190 -223
- package/dist/cli/agent.js +3 -1
- package/dist/cli/aid-bind-command.js +53 -0
- package/dist/cli/aun-commands.js +384 -91
- package/dist/cli/bench.js +1 -1
- package/dist/cli/cli-argv.js +74 -0
- package/dist/cli/daemon-commands.js +105 -74
- package/dist/cli/diag.js +1 -1
- package/dist/cli/fs-command.js +18 -19
- package/dist/cli/getmeta-command.js +159 -6
- package/dist/cli/index.js +6 -12
- package/dist/cli/init-channel.js +8 -55
- package/dist/cli/init.js +125 -218
- package/dist/cli/queue-command.js +11 -8
- package/dist/cli/restart-monitor.js +177 -85
- package/dist/cli/session-command.js +1 -1
- package/dist/cli/stats.js +7 -5
- package/dist/cli/thread-command.js +103 -30
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg-diag.js +1 -0
- package/dist/config/access-policy.js +2 -2
- package/dist/config/boot-log.js +14 -11
- package/dist/config/config-field-policy.js +9 -1
- package/dist/config/config-manager.js +176 -90
- package/dist/config/config-operation-service.js +7 -14
- package/dist/config/contact-book-store.js +142 -26
- package/dist/config/contact-book.js +4 -2
- package/dist/config/lifecycle.js +1 -1
- package/dist/config/owner-config.js +96 -0
- package/dist/config/peer-role-resolver.js +12 -18
- package/dist/config/providers-config.js +382 -0
- package/dist/config/providers-import.js +74 -0
- package/dist/config/providers-management.js +328 -0
- package/dist/config/providers.js +22 -0
- package/dist/config/resolved-config-op.js +17 -14
- package/dist/config/snapshot.js +28 -16
- package/dist/config-store.js +18 -14
- package/dist/core/agent-ipc-registration.js +21 -63
- package/dist/core/agent-runtime.js +16 -5
- package/dist/core/auth/agent-delegation.js +199 -25
- package/dist/core/auth/auth-gateway.js +44 -2
- package/dist/core/auth/authorization-denial.js +1 -1
- package/dist/core/auth/debug-context.js +2 -1
- package/dist/core/auth/delegation-authorization.js +2 -2
- package/dist/core/auth/delegation-diagnostics.js +4 -1
- package/dist/core/auth/operation-authorizer.js +10 -1
- package/dist/core/auth/operation-catalog.js +19 -1
- package/dist/core/bootstrap-service.js +43 -20
- package/dist/core/channel-loader.js +0 -1
- package/dist/core/channel-runtime.js +30 -4
- package/dist/core/command/agent-control.js +196 -37
- package/dist/core/command/cli-intent-parser.js +60 -4
- package/dist/core/command/command-handler.js +212 -60
- package/dist/core/command/connect-menu.js +1 -0
- package/dist/core/command/diag-service.js +5 -4
- package/dist/core/command/file-search.js +368 -0
- package/dist/core/command/menu-catalog.js +2 -1
- package/dist/core/command/menu-handler.js +292 -107
- package/dist/core/command/menu-protocol.js +23 -0
- package/dist/core/command/role-menu.js +7 -19
- package/dist/core/command/skill-slash.js +130 -25
- package/dist/core/command/slash-handler.js +101 -53
- package/dist/core/command/topic-slash.js +16 -5
- package/dist/core/daemon-bootstrap.js +7 -1
- package/dist/core/daemon-control.js +19 -1
- package/dist/core/daemon-lifecycle.js +2 -1
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/evolagent-registry.js +13 -2
- package/dist/core/evolagent.js +3 -6
- package/dist/core/handoff/ipc-registration.js +2 -2
- package/dist/core/handoff/runtime.js +40 -6
- package/dist/core/handoff/store.js +1 -0
- package/dist/core/inference/text-inference.js +95 -6
- package/dist/core/ipc-registration.js +43 -24
- package/dist/core/memory/consolidation-context.js +4 -1
- package/dist/core/memory/consolidation.js +25 -14
- package/dist/core/message/aun-ipc-sender.js +296 -88
- package/dist/core/message/aun-request-registry.js +226 -0
- package/dist/core/message/create-status.js +33 -4
- package/dist/core/message/message-bridge.js +62 -13
- package/dist/core/message/message-log.js +0 -1
- package/dist/core/message/message-queue.js +4 -1
- package/dist/core/message/message-utils.js +8 -1
- package/dist/core/message/peer-mode.js +17 -9
- package/dist/core/message/response-engine.js +266 -124
- package/dist/core/message/retry-scheduler.js +11 -8
- package/dist/core/model/catalog-service.js +60 -18
- package/dist/core/model/model-catalog.js +112 -9
- package/dist/core/model/model-fallback.js +94 -26
- package/dist/core/ownership/owner-resolver.js +687 -0
- package/dist/core/permission/approval-gateway.js +196 -62
- package/dist/core/permission/ec-command-parser.js +138 -25
- package/dist/core/permission/filesystem-approval-scope.js +141 -0
- package/dist/core/permission/protected-paths.js +14 -1
- package/dist/core/permission/sandbox-runtime.js +171 -18
- package/dist/core/permission/tool-policy.js +13 -2
- package/dist/core/role/runtime-policy.js +3 -4
- package/dist/core/session/session-idle-monitor.js +10 -8
- package/dist/core/session/session-manager.js +72 -45
- package/dist/core/session/session-mapper.js +18 -7
- package/dist/core/session/session-renew.js +5 -4
- package/dist/core/session/session-title.js +2 -1
- package/dist/core/session/session-turn-coordinator.js +4 -2
- package/dist/core/skill/index-generator.js +2 -16
- package/dist/core/task/task-recovery-service.js +15 -2
- package/dist/core/thread/command-parser.js +28 -13
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +11 -8
- package/dist/core/thread/thread-operation.js +79 -44
- package/dist/core/thread/thread-route.js +54 -6
- package/dist/core/thread/thread-service.js +236 -45
- package/dist/core/thread/topic-id.js +248 -0
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/eck/message-renderer.js +12 -2
- package/dist/index.js +50 -27
- package/dist/ipc.js +59 -6
- package/dist/paths.js +1 -0
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +10 -3
- package/dist/stats/db.js +8 -0
- package/dist/stats/writer.js +26 -4
- package/dist/trigger/authorization.js +48 -3
- package/dist/trigger/feedback.js +28 -10
- package/dist/trigger/ipc-service.js +86 -10
- package/dist/trigger/local-files.js +55 -23
- package/dist/trigger/scheduler.js +57 -11
- package/dist/trigger/system-definitions.js +1 -0
- package/dist/trigger/validation.js +44 -15
- package/dist/utils/aid-bind.js +17 -297
- package/dist/utils/avatar-upload.js +16 -4
- package/dist/utils/cross-platform.js +115 -36
- package/dist/utils/ecweb-supervisor.js +1 -1
- package/dist/utils/ecweb-utils.js +8 -1
- package/dist/utils/error-utils.js +44 -6
- package/dist/utils/instance-registry.js +12 -2
- package/dist/utils/npm-ops.js +102 -27
- package/dist/utils/package-version-info.js +72 -27
- package/dist/utils/restart-safety.js +50 -0
- package/dist/utils/upgrade-jobs.js +304 -0
- package/dist/utils/windows-autostart.js +17 -10
- package/kits/docs/INDEX.md +5 -0
- package/kits/docs/aun/ABILITY_CALLING.md +239 -0
- package/kits/docs/evolcore/INDEX.md +14 -3
- package/kits/docs/evolcore/agent-create.md +55 -141
- package/kits/docs/evolcore/agent.md +38 -16
- package/kits/docs/evolcore/aid.md +34 -0
- package/kits/docs/evolcore/config.md +20 -1
- package/kits/docs/evolcore/event.md +2 -2
- package/kits/docs/evolcore/fs.md +18 -2
- package/kits/docs/evolcore/group-collaboration.md +13 -246
- package/kits/docs/evolcore/group.md +2 -1
- package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +65 -1
- package/kits/docs/evolcore/msg.md +64 -2
- package/kits/docs/evolcore/skill.md +86 -0
- package/kits/docs/evolcore/stats.md +6 -0
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +145 -51
- package/kits/docs/evolcore/trigger.md +48 -3
- package/kits/eck_manifest.json +21 -0
- package/kits/eck_message_manifest.json +4 -4
- package/kits/migrations/migrate-role-config-v5.mjs +20 -7
- package/kits/rules/01-overview.md +2 -1
- package/kits/rules/03-identity.md +3 -1
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/07-memory-and-thread.md +1 -1
- package/kits/schemas/_meta.json +16 -1
- package/kits/schemas/agent-config.schema.13.json +44 -2
- package/kits/schemas/contact-book.schema.3.json +5 -0
- package/kits/schemas/daemon.schema.6.json +3 -1
- package/kits/schemas/daemon.schema.8.json +329 -0
- package/kits/schemas/defaults.schema.5.json +39 -3
- package/kits/schemas/providers.schema.1.json +76 -0
- package/kits/schemas/relation-config.schema.9.json +5 -1
- package/kits/skills/.switches.json +28 -0
- package/kits/skills/aid-ability/SKILL.md +214 -0
- package/kits/skills/ec-agent-create/SKILL.md +162 -0
- package/kits/skills/ec-group/SKILL.md +2 -1
- package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
- package/kits/skills/ec-identity/SKILL.md +143 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
- package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
- package/kits/skills/ec-trigger/SKILL.md +167 -0
- package/kits/skills/ec-trigger/references/examples.md +153 -0
- package/kits/skills/thread-ops/SKILL.md +108 -420
- package/kits/templates/message-fragments/thread-context.md +1 -2
- package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
- package/kits/templates/roles/member.json +1 -1
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +1 -0
- package/kits/templates/system-fragments/channel.md +2 -1
- package/kits/templates/system-fragments/commands.md +5 -4
- package/kits/templates/system-fragments/identity.md +2 -0
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -3
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { ownerResolver } from '../ownership/owner-resolver.js';
|
|
1
3
|
import { agentFullAccessStatus, agentFullAccessWriteError } from '../role/runtime-policy.js';
|
|
2
4
|
import { initializationSummary } from '../../cli/agent-create.js';
|
|
3
5
|
import { agentDelete, agentEnable, agentDisable, agentList, agentShow, agentSet, agentReload, } from '../../cli/agent.js';
|
|
@@ -12,7 +14,8 @@ import { uploadAvatar, uploadAvatarUrl } from '../../utils/avatar-upload.js';
|
|
|
12
14
|
import { agentmdGet, agentmdPut, updateAgentMdFrontmatterName } from '../../aun/aid/agentmd.js';
|
|
13
15
|
import { isValidAid } from '../../aun/aid/validation.js';
|
|
14
16
|
import { isSupportedBaseagent } from '../../agents/baseagent.js';
|
|
15
|
-
|
|
17
|
+
import { resolveProviderServiceForBaseagent } from '../../config/providers.js';
|
|
18
|
+
const SUPPORTED_AGENT_PATCH_FIELDS = new Set(['aid', 'name', 'avatar', 'active_baseagent', 'baseagents', 'projects', 'owner', 'owners', 'fullaccess', 'chatmode', 'channels', 'channelOwners']);
|
|
16
19
|
const HIDDEN_VALUE = '[hidden]';
|
|
17
20
|
const SENSITIVE_CONFIG_KEYS = new Set([
|
|
18
21
|
'apikey',
|
|
@@ -192,6 +195,28 @@ function normalizeStringList(value, label) {
|
|
|
192
195
|
}
|
|
193
196
|
return { ok: true, value: out };
|
|
194
197
|
}
|
|
198
|
+
function normalizeOwnerPatch(value, label, options) {
|
|
199
|
+
if (Object.hasOwn(value, 'owner')) {
|
|
200
|
+
if (value.owner === null && !options.required)
|
|
201
|
+
return { ok: true, value: undefined };
|
|
202
|
+
if (typeof value.owner !== 'string')
|
|
203
|
+
return { ok: false, error: `${label}.owner 必须是字符串` };
|
|
204
|
+
const owner = value.owner.trim();
|
|
205
|
+
if (!owner && options.required)
|
|
206
|
+
return { ok: false, error: `${label}.owner 不能为空` };
|
|
207
|
+
return { ok: true, value: owner || undefined };
|
|
208
|
+
}
|
|
209
|
+
if (Object.hasOwn(value, 'owners')) {
|
|
210
|
+
if (!Array.isArray(value.owners))
|
|
211
|
+
return { ok: false, error: `${label}.owners 必须是字符串数组` };
|
|
212
|
+
const first = value.owners.find(item => typeof item === 'string' && item.trim());
|
|
213
|
+
const owner = typeof first === 'string' ? first.trim() : undefined;
|
|
214
|
+
if (!owner && options.required)
|
|
215
|
+
return { ok: false, error: `${label}.owners 至少需要一个 owner` };
|
|
216
|
+
return { ok: true, value: owner };
|
|
217
|
+
}
|
|
218
|
+
return { ok: false, error: `${label} 缺少 owner` };
|
|
219
|
+
}
|
|
195
220
|
function normalizeChannelOwnersPatch(value) {
|
|
196
221
|
if (!Array.isArray(value))
|
|
197
222
|
return { ok: false, error: 'channelOwners 必须是数组' };
|
|
@@ -207,15 +232,15 @@ function normalizeChannelOwnersPatch(value) {
|
|
|
207
232
|
if (!type || !name)
|
|
208
233
|
return { ok: false, error: `channelOwners[${idx}] 缺少 type/name` };
|
|
209
234
|
if (type === 'aun')
|
|
210
|
-
return { ok: false, error: 'AUN 渠道 owner 由 agent 顶层
|
|
211
|
-
const
|
|
212
|
-
if (!
|
|
213
|
-
return
|
|
235
|
+
return { ok: false, error: 'AUN 渠道 owner 由 agent 顶层 owner 管理,不支持 channelOwners 编辑' };
|
|
236
|
+
const owner = normalizeOwnerPatch(item, `channelOwners[${idx}]`, { required: false });
|
|
237
|
+
if (!owner.ok)
|
|
238
|
+
return owner;
|
|
214
239
|
const key = `${type}\0${name}`;
|
|
215
240
|
if (seen.has(key))
|
|
216
241
|
return { ok: false, error: `channelOwners 重复渠道: ${type}/${name}` };
|
|
217
242
|
seen.add(key);
|
|
218
|
-
out.push({ type, name,
|
|
243
|
+
out.push({ type, name, owner: owner.value });
|
|
219
244
|
}
|
|
220
245
|
return { ok: true, value: out };
|
|
221
246
|
}
|
|
@@ -237,14 +262,17 @@ function applyChannelOwnersPatch(config, patch) {
|
|
|
237
262
|
ownerAids: channel.ownerAids,
|
|
238
263
|
admins: channel.admins,
|
|
239
264
|
});
|
|
240
|
-
|
|
241
|
-
|
|
265
|
+
if (item.owner)
|
|
266
|
+
channel.owner = item.owner;
|
|
267
|
+
else
|
|
268
|
+
delete channel.owner;
|
|
269
|
+
delete channel.owners;
|
|
242
270
|
delete channel.ownerId;
|
|
243
271
|
delete channel.ownerAid;
|
|
244
272
|
delete channel.ownerIds;
|
|
245
273
|
delete channel.ownerAids;
|
|
246
274
|
delete channel.admins;
|
|
247
|
-
const after = JSON.stringify({
|
|
275
|
+
const after = JSON.stringify({ owner: channel.owner });
|
|
248
276
|
if (before !== after)
|
|
249
277
|
changed = true;
|
|
250
278
|
}
|
|
@@ -294,7 +322,8 @@ function buildSafeAgentConfig(config) {
|
|
|
294
322
|
return sanitizeConfigValue({
|
|
295
323
|
...config,
|
|
296
324
|
active_baseagent: config.active_baseagent ?? null,
|
|
297
|
-
|
|
325
|
+
owner: ownerResolver.knownOwner(config.aid) ?? null,
|
|
326
|
+
owners: ownerResolver.knownOwners(config.aid),
|
|
298
327
|
channels: config.channels ?? [],
|
|
299
328
|
baseagents: config.baseagents ?? {},
|
|
300
329
|
projects: stripUnsupportedProjectFields(config.projects) ?? {},
|
|
@@ -311,6 +340,7 @@ function buildCreateProgressOnlyAgent(aid, progress) {
|
|
|
311
340
|
model: null,
|
|
312
341
|
effort: null,
|
|
313
342
|
chatmode: null,
|
|
343
|
+
owner: null,
|
|
314
344
|
owners: [],
|
|
315
345
|
channels: [],
|
|
316
346
|
},
|
|
@@ -325,6 +355,71 @@ function buildCreateProgressOnlyAgent(aid, progress) {
|
|
|
325
355
|
createProgress: progress,
|
|
326
356
|
};
|
|
327
357
|
}
|
|
358
|
+
function failedCreateRetryAllowed(aid, agentDir, service) {
|
|
359
|
+
const progress = readCreateStatus(agentDir);
|
|
360
|
+
if ((!progress && fs.existsSync(path.join(agentDir, 'create-status.json')))
|
|
361
|
+
|| (progress && (!Array.isArray(progress.steps)
|
|
362
|
+
|| progress.steps.some(step => !step || typeof step.phase !== 'string'
|
|
363
|
+
|| !['in_progress', 'done', 'warn', 'failed'].includes(step.state))))) {
|
|
364
|
+
return { allowed: false, force: false, error: '已有创建进度无法读取,拒绝覆盖' };
|
|
365
|
+
}
|
|
366
|
+
if (progress && progress.aid !== aid) {
|
|
367
|
+
return { allowed: false, force: false, error: '创建进度状态与 AID 不匹配' };
|
|
368
|
+
}
|
|
369
|
+
if (progress?.status === 'in_progress') {
|
|
370
|
+
return { allowed: false, force: false, error: '该 Agent 正在创建中' };
|
|
371
|
+
}
|
|
372
|
+
if (progress?.status === 'failed' && (progress.currentPhase === 'hot_loading'
|
|
373
|
+
|| progress.currentPhase === 'applying_config'
|
|
374
|
+
|| progress.steps.some(step => step.phase === 'hot_loading' || step.phase === 'applying_config'))) {
|
|
375
|
+
return { allowed: false, force: false, error: '该 Agent 已进入加载流程,拒绝重建' };
|
|
376
|
+
}
|
|
377
|
+
const configPath = path.join(agentDir, 'config.json');
|
|
378
|
+
if (!fs.existsSync(configPath)) {
|
|
379
|
+
if (progress && progress.status !== 'failed') {
|
|
380
|
+
return { allowed: false, force: false, error: '已有创建记录不是可重试的失败状态' };
|
|
381
|
+
}
|
|
382
|
+
return { allowed: true, force: false };
|
|
383
|
+
}
|
|
384
|
+
if (progress?.status !== 'failed') {
|
|
385
|
+
return { allowed: false, force: false, error: `Agent "${aid}" already exists` };
|
|
386
|
+
}
|
|
387
|
+
let lifecycle;
|
|
388
|
+
try {
|
|
389
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
390
|
+
if (!config || typeof config !== 'object' || Array.isArray(config) || config.aid !== aid) {
|
|
391
|
+
return { allowed: false, force: false, error: '已有 Agent 配置与 AID 不匹配,拒绝覆盖' };
|
|
392
|
+
}
|
|
393
|
+
lifecycle = config && typeof config === 'object' && !Array.isArray(config)
|
|
394
|
+
? config.lifecycle
|
|
395
|
+
: undefined;
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
return { allowed: false, force: false, error: '已有 Agent 配置无法读取,拒绝覆盖' };
|
|
399
|
+
}
|
|
400
|
+
if (lifecycle !== 'created' && lifecycle !== 'ownerpending') {
|
|
401
|
+
return { allowed: false, force: false, error: `Agent "${aid}" 已进入运行生命周期,拒绝重建` };
|
|
402
|
+
}
|
|
403
|
+
// A legacy retry may have overwritten the original progress. Check live state
|
|
404
|
+
// independently before allowing the creator's destructive --force path.
|
|
405
|
+
if (!service)
|
|
406
|
+
return { allowed: false, force: false, error: '无法确认 Agent 运行状态,拒绝重建' };
|
|
407
|
+
try {
|
|
408
|
+
if (service.info(aid))
|
|
409
|
+
return { allowed: false, force: false, error: '该 Agent 已加载,拒绝重建' };
|
|
410
|
+
const ownership = ownerResolver.snapshot(aid);
|
|
411
|
+
if (ownership.connected || ownership.consensusStatus === 'consensus' || ownership.task?.status === 'completed') {
|
|
412
|
+
return { allowed: false, force: false, error: '该 Agent 已连接或已确认 Ownership,拒绝重建' };
|
|
413
|
+
}
|
|
414
|
+
if (ownership.requestStatus === 'error') {
|
|
415
|
+
return { allowed: false, force: false, error: '无法确认 Agent Ownership 状态,拒绝重建' };
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
return { allowed: false, force: false, error: '无法确认 Agent 运行状态,拒绝重建' };
|
|
420
|
+
}
|
|
421
|
+
return { allowed: true, force: true };
|
|
422
|
+
}
|
|
328
423
|
/** 后台异步:实际创建 agent + 落 model/effort/chatmode,全程写构建进度(D3)。
|
|
329
424
|
* 失败仅写日志 + create-status,不回传(受理即返回)。
|
|
330
425
|
* agentSet key 对照 cli/agent.ts 的 setNestedValue:
|
|
@@ -338,6 +433,10 @@ async function runCreateInBackground(opts, w, service) {
|
|
|
338
433
|
project: opts.project, owner: opts.owner,
|
|
339
434
|
description: opts.description,
|
|
340
435
|
tags: opts.tags,
|
|
436
|
+
// Publish the avatar before hot-load starts Ownership with agent.md.
|
|
437
|
+
avatarUrl: opts.avatarUrl,
|
|
438
|
+
force: opts.retryFailedCreate === true,
|
|
439
|
+
onOwnershipBinding: binding => w.setOwnershipBinding(binding),
|
|
341
440
|
onPhase: (phase, state, detail) => {
|
|
342
441
|
if (state === 'begin') {
|
|
343
442
|
curPhase = phase;
|
|
@@ -355,24 +454,51 @@ async function runCreateInBackground(opts, w, service) {
|
|
|
355
454
|
? await service.create(createOptions)
|
|
356
455
|
: await agentCreateNonInteractive(createOptions);
|
|
357
456
|
if (!('ok' in res) || res.ok !== true) {
|
|
358
|
-
//
|
|
359
|
-
const err = res.error;
|
|
457
|
+
// Service adapters may return a failure without emitting an onPhase callback.
|
|
458
|
+
const err = String(res.error || 'Agent creation failed');
|
|
459
|
+
w.finishFailed(curPhase, err);
|
|
360
460
|
logger.warn(`[agent-control] create ${opts.aid} failed: ${err}`);
|
|
361
461
|
return;
|
|
362
462
|
}
|
|
363
|
-
|
|
364
|
-
|
|
463
|
+
if (res.aidCreated && res.ownershipBinding)
|
|
464
|
+
w.setOwnershipBinding(res.ownershipBinding);
|
|
465
|
+
// 环节 4:applying_config(provider/model/effort/chatmode,agentCreateNonInteractive 之外)
|
|
466
|
+
if (opts.provider || opts.providerServiceType || opts.model || opts.effort || opts.chatmode) {
|
|
365
467
|
curPhase = 'applying_config';
|
|
366
468
|
w.begin('applying_config');
|
|
367
469
|
let warned;
|
|
368
|
-
if (opts.
|
|
470
|
+
if (opts.provider) {
|
|
471
|
+
const config = service?.readConfig(opts.aid) ?? cfgRead(ConfigTarget.Agent, { self: opts.aid });
|
|
472
|
+
if (!config)
|
|
473
|
+
throw new Error('Agent config is unavailable after creation');
|
|
474
|
+
const baseagents = config.baseagents && typeof config.baseagents === 'object' ? { ...config.baseagents } : {};
|
|
475
|
+
const current = baseagents[opts.baseagent] && typeof baseagents[opts.baseagent] === 'object'
|
|
476
|
+
? { ...baseagents[opts.baseagent] }
|
|
477
|
+
: {};
|
|
478
|
+
baseagents[opts.baseagent] = {
|
|
479
|
+
...current,
|
|
480
|
+
provider: opts.provider,
|
|
481
|
+
...(opts.providerServiceType ? { providerServiceType: opts.providerServiceType } : {}),
|
|
482
|
+
...(opts.model ? { model: opts.model } : {}),
|
|
483
|
+
...(opts.effort ? { effort: opts.effort } : {}),
|
|
484
|
+
};
|
|
485
|
+
config.baseagents = baseagents;
|
|
486
|
+
if (service)
|
|
487
|
+
service.writeConfig(opts.aid, config);
|
|
488
|
+
else
|
|
489
|
+
cfgWrite(ConfigTarget.Agent, config, { self: opts.aid });
|
|
490
|
+
const reload = service ? await service.reload(opts.aid) : await agentReload(opts.aid);
|
|
491
|
+
if (!('ok' in reload) || !reload.ok)
|
|
492
|
+
warned = `provider saved but Agent reload failed: ${reload.error || 'unknown error'}`;
|
|
493
|
+
}
|
|
494
|
+
if (!opts.provider && opts.model) {
|
|
369
495
|
const r = service
|
|
370
496
|
? await service.setConfig(opts.aid, `baseagents.${opts.baseagent}.model`, opts.model)
|
|
371
497
|
: await agentSet(opts.aid, `baseagents.${opts.baseagent}.model`, opts.model);
|
|
372
498
|
if (!('ok' in r) || !r.ok)
|
|
373
499
|
warned = `model: ${r.error}`;
|
|
374
500
|
}
|
|
375
|
-
if (opts.effort) {
|
|
501
|
+
if (!opts.provider && opts.effort) {
|
|
376
502
|
const r = service
|
|
377
503
|
? await service.setConfig(opts.aid, `baseagents.${opts.baseagent}.effort`, opts.effort)
|
|
378
504
|
: await agentSet(opts.aid, `baseagents.${opts.baseagent}.effort`, opts.effort);
|
|
@@ -444,6 +570,8 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
|
|
|
444
570
|
if (!a.aid || !a.name || !a.baseagent) {
|
|
445
571
|
return { error: '缺少必填参数:aid / name / baseagent', code: 'INVALID_ARGS' };
|
|
446
572
|
}
|
|
573
|
+
if (typeof a.aid !== 'string' || !isValidAid(a.aid))
|
|
574
|
+
return { error: '无效 Agent AID', code: 'INVALID_ARGS' };
|
|
447
575
|
const owner = typeof a.owner === 'string' && a.owner.trim() ? a.owner.trim() : peerId.trim();
|
|
448
576
|
if (!owner)
|
|
449
577
|
return { error: '缺少 owner AID', code: 'INVALID_ARGS' };
|
|
@@ -453,16 +581,51 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
|
|
|
453
581
|
return { error: 'project 缺失(调用方应先解析默认项目路径)', code: 'INVALID_ARGS' };
|
|
454
582
|
}
|
|
455
583
|
const model = typeof a.model === 'string' && a.model.trim() ? a.model.trim() : undefined;
|
|
584
|
+
if (a.provider !== undefined && typeof a.provider !== 'string')
|
|
585
|
+
return { error: 'provider 必须是字符串', code: 'INVALID_ARGS' };
|
|
586
|
+
const provider = typeof a.provider === 'string' && a.provider.trim() ? a.provider.trim() : undefined;
|
|
587
|
+
if (a.providerServiceType !== undefined && typeof a.providerServiceType !== 'string')
|
|
588
|
+
return { error: 'providerServiceType 必须是字符串', code: 'INVALID_ARGS' };
|
|
589
|
+
const providerServiceType = typeof a.providerServiceType === 'string' && a.providerServiceType.trim() ? a.providerServiceType.trim() : undefined;
|
|
590
|
+
if (provider) {
|
|
591
|
+
try {
|
|
592
|
+
const resolved = resolveProviderServiceForBaseagent(provider, a.baseagent, providerServiceType);
|
|
593
|
+
if (model && resolved.modelOverrides[model]?.enabled === false)
|
|
594
|
+
throw new Error(`Model ${model} is disabled for provider ${provider}`);
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
return { error: error.message || String(error), code: 'INVALID_ARGS' };
|
|
598
|
+
}
|
|
599
|
+
}
|
|
456
600
|
const rawEffort = typeof a.effort === 'string' && a.effort.trim() ? a.effort.trim() : undefined;
|
|
457
601
|
const effort = rawEffort && rawEffort !== 'auto' ? rawEffort : undefined;
|
|
458
602
|
const description = typeof a.description === 'string' && a.description.trim()
|
|
459
603
|
? a.description.trim()
|
|
460
604
|
: undefined;
|
|
461
605
|
const tags = Array.isArray(a.tags) ? a.tags : undefined;
|
|
606
|
+
let avatarUrl;
|
|
607
|
+
if (a.avatarUrl !== undefined) {
|
|
608
|
+
if (typeof a.avatarUrl !== 'string' || !a.avatarUrl.trim()) {
|
|
609
|
+
return { error: 'avatarUrl 必须是非空 HTTPS URL', code: 'INVALID_ARGS' };
|
|
610
|
+
}
|
|
611
|
+
try {
|
|
612
|
+
const url = new URL(a.avatarUrl.trim());
|
|
613
|
+
if (url.protocol !== 'https:' || url.username || url.password || (url.port && url.port !== '443'))
|
|
614
|
+
throw new Error('invalid avatar URL');
|
|
615
|
+
avatarUrl = url.toString();
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
return { error: 'avatarUrl 必须是不含认证信息的 HTTPS URL', code: 'INVALID_ARGS' };
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
const agentDir = path.join(resolvePaths().agentsDir, a.aid);
|
|
622
|
+
const retry = failedCreateRetryAllowed(a.aid, agentDir, service);
|
|
623
|
+
if (!retry.allowed)
|
|
624
|
+
return { error: retry.error || 'Agent 已存在', code: 'CONFLICT' };
|
|
462
625
|
// D3: accepted=true 必须意味着后续 query 能查到该 AID 的创建状态。
|
|
463
626
|
let progressWriter;
|
|
464
627
|
try {
|
|
465
|
-
progressWriter = new CreateStatusWriter(
|
|
628
|
+
progressWriter = new CreateStatusWriter(agentDir, a.aid, { requesterAid: peerId, ownerAid: owner });
|
|
466
629
|
}
|
|
467
630
|
catch (e) {
|
|
468
631
|
return { error: `创建进度状态初始化失败: ${e?.message || e}`, code: 'INTERNAL' };
|
|
@@ -471,10 +634,11 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
|
|
|
471
634
|
void runCreateInBackground({
|
|
472
635
|
aid: a.aid, name: a.name, baseagent: a.baseagent,
|
|
473
636
|
project: a.project, owner,
|
|
474
|
-
model, effort, description, tags, chatmode: a.chatmode,
|
|
637
|
+
provider, providerServiceType, model, effort, description, tags, chatmode: a.chatmode, avatarUrl,
|
|
638
|
+
retryFailedCreate: retry.force,
|
|
475
639
|
eventBus,
|
|
476
640
|
}, progressWriter, service).catch(e => logger.error(`[agent-control] runCreateInBackground unhandled ${a.aid}: ${e?.message || e}`));
|
|
477
|
-
return { data: { accepted: true, aid: a.aid } };
|
|
641
|
+
return { data: { accepted: true, aid: a.aid, creationId: progressWriter.creationId, ...(avatarUrl ? { avatarAccepted: true } : {}) } };
|
|
478
642
|
}
|
|
479
643
|
if (action === 'delete') {
|
|
480
644
|
if (!a.aid)
|
|
@@ -551,8 +715,8 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
|
|
|
551
715
|
* 直接通过 ConfigManager 读写 agent config(不走 agentSet,避免其内部自动 evolagent.reload)——
|
|
552
716
|
* 重载由用户在 Agents 页操作列手动触发(带任务执行检查)。
|
|
553
717
|
* AUN 渠道绑定 agent 顶层 aid,不可通过 patch 编辑:拒绝改 aid、拒绝 channels 数组里出现 aun 条目。
|
|
554
|
-
* 可写字段:name / avatar(旧版 App 兼容,单独提交 data URL)/ active_baseagent / baseagents / projects / owners
|
|
555
|
-
* channelOwners(按 type/name 局部更新非 AUN channel
|
|
718
|
+
* 可写字段:name / avatar(旧版 App 兼容,单独提交 data URL)/ active_baseagent / baseagents / projects / owner(旧版 owners[] 兼容)/
|
|
719
|
+
* fullaccess / chatmode / channels(非 aun)/ channelOwners(按 type/name 局部更新非 AUN channel owner,避免前端回写脱敏 credentials)。 */
|
|
556
720
|
export async function execAgentUpdate(args, subject) {
|
|
557
721
|
const a = args ?? {};
|
|
558
722
|
if (!a.aid)
|
|
@@ -606,7 +770,7 @@ export async function execAgentUpdate(args, subject) {
|
|
|
606
770
|
return execAidAvatar({ aid: a.aid, data: p.avatar });
|
|
607
771
|
let touched = false;
|
|
608
772
|
const data = { aid: a.aid };
|
|
609
|
-
const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owners !== undefined || p.fullaccess !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
|
|
773
|
+
const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owner !== undefined || p.owners !== undefined || p.fullaccess !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
|
|
610
774
|
if (p.active_baseagent !== undefined) {
|
|
611
775
|
if (typeof p.active_baseagent !== 'string' || !p.active_baseagent.trim()) {
|
|
612
776
|
return { error: `无效 active_baseagent: ${JSON.stringify(p.active_baseagent)}(必须是非空字符串)`, code: 'INVALID_ARGS' };
|
|
@@ -638,21 +802,8 @@ export async function execAgentUpdate(args, subject) {
|
|
|
638
802
|
else
|
|
639
803
|
delete config.projects;
|
|
640
804
|
}
|
|
641
|
-
if (p.owners !== undefined) {
|
|
642
|
-
|
|
643
|
-
return { error: 'owners must contain at least one owner', code: 'LAST_OWNER_PROTECTED' };
|
|
644
|
-
}
|
|
645
|
-
const owners = [];
|
|
646
|
-
for (const rawOwner of p.owners) {
|
|
647
|
-
if (typeof rawOwner !== 'string' || !rawOwner.trim() || !isValidAid(rawOwner.trim())) {
|
|
648
|
-
return { error: `Invalid owner AID: ${JSON.stringify(rawOwner)}`, code: 'INVALID_ARGS' };
|
|
649
|
-
}
|
|
650
|
-
const owner = rawOwner.trim();
|
|
651
|
-
if (!owners.includes(owner))
|
|
652
|
-
owners.push(owner);
|
|
653
|
-
}
|
|
654
|
-
config.owners = owners;
|
|
655
|
-
touched = true;
|
|
805
|
+
if (p.owner !== undefined || p.owners !== undefined) {
|
|
806
|
+
return { error: 'Root owner/owners configuration is not supported; use ec aid bind', code: 'INVALID_ARGS' };
|
|
656
807
|
}
|
|
657
808
|
if (p.fullaccess !== undefined) {
|
|
658
809
|
config.fullaccess = { enabled: p.fullaccess.enabled };
|
|
@@ -728,6 +879,7 @@ export async function execAgentQuery(args, service, subject) {
|
|
|
728
879
|
const config = cfgRead(ConfigTarget.Agent, { self: aid });
|
|
729
880
|
const safeConfig = buildSafeAgentConfig(config);
|
|
730
881
|
const safeAgentConfig = safeConfig ?? {};
|
|
882
|
+
const ownership = ownerResolver.snapshot(aid);
|
|
731
883
|
const fullaccessStatus = agentFullAccessStatus(aid, subject?.principalId ?? subject?.actorId);
|
|
732
884
|
const data = {
|
|
733
885
|
...res,
|
|
@@ -737,9 +889,16 @@ export async function execAgentQuery(args, service, subject) {
|
|
|
737
889
|
active_baseagent: safeAgentConfig.active_baseagent ?? res.config?.baseagent ?? null,
|
|
738
890
|
projects: safeAgentConfig.projects ?? {},
|
|
739
891
|
baseagents: safeAgentConfig.baseagents ?? {},
|
|
892
|
+
owner: safeConfig ? safeAgentConfig.owner : res.config?.owner ?? null,
|
|
740
893
|
owners: safeAgentConfig.owners ?? res.config?.owners ?? [],
|
|
741
894
|
},
|
|
742
895
|
safeConfig,
|
|
896
|
+
ownership: {
|
|
897
|
+
relation: ownership.relation ?? null,
|
|
898
|
+
consensusStatus: ownership.consensusStatus,
|
|
899
|
+
checkedAt: ownership.checkedAt ?? null,
|
|
900
|
+
authorizationStatus: ownership.authorizationStatus,
|
|
901
|
+
},
|
|
743
902
|
fullaccessStatus: {
|
|
744
903
|
...fullaccessStatus,
|
|
745
904
|
canConfigure: agentFullAccessWriteError(aid, subject) === undefined,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { parseAgentWelcomeArgs, parseInitializationArgs } from '../../cli/agent-create.js';
|
|
1
|
+
import { parseAgentWelcomeArgs, parseInitializationArgs, resolveAgentCreateMode } from '../../cli/agent-create.js';
|
|
2
|
+
import { parseOwnershipCommand } from '../../aun/aid/ownership-operation.js';
|
|
2
3
|
import { normalizeCliArgv } from '../../cli/cli-argv.js';
|
|
3
4
|
import { resolveConfigCommand, } from '../../config/resolved-config-op.js';
|
|
4
5
|
export { normalizeCliArgv, parseLegacyCliCommand, validateCliArgv } from '../../cli/cli-argv.js';
|
|
@@ -24,6 +25,8 @@ export function parseCliIntent(inputArgv, source = 'menu.cli', options = {}) {
|
|
|
24
25
|
const cmd = argv[0];
|
|
25
26
|
if (cmd === 'model')
|
|
26
27
|
return parseModelCommand(argv, source);
|
|
28
|
+
if (cmd === 'thread')
|
|
29
|
+
return parseThreadCommand(argv, source);
|
|
27
30
|
if (cmd === 'config')
|
|
28
31
|
return parseConfigCommand(argv, source, options.defaultRelation);
|
|
29
32
|
if (cmd === 'stats')
|
|
@@ -31,7 +34,7 @@ export function parseCliIntent(inputArgv, source = 'menu.cli', options = {}) {
|
|
|
31
34
|
if (cmd === 'agent')
|
|
32
35
|
return parseAgentCommand(argv, source);
|
|
33
36
|
if (cmd === 'aid')
|
|
34
|
-
return parseAidCommand(argv, source);
|
|
37
|
+
return parseAidCommand(argv, source, options.defaultRelation?.self);
|
|
35
38
|
if (cmd === 'storage')
|
|
36
39
|
return parseStorageCommand(argv, source);
|
|
37
40
|
if (cmd === 'version') {
|
|
@@ -48,6 +51,36 @@ export function parseCliIntent(inputArgv, source = 'menu.cli', options = {}) {
|
|
|
48
51
|
}
|
|
49
52
|
return raw(source, argv, `Unknown command: ${cmd}`);
|
|
50
53
|
}
|
|
54
|
+
function parseThreadCommand(argv, source) {
|
|
55
|
+
if (argv[1] !== 'summary' || !['show', 'log'].includes(argv[2] ?? '')) {
|
|
56
|
+
return raw(source, argv, 'Only thread summary show/log is available through remote CLI');
|
|
57
|
+
}
|
|
58
|
+
const action = argv[2];
|
|
59
|
+
const parsed = parseArgs(argv.slice(3));
|
|
60
|
+
const args = parsed.args;
|
|
61
|
+
if (Object.keys(args).some(key => !['self', 'format'].includes(key))) {
|
|
62
|
+
return raw(source, argv, 'Unsupported thread summary option');
|
|
63
|
+
}
|
|
64
|
+
if (parsed.positionals.length !== 1 || typeof args.self !== 'string' || !args.self.trim()) {
|
|
65
|
+
return raw(source, argv, 'thread summary show/log requires <peer>/<threadId> and --self');
|
|
66
|
+
}
|
|
67
|
+
if (args.format !== 'json') {
|
|
68
|
+
return raw(source, argv, 'Remote thread summary reads require --format json');
|
|
69
|
+
}
|
|
70
|
+
const pieces = parsed.positionals[0].split('/');
|
|
71
|
+
if (pieces.length !== 2 || !pieces[0] || !pieces[1]
|
|
72
|
+
|| pieces[1] === 'main' || pieces[1] === 'current'
|
|
73
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(pieces[1])) {
|
|
74
|
+
return raw(source, argv, 'A concrete peer/threadId reference is required');
|
|
75
|
+
}
|
|
76
|
+
const operation = action === 'show' ? 'ec.thread.summary-show' : 'ec.thread.summary-log';
|
|
77
|
+
return recognized(operation, 'relation', source, {
|
|
78
|
+
self: args.self,
|
|
79
|
+
peer: pieces[0],
|
|
80
|
+
threadId: pieces[1],
|
|
81
|
+
action,
|
|
82
|
+
}, argv);
|
|
83
|
+
}
|
|
51
84
|
export function rawCliIntent(argv, source = 'menu.cli') {
|
|
52
85
|
return {
|
|
53
86
|
operation: 'cli.exec.raw',
|
|
@@ -157,7 +190,16 @@ function parseStatsCommand(argv, source) {
|
|
|
157
190
|
}
|
|
158
191
|
function parseAgentCommand(argv, source) {
|
|
159
192
|
const subcmd = argv[1];
|
|
160
|
-
|
|
193
|
+
let createMode;
|
|
194
|
+
if (subcmd === 'new') {
|
|
195
|
+
try {
|
|
196
|
+
createMode = resolveAgentCreateMode(argv.slice(1));
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return raw(source, argv, 'Invalid creation mode');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (createMode === 'initialize' || subcmd === 'initialize') {
|
|
161
203
|
try {
|
|
162
204
|
const parsed = parseInitializationArgs(argv.slice(1));
|
|
163
205
|
return recognized('agent.initialize', 'control', source, { aid: parsed.aid }, argv, true);
|
|
@@ -195,8 +237,22 @@ function parseAgentCommand(argv, source) {
|
|
|
195
237
|
return recognized('agent.getConfig', 'control', source, args, argv, true);
|
|
196
238
|
return raw(source, argv, `Unknown agent subcommand: ${subcmd}`);
|
|
197
239
|
}
|
|
198
|
-
function parseAidCommand(argv, source) {
|
|
240
|
+
function parseAidCommand(argv, source, defaultSelfAid) {
|
|
199
241
|
const subcmd = argv[1];
|
|
242
|
+
if (subcmd === 'bind') {
|
|
243
|
+
try {
|
|
244
|
+
const command = parseOwnershipCommand(argv.slice(1));
|
|
245
|
+
const subjectAid = command.subjectAid ?? defaultSelfAid;
|
|
246
|
+
return recognized(command.action === 'bind' ? 'ec.aid.bind' : 'ec.aid.bind.status', 'agent', source, {
|
|
247
|
+
...(subjectAid ? { self: subjectAid } : {}),
|
|
248
|
+
...(command.subjectAid ? { subjectAid: command.subjectAid } : {}),
|
|
249
|
+
...(command.action === 'bind' ? { ownerAid: command.ownerAid } : {}),
|
|
250
|
+
}, argv, command.action === 'bind');
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
return raw(source, argv, error instanceof Error ? error.message : 'Invalid aid bind command');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
200
256
|
if (subcmd === 'avatar') {
|
|
201
257
|
const tail = argv.slice(2);
|
|
202
258
|
const aid = tail[0];
|