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
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import crypto from 'crypto';
|
|
13
13
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
14
14
|
import { logger } from '../../utils/logger.js';
|
|
15
|
+
import { sessionTopicThreadId } from '../thread/topic-id.js';
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
16
17
|
// DebugDelegationRegistry
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
@@ -101,7 +102,7 @@ export function buildDebugTaskContext(input) {
|
|
|
101
102
|
let peerKeyId = chatType === 'group'
|
|
102
103
|
? (meta.groupId || session.channelId)
|
|
103
104
|
: (meta.peerId || session.channelId);
|
|
104
|
-
let threadId = session
|
|
105
|
+
let threadId = sessionTopicThreadId(session);
|
|
105
106
|
if (session.channelId?.startsWith('trigger:') && session.selfAID && input.getTrigger) {
|
|
106
107
|
const triggerId = session.channelId.slice('trigger:'.length);
|
|
107
108
|
const origin = input.getTrigger(session.selfAID, triggerId)?.origin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { authorizeOperation, buildAuthSubject } from './auth-gateway.js';
|
|
1
|
+
import { authorizeFreshOperation as authorizeOperation, buildAuthSubject } from './auth-gateway.js';
|
|
2
2
|
import { trustedExecutionIdentityInput } from './agent-delegation.js';
|
|
3
3
|
import { isManagementRole } from '../../config/builtin-roles.js';
|
|
4
4
|
import { parsePeerKey } from '../relation/peer-identity.js';
|
|
@@ -35,7 +35,7 @@ export function createDelegationAuthorizer({ agentDelegationRegistry, sessionMan
|
|
|
35
35
|
&& !(operation === 'agent.show' && isManagementRole(subject.role))) {
|
|
36
36
|
return { ok: false, code: 'SCOPE_MISMATCH', error: 'only the current Agent can be targeted' };
|
|
37
37
|
}
|
|
38
|
-
const decision = authorizeOperation({
|
|
38
|
+
const decision = await authorizeOperation({
|
|
39
39
|
source: 'agent-tool',
|
|
40
40
|
subject,
|
|
41
41
|
intent: {
|
|
@@ -89,7 +89,7 @@ function readState(value) {
|
|
|
89
89
|
}
|
|
90
90
|
if (state.credentialType === 'task' || state.credentialType === 'codex-session')
|
|
91
91
|
sanitized.credentialType = state.credentialType;
|
|
92
|
-
if (state.revocationReason && ['completed', 'interrupted', 'replaced', 'policy_revoked', 'failed', 'revoked'].includes(state.revocationReason)) {
|
|
92
|
+
if (state.revocationReason && ['completed', 'tool_completed', 'interrupted', 'replaced', 'policy_revoked', 'failed', 'revoked'].includes(state.revocationReason)) {
|
|
93
93
|
sanitized.revocationReason = state.revocationReason;
|
|
94
94
|
}
|
|
95
95
|
return sanitized;
|
|
@@ -166,6 +166,9 @@ export class DelegationDiagnostics {
|
|
|
166
166
|
if (approval.status === 'expired' || approval.expiresAt !== undefined && approval.expiresAt <= Date.now()) {
|
|
167
167
|
return 'approval_expired';
|
|
168
168
|
}
|
|
169
|
+
// Provider finished the tool item without spending it; the task itself is still live.
|
|
170
|
+
if (approval.revocationReason === 'tool_completed')
|
|
171
|
+
return 'approval_not_found';
|
|
169
172
|
if (approval.status !== 'active')
|
|
170
173
|
return this.taskCause(approval);
|
|
171
174
|
return 'approval_not_found';
|
|
@@ -115,7 +115,8 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
115
115
|
// still has to name a known operation and pass structural command parsing,
|
|
116
116
|
// but relation/Agent role rules, source lists, and daemon-owner gates are
|
|
117
117
|
// not meaningful limits for code already approved for host-level execution.
|
|
118
|
-
if (ctx.processRole === 'fullaccess-run' && ctx.dataScope === 'daemon'
|
|
118
|
+
if (ctx.processRole === 'fullaccess-run' && ctx.dataScope === 'daemon'
|
|
119
|
+
&& operation !== 'ec.aid.bind' && operation !== 'ec.aid.bind.status') {
|
|
119
120
|
return {
|
|
120
121
|
allow: true,
|
|
121
122
|
operation,
|
|
@@ -136,6 +137,14 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
136
137
|
if (!sourceAllowed) {
|
|
137
138
|
return denyDecision(ctx, 'NOT_ALLOWED', `Operation ${operation} is not available from source ${ctx.source}`, operation, intent.scope, opMeta.dangerous);
|
|
138
139
|
}
|
|
140
|
+
if (operation === 'ec.aid.bind' || operation === 'ec.aid.bind.status') {
|
|
141
|
+
const permitted = intent.scope === 'agent' && ctx.processRole !== 'fullaccess-run' && ctx.processRole !== 'daemon-service'
|
|
142
|
+
&& (ctx.isDaemonOwner === true || ctx.processRole === 'daemon-owner'
|
|
143
|
+
|| (isCurrentAgentTarget(ctx) && (role === 'owner' || (operation === 'ec.aid.bind.status' && role === 'admin'))));
|
|
144
|
+
if (!permitted)
|
|
145
|
+
return denyDecision(ctx, 'NOT_ALLOWED', 'Protocol Owner binding requires the subject Owner or daemon Owner', operation, intent.scope, opMeta.dangerous);
|
|
146
|
+
return { allow: true, operation, scope: intent.scope, role, dangerous: opMeta.dangerous, matchedRule: 'protocol-owner-binding' };
|
|
147
|
+
}
|
|
139
148
|
if (ctx.processRole === 'daemon-service') {
|
|
140
149
|
// ECWeb uses the authenticated daemon service for its read-only menu
|
|
141
150
|
// bootstrap (model/effort, agent metadata, trigger views, etc.). These
|
|
@@ -388,6 +388,14 @@ const OPERATIONS = [
|
|
|
388
388
|
description: '获取文件内容(需路径沙箱检查)',
|
|
389
389
|
sources: ['slash', 'menu'],
|
|
390
390
|
},
|
|
391
|
+
{
|
|
392
|
+
id: 'file.search',
|
|
393
|
+
category: 'read',
|
|
394
|
+
dangerous: false,
|
|
395
|
+
defaultScopes: ['filesystem'],
|
|
396
|
+
description: '搜索当前项目文件(需文件权限和项目路径沙箱检查)',
|
|
397
|
+
sources: ['menu'],
|
|
398
|
+
},
|
|
391
399
|
{
|
|
392
400
|
id: 'file.root.agent',
|
|
393
401
|
category: 'read',
|
|
@@ -798,7 +806,9 @@ const OPERATIONS = [
|
|
|
798
806
|
dangerous: false,
|
|
799
807
|
defaultScopes: ['relation', 'agent'],
|
|
800
808
|
description: `${action} managed conversation threads`,
|
|
801
|
-
sources: ['
|
|
809
|
+
sources: (['summary-show', 'summary-log'].includes(action)
|
|
810
|
+
? ['agent-tool', 'menu.cli']
|
|
811
|
+
: ['agent-tool']),
|
|
802
812
|
})),
|
|
803
813
|
{
|
|
804
814
|
id: 'agent.bootstrapComplete',
|
|
@@ -1111,6 +1121,14 @@ const OPERATIONS = [
|
|
|
1111
1121
|
description: 'Inspect the current Agent local AID identity and signing state',
|
|
1112
1122
|
sources: ['agent-tool'],
|
|
1113
1123
|
},
|
|
1124
|
+
{
|
|
1125
|
+
id: 'ec.aid.bind', category: 'write-agent', dangerous: true, defaultScopes: ['agent'],
|
|
1126
|
+
description: 'Request a protocol Owner binding using the subject SDK client', sources: ['agent-tool', 'menu.cli'],
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
id: 'ec.aid.bind.status', category: 'read', dangerous: false, defaultScopes: ['agent'],
|
|
1130
|
+
description: 'Refresh the protocol Owner consensus and binding task projection', sources: ['agent-tool', 'menu.cli'],
|
|
1131
|
+
},
|
|
1114
1132
|
{
|
|
1115
1133
|
id: 'ec.aid.lookup',
|
|
1116
1134
|
category: 'read',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { hasSuppliedInitialization } from '../cli/agent-create.js';
|
|
2
|
+
import { ownerResolver, OWNERSHIP_AUTHORIZATION_MAX_AGE_MS } from './ownership/owner-resolver.js';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import { randomBytes } from 'crypto';
|
|
@@ -10,7 +11,6 @@ import { loadAgent, saveAgent } from '../config-store.js';
|
|
|
10
11
|
import { resolveAgentLifecycle, withLifecycleForWrite } from '../config/lifecycle.js';
|
|
11
12
|
import { renderTemplate } from '../eck/manifest-engine.js';
|
|
12
13
|
import { activeBaseagent } from './model/config-scope.js';
|
|
13
|
-
import { getFirstStaticAgentOwner } from '../config/peer-role-resolver.js';
|
|
14
14
|
import { buildEnvelope } from './message/message-utils.js';
|
|
15
15
|
import { BOOTSTRAP_MESSAGE_TTL_MS, BOOTSTRAP_NOTIFICATION_WINDOW_MS, bootstrapInitialMessageOperationId, bootstrapInitialMessageOperationPrefix, bootstrapInitialRetryOperationId, cancelPendingBootstrapPrompts, postBootstrapWelcomeStatus, postBootstrapWelcomeOperationId, } from './bootstrap-messages.js';
|
|
16
16
|
import { findLatestMessageLogOperation } from './message/message-log.js';
|
|
@@ -19,15 +19,24 @@ import { chatDirPath } from './session/session-fs-store.js';
|
|
|
19
19
|
/** Coordinate the write-ahead completion welcome with the lifecycle commit. */
|
|
20
20
|
export async function completeBootstrapWithWelcome(service, aid, welcome, sessions) {
|
|
21
21
|
const lifecycle = service.lifecycleOf(aid);
|
|
22
|
-
|
|
22
|
+
const config = loadAgent(aid);
|
|
23
|
+
const suppliedOwnerPending = lifecycle === 'ownerpending' && config?.initialization?.mode === 'supplied';
|
|
24
|
+
if (lifecycle !== 'bootstrapping' && lifecycle !== 'active' && !suppliedOwnerPending) {
|
|
23
25
|
const result = service.completeBootstrap(aid);
|
|
24
26
|
return { ...result, reloaded: false };
|
|
25
27
|
}
|
|
26
|
-
if (lifecycle === 'bootstrapping') {
|
|
28
|
+
if (lifecycle === 'bootstrapping' || suppliedOwnerPending) {
|
|
27
29
|
// Existing per-Owner records are immutable retry snapshots. New interactive
|
|
28
30
|
// Bootstrap completions require the welcome text prepared by the Agent.
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
+
await ownerResolver.refresh(aid, { maxAgeMs: OWNERSHIP_AUTHORIZATION_MAX_AGE_MS });
|
|
32
|
+
const owners = ownerResolver.protocolOwners(aid);
|
|
33
|
+
if (owners.length === 0) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false, code: 'OWNER_CONSENSUS_PENDING', reloaded: false,
|
|
36
|
+
error: `Fresh Ownership consensus is required before activating ${aid}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const deliveries = owners.length ? postBootstrapWelcomeStatus(aid, owners).deliveries : [];
|
|
31
40
|
const alreadyPrepared = deliveries.length > 0 && deliveries.every(delivery => delivery.status !== 'not_prepared');
|
|
32
41
|
if (config?.initialization?.mode !== 'supplied' && !alreadyPrepared) {
|
|
33
42
|
try {
|
|
@@ -108,7 +117,7 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
108
117
|
mainSession ??= ownerSession;
|
|
109
118
|
}
|
|
110
119
|
}
|
|
111
|
-
const result = service.completeBootstrap(aid);
|
|
120
|
+
const result = service.completeBootstrap(aid, { allowSuppliedOwnerPending: suppliedOwnerPending });
|
|
112
121
|
if (!result.ok)
|
|
113
122
|
return { ...result, reloaded: false };
|
|
114
123
|
if (!welcome) {
|
|
@@ -129,7 +138,7 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
129
138
|
logger.warn(`[Bootstrap] Completion committed; welcome reconciliation failed for ${aid}: ${message}`);
|
|
130
139
|
welcomeResult = { deliveries: [], error: message };
|
|
131
140
|
try {
|
|
132
|
-
welcomeResult = { ...postBootstrapWelcomeStatus(aid,
|
|
141
|
+
welcomeResult = { ...postBootstrapWelcomeStatus(aid, ownerResolver.protocolOwners(aid)), error: message };
|
|
133
142
|
}
|
|
134
143
|
catch {
|
|
135
144
|
// A local store failure must not turn an already committed lifecycle
|
|
@@ -151,6 +160,8 @@ export function createBootstrapOwnerBoundHandler({ getService, agentRegistry, ch
|
|
|
151
160
|
if (!service)
|
|
152
161
|
return;
|
|
153
162
|
const instance = channelInstances.find(candidate => {
|
|
163
|
+
if (candidate.channelType !== 'aun')
|
|
164
|
+
return false;
|
|
154
165
|
const owner = agentRegistry.resolveByChannel(candidate.adapter.channelKey)
|
|
155
166
|
?? agentRegistry.resolveByChannel(candidate.adapter.channelName);
|
|
156
167
|
return owner?.aid === agentAid;
|
|
@@ -182,7 +193,8 @@ export function createBootstrapCompletionHandler({ service, agentRegistry, chann
|
|
|
182
193
|
});
|
|
183
194
|
const welcome = aunInstance?.channel;
|
|
184
195
|
const owningAgent = agentRegistry.get(aid);
|
|
185
|
-
|
|
196
|
+
await ownerResolver.refresh(aid, { maxAgeMs: OWNERSHIP_AUTHORIZATION_MAX_AGE_MS });
|
|
197
|
+
const firstOwnerAid = ownerResolver.owner(aid);
|
|
186
198
|
const sessions = aunInstance && firstOwnerAid && owningAgent
|
|
187
199
|
? {
|
|
188
200
|
ensurePostBootstrapMainSession: async (owner) => {
|
|
@@ -224,7 +236,8 @@ export class BootstrapService {
|
|
|
224
236
|
const aid = agent?.aid || ctx.agentAid;
|
|
225
237
|
if (!aid)
|
|
226
238
|
return false;
|
|
227
|
-
|
|
239
|
+
const loadedConfig = loadAgent(aid) || agent?.config;
|
|
240
|
+
if (hasSuppliedInitialization(aid) || loadedConfig?.initialization)
|
|
228
241
|
return false;
|
|
229
242
|
const key = aid;
|
|
230
243
|
if (this.inFlight.has(key))
|
|
@@ -233,7 +246,6 @@ export class BootstrapService {
|
|
|
233
246
|
let lifecycleStarted = false;
|
|
234
247
|
let notificationPersisted = false;
|
|
235
248
|
let attemptedOperationId;
|
|
236
|
-
const loadedConfig = loadAgent(aid) || agent?.config;
|
|
237
249
|
if (!loadedConfig) {
|
|
238
250
|
this.inFlight.delete(key);
|
|
239
251
|
return false;
|
|
@@ -243,15 +255,21 @@ export class BootstrapService {
|
|
|
243
255
|
this.inFlight.delete(key);
|
|
244
256
|
return false;
|
|
245
257
|
}
|
|
246
|
-
if (lifecycle !== 'created' && lifecycle !== 'bootstrapping') {
|
|
258
|
+
if (lifecycle !== 'created' && lifecycle !== 'ownerpending' && lifecycle !== 'bootstrapping') {
|
|
247
259
|
this.inFlight.delete(key);
|
|
248
260
|
logger.warn(`[Bootstrap] Refusing invalid lifecycle for ${aid}: ${String(loadedConfig.lifecycle)}`);
|
|
249
261
|
return false;
|
|
250
262
|
}
|
|
251
263
|
const config = { ...loadedConfig, lifecycle };
|
|
252
|
-
const starting = lifecycle
|
|
264
|
+
const starting = lifecycle !== 'bootstrapping';
|
|
253
265
|
const channelType = ctx.channelType || this.channelTypeFromKey(ctx.channelKey);
|
|
266
|
+
if (channelType === 'aun')
|
|
267
|
+
await ownerResolver.refresh(aid, { maxAgeMs: OWNERSHIP_AUTHORIZATION_MAX_AGE_MS });
|
|
254
268
|
const configuredRecipient = this.resolveConfiguredRecipient(config, ctx.channelKey, channelType);
|
|
269
|
+
if (channelType === 'aun' && (!configuredRecipient || ownerResolver.owner(aid) !== configuredRecipient)) {
|
|
270
|
+
this.inFlight.delete(key);
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
255
273
|
const recipientId = ctx.recipientId || configuredRecipient;
|
|
256
274
|
if (!recipientId) {
|
|
257
275
|
this.inFlight.delete(key);
|
|
@@ -261,10 +279,9 @@ export class BootstrapService {
|
|
|
261
279
|
this.inFlight.delete(key);
|
|
262
280
|
return false;
|
|
263
281
|
}
|
|
264
|
-
// Bootstrap is initiated by connection/
|
|
265
|
-
// an existing group message.
|
|
266
|
-
//
|
|
267
|
-
// group context must never change this initial delivery target.
|
|
282
|
+
// Bootstrap is initiated by connection/Owner binding, not by a reply to
|
|
283
|
+
// an existing group message. The initial prompt always uses a private
|
|
284
|
+
// route to the protocol-confirmed Owner.
|
|
268
285
|
const delivery = { chatType: 'private' };
|
|
269
286
|
const channelId = channelType === 'aun'
|
|
270
287
|
? recipientId
|
|
@@ -382,7 +399,7 @@ export class BootstrapService {
|
|
|
382
399
|
this.inFlight.delete(key);
|
|
383
400
|
}
|
|
384
401
|
}
|
|
385
|
-
completeBootstrap(aid) {
|
|
402
|
+
completeBootstrap(aid, options = {}) {
|
|
386
403
|
const agent = this.agentRegistry.get(aid);
|
|
387
404
|
const loadedConfig = loadAgent(aid) || agent?.config;
|
|
388
405
|
if (!loadedConfig)
|
|
@@ -390,7 +407,9 @@ export class BootstrapService {
|
|
|
390
407
|
const lifecycle = resolveAgentLifecycle(loadedConfig);
|
|
391
408
|
if (lifecycle === 'active')
|
|
392
409
|
return { ok: true, aid, transitioned: false };
|
|
393
|
-
|
|
410
|
+
const suppliedOwnerPending = options.allowSuppliedOwnerPending === true
|
|
411
|
+
&& lifecycle === 'ownerpending' && loadedConfig.initialization?.mode === 'supplied';
|
|
412
|
+
if (lifecycle !== 'bootstrapping' && !suppliedOwnerPending) {
|
|
394
413
|
return {
|
|
395
414
|
ok: false,
|
|
396
415
|
code: 'INVALID_LIFECYCLE',
|
|
@@ -426,8 +445,12 @@ export class BootstrapService {
|
|
|
426
445
|
throw new Error(`Agent "${aid}" disappeared while updating lifecycle`);
|
|
427
446
|
saveAgent(withLifecycleForWrite(cfg, lifecycle));
|
|
428
447
|
}
|
|
429
|
-
resolveConfiguredRecipient(config,
|
|
430
|
-
|
|
448
|
+
resolveConfiguredRecipient(config, channelKey, channelType) {
|
|
449
|
+
if (channelType === 'aun' || channelKey === 'aun' || channelKey.startsWith('aun#'))
|
|
450
|
+
return ownerResolver.owner(config.aid);
|
|
451
|
+
const channel = config.channels?.find(item => item.type !== 'aun'
|
|
452
|
+
&& (item.type === channelKey || `${item.type}#${config.aid}#${item.name}` === channelKey));
|
|
453
|
+
return channel?.owner ?? channel?.owners?.[0];
|
|
431
454
|
}
|
|
432
455
|
defaultChannelIdForConnection(channelType, recipientId) {
|
|
433
456
|
if (channelType === 'aun')
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import { getOwners } from './ownership/owner-resolver.js';
|
|
2
3
|
import fs from 'fs';
|
|
4
|
+
import { removeRestartRequest } from '../utils/restart-safety.js';
|
|
3
5
|
import { tryParseChannelKey } from './channel-loader.js';
|
|
4
6
|
import { agentMdPath } from '../paths.js';
|
|
5
7
|
import { registerAdapterInteractions } from './interaction-router.js';
|
|
@@ -13,6 +15,7 @@ import { getFirstStaticAgentOwner } from '../config/peer-role-resolver.js';
|
|
|
13
15
|
import { isManagementRole } from '../config/builtin-roles.js';
|
|
14
16
|
import { pendingInterruptHints } from './message/pending-hints.js';
|
|
15
17
|
import { logger } from '../utils/logger.js';
|
|
18
|
+
import { sessionLocalTopicId } from './thread/topic-id.js';
|
|
16
19
|
export function createAgentStorageClientResolver(channelInstances) {
|
|
17
20
|
return (channelKey, targetAid) => {
|
|
18
21
|
const instance = channelInstances.find(candidate => candidate.channelType === 'aun'
|
|
@@ -145,7 +148,7 @@ export function registerChannelInstance(inst, dependencies) {
|
|
|
145
148
|
const owningAgent = resolveOwningAgent(channelKey, inst.adapter.channelName);
|
|
146
149
|
return {
|
|
147
150
|
observable: owningAgent?.getObservable() ?? false,
|
|
148
|
-
owners: owningAgent ?
|
|
151
|
+
owners: owningAgent ? getOwners(owningAgent.aid) : [],
|
|
149
152
|
};
|
|
150
153
|
});
|
|
151
154
|
}
|
|
@@ -163,6 +166,7 @@ export function createChannelStartupNotifications({ channelInstances, agentRegis
|
|
|
163
166
|
const onlineNoticeSent = new Set();
|
|
164
167
|
let pendingRestartNoticeInFlight = null;
|
|
165
168
|
let pendingRestartNoticeSent = false;
|
|
169
|
+
let pendingRestartRetry;
|
|
166
170
|
const sendOnlineNoticeForChannel = (inst) => {
|
|
167
171
|
const name = inst.adapter.channelName;
|
|
168
172
|
const agent = agentRegistry.resolveByChannel(inst.adapter.channelKey) ?? agentRegistry.resolveByChannel(name);
|
|
@@ -219,6 +223,20 @@ export function createChannelStartupNotifications({ channelInstances, agentRegis
|
|
|
219
223
|
if (pendingRestartNoticeSent || !fs.existsSync(pendingFile))
|
|
220
224
|
return;
|
|
221
225
|
const pending = JSON.parse(fs.readFileSync(pendingFile, 'utf-8'));
|
|
226
|
+
if (pending.requestId && pending.requesterPid) {
|
|
227
|
+
if (pending.requesterPid === process.pid)
|
|
228
|
+
return;
|
|
229
|
+
if (pending.status !== 'ready' || pending.daemonPid !== process.pid) {
|
|
230
|
+
if (!pendingRestartRetry) {
|
|
231
|
+
pendingRestartRetry = setTimeout(() => {
|
|
232
|
+
pendingRestartRetry = undefined;
|
|
233
|
+
void trySendPendingRestartNotice();
|
|
234
|
+
}, 1_000);
|
|
235
|
+
pendingRestartRetry.unref();
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
222
240
|
const adapter = commandHandler.getAdapter(pending.channel)
|
|
223
241
|
?? channelInstances.find(inst => inst.adapter.channelKey === pending.channel)?.adapter;
|
|
224
242
|
if (!adapter)
|
|
@@ -237,7 +255,10 @@ export function createChannelStartupNotifications({ channelInstances, agentRegis
|
|
|
237
255
|
});
|
|
238
256
|
if (!restartDelivery.valid) {
|
|
239
257
|
logger.warn(`[Restart] Discarding pending notification without a valid persisted delivery route: channel=${pending.channel} channelId=${pending.channelId}`);
|
|
240
|
-
|
|
258
|
+
if (pending.requestId)
|
|
259
|
+
removeRestartRequest(pendingFile, pending.requestId);
|
|
260
|
+
else
|
|
261
|
+
fs.rmSync(pendingFile, { force: true });
|
|
241
262
|
return;
|
|
242
263
|
}
|
|
243
264
|
const replyContext = {
|
|
@@ -271,7 +292,12 @@ export function createChannelStartupNotifications({ channelInstances, agentRegis
|
|
|
271
292
|
subtype: restartNotice.subtype,
|
|
272
293
|
});
|
|
273
294
|
pendingRestartNoticeSent = true;
|
|
274
|
-
|
|
295
|
+
if (pendingRestartRetry)
|
|
296
|
+
clearTimeout(pendingRestartRetry);
|
|
297
|
+
if (pending.requestId)
|
|
298
|
+
removeRestartRequest(pendingFile, pending.requestId);
|
|
299
|
+
else
|
|
300
|
+
fs.rmSync(pendingFile, { force: true });
|
|
275
301
|
logger.info(`[Restart] Notification sent via ${pending.channel}`);
|
|
276
302
|
})();
|
|
277
303
|
try {
|
|
@@ -390,7 +416,7 @@ export function wrapChannelSend(inst, dependencies) {
|
|
|
390
416
|
from: owningAgent?.aid ?? envelope.agentName ?? session.selfAID ?? 'self',
|
|
391
417
|
to: String(target || envelope.channelId),
|
|
392
418
|
sessionId: session.id,
|
|
393
|
-
threadId: envelope.replyContext?.
|
|
419
|
+
threadId: envelope.replyContext?.localTopicId || sessionLocalTopicId(session) || '',
|
|
394
420
|
chatType: isGroup ? 'group' : 'private',
|
|
395
421
|
groupId: isGroup ? String(session.metadata?.groupId || session.channelId) : null,
|
|
396
422
|
msgId: `${envelope.taskId || 'out'}_${Date.now()}`,
|