evolcore 0.0.25 → 0.0.27
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 +632 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +203 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +40 -29
- package/bin/install-codex-managed-hooks.mjs +582 -555
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +172 -33
- package/dist/agents/codex/app-server-client.js +76 -31
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +434 -446
- package/dist/agents/ecagent-runner.js +174 -34
- package/dist/agents/gemini-runner.js +8 -7
- package/dist/agents/runner-types.js +75 -19
- package/dist/aun/aid/agentmd.js +151 -36
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +4 -4
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +162 -39
- package/dist/aun/{menu-client.js → menu/client.js} +85 -6
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +85 -19
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +19 -9
- package/dist/aun/msg/upload.js +43 -80
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +842 -318
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +212 -89
- package/dist/cli/agent-create.js +626 -11
- package/dist/cli/agent.js +125 -13
- package/dist/cli/aun-commands.js +487 -337
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +55 -33
- package/dist/cli/contact.js +72 -15
- package/dist/cli/ctl-command.js +24 -24
- package/dist/cli/daemon-commands.js +140 -63
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +70 -70
- package/dist/cli/handoff-command.js +46 -14
- package/dist/cli/index.js +91 -79
- package/dist/cli/init.js +34 -1
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +5 -1
- package/dist/cli/menu-client.js +51 -32
- package/dist/cli/model.js +3 -3
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +31 -31
- package/dist/cli/response.js +32 -32
- package/dist/cli/restart-monitor.js +103 -42
- package/dist/cli/stats.js +51 -51
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +74 -64
- package/dist/config/builtin-roles.js +11 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +160 -0
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +97 -8
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +30 -7
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +7 -1
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +53 -49
- package/dist/core/auth/operation-authorizer.js +90 -7
- package/dist/core/auth/operation-catalog.js +145 -4
- package/dist/core/auth/remote-access-store.js +155 -10
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +111 -20
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +159 -65
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +46 -7
- package/dist/core/command/menu-handler.js +392 -100
- package/dist/core/command/menu-protocol.js +45 -6
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +123 -43
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +146 -34
- package/dist/core/message/message-bridge.js +163 -20
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +99 -41
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +755 -144
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +112 -41
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +108 -17
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +9 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +34 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +588 -217
- package/dist/ipc.js +193 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +2 -0
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/price-resolver.js +28 -10
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/cross-platform.js +30 -1
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +61 -2
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +26 -14
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/npm-ops.js +176 -35
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +196 -23
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +60 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +69 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +379 -367
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +76 -71
- package/kits/docs/evolcore/agent-create.md +202 -165
- package/kits/docs/evolcore/agent.md +99 -67
- package/kits/docs/evolcore/aid.md +68 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +241 -195
- package/kits/docs/evolcore/contact.md +75 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +244 -244
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +267 -152
- package/kits/docs/evolcore/menu-client.md +58 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +169 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +53 -50
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +623 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +269 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +42 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +217 -190
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +166 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +76 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +65 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +451 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +215 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +92 -92
- package/kits/templates/roles/member.json +101 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +90 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +53 -34
- package/kits/templates/system-fragments/channel.md +28 -64
- package/kits/templates/system-fragments/commands.md +36 -28
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/reply.md +56 -0
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +104 -98
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { loadAgent } from '../../config-store.js';
|
|
2
|
+
import { initializationBlocksTasks } from '../../cli/agent-create.js';
|
|
1
3
|
import { createHash, randomBytes } from 'crypto';
|
|
4
|
+
import { agentStorageMenuService, isAgentStorageMenuRequest } from '../command/agent-storage-menu.js';
|
|
2
5
|
import { logger } from '../../utils/logger.js';
|
|
3
6
|
import { StreamDebouncer } from './stream-debouncer.js';
|
|
4
7
|
import { appendMessageLog, appendMessageLogStrict, buildInboundEntry, isTransientProtocolMessage } from './message-log.js';
|
|
5
8
|
import { buildEnvelope, isInteractionSendAccepted, sendInteractionPayload } from './message-utils.js';
|
|
6
9
|
import { chatDirPath } from '../session/session-fs-store.js';
|
|
10
|
+
import { readTopicLable } from '../session/session-mapper.js';
|
|
7
11
|
import { formatChannelKey, tryParseChannelKey } from '../channel-loader.js';
|
|
8
12
|
import { agentDir, resolvePaths } from '../../paths.js';
|
|
9
13
|
import { listStaticAgentAdmins, listStaticAgentOwners, resolvePeerRoleDetail, } from '../../config/peer-role-resolver.js';
|
|
@@ -25,8 +29,9 @@ import { createRootCausation, deriveCausation, normalizeCausation } from '../cau
|
|
|
25
29
|
import { recordCausationSpan } from '../causation/audit.js';
|
|
26
30
|
import { renderActionAsText } from '../interaction-router.js';
|
|
27
31
|
import { planApprovalRoute } from '../permission/approval-gateway.js';
|
|
28
|
-
import { parseFullAccessCommand } from '../command/slash-gate.js';
|
|
32
|
+
import { guardGroupSlashCommand, parseFullAccessCommand } from '../command/slash-gate.js';
|
|
29
33
|
import { isFullAccessEnabled } from '../../config-store.js';
|
|
34
|
+
import { createAgentPolicyAuthorization } from '../role/runtime-policy.js';
|
|
30
35
|
import { auditFullAccessEvent } from '../auth/authorization-audit.js';
|
|
31
36
|
import { consumeAdmissionReplyBudget, clearAdmissionReplyBudgets, evaluateInboundAdmissionPreflight, evaluateOrdinaryInboundAdmission, } from './message-admission.js';
|
|
32
37
|
const CONTACT_REJECTION_NOTICE = '[rejection] Not accepting messages from you.';
|
|
@@ -113,6 +118,7 @@ export class MessageBridge {
|
|
|
113
118
|
aidStatsCollector;
|
|
114
119
|
contactBindRuntimeChecker;
|
|
115
120
|
interactionRouter;
|
|
121
|
+
groupInviteReviewService;
|
|
116
122
|
constructor(defaultProjectPath, sessionManager, processor, messageQueue, cmdHandler, eventBus, defaultDebounce, processOwnersProvider) {
|
|
117
123
|
this.defaultProjectPath = defaultProjectPath;
|
|
118
124
|
this.sessionManager = sessionManager;
|
|
@@ -144,6 +150,12 @@ export class MessageBridge {
|
|
|
144
150
|
setInteractionRouter(router) {
|
|
145
151
|
this.interactionRouter = router;
|
|
146
152
|
}
|
|
153
|
+
setGroupInviteReviewService(service) {
|
|
154
|
+
this.groupInviteReviewService = service;
|
|
155
|
+
}
|
|
156
|
+
registerGroupInviteReviewChannel(binding) {
|
|
157
|
+
this.groupInviteReviewService?.attach(binding);
|
|
158
|
+
}
|
|
147
159
|
/**
|
|
148
160
|
* AUN supplies an authenticated sender AID, while the IM-side code proves
|
|
149
161
|
* possession of the external account. This command only creates that
|
|
@@ -483,7 +495,7 @@ export class MessageBridge {
|
|
|
483
495
|
...(msg.replyContext ?? {}),
|
|
484
496
|
metadata: {
|
|
485
497
|
...(msg.replyContext?.metadata ?? {}),
|
|
486
|
-
...evolMenuResponseTransportMetadata(),
|
|
498
|
+
...evolMenuResponseTransportMetadata(msg.protectedHeaders?.sdk_version),
|
|
487
499
|
},
|
|
488
500
|
},
|
|
489
501
|
}), {
|
|
@@ -500,9 +512,31 @@ export class MessageBridge {
|
|
|
500
512
|
async sendAdmissionControlReply(context, msg, sendReply, text) {
|
|
501
513
|
if (!text || !consumeAdmissionReplyBudget(context))
|
|
502
514
|
return false;
|
|
503
|
-
|
|
515
|
+
if (context.chatType === 'group' && /^\s*\/(?:bind|request)(?:\s|$)/i.test(msg.content)) {
|
|
516
|
+
await this.sendSlashControlReply(context.channelKey, msg, sendReply, { kind: 'command.error', text });
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
await sendReply(msg.channelId, text, msg.replyContext);
|
|
520
|
+
}
|
|
504
521
|
return true;
|
|
505
522
|
}
|
|
523
|
+
/** Controls handled before the normal slash handler still need structured group feedback. */
|
|
524
|
+
async sendSlashControlReply(channel, msg, sendReply, payload, adapter = this.processor.getChannelInfo?.(channel)?.adapter) {
|
|
525
|
+
if (msg.chatType === 'group' && adapter?.send) {
|
|
526
|
+
await adapter.send(buildEnvelope({
|
|
527
|
+
taskId: `cmd-${randomBytes(5).toString('hex')}`,
|
|
528
|
+
channel,
|
|
529
|
+
channelId: msg.channelId,
|
|
530
|
+
chatmode: 'interactive',
|
|
531
|
+
replyContext: {
|
|
532
|
+
...msg.replyContext,
|
|
533
|
+
...(msg.threadId ? { threadId: msg.threadId } : {}),
|
|
534
|
+
},
|
|
535
|
+
}), payload);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
await sendReply(msg.channelId, payload.text, msg.replyContext);
|
|
539
|
+
}
|
|
506
540
|
admissionDeniedNotice(context, channelType) {
|
|
507
541
|
if (context.contactStatus === 'pending') {
|
|
508
542
|
return '联系人申请审核中;可再次发送 /request 更新说明。';
|
|
@@ -773,6 +807,20 @@ export class MessageBridge {
|
|
|
773
807
|
}
|
|
774
808
|
return;
|
|
775
809
|
}
|
|
810
|
+
if (!trustedHandoffEcho && selfAid && actorId && this.groupInviteReviewService) {
|
|
811
|
+
const inviteCommand = await this.groupInviteReviewService.handleCommand({
|
|
812
|
+
selfAid,
|
|
813
|
+
ownerAid: actorId,
|
|
814
|
+
channelKey,
|
|
815
|
+
channelType: resolvedChannelType,
|
|
816
|
+
chatType,
|
|
817
|
+
content,
|
|
818
|
+
});
|
|
819
|
+
if (inviteCommand.handled) {
|
|
820
|
+
await this.sendAdmissionControlReply(admissionPreflight.context, msg, sendReply, inviteCommand.text ?? '群邀请命令已处理。');
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
776
824
|
if (!trustedHandoffEcho && await this.handleReservedContactControl({
|
|
777
825
|
context: admissionPreflight.context,
|
|
778
826
|
msg,
|
|
@@ -801,6 +849,16 @@ export class MessageBridge {
|
|
|
801
849
|
: { isMenu: false };
|
|
802
850
|
let menuResponseWarning;
|
|
803
851
|
if (menuControl.isMenu) {
|
|
852
|
+
// Menu is an AUN private control plane. Group messages must never
|
|
853
|
+
// execute Menu commands or participate in token issuance/rotation.
|
|
854
|
+
if (msg.chatType === 'group') {
|
|
855
|
+
this.logMenuDiagnostic('unsupported-chat-type', channelName, msg, menuControl, 'MENU_PRIVATE_ONLY');
|
|
856
|
+
logMenuRequestCompleted(menuControl.request, undefined, this.menuFlowContext(channelName, msg), {
|
|
857
|
+
delivery: 'dropped',
|
|
858
|
+
reason: 'unsupported-chat-type',
|
|
859
|
+
});
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
804
862
|
// AUN captures this mark at its adapter boundary. Legacy/test
|
|
805
863
|
// adapters fall back to the bridge entry mark captured above.
|
|
806
864
|
Object.assign(msg, menuTiming);
|
|
@@ -837,7 +895,10 @@ export class MessageBridge {
|
|
|
837
895
|
const tokenSupplied = Object.prototype.hasOwnProperty.call(menuControl.request, 'menu_token');
|
|
838
896
|
const tokenValid = (menuTokenRequired || tokenSupplied)
|
|
839
897
|
&& !!tokenOwnerAid
|
|
840
|
-
&& this.menuTokenStore.use(tokenOwnerAid, msg.peerId, menuControl.request.menu_token
|
|
898
|
+
&& this.menuTokenStore.use(tokenOwnerAid, msg.peerId, menuControl.request.menu_token, {
|
|
899
|
+
deviceId: msg.peerDeviceId,
|
|
900
|
+
slotId: msg.peerSlotId,
|
|
901
|
+
});
|
|
841
902
|
if (menuTokenRequired && !tokenValid) {
|
|
842
903
|
this.logMenuDiagnostic('token-required', channelName, msg, menuControl, 'MENU_TOKEN_REQUIRED');
|
|
843
904
|
await this.sendMenuResponse(adapter, channelName, msg, menuFailure(header, {
|
|
@@ -915,6 +976,11 @@ export class MessageBridge {
|
|
|
915
976
|
// internal per-call authorization carried into ResponseEngine.
|
|
916
977
|
const fullAccessCommand = parseFullAccessCommand(content);
|
|
917
978
|
if (fullAccessCommand.matched) {
|
|
979
|
+
const groupGuard = guardGroupSlashCommand(content, chatType);
|
|
980
|
+
if (groupGuard?.kind === 'command.error') {
|
|
981
|
+
await this.sendSlashControlReply(channelName, msg, sendReply, groupGuard, adapter);
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
918
984
|
const reject = async (text) => {
|
|
919
985
|
logger.warn(`[MessageBridge] fullaccess command rejected: channel=${channelName} `
|
|
920
986
|
+ `actor=${authSubject.principalId ?? authSubject.actorId ?? '<none>'} reason=${text}`);
|
|
@@ -987,6 +1053,11 @@ export class MessageBridge {
|
|
|
987
1053
|
...(chatType === 'private' ? { routeId: msg.channelId } : {}),
|
|
988
1054
|
});
|
|
989
1055
|
}
|
|
1056
|
+
const initializationConfig = selfAid ? loadAgent(selfAid) : null;
|
|
1057
|
+
if (initializationConfig && initializationBlocksTasks(initializationConfig)) {
|
|
1058
|
+
await sendReply(msg.channelId, 'Agent 初始化尚未完成,请由创建者查询 ec agent show 或恢复初始化。');
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
990
1061
|
// 1. owner 绑定(按实例名绑定)
|
|
991
1062
|
if (adapter && actorId && roleDetail.effectiveRole === 'owner') {
|
|
992
1063
|
await this.bootstrapService?.tryStartBootstrap({
|
|
@@ -1002,6 +1073,13 @@ export class MessageBridge {
|
|
|
1002
1073
|
// 2. 命令快速路径(去除引用前缀后检查,兼容话题中引用上文的情况)
|
|
1003
1074
|
const contentForCmd = content.replace(/^(>[^\n]*\n)+\n?/, '').trim();
|
|
1004
1075
|
const cmdContent = contentForCmd || content;
|
|
1076
|
+
if (msg.source !== 'handoff' && !executionPermissionOverride) {
|
|
1077
|
+
const groupGuard = guardGroupSlashCommand(cmdContent, chatType);
|
|
1078
|
+
if (groupGuard?.kind === 'command.error') {
|
|
1079
|
+
await this.sendSlashControlReply(channelName, msg, sendReply, groupGuard, adapter);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1005
1083
|
const isCmd = msg.source !== 'handoff'
|
|
1006
1084
|
// Once /fa has been accepted, its remainder is always model input.
|
|
1007
1085
|
// A prompt such as `/fa /status` must not be re-routed as the
|
|
@@ -1059,6 +1137,14 @@ export class MessageBridge {
|
|
|
1059
1137
|
return sendReply(msg.channelId, text, msg.replyContext);
|
|
1060
1138
|
}, msg.peerId, msg.threadId, msg.chatType, msg.source, msg.replyContext, msg.messageId, msg.selfAID, authSubject))
|
|
1061
1139
|
return;
|
|
1140
|
+
// Commands retain their normal route. Only authenticated direct model
|
|
1141
|
+
// input can obtain the Agent policy's per-call authorization.
|
|
1142
|
+
if (!executionPermissionOverride && selfAid && owningAgent?.aid === selfAid) {
|
|
1143
|
+
executionPermissionOverride = createAgentPolicyAuthorization({
|
|
1144
|
+
agentAid: selfAid, actor: roleDetail.actor, chatType,
|
|
1145
|
+
source: msg.source, peerType: msg.peerType,
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1062
1148
|
// 3. session 解析(使用 Channel 层填充的 chatType)
|
|
1063
1149
|
if (!(await this.canCreateThreadSession(channelName, msg, chatType))) {
|
|
1064
1150
|
// 静默丢弃:绝不向群里注入回复。
|
|
@@ -1102,7 +1188,7 @@ export class MessageBridge {
|
|
|
1102
1188
|
// has been appended and create another renewed session.
|
|
1103
1189
|
releaseAdmission = await this.acquireAdmission(admissionRoute);
|
|
1104
1190
|
const hadMainSession = msg.threadId ? true : this.sessionManager.hasMainSession(channelName, msg.channelId, msg.channelType || effectiveChannelType, msg.selfAID || selfAid);
|
|
1105
|
-
let session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, this.extractTopicName(msg), msg.peerId, chatType, owningAgent?.baseagent, msg.selfAID, msg.channelType || effectiveChannelType, msg.peerType, identity);
|
|
1191
|
+
let session = await this.sessionManager.getOrCreateSession(channelName, msg.channelId, effectiveProjectPath, msg.threadId, Object.keys(metadata).length ? metadata : undefined, this.extractTopicName(msg), msg.peerId, chatType, owningAgent?.baseagent, msg.selfAID, msg.channelType || effectiveChannelType, msg.peerType, identity, readTopicLable(msg) ?? readTopicLable(msg.replyContext?.metadata));
|
|
1106
1192
|
if (session.threadId && typeof this.messageQueue.reserveSessionIngress === 'function') {
|
|
1107
1193
|
releaseSessionIngress = this.messageQueue.reserveSessionIngress(session.id);
|
|
1108
1194
|
}
|
|
@@ -1158,6 +1244,7 @@ export class MessageBridge {
|
|
|
1158
1244
|
mentions: msg.mentions, mentionAids: msg.mentionAids, threadId: msg.threadId,
|
|
1159
1245
|
isMentioned: msg.isMentioned,
|
|
1160
1246
|
topicName: this.extractTopicName(msg),
|
|
1247
|
+
lable: session.lable,
|
|
1161
1248
|
replyContext: msg.replyContext,
|
|
1162
1249
|
source: msg.source,
|
|
1163
1250
|
...(executionPermissionOverride ? { executionPermissionOverride } : {}),
|
|
@@ -1380,6 +1467,8 @@ export class MessageBridge {
|
|
|
1380
1467
|
const menuAuthSubject = {
|
|
1381
1468
|
...authSubject,
|
|
1382
1469
|
requestId: parsed.id,
|
|
1470
|
+
menuEncrypted: msg.encrypted === true,
|
|
1471
|
+
fromControlChannel: authSubject.fromControlChannel || msg.isControlChannel === true,
|
|
1383
1472
|
...(activeSession?.id ? { sessionId: activeSession.id } : {}),
|
|
1384
1473
|
};
|
|
1385
1474
|
const isTokenRequest = parsed.type === 'menu.token.request';
|
|
@@ -1410,8 +1499,22 @@ export class MessageBridge {
|
|
|
1410
1499
|
return;
|
|
1411
1500
|
}
|
|
1412
1501
|
}
|
|
1502
|
+
// Reauthorize even cached responses: roots expire and static owners can be revoked.
|
|
1503
|
+
const isStorageRequest = isAgentStorageMenuRequest(parsed.request);
|
|
1504
|
+
if (isStorageRequest) {
|
|
1505
|
+
try {
|
|
1506
|
+
agentStorageMenuService.preflight(parsed.request, menuAuthSubject);
|
|
1507
|
+
}
|
|
1508
|
+
catch (error) {
|
|
1509
|
+
await this.sendMenuResponse(adapter, channel, msg, menuFailure(header, normalizeMenuError(error)));
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1413
1513
|
const scope = msg.chatType === 'group' ? (msg.groupId || msg.channelId) : msg.peerId;
|
|
1414
|
-
|
|
1514
|
+
// Separate installations can generate identical request IDs. Token
|
|
1515
|
+
// issuance and replay must remain scoped to the authenticated requester.
|
|
1516
|
+
const dedupKey = [msg.selfAID || channel, channelType, msg.chatType || 'private', scope, msg.peerId,
|
|
1517
|
+
msg.peerDeviceId || '', msg.peerSlotId || '', msg.threadId || '', parsed.id].join('\u001f');
|
|
1415
1518
|
let afterResponse;
|
|
1416
1519
|
const deduped = await this.menuDeduper.execute(dedupKey, menuPayloadFingerprint(parsed.raw), () => isTokenRequest
|
|
1417
1520
|
? this.issueMenuTokenResponse(header, channel, msg)
|
|
@@ -1424,6 +1527,16 @@ export class MessageBridge {
|
|
|
1424
1527
|
}));
|
|
1425
1528
|
return;
|
|
1426
1529
|
}
|
|
1530
|
+
// A replay may have awaited an in-flight request; check again before release.
|
|
1531
|
+
if (isStorageRequest) {
|
|
1532
|
+
try {
|
|
1533
|
+
agentStorageMenuService.preflight(parsed.request, menuAuthSubject, false);
|
|
1534
|
+
}
|
|
1535
|
+
catch (error) {
|
|
1536
|
+
await this.sendMenuResponse(adapter, channel, msg, menuFailure(header, normalizeMenuError(error)));
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1427
1540
|
if (deduped.replayed)
|
|
1428
1541
|
this.logMenuDiagnostic('request-replay', channel, msg, parsed);
|
|
1429
1542
|
if (deduped.retry)
|
|
@@ -1438,7 +1551,20 @@ export class MessageBridge {
|
|
|
1438
1551
|
await deferredEffect();
|
|
1439
1552
|
}
|
|
1440
1553
|
catch (error) {
|
|
1441
|
-
|
|
1554
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1555
|
+
const code = error && typeof error === 'object' && 'code' in error
|
|
1556
|
+
? String(error.code ?? 'EXEC_FAILED')
|
|
1557
|
+
: 'EXEC_FAILED';
|
|
1558
|
+
logger.warn(`[MenuControl] deferred effect failed: request=${parsed.id} error=${detail}`);
|
|
1559
|
+
// File fetch is acknowledged before the upload completes. Send a
|
|
1560
|
+
// second response with the same request id so the client can finish
|
|
1561
|
+
// the pending fetch with an actionable error instead of timing out.
|
|
1562
|
+
const failedResponse = menuFailure(header, {
|
|
1563
|
+
code,
|
|
1564
|
+
message: detail.startsWith('文件发送失败') ? detail : `文件发送失败: ${detail}`,
|
|
1565
|
+
});
|
|
1566
|
+
await this.menuDeduper.replaceResult(dedupKey, menuPayloadFingerprint(parsed.raw), deduped.value, failedResponse);
|
|
1567
|
+
await this.sendMenuResponse(adapter, channel, msg, failedResponse);
|
|
1442
1568
|
}
|
|
1443
1569
|
}
|
|
1444
1570
|
}
|
|
@@ -1448,11 +1574,20 @@ export class MessageBridge {
|
|
|
1448
1574
|
const name = header.name ?? '';
|
|
1449
1575
|
const cmd = typeof request.cmd === 'string' ? request.cmd : undefined;
|
|
1450
1576
|
const args = request.args;
|
|
1577
|
+
const transportReplyContext = {
|
|
1578
|
+
...(msg.replyContext ?? {}),
|
|
1579
|
+
...(msg.threadId ? { threadId: msg.threadId } : {}),
|
|
1580
|
+
};
|
|
1581
|
+
// Explicit group context can target a different conversation. Its
|
|
1582
|
+
// sessions must not inherit the thread of the source conversation.
|
|
1583
|
+
const replyContextFor = (channelId) => channelId === msg.channelId ? transportReplyContext : undefined;
|
|
1451
1584
|
switch (request.type) {
|
|
1452
1585
|
case 'menu.list':
|
|
1453
1586
|
if (args?.view === 'catalog') {
|
|
1454
1587
|
validateMenuCatalogArgs(args);
|
|
1455
|
-
const data = await this.cmdHandler.getMenuCatalog(channel, msg.channelId, authSubject, args.context, msg.isControlChannel ? 'control' : 'agent'
|
|
1588
|
+
const data = await this.cmdHandler.getMenuCatalog(channel, msg.channelId, authSubject, args.context, msg.isControlChannel ? 'control' : 'agent', !msg.isControlChannel || (msg.encrypted === true
|
|
1589
|
+
&& msg.protectedHeaders?.auth_method !== 'remote-access-token'
|
|
1590
|
+
&& msg.protectedHeaders?.auth_method !== 'ecweb-token'));
|
|
1456
1591
|
return menuSuccess(header, data);
|
|
1457
1592
|
}
|
|
1458
1593
|
if (args?.view !== undefined) {
|
|
@@ -1462,7 +1597,7 @@ export class MessageBridge {
|
|
|
1462
1597
|
case 'menu.query': {
|
|
1463
1598
|
if (name === 'menu' && args?.view === 'values') {
|
|
1464
1599
|
validateMenuValueBatchArgs(args);
|
|
1465
|
-
const data = await this.cmdHandler.execMenuValueBatch(channel, msg.channelId, authSubject, args, args.context, msg.isControlChannel ? 'control' : 'agent');
|
|
1600
|
+
const data = await this.cmdHandler.execMenuValueBatch(channel, msg.channelId, authSubject, args, args.context, msg.isControlChannel ? 'control' : 'agent', transportReplyContext);
|
|
1466
1601
|
return menuSuccess(header, data);
|
|
1467
1602
|
}
|
|
1468
1603
|
if (name === 'menu') {
|
|
@@ -1475,7 +1610,7 @@ export class MessageBridge {
|
|
|
1475
1610
|
channelId: msg.channelId,
|
|
1476
1611
|
args,
|
|
1477
1612
|
});
|
|
1478
|
-
const result = await this.cmdHandler.execMenuQuery(this.resolveCmd(name, cmd), channel, execution.channelId, execution.subject.actorId, execution.args, execution.subject.chatType, execution.subject.fromControlChannel, execution.subject.identity, execution.subject);
|
|
1613
|
+
const result = await this.cmdHandler.execMenuQuery(this.resolveCmd(name, cmd), channel, execution.channelId, execution.subject.actorId, execution.args, execution.subject.chatType, execution.subject.fromControlChannel, execution.subject.identity, execution.subject, 'menu', replyContextFor(execution.channelId));
|
|
1479
1614
|
if ('error' in result)
|
|
1480
1615
|
throw result;
|
|
1481
1616
|
return menuSuccess(header, result.data);
|
|
@@ -1492,7 +1627,7 @@ export class MessageBridge {
|
|
|
1492
1627
|
if ((name === 'topic' || cmd === '/topic') && args?.mode === 'fork-turns' && msg.threadId && !args?.sourceThreadId) {
|
|
1493
1628
|
optionArgs = { ...(execution.args ?? {}), sourceThreadId: msg.threadId };
|
|
1494
1629
|
}
|
|
1495
|
-
const data = await this.cmdHandler.getSubMenuItems(this.resolveCmd(name, cmd), channel, execution.channelId, execution.subject.actorId, optionArgs, execution.subject.identity, execution.subject.chatType, execution.subject.fromControlChannel, execution.subject) ?? [];
|
|
1630
|
+
const data = await this.cmdHandler.getSubMenuItems(this.resolveCmd(name, cmd), channel, execution.channelId, execution.subject.actorId, optionArgs, execution.subject.identity, execution.subject.chatType, execution.subject.fromControlChannel, execution.subject, 'menu', replyContextFor(execution.channelId)) ?? [];
|
|
1496
1631
|
return menuSuccess(header, data);
|
|
1497
1632
|
}
|
|
1498
1633
|
case 'menu.update': {
|
|
@@ -1503,10 +1638,7 @@ export class MessageBridge {
|
|
|
1503
1638
|
channelId: msg.channelId,
|
|
1504
1639
|
args,
|
|
1505
1640
|
});
|
|
1506
|
-
const result = await this.cmdHandler.execMenuUpdate(this.resolveCmd(name, cmd), request.value, channel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.fromControlChannel, execution.args, execution.subject, 'menu',
|
|
1507
|
-
...(msg.replyContext ?? {}),
|
|
1508
|
-
...(msg.threadId ? { threadId: msg.threadId } : {}),
|
|
1509
|
-
});
|
|
1641
|
+
const result = await this.cmdHandler.execMenuUpdate(this.resolveCmd(name, cmd), request.value, channel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.fromControlChannel, execution.args, execution.subject, 'menu', replyContextFor(execution.channelId));
|
|
1510
1642
|
if ('error' in result)
|
|
1511
1643
|
throw result;
|
|
1512
1644
|
return menuSuccess(header, result.data);
|
|
@@ -1569,9 +1701,11 @@ export class MessageBridge {
|
|
|
1569
1701
|
const agentName = this.agentRegistry?.resolveByChannel(channel)?.name ?? '<unknown>';
|
|
1570
1702
|
const replyContext = {
|
|
1571
1703
|
...(msg.replyContext ?? {}),
|
|
1704
|
+
...(msg.peerDeviceId ? { toDeviceId: msg.peerDeviceId } : {}),
|
|
1572
1705
|
metadata: {
|
|
1573
1706
|
...(msg.replyContext?.metadata ?? {}),
|
|
1574
|
-
...evolMenuResponseTransportMetadata(),
|
|
1707
|
+
...evolMenuResponseTransportMetadata(msg.protectedHeaders?.sdk_version),
|
|
1708
|
+
...(isAgentStorageMenuRequest(request) ? { encrypted: true } : {}),
|
|
1575
1709
|
},
|
|
1576
1710
|
};
|
|
1577
1711
|
if (msg.channelType === 'aun' && !replyContext.delivery) {
|
|
@@ -1615,6 +1749,9 @@ export class MessageBridge {
|
|
|
1615
1749
|
clientName: this.menuTokenHeaderValue(headers.client_name ?? headers.app_name),
|
|
1616
1750
|
clientVersion: this.menuTokenHeaderValue(headers.client_version ?? headers.app_version),
|
|
1617
1751
|
evolVersion: this.menuTokenHeaderValue(headers.evol_version),
|
|
1752
|
+
}, {
|
|
1753
|
+
deviceId: msg.peerDeviceId,
|
|
1754
|
+
slotId: msg.peerSlotId,
|
|
1618
1755
|
});
|
|
1619
1756
|
if (!issued) {
|
|
1620
1757
|
return menuFailure(header, { code: 'MENU_TOKEN_REJECTED', message: '授权申请未通过' });
|
|
@@ -1732,20 +1869,25 @@ export class MessageBridge {
|
|
|
1732
1869
|
logger.info(`[${channel}] ${channelId}: ${content}${source === 'card-trigger' ? ' [card]' : ''}`);
|
|
1733
1870
|
const adapter = this.processor.getChannelInfo?.(channel)?.adapter;
|
|
1734
1871
|
const cmdResult = await this.cmdHandler.handle(content, channel, channelId, async (_cid, text, opts, updatePayload) => {
|
|
1735
|
-
|
|
1872
|
+
const payload = updatePayload ?? (chatType === 'group' ? { kind: 'command.result', text } : undefined);
|
|
1873
|
+
if (payload && adapter?.send) {
|
|
1736
1874
|
const envelope = buildEnvelope({
|
|
1737
1875
|
taskId: `cmd-update-${randomBytes(5).toString('hex')}`,
|
|
1738
1876
|
channel,
|
|
1739
1877
|
channelId,
|
|
1740
1878
|
agentName: this.agentRegistry?.resolveByChannel(channel)?.name ?? '<unknown>',
|
|
1741
1879
|
chatmode: 'interactive',
|
|
1742
|
-
replyContext:
|
|
1880
|
+
replyContext: {
|
|
1881
|
+
...(opts ?? {}),
|
|
1882
|
+
...(replyContext ?? {}),
|
|
1883
|
+
metadata: { ...opts?.metadata, ...replyContext?.metadata },
|
|
1884
|
+
},
|
|
1743
1885
|
});
|
|
1744
|
-
await adapter.send(envelope,
|
|
1886
|
+
await adapter.send(envelope, payload);
|
|
1745
1887
|
return;
|
|
1746
1888
|
}
|
|
1747
1889
|
await sendReply(text, opts, updatePayload);
|
|
1748
|
-
}, userId, threadId, chatType, source, messageId, selfAID, authSubject?.identity, authSubject, replyContext);
|
|
1890
|
+
}, userId, threadId, chatType, source, messageId, selfAID, authSubject?.identity, authSubject, replyContext, true);
|
|
1749
1891
|
logger.debug(`[MessageBridge] handleCommand: result type=${typeof cmdResult}`);
|
|
1750
1892
|
if (cmdResult === undefined)
|
|
1751
1893
|
return false;
|
|
@@ -1830,6 +1972,7 @@ export class MessageBridge {
|
|
|
1830
1972
|
}
|
|
1831
1973
|
/** 注销单个渠道的 debouncer(热重载断开渠道时调用) */
|
|
1832
1974
|
removeChannel(channelName) {
|
|
1975
|
+
this.groupInviteReviewService?.detach(channelName);
|
|
1833
1976
|
const d = this.debouncers.get(channelName);
|
|
1834
1977
|
if (d) {
|
|
1835
1978
|
d.dispose();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { appendJsonl, chatDirPath } from '../session/session-fs-store.js';
|
|
3
|
+
import { appendJsonl, appendJsonlDurable, chatDirPath } from '../session/session-fs-store.js';
|
|
4
4
|
import { logger } from '../../utils/logger.js';
|
|
5
5
|
const TRANSIENT_PROTOCOL_TYPE_PREFIXES = [
|
|
6
6
|
'contact.request.',
|
|
@@ -313,13 +313,13 @@ export function appendMessageLog(chatDir, entry) {
|
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
/** Strict conversation-history append used by handoff reply binding. */
|
|
316
|
-
export function appendMessageLogStrict(chatDir, entry) {
|
|
316
|
+
export function appendMessageLogStrict(chatDir, entry, durable = false) {
|
|
317
317
|
if (isTransientProtocolMessage(entry))
|
|
318
318
|
return;
|
|
319
319
|
if (entry.dir === 'in' && hasDuplicate(chatDir, entry.msgId))
|
|
320
320
|
return;
|
|
321
321
|
fs.mkdirSync(chatDir, { recursive: true });
|
|
322
|
-
appendJsonl(messageLogPath(chatDir), entry);
|
|
322
|
+
(durable ? appendJsonlDurable : appendJsonl)(messageLogPath(chatDir), entry);
|
|
323
323
|
if (entry.dir === 'in')
|
|
324
324
|
rememberMessageId(chatDir, entry.msgId);
|
|
325
325
|
}
|
|
@@ -343,6 +343,8 @@ export function buildInboundEntry(opts) {
|
|
|
343
343
|
msgType: isCommand ? 'command' : (opts.msgType ?? 'text'),
|
|
344
344
|
payloadType: opts.payloadType,
|
|
345
345
|
payloadSummary: opts.payloadSummary,
|
|
346
|
+
groupAttention: opts.groupAttention,
|
|
347
|
+
groupDelivery: opts.groupDelivery,
|
|
346
348
|
content: opts.content,
|
|
347
349
|
replyTo: opts.replyTo ?? null,
|
|
348
350
|
agent: null,
|