evolcore 0.0.35 → 0.0.36
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 +31 -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 +134 -48
- 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 +109 -34
- 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
|
@@ -2,6 +2,7 @@ import { getRunnerCatalog, catalogEfforts, assertCatalogSelectable, } from '../c
|
|
|
2
2
|
// Ecagent/OpenAI API 不认识 Claude Code SDK 的窗口后缀,必须传入基础模型 ID。
|
|
3
3
|
import { stripContextWindowSuffix } from '../core/model/context-window-suffix.js';
|
|
4
4
|
import fs from 'fs';
|
|
5
|
+
import { assertOwnershipAuthorization } from '../core/ownership/owner-resolver.js';
|
|
5
6
|
import path from 'path';
|
|
6
7
|
import { AgentHarness, JsonlSessionRepo, NodeExecutionEnv, } from '../../ecagent/dist/node.js';
|
|
7
8
|
import { Type, createModels, createProvider, } from '../../ecagent/dist/runtime/index.js';
|
|
@@ -16,6 +17,7 @@ import { ErrorType } from '../utils/error-utils.js';
|
|
|
16
17
|
import { summarizeToolInputForAudit } from '../utils/tool-summary.js';
|
|
17
18
|
import { auditToolPreflightDenial } from '../core/auth/authorization-audit.js';
|
|
18
19
|
import { resolveEcagentConfig } from './baseagent.js';
|
|
20
|
+
import { resolveProviderServiceForBaseagent } from '../config/providers.js';
|
|
19
21
|
import { buildModelRequestHeaders } from './request-identity.js';
|
|
20
22
|
import { appendRequestPath } from './request-identity.js';
|
|
21
23
|
import { resolveModelSpec } from '../stats/billing.js';
|
|
@@ -790,6 +792,32 @@ export class EcagentRunner {
|
|
|
790
792
|
setSendPrompt(fn) { this.sendPromptFn = fn; }
|
|
791
793
|
setPermissionContext(sessionId, context) { this.permissionContexts.set(sessionId, context); }
|
|
792
794
|
setCompactStartCallback(callback) { this.onCompactStart = callback; }
|
|
795
|
+
currentProviderConfig(providerOverride) {
|
|
796
|
+
const providerId = providerOverride ?? this.config.providerId;
|
|
797
|
+
if (!providerId)
|
|
798
|
+
return this.config;
|
|
799
|
+
const provider = resolveProviderServiceForBaseagent(providerId, 'ecagent', this.config.providerServiceType);
|
|
800
|
+
if (provider.style !== 'openai-compatible') {
|
|
801
|
+
throw new Error(`Provider ${providerId} uses unsupported ecagent style: ${provider.style}`);
|
|
802
|
+
}
|
|
803
|
+
if (!provider.apiKey)
|
|
804
|
+
throw new Error(`Provider ${providerId} has no API key`);
|
|
805
|
+
return {
|
|
806
|
+
...this.config,
|
|
807
|
+
apiKey: provider.apiKey,
|
|
808
|
+
baseUrl: provider.baseUrl,
|
|
809
|
+
headers: buildModelRequestHeaders({
|
|
810
|
+
baseagent: 'ecagent',
|
|
811
|
+
baseUrl: provider.baseUrl,
|
|
812
|
+
agentAid: this.agentAid,
|
|
813
|
+
configuredHeaders: provider.headers,
|
|
814
|
+
}),
|
|
815
|
+
queryParams: provider.queryParams,
|
|
816
|
+
providerServiceType: provider.serviceType,
|
|
817
|
+
providerStyle: provider.style,
|
|
818
|
+
modelOverrides: provider.modelOverrides,
|
|
819
|
+
};
|
|
820
|
+
}
|
|
793
821
|
listModes() {
|
|
794
822
|
return [
|
|
795
823
|
{ key: 'readonly', nameZh: '只读', description: '只读操作自动执行,写入直接拒绝', available: true },
|
|
@@ -891,6 +919,7 @@ export class EcagentRunner {
|
|
|
891
919
|
};
|
|
892
920
|
let completeSent = false;
|
|
893
921
|
try {
|
|
922
|
+
const connection = this.currentProviderConfig(request.modelOverride?.provider);
|
|
894
923
|
await fs.promises.mkdir(request.projectPath, { recursive: true });
|
|
895
924
|
const previousRuntime = this.runtimes.get(request.sessionId);
|
|
896
925
|
const runtime = await this.getOrCreateRuntime(request.sessionId, request.projectPath, request.initialAgentSessionId, request.modelOverride);
|
|
@@ -908,19 +937,19 @@ export class EcagentRunner {
|
|
|
908
937
|
if (fullaccess && !hasTrustedFullAccessContext(this.permissionContexts.get(request.sessionId))) {
|
|
909
938
|
throw new Error('Ecagent fullaccess requires a trusted per-call execution authorization');
|
|
910
939
|
}
|
|
911
|
-
const model = createModel(modelId,
|
|
940
|
+
const model = createModel(modelId, connection.baseUrl);
|
|
912
941
|
const nodeEnv = new NodeExecutionEnv({ cwd: request.projectPath, shellEnv: { ...process.env, ...request.runtimeEnv, EVOLCORE_SESSION_ID: request.sessionId, EVOLCORE_HOME: resolveRoot() } });
|
|
913
942
|
const models = createModels();
|
|
914
|
-
const transport = createOpenAiTransport(
|
|
943
|
+
const transport = createOpenAiTransport(connection);
|
|
915
944
|
models.setProvider(createProvider({
|
|
916
945
|
id: PROVIDER_ID,
|
|
917
946
|
name: 'EvolCore Gateway',
|
|
918
|
-
baseUrl:
|
|
947
|
+
baseUrl: connection.baseUrl,
|
|
919
948
|
models: [model],
|
|
920
949
|
auth: { apiKey: {
|
|
921
950
|
name: 'EvolCore gateway',
|
|
922
|
-
login: async () => ({ type: 'api_key', key:
|
|
923
|
-
resolve: async () => ({ auth: { apiKey:
|
|
951
|
+
login: async () => ({ type: 'api_key', key: connection.apiKey }),
|
|
952
|
+
resolve: async () => ({ auth: { apiKey: connection.apiKey }, source: 'provider' }),
|
|
924
953
|
} },
|
|
925
954
|
api: transport,
|
|
926
955
|
}));
|
|
@@ -933,9 +962,9 @@ export class EcagentRunner {
|
|
|
933
962
|
tools: createTools(nodeEnv, request.projectPath, request.runtimeEnv, request.modelOverride?.bootstrapAgentMdPath, fullaccess, request.modelOverride?.personalMdPath, this.permissionContexts.get(request.sessionId)?.systemSessionGrants),
|
|
934
963
|
systemPrompt: [DEFAULT_SYSTEM_PROMPT, request.systemPromptAppend].filter(Boolean).join('\n\n'),
|
|
935
964
|
streamOptions: {
|
|
936
|
-
timeoutMs:
|
|
937
|
-
maxRetries:
|
|
938
|
-
maxRetryDelayMs:
|
|
965
|
+
timeoutMs: connection.timeoutMs,
|
|
966
|
+
maxRetries: connection.maxRetries,
|
|
967
|
+
maxRetryDelayMs: connection.maxRetryDelayMs,
|
|
939
968
|
},
|
|
940
969
|
});
|
|
941
970
|
runtime.harness = harness;
|
|
@@ -1214,6 +1243,12 @@ export class EcagentRunner {
|
|
|
1214
1243
|
}
|
|
1215
1244
|
async authorizeTool(sessionId, projectPath, mode, toolName, input, turn) {
|
|
1216
1245
|
const permissionContext = this.permissionContexts.get(sessionId);
|
|
1246
|
+
try {
|
|
1247
|
+
await assertOwnershipAuthorization(permissionContext);
|
|
1248
|
+
}
|
|
1249
|
+
catch (error) {
|
|
1250
|
+
return { block: true, reason: error instanceof Error ? error.message : String(error) };
|
|
1251
|
+
}
|
|
1217
1252
|
const recordBlockedOperation = async (policyCode, operationInput = input, matchedPath) => {
|
|
1218
1253
|
const summary = summarizeToolInputForAudit(toolName, operationInput).slice(0, 512);
|
|
1219
1254
|
auditToolPreflightDenial({
|
|
@@ -1418,12 +1453,13 @@ export class EcagentRunner {
|
|
|
1418
1453
|
const compactEffort = modelOverride?.effortMode === 'model_default'
|
|
1419
1454
|
? undefined
|
|
1420
1455
|
: modelOverride?.effort ?? this.effort;
|
|
1421
|
-
const
|
|
1456
|
+
const connection = this.currentProviderConfig();
|
|
1457
|
+
const model = createModel(compactModel, connection.baseUrl);
|
|
1422
1458
|
const env = new NodeExecutionEnv({ cwd: runtime.projectPath });
|
|
1423
1459
|
const models = createModels();
|
|
1424
|
-
const transport = createOpenAiTransport(
|
|
1460
|
+
const transport = createOpenAiTransport(connection);
|
|
1425
1461
|
models.setProvider(createProvider({
|
|
1426
|
-
id: PROVIDER_ID, auth: { apiKey: { name: 'EvolCore gateway', login: async () => ({ type: 'api_key', key:
|
|
1462
|
+
id: PROVIDER_ID, auth: { apiKey: { name: 'EvolCore gateway', login: async () => ({ type: 'api_key', key: connection.apiKey }), resolve: async () => ({ auth: { apiKey: connection.apiKey } }) } },
|
|
1427
1463
|
models: [model], api: transport,
|
|
1428
1464
|
}));
|
|
1429
1465
|
const harness = new AgentHarness({ env, session: runtime.session, models, model, thinkingLevel: normalizeThinkingLevel(compactEffort), tools: [] });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRunnerCatalog, assertCatalogSelectable } from '../core/model/model-catalog.js';
|
|
2
2
|
// Gemini API 不认识 Claude Code SDK 的窗口后缀,必须传入基础模型 ID。
|
|
3
3
|
import { stripContextWindowSuffix } from '../core/model/context-window-suffix.js';
|
|
4
4
|
/**
|
|
@@ -20,6 +20,7 @@ import os from 'os';
|
|
|
20
20
|
import crypto from 'crypto';
|
|
21
21
|
import { hasTrustedFullAccessContext } from './runner-types.js';
|
|
22
22
|
import { resolveGoogleConfig } from './baseagent.js';
|
|
23
|
+
import { resolveEffective } from '../config/config-manager.js';
|
|
23
24
|
import { commandExists } from '../utils/cross-platform.js';
|
|
24
25
|
import { GeminiSessionFileAdapter } from '../core/session/adapters/gemini-session-file-adapter.js';
|
|
25
26
|
import { logger } from '../utils/logger.js';
|
|
@@ -103,6 +104,7 @@ function isGeminiPermissionDenial(event) {
|
|
|
103
104
|
return /(?:\btool\b.{0,80}\bis not (?:allowed|permitted|authorized)\b|not (?:allowed|permitted|authorized).{0,80}(?:policy|approval)|(?:denied|rejected|blocked).{0,80}(?:by|under|due to).{0,40}(?:policy|approval)|(?:policy|approval).{0,80}(?:denied|rejected|blocked)|(?:approval|confirmation).{0,80}required.{0,80}(?:headless|non[- ]interactive))/i.test(detail);
|
|
104
105
|
}
|
|
105
106
|
const GEMINI_H_CLASS_PATTERNS = [
|
|
107
|
+
String.raw `(?:^|[/\\"])providers\.json(?:_|__|\.lock(?:\.[^/\\"]*)?)?(?:[/\\"]|$)`,
|
|
106
108
|
String.raw `evolcore\.json`,
|
|
107
109
|
String.raw `(?:^|[/\\"])data(?:[/\\"]|$)`,
|
|
108
110
|
String.raw `(?:^|[/\\"])(?:AIDs|aids)(?:[/\\"]|$)`,
|
|
@@ -316,6 +318,8 @@ export class GeminiRunner {
|
|
|
316
318
|
name = 'gemini';
|
|
317
319
|
capabilities = { fullaccess: true, clear: true, compact: false, fork: false, forkAtTurn: false, askUserQuestion: false, planApproval: false, fileRewind: 'unsupported' };
|
|
318
320
|
resolved;
|
|
321
|
+
config;
|
|
322
|
+
agentAid;
|
|
319
323
|
model;
|
|
320
324
|
activeProcesses = new Map();
|
|
321
325
|
activeStreams = new Map();
|
|
@@ -323,7 +327,9 @@ export class GeminiRunner {
|
|
|
323
327
|
onSessionIdUpdate;
|
|
324
328
|
currentMode = 'readonly';
|
|
325
329
|
permissionContexts = new Map();
|
|
326
|
-
constructor(config, callbacks) {
|
|
330
|
+
constructor(config, callbacks, runtime) {
|
|
331
|
+
this.config = config;
|
|
332
|
+
this.agentAid = runtime?.agentAid;
|
|
327
333
|
this.resolved = resolveGoogleConfig(config);
|
|
328
334
|
this.model = stripContextWindowSuffix(this.resolved.model);
|
|
329
335
|
this.onSessionIdUpdate = callbacks.onSessionIdUpdate;
|
|
@@ -331,7 +337,10 @@ export class GeminiRunner {
|
|
|
331
337
|
// ── ModelSwitcher ──
|
|
332
338
|
setModel(model) { this.model = stripContextWindowSuffix(model); }
|
|
333
339
|
getModel() { return this.model; }
|
|
334
|
-
|
|
340
|
+
getModelCatalog() {
|
|
341
|
+
return getRunnerCatalog('gemini', this.agentAid, this.currentProviderConfig());
|
|
342
|
+
}
|
|
343
|
+
async listModels() { const catalog = await this.getModelCatalog(); assertCatalogSelectable(catalog); return catalog.models.map(m => m.id); }
|
|
335
344
|
// ── Effort (not applicable) ──
|
|
336
345
|
setEffort(_effort) { }
|
|
337
346
|
getEffort() { return undefined; }
|
|
@@ -351,14 +360,29 @@ export class GeminiRunner {
|
|
|
351
360
|
setPermissionContext(sessionId, context) {
|
|
352
361
|
this.permissionContexts.set(sessionId, context);
|
|
353
362
|
}
|
|
354
|
-
|
|
363
|
+
currentProviderConfig(providerOverride) {
|
|
364
|
+
const config = this.agentAid
|
|
365
|
+
? { agents: { gemini: resolveEffective({ self: this.agentAid }, { cache: true, expand: false }).baseagents?.gemini ?? this.config.agents?.gemini } }
|
|
366
|
+
: this.config;
|
|
367
|
+
return resolveGoogleConfig(config, providerOverride ? { provider: providerOverride } : undefined);
|
|
368
|
+
}
|
|
369
|
+
buildAgentEnv(sessionId, runtimeEnv, resolved = this.currentProviderConfig()) {
|
|
355
370
|
const env = {
|
|
356
371
|
...process.env,
|
|
357
372
|
EVOLCORE_SESSION_ID: sessionId,
|
|
358
373
|
...(runtimeEnv ?? {}),
|
|
359
374
|
};
|
|
360
|
-
if (
|
|
361
|
-
env.
|
|
375
|
+
if (resolved.apiKey) {
|
|
376
|
+
env.GEMINI_API_KEY = resolved.apiKey;
|
|
377
|
+
env.GOOGLE_API_KEY = resolved.apiKey;
|
|
378
|
+
}
|
|
379
|
+
if (resolved.providerId && resolved.baseUrl) {
|
|
380
|
+
env.GOOGLE_GEMINI_BASE_URL = resolved.baseUrl;
|
|
381
|
+
env.GOOGLE_GENAI_USE_VERTEXAI = 'false';
|
|
382
|
+
env.GOOGLE_GENAI_USE_GCA = 'false';
|
|
383
|
+
env.GEMINI_CLI_CUSTOM_HEADERS = Object.entries(resolved.headers ?? {})
|
|
384
|
+
.map(([name, value]) => `${name}: ${value}`).join(', ');
|
|
385
|
+
}
|
|
362
386
|
return env;
|
|
363
387
|
}
|
|
364
388
|
// ── Stream management ──
|
|
@@ -380,6 +404,8 @@ export class GeminiRunner {
|
|
|
380
404
|
error.code = 'TOPIC_TURN_LEASE_REQUIRED';
|
|
381
405
|
throw error;
|
|
382
406
|
}
|
|
407
|
+
const resolved = this.currentProviderConfig(modelOverride?.provider);
|
|
408
|
+
const env = this.buildAgentEnv(sessionId, runtimeEnv, resolved);
|
|
383
409
|
const topicAgentSessionId = topicBinding ? modelOverride?.backend?.agentSessionId ?? null : undefined;
|
|
384
410
|
const cachedSessionId = topicBinding
|
|
385
411
|
? (topicAgentSessionId && this.activeSessions.get(sessionId) === topicAgentSessionId ? topicAgentSessionId : undefined)
|
|
@@ -410,7 +436,7 @@ export class GeminiRunner {
|
|
|
410
436
|
const geminiHome = path.join(os.homedir(), '.gemini');
|
|
411
437
|
fs.mkdirSync(geminiHome, { recursive: true, mode: 0o700 });
|
|
412
438
|
const selfAid = this.permissionContexts.get(sessionId)?.selfAid;
|
|
413
|
-
const sandboxProbe = executionPermissionMode === 'fullaccess' ? undefined : buildBubblewrapCommand(
|
|
439
|
+
const sandboxProbe = executionPermissionMode === 'fullaccess' ? undefined : buildBubblewrapCommand(resolved.cliPath, [], {
|
|
414
440
|
projectPath,
|
|
415
441
|
selfAid,
|
|
416
442
|
writablePaths: [
|
|
@@ -481,8 +507,7 @@ export class GeminiRunner {
|
|
|
481
507
|
args.push('-r', geminiSessionId);
|
|
482
508
|
}
|
|
483
509
|
// Spawn subprocess
|
|
484
|
-
const
|
|
485
|
-
const sandboxedCommand = executionPermissionMode === 'fullaccess' ? undefined : buildBubblewrapCommand(this.resolved.cliPath, args, {
|
|
510
|
+
const sandboxedCommand = executionPermissionMode === 'fullaccess' ? undefined : buildBubblewrapCommand(resolved.cliPath, args, {
|
|
486
511
|
projectPath,
|
|
487
512
|
selfAid,
|
|
488
513
|
writablePaths: [
|
|
@@ -494,7 +519,7 @@ export class GeminiRunner {
|
|
|
494
519
|
],
|
|
495
520
|
readonlyPaths: tempFiles,
|
|
496
521
|
});
|
|
497
|
-
const child = spawn(sandboxedCommand?.command ??
|
|
522
|
+
const child = spawn(sandboxedCommand?.command ?? resolved.cliPath, sandboxedCommand?.args ?? args, {
|
|
498
523
|
cwd: projectPath,
|
|
499
524
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
500
525
|
env,
|
|
@@ -934,10 +959,9 @@ export class GeminiAgentPlugin {
|
|
|
934
959
|
}
|
|
935
960
|
createAgent(agent, callbacks) {
|
|
936
961
|
const override = agent.config.baseagents?.gemini;
|
|
937
|
-
const syntheticConfig = { agents: { gemini: override } };
|
|
938
962
|
const merged = {
|
|
939
963
|
agents: { gemini: { ...(override || {}) } },
|
|
940
964
|
};
|
|
941
|
-
return { evolagentName: agent.name, baseagent: 'gemini', agent: new GeminiRunner(merged, callbacks) };
|
|
965
|
+
return { evolagentName: agent.name, baseagent: 'gemini', agent: new GeminiRunner(merged, callbacks, { agentAid: agent.aid, agentConfig: agent.config }) };
|
|
942
966
|
}
|
|
943
967
|
}
|
package/dist/aun/aid/client.js
CHANGED
|
@@ -39,7 +39,7 @@ export function suppressSdkLogs() {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
// ==================== SDK package ====================
|
|
42
|
-
export const MIN_AUN_CORE_SDK = [0, 5,
|
|
42
|
+
export const MIN_AUN_CORE_SDK = [0, 5, 22];
|
|
43
43
|
export const AUN_CORE_SDK_PKG = '@agentunion/fastaun';
|
|
44
44
|
function compareVersion(a, min) {
|
|
45
45
|
const parts = a.split('.').map(n => parseInt(n, 10));
|
|
@@ -91,7 +91,7 @@ export function isAunSdkReady() {
|
|
|
91
91
|
return !!(installed && isAunSdkVersionOk(installed.version));
|
|
92
92
|
}
|
|
93
93
|
// ==================== CA Root ====================
|
|
94
|
-
export async function downloadCaRoot(aunPath, gatewayUrl, indent = '') {
|
|
94
|
+
export async function downloadCaRoot(aunPath, gatewayUrl, indent = '', silent = false) {
|
|
95
95
|
const caDir = path.join(aunPath, 'CA', 'root');
|
|
96
96
|
const caCertPath = path.join(caDir, 'root.crt');
|
|
97
97
|
if (fs.existsSync(caCertPath))
|
|
@@ -112,7 +112,8 @@ export async function downloadCaRoot(aunPath, gatewayUrl, indent = '') {
|
|
|
112
112
|
return false;
|
|
113
113
|
}
|
|
114
114
|
fs.writeFileSync(caCertPath, body);
|
|
115
|
-
|
|
115
|
+
if (!silent)
|
|
116
|
+
console.log(`${indent}✓ CA 根证书已下载`);
|
|
116
117
|
return true;
|
|
117
118
|
}
|
|
118
119
|
catch (e) {
|
|
@@ -4,8 +4,11 @@ import path from 'path';
|
|
|
4
4
|
import { parseDocument } from 'yaml';
|
|
5
5
|
import { aidCreate } from './index.js';
|
|
6
6
|
import { DEFAULT_AID_DOMAIN, normalizeAidDomain } from './domain.js';
|
|
7
|
-
import { getAidStore, SLOT } from './store.js';
|
|
8
|
-
import { validateAgentMdDocument, verifyAgentMdUpload } from '@agentunion/fastaun';
|
|
7
|
+
import { getAidStore, loadClient, SLOT } from './store.js';
|
|
8
|
+
import { LocalTokenStore, validateAgentMdDocument, verifyAgentMdUpload, } from '@agentunion/fastaun';
|
|
9
|
+
import { AUN_KEYSTORE_ENCRYPTION_SEED } from './encryption-seed-policy.js';
|
|
10
|
+
import { isValidAid } from './validation.js';
|
|
11
|
+
import { OwnerResolver } from '../../core/ownership/owner-resolver.js';
|
|
9
12
|
import { agentMdPath, resolvePaths } from '../../paths.js';
|
|
10
13
|
import { PeerIdentityCache } from '../../core/relation/peer-identity.js';
|
|
11
14
|
import { agentmdPut, buildInitialAgentMd, invalidateAgentDisplayName, stripAgentMdSignature } from './agentmd.js';
|
|
@@ -107,10 +110,10 @@ function clearControlAgentPeerCaches(aid, root = resolvePaths().root) {
|
|
|
107
110
|
/**
|
|
108
111
|
* Ensure a daemon/control AID has a signed host agent.md.
|
|
109
112
|
*
|
|
110
|
-
* Registration in fastaun creates
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
113
|
+
* Registration in fastaun creates an initial card. This helper upgrades that
|
|
114
|
+
* card, supplements cards missing on older installations, and is idempotent
|
|
115
|
+
* once the local card is canonical. Upload errors are allowed to propagate to
|
|
116
|
+
* the caller so startup can log them without becoming blocked.
|
|
114
117
|
*/
|
|
115
118
|
export async function ensureControlAgentMd(aid, opts = {}) {
|
|
116
119
|
const normalizedAid = String(aid ?? '').trim().replace(/^@/, '');
|
|
@@ -241,7 +244,7 @@ async function candidateExists(store, candidate) {
|
|
|
241
244
|
* - fail-fast:查重探测失败(网关不可达)立即抛错,不掩盖成"均冲突"
|
|
242
245
|
* - 注册后补发控制主机 agent.md;失败只告警,不丢弃已经注册的 AID
|
|
243
246
|
*/
|
|
244
|
-
export async function generateControlAid(aidDomain) {
|
|
247
|
+
export async function generateControlAid(aidDomain, options = {}) {
|
|
245
248
|
const finalAidDomain = aidDomain === undefined
|
|
246
249
|
? resolveControlAidDomain()
|
|
247
250
|
: normalizeAidDomain(aidDomain, 'aidDomain');
|
|
@@ -255,7 +258,9 @@ export async function generateControlAid(aidDomain) {
|
|
|
255
258
|
continue;
|
|
256
259
|
}
|
|
257
260
|
try {
|
|
258
|
-
const created = await aidCreate(candidate
|
|
261
|
+
const created = await aidCreate(candidate, {
|
|
262
|
+
type: 'host', ...(options.silent ? { silent: true } : {}),
|
|
263
|
+
});
|
|
259
264
|
try {
|
|
260
265
|
await ensureControlAgentMd(created.aid, { store: created.store });
|
|
261
266
|
}
|
|
@@ -279,6 +284,12 @@ export async function generateControlAid(aidDomain) {
|
|
|
279
284
|
return { aid: created.aid, gateway: created.gateway };
|
|
280
285
|
}
|
|
281
286
|
catch (e) {
|
|
287
|
+
// Registration may already have saved credentials before authentication
|
|
288
|
+
// failed. Keep that identity so the completed AID can be retried.
|
|
289
|
+
if (store.load(candidate).ok) {
|
|
290
|
+
logger.warn(`[control-aid] ${candidate} 已注册,保留身份以恢复初始化: ${e}`);
|
|
291
|
+
return { aid: candidate, gateway: '' };
|
|
292
|
+
}
|
|
282
293
|
// 查重与实际注册之间存在 TOCTOU 竞态;注册接口也可能因服务端暂时失败而拒绝,
|
|
283
294
|
// 这些情况都换一个候选继续尝试。查重阶段的网关错误仍在 candidateExists 中 fail-fast。
|
|
284
295
|
lastRegistrationError = e;
|
|
@@ -304,3 +315,254 @@ export async function generateControlAid(aidDomain) {
|
|
|
304
315
|
store.close();
|
|
305
316
|
}
|
|
306
317
|
}
|
|
318
|
+
const REGISTRATION_OPERATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
319
|
+
/** Submit an explicit Owner binding after the AID and its final agent.md exist. */
|
|
320
|
+
export async function submitControlAidRegistration(aid, owner, options = {}) {
|
|
321
|
+
const ownerAid = owner.toLowerCase();
|
|
322
|
+
if (!isValidAid(aid) || !isValidAid(ownerAid) || aid.toLowerCase() === ownerAid) {
|
|
323
|
+
return { status: 'failed', error: { code: 'INVALID_OWNER', message: 'A distinct valid Owner AID is required' } };
|
|
324
|
+
}
|
|
325
|
+
const deadline = Date.now() + (options.timeoutMs ?? 15_000);
|
|
326
|
+
let records;
|
|
327
|
+
let store;
|
|
328
|
+
let client;
|
|
329
|
+
let operationId;
|
|
330
|
+
let task;
|
|
331
|
+
let connecting = false;
|
|
332
|
+
let sentOperationIds = new Set();
|
|
333
|
+
let invitationObserver;
|
|
334
|
+
const resolver = new OwnerResolver();
|
|
335
|
+
async function bounded(operation, timeoutMs = deadline - Date.now()) {
|
|
336
|
+
let timer;
|
|
337
|
+
try {
|
|
338
|
+
return await Promise.race([operation, new Promise((_resolve, reject) => {
|
|
339
|
+
timer = setTimeout(() => reject(Object.assign(new Error('Registration invitation submission timed out'), {
|
|
340
|
+
code: 'BIND_SUBMIT_TIMEOUT',
|
|
341
|
+
})), Math.max(0, timeoutMs));
|
|
342
|
+
})]);
|
|
343
|
+
}
|
|
344
|
+
finally {
|
|
345
|
+
if (timer)
|
|
346
|
+
clearTimeout(timer);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function readTask() {
|
|
350
|
+
const raw = records.loadOwnershipTask(aid, operationId)?.task;
|
|
351
|
+
if (!raw)
|
|
352
|
+
return;
|
|
353
|
+
if (raw.operation_id !== operationId || raw.operation !== 'bind' || raw.sub_aid !== aid
|
|
354
|
+
|| raw.owner_aid !== ownerAid || raw.initiator_aid !== aid || raw.new_owner_aid !== undefined
|
|
355
|
+
|| !['pending', 'completed', 'rejected', 'stopped', 'error'].includes(String(raw.status))
|
|
356
|
+
|| typeof raw.step !== 'string' || !Number.isSafeInteger(raw.base_relation_version)
|
|
357
|
+
|| raw.target_relation_version !== Number(raw.base_relation_version) + 1) {
|
|
358
|
+
throw Object.assign(new Error('SDK registration task does not match its original intent'), { code: 'TASK_MISMATCH' });
|
|
359
|
+
}
|
|
360
|
+
task = {
|
|
361
|
+
operation_id: operationId, operation: 'bind', sub_aid: aid, owner_aid: ownerAid,
|
|
362
|
+
base_relation_version: raw.base_relation_version,
|
|
363
|
+
target_relation_version: raw.target_relation_version,
|
|
364
|
+
status: raw.status, step: raw.step,
|
|
365
|
+
...(typeof raw.code === 'string' ? { code: raw.code } : {}),
|
|
366
|
+
...(typeof raw.reason === 'string' ? { reason: raw.reason } : {}),
|
|
367
|
+
...(typeof raw.retryable === 'boolean' ? { retryable: raw.retryable } : {}),
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function result(status, error) {
|
|
371
|
+
return { status, ...(operationId ? { operationId } : {}), ...(task ? { task } : {}), ...(error ? { error } : {}) };
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
records = new LocalTokenStore(resolvePaths().root, { encryptionSeed: AUN_KEYSTORE_ENCRYPTION_SEED });
|
|
375
|
+
const intent = records.loadMetadata(aid)?.registration_intent;
|
|
376
|
+
const registrationIntentOwner = typeof intent?.owner === 'string' ? intent.owner.toLowerCase() : undefined;
|
|
377
|
+
// Preserve an existing SDK registration task and let the same SDK client
|
|
378
|
+
// resume it during connect before OwnerResolver checks/binds the subject.
|
|
379
|
+
if (intent && Object.prototype.hasOwnProperty.call(intent, 'owner')) {
|
|
380
|
+
if (!registrationIntentOwner) {
|
|
381
|
+
return result('unknown', {
|
|
382
|
+
code: 'REGISTRATION_INTENT_PRESENT',
|
|
383
|
+
message: 'Control AID has an invalid SDK registration Owner intent',
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (registrationIntentOwner !== ownerAid) {
|
|
387
|
+
return result('failed', { code: 'OWNER_INTENT_CONFLICT', message: 'Control AID was registered for a different Owner' });
|
|
388
|
+
}
|
|
389
|
+
if (typeof intent.operation_id === 'string' && REGISTRATION_OPERATION_ID.test(intent.operation_id)) {
|
|
390
|
+
operationId = intent.operation_id;
|
|
391
|
+
readTask();
|
|
392
|
+
}
|
|
393
|
+
if (!operationId) {
|
|
394
|
+
return result('unknown', {
|
|
395
|
+
code: 'REGISTRATION_INTENT_PRESENT',
|
|
396
|
+
message: 'Control AID has an SDK registration intent without a valid operation ID',
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (options.agentMdError) {
|
|
401
|
+
return result('failed', { code: 'CONTROL_AGENTMD_NOT_READY', message: options.agentMdError });
|
|
402
|
+
}
|
|
403
|
+
store = await bounded(getAidStore({ slotId: SLOT.cli }));
|
|
404
|
+
const ownershipTasks = records.listOwnershipTasks(aid).map(snapshot => snapshot.task);
|
|
405
|
+
const conflictingTask = ownershipTasks.find(candidate => candidate.sub_aid === aid
|
|
406
|
+
&& (candidate.status === 'pending' || candidate.status === 'error' && candidate.retryable === true)
|
|
407
|
+
&& !(candidate.operation === 'bind' && candidate.owner_aid === ownerAid
|
|
408
|
+
&& candidate.initiator_aid === aid && candidate.new_owner_aid === undefined));
|
|
409
|
+
if (conflictingTask) {
|
|
410
|
+
return result('failed', { code: 'BIND_CONFLICT', message: 'A different active ownership task must be resolved first' });
|
|
411
|
+
}
|
|
412
|
+
client = await bounded(loadClient(store, aid));
|
|
413
|
+
connecting = true;
|
|
414
|
+
sentOperationIds = new Set();
|
|
415
|
+
invitationObserver = observeInvitationSend(client, ownerAid, sentOperationIds);
|
|
416
|
+
await bounded(client.connect({
|
|
417
|
+
connection_kind: 'long', auto_reconnect: false, background_sync: false,
|
|
418
|
+
connect_timeout: 10, call_timeout: 10,
|
|
419
|
+
}));
|
|
420
|
+
if (registrationIntentOwner === ownerAid && operationId) {
|
|
421
|
+
readTask();
|
|
422
|
+
if ((!task || task.status === 'pending') && !sentOperationIds.has(operationId)) {
|
|
423
|
+
await bounded(invitationObserver.waitFor(operationId));
|
|
424
|
+
readTask();
|
|
425
|
+
}
|
|
426
|
+
if (!task) {
|
|
427
|
+
return result('unknown', {
|
|
428
|
+
code: 'BIND_TASK_NOT_PERSISTED',
|
|
429
|
+
message: 'SDK did not expose the recovered registration task after connect',
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
if (task?.status === 'completed') {
|
|
433
|
+
const consensus = await bounded(client.checkOwnershipConsensus(aid));
|
|
434
|
+
if (consensus.status === 'consensus' && consensus.sub_aid === aid && consensus.owner_aid === ownerAid) {
|
|
435
|
+
return result('already_bound');
|
|
436
|
+
}
|
|
437
|
+
return result('failed', {
|
|
438
|
+
code: 'CONSENSUS_REQUIRED',
|
|
439
|
+
message: 'A completed binding task has no current verified Owner consensus',
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
if (task && (['rejected', 'stopped', 'error'].includes(task.status) || task.code)) {
|
|
443
|
+
return result('failed', { code: task.code ?? 'BIND_SUBMIT_FAILED', message: task.reason ?? `Binding task ${task.status}` });
|
|
444
|
+
}
|
|
445
|
+
if (sentOperationIds.has(operationId))
|
|
446
|
+
return result('submitted');
|
|
447
|
+
return result('unknown', {
|
|
448
|
+
code: 'BIND_SUBMIT_UNKNOWN',
|
|
449
|
+
message: 'SDK is recovering the original registration task; no matching message.send acknowledgement was observed',
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
// Reuse the same service as agent-create, including its fresh consensus
|
|
453
|
+
// check, explicit SDK bind call, and persistent task projection.
|
|
454
|
+
resolver.attachClient(aid, client, true);
|
|
455
|
+
const view = await bounded(resolver.bind(aid, ownerAid));
|
|
456
|
+
if (view.consensusStatus === 'consensus' && view.ownerAid === ownerAid) {
|
|
457
|
+
return result('already_bound');
|
|
458
|
+
}
|
|
459
|
+
const returnedTask = view.task;
|
|
460
|
+
if (!returnedTask || returnedTask.operation !== 'bind' || returnedTask.sub_aid !== aid
|
|
461
|
+
|| returnedTask.owner_aid !== ownerAid || returnedTask.new_owner_aid !== undefined
|
|
462
|
+
|| typeof returnedTask.operation_id !== 'string' || !REGISTRATION_OPERATION_ID.test(returnedTask.operation_id)) {
|
|
463
|
+
throw Object.assign(new Error('SDK returned a binding task for a different subject or Owner'), { code: 'TASK_MISMATCH' });
|
|
464
|
+
}
|
|
465
|
+
operationId = returnedTask.operation_id;
|
|
466
|
+
readTask();
|
|
467
|
+
if (!task) {
|
|
468
|
+
throw Object.assign(new Error('SDK binding task was not persisted'), { code: 'BIND_TASK_NOT_PERSISTED' });
|
|
469
|
+
}
|
|
470
|
+
if (task.status === 'completed') {
|
|
471
|
+
const consensus = await bounded(client.checkOwnershipConsensus(aid));
|
|
472
|
+
if (consensus.status === 'consensus' && consensus.sub_aid === aid && consensus.owner_aid === ownerAid) {
|
|
473
|
+
return result('already_bound');
|
|
474
|
+
}
|
|
475
|
+
return result('failed', { code: 'CONSENSUS_REQUIRED', message: 'Completed binding has no current verified Owner consensus' });
|
|
476
|
+
}
|
|
477
|
+
if (['rejected', 'stopped', 'error'].includes(task.status)) {
|
|
478
|
+
return result('failed', { code: task.code ?? 'BIND_SUBMIT_FAILED', message: task.reason ?? `Binding task ${task.status}` });
|
|
479
|
+
}
|
|
480
|
+
if (task.code) {
|
|
481
|
+
return result('failed', { code: task.code, message: task.reason ?? 'SDK binding did not finish submitting the invitation' });
|
|
482
|
+
}
|
|
483
|
+
if (!sentOperationIds.has(operationId)) {
|
|
484
|
+
return result('unknown', { code: 'BIND_SUBMIT_UNKNOWN', message: 'SDK persisted the binding task without confirming its message.send acknowledgement' });
|
|
485
|
+
}
|
|
486
|
+
return result('submitted');
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
489
|
+
const details = error;
|
|
490
|
+
const code = typeof details.stringCode === 'string' ? details.stringCode
|
|
491
|
+
: typeof details.code === 'string' ? details.code : undefined;
|
|
492
|
+
const uncertain = connecting && (code === 'BIND_SUBMIT_TIMEOUT' || !code
|
|
493
|
+
|| resolver.snapshot(aid).requestStatus === 'interrupted');
|
|
494
|
+
return result(uncertain ? 'unknown' : 'failed', {
|
|
495
|
+
code: uncertain ? 'BIND_SUBMIT_UNKNOWN' : code ?? 'BIND_SUBMIT_FAILED',
|
|
496
|
+
message: details.message ?? String(error),
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
finally {
|
|
500
|
+
resolver.stop();
|
|
501
|
+
invitationObserver?.restore();
|
|
502
|
+
if (client) {
|
|
503
|
+
try {
|
|
504
|
+
await bounded(client.close(), 2_000);
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
logger.warn(`[control-aid] ${aid} invitation client cleanup: ${error}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
store?.close();
|
|
512
|
+
}
|
|
513
|
+
finally {
|
|
514
|
+
records?.close();
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function observeInvitationSend(client, ownerAid, sentOperationIds) {
|
|
519
|
+
const target = client;
|
|
520
|
+
const original = target.call;
|
|
521
|
+
if (typeof original !== 'function')
|
|
522
|
+
return { waitFor: async () => false, restore: () => { } };
|
|
523
|
+
const waiters = new Map();
|
|
524
|
+
const bound = original.bind(client);
|
|
525
|
+
const wrapped = async (method, params) => {
|
|
526
|
+
const response = await bound(method, params);
|
|
527
|
+
const recipient = typeof params?.to === 'string' ? params.to.toLowerCase() : undefined;
|
|
528
|
+
const payloadValue = params?.payload;
|
|
529
|
+
if (method === 'message.send' && recipient === ownerAid
|
|
530
|
+
&& payloadValue && typeof payloadValue === 'object' && !Array.isArray(payloadValue)) {
|
|
531
|
+
const payload = payloadValue;
|
|
532
|
+
const result = response && typeof response === 'object' && !Array.isArray(response)
|
|
533
|
+
? response : undefined;
|
|
534
|
+
if (payload.action === 'bind.request' && typeof payload.operation_id === 'string'
|
|
535
|
+
&& typeof result?.message_id === 'string') {
|
|
536
|
+
sentOperationIds.add(payload.operation_id);
|
|
537
|
+
const pending = waiters.get(payload.operation_id);
|
|
538
|
+
if (pending) {
|
|
539
|
+
waiters.delete(payload.operation_id);
|
|
540
|
+
for (const settle of pending)
|
|
541
|
+
settle(true);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return response;
|
|
546
|
+
};
|
|
547
|
+
target.call = wrapped;
|
|
548
|
+
return {
|
|
549
|
+
waitFor: operationId => {
|
|
550
|
+
if (sentOperationIds.has(operationId))
|
|
551
|
+
return Promise.resolve(true);
|
|
552
|
+
return new Promise(resolve => {
|
|
553
|
+
const pending = waiters.get(operationId) ?? new Set();
|
|
554
|
+
pending.add(resolve);
|
|
555
|
+
waiters.set(operationId, pending);
|
|
556
|
+
});
|
|
557
|
+
},
|
|
558
|
+
restore: () => {
|
|
559
|
+
if (target.call === wrapped)
|
|
560
|
+
target.call = original;
|
|
561
|
+
for (const pending of waiters.values()) {
|
|
562
|
+
for (const settle of pending)
|
|
563
|
+
settle(false);
|
|
564
|
+
}
|
|
565
|
+
waiters.clear();
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
}
|
package/dist/aun/aid/identity.js
CHANGED
|
@@ -224,7 +224,10 @@ export async function aidCreate(aid, opts) {
|
|
|
224
224
|
// 新注册流程:AIDStore.register → downloadCaRoot → load → authenticate
|
|
225
225
|
const store = await getAidStore({ slotId: SLOT.cli, aunPath });
|
|
226
226
|
try {
|
|
227
|
-
const regResult = await store.register(aid, {
|
|
227
|
+
const regResult = await store.register(aid, {
|
|
228
|
+
type: opts?.type ?? 'agent',
|
|
229
|
+
...(opts?.owner?.trim() ? { owner: opts.owner.trim() } : {}),
|
|
230
|
+
});
|
|
228
231
|
if (!regResult.ok) {
|
|
229
232
|
const e = new Error(regResult.error.message);
|
|
230
233
|
e.code = regResult.error.code;
|
|
@@ -236,11 +239,11 @@ export async function aidCreate(aid, opts) {
|
|
|
236
239
|
try {
|
|
237
240
|
const { GatewayDiscovery } = await import('@agentunion/fastaun');
|
|
238
241
|
const discovery = new GatewayDiscovery({});
|
|
239
|
-
gatewayUrl = await discovery.discover(`https://${aid}/.well-known/aun-gateway
|
|
242
|
+
gatewayUrl = await discovery.discover(`https://${aid}/.well-known/aun-gateway`, 15_000);
|
|
240
243
|
}
|
|
241
244
|
catch { /* fall through */ }
|
|
242
245
|
if (gatewayUrl) {
|
|
243
|
-
await downloadCaRoot(aunPath, gatewayUrl);
|
|
246
|
+
await downloadCaRoot(aunPath, gatewayUrl, '', opts?.silent === true);
|
|
244
247
|
}
|
|
245
248
|
// 重建 store(CA 可能刚下载,需要 rootCaPath 生效)
|
|
246
249
|
store.close();
|