evolcore 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/README.md +31 -20
- package/bin/ec-safe-output.js +14 -2
- package/dist/agents/baseagent-availability.js +1 -0
- package/dist/agents/claude-runner.js +32 -46
- package/dist/agents/codex-runner.js +54 -30
- package/dist/agents/ecagent-runner.js +18 -7
- package/dist/agents/gemini-runner.js +1 -2
- package/dist/agents/runner-types.js +28 -6
- package/dist/aun/aid/agentmd.js +21 -0
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +23 -98
- package/dist/aun/aid/ownership-operation.js +35 -12
- package/dist/aun/group/invite-service.js +6 -0
- package/dist/aun/msg/p2p.js +8 -12
- package/dist/channels/aun.js +66 -48
- package/dist/channels/dingtalk.js +8 -2
- package/dist/channels/feishu.js +6 -1
- package/dist/channels/wecom.js +7 -3
- package/dist/cli/agent-create.js +30 -6
- package/dist/cli/agent.js +30 -37
- package/dist/cli/aid-bind-command.js +16 -2
- package/dist/cli/aun-commands.js +31 -23
- package/dist/cli/config.js +15 -18
- package/dist/cli/contact.js +9 -12
- package/dist/cli/ctl-command.js +3 -3
- package/dist/cli/daemon-commands.js +242 -17
- package/dist/cli/diag.js +7 -3
- package/dist/cli/fs-command.js +5 -4
- package/dist/cli/handoff-command.js +11 -11
- package/dist/cli/help.js +18 -0
- package/dist/cli/index.js +25 -13
- package/dist/cli/init-channel.js +2 -1
- package/dist/cli/memory-command.js +47 -27
- package/dist/cli/model.js +5 -4
- package/dist/cli/queue-command.js +3 -3
- package/dist/cli/response.js +5 -4
- package/dist/cli/restart-monitor.js +35 -13
- package/dist/cli/skill-command.js +13 -13
- package/dist/cli/task-command.js +3 -3
- package/dist/cli/task-context.js +1 -0
- package/dist/cli/thread-command.js +5 -3
- package/dist/cli/trigger-command.js +3 -3
- package/dist/cli/version.js +6 -2
- package/dist/config/config-field-policy.js +1 -0
- package/dist/contracts/ecweb-service-protocol.js +44 -0
- package/dist/core/agent-runtime.js +6 -0
- package/dist/core/auth/agent-delegation.js +7 -4
- package/dist/core/auth/auth-gateway.js +3 -1
- package/dist/core/auth/authorization-audit.js +5 -1
- package/dist/core/auth/debug-context.js +5 -1
- package/dist/core/auth/operation-catalog.js +17 -1
- package/dist/core/bootstrap-service.js +20 -12
- package/dist/core/command/cli-intent-parser.js +5 -2
- package/dist/core/command/command-handler.js +20 -5
- package/dist/core/command/menu-catalog.js +48 -12
- package/dist/core/command/menu-handler.js +74 -6
- package/dist/core/command/menu-protocol.js +20 -1
- package/dist/core/command/slash-gate.js +17 -3
- package/dist/core/command/slash-handler.js +90 -7
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/interaction-router.js +2 -1
- package/dist/core/ipc-registration.js +26 -7
- package/dist/core/memory/batch-meta.js +2 -0
- package/dist/core/memory/consolidation-context.js +42 -51
- package/dist/core/memory/consolidation-ops-records.js +39 -7
- package/dist/core/memory/consolidation-trigger.js +71 -64
- package/dist/core/memory/consolidation.js +226 -20
- package/dist/core/memory/memory-writer.js +160 -34
- package/dist/core/memory/relation-idle-monitor.js +287 -0
- package/dist/core/memory/relation-sweep.js +206 -0
- package/dist/core/message/aun-ipc-sender.js +5 -0
- package/dist/core/message/message-bridge.js +64 -55
- package/dist/core/message/message-log.js +17 -0
- package/dist/core/message/message-queue.js +6 -0
- package/dist/core/message/outbound.js +70 -0
- package/dist/core/message/peer-mode.js +7 -2
- package/dist/core/message/response-engine.js +341 -73
- package/dist/core/ownership/owner-resolver.js +465 -140
- package/dist/core/permission/ec-command-parser.js +19 -3
- package/dist/core/permission/protected-paths.js +51 -0
- package/dist/core/permission/tool-policy.js +7 -7
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/session/session-manager.js +25 -5
- package/dist/core/system-session/memory.js +3 -18
- package/dist/ecweb/basic-settings-service.js +709 -0
- package/dist/ecweb/providers-service.js +172 -0
- package/dist/index.js +92 -4
- package/dist/ipc.js +78 -11
- package/dist/stats/db.js +33 -0
- package/dist/stats/index.js +2 -2
- package/dist/stats/query.js +246 -0
- package/dist/stats/writer.js +41 -1
- package/dist/trigger/application-service.js +12 -0
- package/dist/trigger/authorization.js +2 -2
- package/dist/trigger/history.js +36 -0
- package/dist/trigger/scheduler.js +3 -0
- package/dist/utils/ecweb-supervisor.js +31 -10
- package/dist/utils/error-utils.js +8 -4
- package/dist/utils/evolcore-version.js +3 -2
- package/dist/utils/host-info.js +52 -0
- package/dist/utils/welcome.js +18 -24
- package/ecagent/dist/harness/agent-harness.js +4 -1
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/agent.md +1 -1
- package/kits/docs/evolcore/aid.md +58 -8
- package/kits/docs/evolcore/config.md +9 -7
- package/kits/docs/evolcore/memory-architecture.md +3 -4
- package/kits/docs/evolcore/memory-consolidation.md +28 -7
- package/kits/docs/evolcore/memory-tags.md +1 -1
- package/kits/docs/evolcore/memory.md +1 -1
- package/kits/docs/evolcore/menu-client.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +6 -0
- package/kits/docs/evolcore/msg.md +1 -1
- package/kits/eck_manifest.json +3 -3
- package/kits/rules/04-relation.md +3 -2
- package/kits/schemas/agent-config.schema.13.json +5 -1
- package/kits/templates/memory-consolidation/generalize.md +32 -4
- package/kits/templates/memory-consolidation/notes.md +2 -2
- package/kits/templates/memory-consolidation/promote.md +10 -2
- package/kits/templates/system-fragments/baseagent.md +5 -0
- package/kits/templates/system-fragments/memory.md +12 -3
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/{rules/07-memory-and-thread.md → templates/system-fragments/thread.md} +17 -80
- package/package.json +3 -3
package/dist/channels/aun.js
CHANGED
|
@@ -568,23 +568,18 @@ function setIfDefined(target, key, value) {
|
|
|
568
568
|
if (value !== undefined)
|
|
569
569
|
target[key] = value;
|
|
570
570
|
}
|
|
571
|
-
function
|
|
571
|
+
function rawErrorText(raw) {
|
|
572
572
|
if (typeof raw !== 'string' || !raw.trim())
|
|
573
573
|
return undefined;
|
|
574
574
|
const text = raw.trim();
|
|
575
575
|
const htmlStart = text.toLowerCase().indexOf('<html');
|
|
576
576
|
return htmlStart >= 0 ? text.slice(0, htmlStart).trimEnd() : text;
|
|
577
577
|
}
|
|
578
|
-
function projectedRawError(raw, displayRaw) {
|
|
579
|
-
if (typeof raw !== 'string')
|
|
580
|
-
return raw;
|
|
581
|
-
return raw.trim() ? displayRaw : raw;
|
|
582
|
-
}
|
|
583
578
|
function appendRawErrorText(text, raw) {
|
|
584
|
-
const
|
|
585
|
-
if (!
|
|
579
|
+
const rawText = rawErrorText(raw);
|
|
580
|
+
if (!rawText || text.includes(rawText))
|
|
586
581
|
return text;
|
|
587
|
-
return `${text}\n原因:${
|
|
582
|
+
return `${text}\n原因:${rawText}`;
|
|
588
583
|
}
|
|
589
584
|
/**
|
|
590
585
|
* 把 AUNChannel 投递的 opts 映射成渠道无关的 InboundMessage。
|
|
@@ -4045,6 +4040,9 @@ export class AUNChannel {
|
|
|
4045
4040
|
finalPayload.task_id = context.metadata.taskId;
|
|
4046
4041
|
if (context?.metadata?.chatmode && !finalPayload.chatmode)
|
|
4047
4042
|
finalPayload.chatmode = context.metadata.chatmode;
|
|
4043
|
+
// 结构化/通知类 payload 与文本路径共用同一份诊断字典;缺省不带,sentAt 由发送时刻盖戳。
|
|
4044
|
+
if (context?.debug)
|
|
4045
|
+
finalPayload.debug = { ...context.debug, sentAt: localTimestamp() };
|
|
4048
4046
|
return finalPayload;
|
|
4049
4047
|
}
|
|
4050
4048
|
/**
|
|
@@ -4299,15 +4297,17 @@ export class AUNChannel {
|
|
|
4299
4297
|
const now = Date.now();
|
|
4300
4298
|
const mapTtl = typeof action.expiresAt === 'number' && Number.isFinite(action.expiresAt)
|
|
4301
4299
|
? Math.max(0, action.expiresAt - now)
|
|
4302
|
-
:
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4300
|
+
: undefined;
|
|
4301
|
+
if (mapTtl !== undefined) {
|
|
4302
|
+
const mapTimer = setTimeout(() => {
|
|
4303
|
+
this.cardMessageIdMap.delete(messageId);
|
|
4304
|
+
const ids = this.interactionCardMessageIds.get(action.requestId);
|
|
4305
|
+
ids?.delete(messageId);
|
|
4306
|
+
if (ids && ids.size === 0)
|
|
4307
|
+
this.interactionCardMessageIds.delete(action.requestId);
|
|
4308
|
+
}, mapTtl);
|
|
4309
|
+
mapTimer.unref?.();
|
|
4310
|
+
}
|
|
4311
4311
|
const ownedTimer = setTimeout(() => {
|
|
4312
4312
|
this.ownedCardMsgIds.delete(messageId);
|
|
4313
4313
|
this.ownedCardTopics.delete(messageId);
|
|
@@ -4492,6 +4492,7 @@ export class AUNChannel {
|
|
|
4492
4492
|
channelId,
|
|
4493
4493
|
delivery,
|
|
4494
4494
|
dedupeKey: opts.dedupeKey,
|
|
4495
|
+
critical: opts.critical,
|
|
4495
4496
|
type: 'payload',
|
|
4496
4497
|
contentKind: opts.contentKind,
|
|
4497
4498
|
payload: finalPayload,
|
|
@@ -4865,7 +4866,10 @@ export class AUNChannel {
|
|
|
4865
4866
|
}).effectiveRole;
|
|
4866
4867
|
}
|
|
4867
4868
|
catch { /* 角色解析失败按未知处理 */ }
|
|
4868
|
-
chatmode = chatmodeForPeerIdentity({ isMachine: info.type !== 'human', type: info.type ?? undefined }, peerRole
|
|
4869
|
+
chatmode = chatmodeForPeerIdentity({ isMachine: info.type !== 'human', type: info.type ?? undefined }, peerRole, {
|
|
4870
|
+
self: this.config.aid,
|
|
4871
|
+
peerKey: formatPeerKey('aun', args.to),
|
|
4872
|
+
});
|
|
4869
4873
|
}
|
|
4870
4874
|
if (chatmode && !finalPayload.chatmode)
|
|
4871
4875
|
finalPayload.chatmode = chatmode;
|
|
@@ -6604,26 +6608,36 @@ export class AUNChannelPlugin {
|
|
|
6604
6608
|
}
|
|
6605
6609
|
const taskBase = () => channel.buildTaskPayloadBase(envelope, replyCtx);
|
|
6606
6610
|
switch (payload.kind) {
|
|
6607
|
-
case 'result.text':
|
|
6608
|
-
case 'command.result':
|
|
6609
6611
|
case 'command.error': {
|
|
6612
|
+
const raw = rawErrorText(payload.raw) ?? payload.text;
|
|
6613
|
+
const errorPayload = {
|
|
6614
|
+
type: 'error',
|
|
6615
|
+
...taskBase(),
|
|
6616
|
+
subtype: payload.kind,
|
|
6617
|
+
text: appendRawErrorText(payload.text, raw),
|
|
6618
|
+
message: payload.text,
|
|
6619
|
+
user_message: payload.text,
|
|
6620
|
+
raw,
|
|
6621
|
+
recoverable: true,
|
|
6622
|
+
};
|
|
6623
|
+
for (const key of ['format', 'reason', 'reasonCode', 'nextStep']) {
|
|
6624
|
+
setIfDefined(errorPayload, key, payload[key]);
|
|
6625
|
+
}
|
|
6626
|
+
await channel.sendReliableStructured(channelId, errorPayload, { ...(replyCtx ?? {}), suppressPeerMention: true }, payload.text);
|
|
6627
|
+
return;
|
|
6628
|
+
}
|
|
6629
|
+
case 'result.text':
|
|
6630
|
+
case 'command.result': {
|
|
6610
6631
|
// Group command feedback is control traffic, not model input for
|
|
6611
6632
|
// the other agents in the conversation.
|
|
6612
|
-
if (delivery.chatType === 'group'
|
|
6613
|
-
&& (payload.kind === 'command.result' || payload.kind === 'command.error')) {
|
|
6614
|
-
const isError = payload.kind === 'command.error';
|
|
6633
|
+
if (delivery.chatType === 'group' && payload.kind === 'command.result') {
|
|
6615
6634
|
const feedback = {
|
|
6616
|
-
type:
|
|
6635
|
+
type: 'notice',
|
|
6617
6636
|
...taskBase(),
|
|
6618
6637
|
subtype: payload.kind,
|
|
6619
6638
|
text: payload.text,
|
|
6620
|
-
|
|
6621
|
-
? { message: payload.text, user_message: payload.text, recoverable: true }
|
|
6622
|
-
: { severity: 'info' }),
|
|
6639
|
+
severity: 'info',
|
|
6623
6640
|
};
|
|
6624
|
-
for (const key of ['format', 'reason', 'reasonCode', 'nextStep']) {
|
|
6625
|
-
setIfDefined(feedback, key, payload[key]);
|
|
6626
|
-
}
|
|
6627
6641
|
await channel.sendReliableStructured(channelId, feedback, { ...(replyCtx ?? {}), suppressPeerMention: true }, payload.text);
|
|
6628
6642
|
return;
|
|
6629
6643
|
}
|
|
@@ -6699,35 +6713,29 @@ export class AUNChannelPlugin {
|
|
|
6699
6713
|
return;
|
|
6700
6714
|
}
|
|
6701
6715
|
case 'system.error': {
|
|
6702
|
-
const raw =
|
|
6703
|
-
const projectedRaw = projectedRawError(payload.raw, raw);
|
|
6716
|
+
const raw = rawErrorText(payload.raw) ?? payload.text;
|
|
6704
6717
|
const errorPayload = {
|
|
6705
|
-
type:
|
|
6718
|
+
type: 'error',
|
|
6706
6719
|
...taskBase(),
|
|
6707
6720
|
subtype: payload.subtype,
|
|
6708
|
-
text: payload.
|
|
6709
|
-
|
|
6710
|
-
: appendRawErrorText(payload.text, raw),
|
|
6711
|
-
...(projectedRaw !== undefined ? { raw: projectedRaw } : {}),
|
|
6721
|
+
text: appendRawErrorText(payload.text, raw),
|
|
6722
|
+
raw,
|
|
6712
6723
|
...(payload.reason !== undefined ? { reason: payload.reason } : {}),
|
|
6713
|
-
...(payload.recoverable
|
|
6714
|
-
? { severity: 'warn' }
|
|
6715
|
-
: { recoverable: false }),
|
|
6724
|
+
...(payload.recoverable !== undefined ? { recoverable: payload.recoverable } : {}),
|
|
6716
6725
|
};
|
|
6717
6726
|
await channel.sendReliableStructured(channelId, errorPayload, { ...(replyCtx ?? {}), suppressPeerMention: true }, payload.text);
|
|
6718
6727
|
return;
|
|
6719
6728
|
}
|
|
6720
6729
|
case 'result.error': {
|
|
6721
|
-
const raw =
|
|
6722
|
-
const projectedRaw = projectedRawError(payload.raw, raw);
|
|
6730
|
+
const raw = rawErrorText(payload.raw) ?? payload.text;
|
|
6723
6731
|
const errorPayload = {
|
|
6724
6732
|
type: 'error',
|
|
6725
6733
|
...taskBase(),
|
|
6726
6734
|
text: appendRawErrorText(payload.text, raw),
|
|
6735
|
+
raw,
|
|
6727
6736
|
};
|
|
6728
6737
|
setIfDefined(errorPayload, 'subtype', payload.subtype);
|
|
6729
6738
|
setIfDefined(errorPayload, 'reason', payload.reason);
|
|
6730
|
-
setIfDefined(errorPayload, 'raw', projectedRaw);
|
|
6731
6739
|
await channel.sendReliableStructured(channelId, errorPayload, { ...(replyCtx ?? {}), suppressPeerMention: true }, payload.text);
|
|
6732
6740
|
return;
|
|
6733
6741
|
}
|
|
@@ -6859,9 +6867,10 @@ export class AUNChannelPlugin {
|
|
|
6859
6867
|
case 'interaction': {
|
|
6860
6868
|
const req = payload.interaction;
|
|
6861
6869
|
const cardTtlMs = AUN_INTERACTION_CARD_TTL_MS;
|
|
6870
|
+
const indefiniteBlockingInteraction = req.blocking === true && req.expiresAt === undefined;
|
|
6862
6871
|
const cardExpiresAt = typeof req.expiresAt === 'number' && Number.isFinite(req.expiresAt)
|
|
6863
6872
|
? req.expiresAt
|
|
6864
|
-
: Date.now() + cardTtlMs;
|
|
6873
|
+
: indefiniteBlockingInteraction ? undefined : Date.now() + cardTtlMs;
|
|
6865
6874
|
const toInteractionReceipt = (result) => {
|
|
6866
6875
|
if ((result.status === undefined || result.status === 'sent') && result.messageId) {
|
|
6867
6876
|
return sentReceipt(envelope, [result.messageId], replyCtx?.threadId);
|
|
@@ -6903,15 +6912,21 @@ export class AUNChannelPlugin {
|
|
|
6903
6912
|
const aunCard = withAunAttention({
|
|
6904
6913
|
type: 'action_card',
|
|
6905
6914
|
title: action.title,
|
|
6915
|
+
...(req.blocking === true ? { blocking: true } : {}),
|
|
6916
|
+
...(action.recommendedOption ? { recommended_option: action.recommendedOption } : {}),
|
|
6906
6917
|
actions: action.buttons.map(btn => ({
|
|
6907
|
-
label:
|
|
6918
|
+
label: action.recommendedOption === btn.key ? `💡 ${btn.label}` : btn.label,
|
|
6919
|
+
value: btn.key, style: btn.style ?? 'default', behavior: 'reply',
|
|
6908
6920
|
})),
|
|
6909
6921
|
});
|
|
6910
6922
|
// AUN action_card 以 compose behavior 声明自由文本动作。新版客户端
|
|
6911
6923
|
// 在卡片内采集并确认;旧版客户端可继续从主编辑器采集。两者都结构化
|
|
6912
6924
|
// 回传 action_card_reply{behavior:"compose"},Core 不拦截普通消息队列。
|
|
6913
6925
|
if (action.allowCustomInput) {
|
|
6914
|
-
aunCard.actions.push({
|
|
6926
|
+
aunCard.actions.push({
|
|
6927
|
+
label: '✏️ 手动输入', style: 'default', behavior: 'compose',
|
|
6928
|
+
...(cardExpiresAt !== undefined ? { compose_timeout_ms: Math.max(0, cardExpiresAt - Date.now()) } : {}),
|
|
6929
|
+
});
|
|
6915
6930
|
}
|
|
6916
6931
|
if (action.body) {
|
|
6917
6932
|
aunCard.text = action.body;
|
|
@@ -6928,7 +6943,10 @@ export class AUNChannelPlugin {
|
|
|
6928
6943
|
contentKind: 'card',
|
|
6929
6944
|
context: cardReplyContext,
|
|
6930
6945
|
dedupeKey: req.id.startsWith('gir-') || isAsyncQuestion ? operationId : undefined,
|
|
6931
|
-
|
|
6946
|
+
...(isAsyncQuestion && cardExpiresAt !== undefined
|
|
6947
|
+
? { ttl: Math.max(0, cardExpiresAt - Date.now()) }
|
|
6948
|
+
: {}),
|
|
6949
|
+
...(indefiniteBlockingInteraction ? { critical: true } : {}),
|
|
6932
6950
|
logText: action.title ? `[card] ${action.title}` : '[card]',
|
|
6933
6951
|
postSend: {
|
|
6934
6952
|
type: 'register_interaction_card',
|
|
@@ -88,7 +88,13 @@ export function buildDingtalkCardParamMap(interaction, state, status = '') {
|
|
|
88
88
|
};
|
|
89
89
|
for (let i = 0; i < DINGTALK_CARD_MAX_BUTTONS; i++) {
|
|
90
90
|
const button = interaction.kind.buttons[i];
|
|
91
|
-
map[`button_${i}_text`] = button
|
|
91
|
+
map[`button_${i}_text`] = button
|
|
92
|
+
? (interaction.kind.kind === 'action'
|
|
93
|
+
&& 'key' in button
|
|
94
|
+
&& interaction.kind.recommendedOption === button.key
|
|
95
|
+
? `💡 ${button.label}`
|
|
96
|
+
: button.label)
|
|
97
|
+
: '';
|
|
92
98
|
map[`button_${i}_style`] = button?.style || 'default';
|
|
93
99
|
map[`button_${i}_visible`] = button ? 'true' : 'false';
|
|
94
100
|
map[`button_${i}_disabled`] = state !== 'pending' || !!(button && 'disabled' in button && button.disabled)
|
|
@@ -1005,7 +1011,7 @@ export class DingtalkChannel {
|
|
|
1005
1011
|
continue;
|
|
1006
1012
|
}
|
|
1007
1013
|
const expired = (entry.interaction.expiresAt != null && entry.interaction.expiresAt <= now)
|
|
1008
|
-
|| entry.createdAt <= now - DINGTALK_CARD_PENDING_TTL_MS;
|
|
1014
|
+
|| (entry.interaction.blocking !== true && entry.createdAt <= now - DINGTALK_CARD_PENDING_TTL_MS);
|
|
1009
1015
|
if (!expired)
|
|
1010
1016
|
continue;
|
|
1011
1017
|
entry.invalidated = true;
|
package/dist/channels/feishu.js
CHANGED
|
@@ -1399,7 +1399,12 @@ export function buildCardV2(interaction, opts) {
|
|
|
1399
1399
|
buttons.forEach((btn, idx) => {
|
|
1400
1400
|
const buttonEl = {
|
|
1401
1401
|
tag: 'button',
|
|
1402
|
-
text: {
|
|
1402
|
+
text: {
|
|
1403
|
+
tag: 'plain_text',
|
|
1404
|
+
content: kind.kind === 'action' && kind.recommendedOption === btn.key
|
|
1405
|
+
? `💡 ${btn.label}`
|
|
1406
|
+
: btn.label,
|
|
1407
|
+
},
|
|
1403
1408
|
type: btn.style === 'danger' ? 'danger' : btn.style === 'primary' ? 'primary' : 'default',
|
|
1404
1409
|
action_type: 'form_submit',
|
|
1405
1410
|
name: `btn_${idx}`,
|
package/dist/channels/wecom.js
CHANGED
|
@@ -257,8 +257,9 @@ export class PersistentWecomCardStore {
|
|
|
257
257
|
let changed = false;
|
|
258
258
|
for (const [taskId, record] of this.records) {
|
|
259
259
|
const terminalExpiry = record.updatedAt + DEFAULT_CARD_RETENTION_MS;
|
|
260
|
-
const pendingExpiry =
|
|
261
|
-
|
|
260
|
+
const pendingExpiry = record.interaction.blocking === true
|
|
261
|
+
? Number.POSITIVE_INFINITY
|
|
262
|
+
: (record.expiresAt ?? record.createdAt + 7 * DEFAULT_CARD_RETENTION_MS) + DEFAULT_CARD_RETENTION_MS;
|
|
262
263
|
const expiresAt = record.status === 'pending' ? pendingExpiry : terminalExpiry;
|
|
263
264
|
if (now > expiresAt) {
|
|
264
265
|
this.records.delete(taskId);
|
|
@@ -322,7 +323,10 @@ export function buildWecomInteractionCard(interaction, taskId) {
|
|
|
322
323
|
.filter(({ button }) => !('disabled' in button) || !button.disabled)
|
|
323
324
|
.slice(0, 6)
|
|
324
325
|
.map(({ button, index }) => ({
|
|
325
|
-
text: truncate(
|
|
326
|
+
text: truncate(interaction.kind.kind === 'action' && 'key' in button
|
|
327
|
+
&& interaction.kind.recommendedOption === button.key
|
|
328
|
+
? `💡 ${button.label}`
|
|
329
|
+
: button.label, 10) || `选项 ${index + 1}`,
|
|
326
330
|
style: buttonStyle(button.style),
|
|
327
331
|
key: interaction.kind.kind === 'command-card' ? `cmd_${index}` : `act_${index}`,
|
|
328
332
|
})),
|
package/dist/cli/agent-create.js
CHANGED
|
@@ -6,6 +6,7 @@ import { parse } from 'yaml';
|
|
|
6
6
|
import { resolvePaths, aunPath as defaultAunPath, agentConfig, agentDataDir, agentPersonalDir, aidLocalDir, agentMdPath } from '../paths.js';
|
|
7
7
|
import { loadDefaults, loadAgent, saveAgent, ensureAgentDirSkeleton } from '../config-store.js';
|
|
8
8
|
import { ConfigTarget, write as cfgWrite, ensureFile as cfgEnsure, read as cfgRead } from '../config/config-manager.js';
|
|
9
|
+
import { daemonUnavailableMessage, queryDaemon } from './help.js';
|
|
9
10
|
import { ipcQuery } from '../ipc.js';
|
|
10
11
|
import { CONFIG_SCHEMA_VERSION } from '../types.js';
|
|
11
12
|
import { ensureInitialRoleRegistry } from '../config/role-service.js';
|
|
@@ -880,8 +881,15 @@ export class AgentInitializationService {
|
|
|
880
881
|
return;
|
|
881
882
|
try {
|
|
882
883
|
const record = readInitialization(aid);
|
|
883
|
-
if (!record ||
|
|
884
|
-
|
|
884
|
+
if (!record || this.running.has(aid))
|
|
885
|
+
return;
|
|
886
|
+
const waitingForOwner = record.status === 'in_progress' && record.phase === 'ownerpending';
|
|
887
|
+
// Records written before ownerBindSubmitted existed could fail by resubmitting the bind
|
|
888
|
+
// while SDK ownership events invalidated the consensus cache. Retry them once the
|
|
889
|
+
// requested Owner is observable; other failures still require an explicit --resume.
|
|
890
|
+
const lostConsensusRace = record.status === 'failed' && record.code === 'CONSENSUS_REQUIRED'
|
|
891
|
+
&& record.plan.ownerAid === ownerAid;
|
|
892
|
+
if (!waitingForOwner && !lostConsensusRace)
|
|
885
893
|
return;
|
|
886
894
|
this.resume(aid, record.actor);
|
|
887
895
|
}
|
|
@@ -1051,8 +1059,20 @@ export class AgentInitializationService {
|
|
|
1051
1059
|
}
|
|
1052
1060
|
this.phase(r, 'hot_loading');
|
|
1053
1061
|
await this.deps.hotLoad(p.aid);
|
|
1054
|
-
if (this.deps.bindOwner)
|
|
1055
|
-
|
|
1062
|
+
if (this.deps.bindOwner) {
|
|
1063
|
+
// Owner-consensus recovery and --resume re-run from the start. The SDK keeps emitting
|
|
1064
|
+
// ownership events for a few seconds after approval, each invalidating the cached
|
|
1065
|
+
// consensus, so resubmitting an accepted bind then fails with CONSENSUS_REQUIRED.
|
|
1066
|
+
// Retry when no pending or completed task for this Owner remains.
|
|
1067
|
+
const bindStillActive = this.deps.ownerBindActive
|
|
1068
|
+
? this.deps.ownerBindActive(p.aid, p.ownerAid)
|
|
1069
|
+
: r.ownerBindSubmitted === true;
|
|
1070
|
+
if (!bindStillActive) {
|
|
1071
|
+
this.phase(r, 'binding_owner');
|
|
1072
|
+
await this.deps.bindOwner(p.aid, p.ownerAid);
|
|
1073
|
+
r.ownerBindSubmitted = true;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1056
1076
|
this.phase(r, 'ownerpending');
|
|
1057
1077
|
const ownership = await this.deps.checkOwner(p.aid, p.ownerAid);
|
|
1058
1078
|
this.check(r);
|
|
@@ -1220,9 +1240,13 @@ export async function runInitializationCommand(args) {
|
|
|
1220
1240
|
return initializationCommandResult(result);
|
|
1221
1241
|
}
|
|
1222
1242
|
const request = async (poll) => {
|
|
1223
|
-
|
|
1243
|
+
const { response, transportError } = await queryDaemon(resolvePaths().socket, {
|
|
1224
1244
|
type: 'evolagent.initialize', argv, poll,
|
|
1225
|
-
}, 10_000)
|
|
1245
|
+
}, 10_000);
|
|
1246
|
+
return response ?? {
|
|
1247
|
+
ok: false, code: 'DAEMON_UNAVAILABLE',
|
|
1248
|
+
error: daemonUnavailableMessage(transportError, 'Initialization requires a running daemon'),
|
|
1249
|
+
};
|
|
1226
1250
|
};
|
|
1227
1251
|
let result = await request(false);
|
|
1228
1252
|
if (parsed.dryRun)
|
package/dist/cli/agent.js
CHANGED
|
@@ -8,6 +8,7 @@ import { initConfigManager } from '../config/config-manager.js';
|
|
|
8
8
|
import { resolveConfigCommand } from '../config/resolved-config-op.js';
|
|
9
9
|
import { executeResolvedConfigCommandAsync } from '../config/config-operation-service.js';
|
|
10
10
|
import { ipcQuery, IpcTransportError } from '../ipc.js';
|
|
11
|
+
import { daemonUnavailableMessage, queryDaemon } from './help.js';
|
|
11
12
|
import { CONFIG_SCHEMA_VERSION } from '../types.js';
|
|
12
13
|
import { ensureInitialRoleRegistry } from '../config/role-service.js';
|
|
13
14
|
import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/project-path.js';
|
|
@@ -30,22 +31,20 @@ export async function runManagedAgentOperation(argv, timeoutMs = 60_000) {
|
|
|
30
31
|
if (!delegationToken) {
|
|
31
32
|
return { ok: false, code: 'DELEGATION_REQUIRED', error: `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task` };
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return { ok: false, code: 'DAEMON_UNAVAILABLE', error: error instanceof Error ? error.message : String(error) };
|
|
48
|
-
}
|
|
34
|
+
const { response, transportError } = await queryDaemon(resolvePaths().socket, {
|
|
35
|
+
type: 'agent.op',
|
|
36
|
+
argv: ['agent', ...argv],
|
|
37
|
+
sessionId,
|
|
38
|
+
delegationToken,
|
|
39
|
+
}, timeoutMs);
|
|
40
|
+
if (!response)
|
|
41
|
+
return {
|
|
42
|
+
ok: false, code: 'DAEMON_UNAVAILABLE',
|
|
43
|
+
error: daemonUnavailableMessage(transportError, 'Unable to connect to the evolcore daemon'),
|
|
44
|
+
};
|
|
45
|
+
if (!response.ok)
|
|
46
|
+
return { ok: false, code: response.code, error: response.error || 'agent operation failed', ...(response.data ? { data: response.data } : {}) };
|
|
47
|
+
return response.result ?? { ok: true, ...(response.data ?? {}) };
|
|
49
48
|
}
|
|
50
49
|
function getAgentMdPath(aid) {
|
|
51
50
|
return getAgentMdPathFromPaths(aid);
|
|
@@ -761,29 +760,23 @@ export async function agentReady(aid, commandArgs) {
|
|
|
761
760
|
};
|
|
762
761
|
}
|
|
763
762
|
const p = resolvePaths();
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
return { ok: false, code: 'DELEGATION_REQUIRED', error: `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task` };
|
|
768
|
-
}
|
|
769
|
-
const result = await ipcQuery(p.socket, {
|
|
770
|
-
type: 'evolagent.bootstrapComplete',
|
|
771
|
-
aid,
|
|
772
|
-
...(managedSessionId ? { argv: ['agent', ...(commandArgs ?? ['ready', aid])] } : {}),
|
|
773
|
-
...(managedSessionId ? { sessionId: managedSessionId, delegationToken } : {}),
|
|
774
|
-
}, 30_000);
|
|
775
|
-
if (!result)
|
|
776
|
-
return { ok: false, code: 'DAEMON_UNAVAILABLE', error: 'Unable to connect to the EvolCore daemon; agent ready requires daemon IPC' };
|
|
777
|
-
if (!result.ok) {
|
|
778
|
-
return { ok: false, code: result.code, error: result.error || 'Failed to complete bootstrap' };
|
|
779
|
-
}
|
|
780
|
-
return { ...result, ok: true, aid, reloaded: result.reloaded === true };
|
|
763
|
+
const delegationToken = managedSessionId ? readDelegationCredential() : undefined;
|
|
764
|
+
if (managedSessionId && !delegationToken) {
|
|
765
|
+
return { ok: false, code: 'DELEGATION_REQUIRED', error: `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task` };
|
|
781
766
|
}
|
|
782
|
-
|
|
767
|
+
const { response: result, transportError } = await queryDaemon(p.socket, {
|
|
768
|
+
type: 'evolagent.bootstrapComplete',
|
|
769
|
+
aid,
|
|
770
|
+
...(managedSessionId ? { argv: ['agent', ...(commandArgs ?? ['ready', aid])] } : {}),
|
|
771
|
+
...(managedSessionId ? { sessionId: managedSessionId, delegationToken } : {}),
|
|
772
|
+
}, 30_000);
|
|
773
|
+
if (!result)
|
|
783
774
|
return {
|
|
784
|
-
ok: false,
|
|
785
|
-
|
|
786
|
-
error: e instanceof Error ? e.message : 'Unable to connect to the EvolCore daemon',
|
|
775
|
+
ok: false, code: 'DAEMON_UNAVAILABLE',
|
|
776
|
+
error: daemonUnavailableMessage(transportError, 'Unable to connect to the EvolCore daemon; agent ready requires daemon IPC'),
|
|
787
777
|
};
|
|
778
|
+
if (!result.ok) {
|
|
779
|
+
return { ok: false, code: result.code, error: result.error || 'Failed to complete bootstrap' };
|
|
788
780
|
}
|
|
781
|
+
return { ...result, ok: true, aid, reloaded: result.reloaded === true };
|
|
789
782
|
}
|
|
@@ -2,9 +2,15 @@ import { ipcQuery } from '../ipc.js';
|
|
|
2
2
|
import { resolvePaths } from '../paths.js';
|
|
3
3
|
import { parseOwnershipCommand, ownershipFailure } from '../aun/aid/ownership-operation.js';
|
|
4
4
|
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
5
|
+
import { MAIN_CLI_BIN } from '../product.js';
|
|
5
6
|
export async function cmdAidBind(args) {
|
|
6
7
|
if (args.includes('--help') || args.includes('-h')) {
|
|
7
|
-
console.log(
|
|
8
|
+
console.log([
|
|
9
|
+
`用法: ${MAIN_CLI_BIN} aid bind <ownerAid> [--subject <subjectAid>] [--format json]`,
|
|
10
|
+
`${MAIN_CLI_BIN} aid bind status [--subject <subjectAid>] [--format json]`,
|
|
11
|
+
`${MAIN_CLI_BIN} aid bind accept <operationId> [--subject <subjectAid>] [--format json]`,
|
|
12
|
+
`${MAIN_CLI_BIN} aid bind reject <operationId> [--reason <text>] [--subject <subjectAid>] [--format json]`,
|
|
13
|
+
].join('\n'));
|
|
8
14
|
return;
|
|
9
15
|
}
|
|
10
16
|
const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
@@ -14,10 +20,11 @@ export async function cmdAidBind(args) {
|
|
|
14
20
|
const delegationToken = sessionId ? readDelegationCredential() : undefined;
|
|
15
21
|
if (sessionId && !delegationToken)
|
|
16
22
|
throw Object.assign(new Error('Active task delegation is required'), { code: 'DELEGATION_REQUIRED' });
|
|
23
|
+
const isDecision = args[0] === 'accept' || args[0] === 'reject';
|
|
17
24
|
const response = await ipcQuery(resolvePaths().socket, {
|
|
18
25
|
type: 'aid.ownership', argv: ['aid', 'bind', ...args],
|
|
19
26
|
...(sessionId ? { sessionId, delegationToken } : {}),
|
|
20
|
-
}, 30_000);
|
|
27
|
+
}, isDecision ? 150_000 : 30_000);
|
|
21
28
|
if (!response?.ok)
|
|
22
29
|
throw Object.assign(new Error(response?.error ?? 'daemon 未运行或 IPC 不可用'), { code: response?.code, retryable: response?.retryable });
|
|
23
30
|
if (formatJson)
|
|
@@ -32,6 +39,13 @@ export async function cmdAidBind(args) {
|
|
|
32
39
|
console.log(`运行态同步: ${state.synchronization.status}`);
|
|
33
40
|
if (state.task)
|
|
34
41
|
console.log(`绑定任务: ${state.task.operation_id} (${state.task.status}/${state.task.step})`);
|
|
42
|
+
if (state.decisionTask)
|
|
43
|
+
console.log(`审批任务: ${state.decisionTask.operation_id} (${state.decisionTask.status}/${state.decisionTask.step})`);
|
|
44
|
+
if (state.decisionConsensus)
|
|
45
|
+
console.log(`审批目标共识: ${state.decisionConsensus.status} (owner=${state.decisionConsensus.owner_aid ?? '-'}, version=${state.decisionConsensus.relation_version}, lock=${state.decisionConsensus.lock})`);
|
|
46
|
+
for (const request of state.requests ?? []) {
|
|
47
|
+
console.log(`待确认邀约: ${request.operation_id} (sub=${request.sub_aid}, owner=${request.owner_aid}, 本端=${request.local_role})`);
|
|
48
|
+
}
|
|
35
49
|
if (state.requestedOwnerAid)
|
|
36
50
|
console.log(`请求绑定: ${state.requestedOwnerAid}`);
|
|
37
51
|
if (state.requestStatus)
|