evolcore 0.0.25 → 0.0.26
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 +607 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +160 -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.js +96 -46
- package/dist/agents/claude-runner.js +50 -12
- package/dist/agents/codex/app-server-client.js +13 -5
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +121 -38
- package/dist/agents/ecagent-runner.js +4 -9
- package/dist/agents/gemini-runner.js +2 -7
- package/dist/agents/runner-types.js +25 -17
- package/dist/aun/aid/agentmd.js +81 -8
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/menu-client.js +74 -0
- package/dist/aun/msg/group.js +1 -1
- package/dist/aun/msg/managed-operation.js +1 -1
- package/dist/aun/msg/p2p.js +6 -1
- package/dist/aun/msg/upload.js +30 -22
- package/dist/channels/aun.js +329 -94
- package/dist/cli/agent-command.js +105 -84
- package/dist/cli/agent-create.js +112 -10
- package/dist/cli/agent.js +16 -5
- package/dist/cli/aun-commands.js +297 -296
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +47 -28
- package/dist/cli/contact.js +70 -13
- package/dist/cli/ctl-command.js +22 -22
- package/dist/cli/daemon-commands.js +105 -40
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +67 -67
- package/dist/cli/handoff-command.js +41 -9
- package/dist/cli/index.js +83 -77
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/menu-client.js +46 -31
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +29 -29
- package/dist/cli/response.js +30 -30
- package/dist/cli/restart-monitor.js +87 -40
- package/dist/cli/stats.js +51 -51
- package/dist/cli/trigger-command.js +56 -56
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-operation-service.js +145 -0
- package/dist/config/contact-operation-service.js +96 -7
- package/dist/config/resolved-config-op.js +27 -7
- package/dist/core/agent-application-service.js +2 -1
- package/dist/core/auth/authorization-audit.js +20 -12
- package/dist/core/auth/operation-authorizer.js +25 -4
- package/dist/core/auth/operation-catalog.js +35 -4
- package/dist/core/auth/remote-access-store.js +40 -1
- package/dist/core/bootstrap-service.js +1 -1
- package/dist/core/command/command-handler.js +83 -26
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/menu-catalog.js +12 -3
- package/dist/core/command/menu-handler.js +47 -26
- package/dist/core/command/menu-protocol.js +5 -0
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +86 -21
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/message/im-renderer.js +72 -21
- package/dist/core/message/message-bridge.js +69 -9
- package/dist/core/message/message-queue.js +26 -0
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +47 -28
- 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/ec-command-parser.js +51 -12
- package/dist/core/permission/sandbox-runtime.js +36 -14
- package/dist/core/permission/tool-policy.js +2 -1
- package/dist/index.js +280 -163
- package/dist/ipc.js +54 -2
- 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/utils/cross-platform.js +30 -1
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +21 -0
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +3 -1
- 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/welcome.js +22 -22
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- 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/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +66 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +56 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +364 -364
- 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 +71 -71
- package/kits/docs/evolcore/agent-create.md +170 -165
- package/kits/docs/evolcore/agent.md +66 -66
- package/kits/docs/evolcore/aid.md +60 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +202 -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 +243 -243
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +152 -152
- package/kits/docs/evolcore/menu-client.md +42 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +166 -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 +50 -50
- package/kits/docs/evolcore/trigger.md +575 -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 +37 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +190 -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 +162 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +75 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +63 -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 +427 -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 +201 -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 +96 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +85 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +31 -29
- package/kits/templates/system-fragments/channel.md +64 -64
- package/kits/templates/system-fragments/commands.md +28 -28
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +100 -98
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { logger } from '../../utils/logger.js';
|
|
2
2
|
import { summarizeToolInput, toolInputForDisplay } from '../../utils/tool-summary.js';
|
|
3
3
|
import { getErrorMessage, isContextTooLongText } from '../../utils/error-utils.js';
|
|
4
|
+
import { tagErrorTextWithEvolcoreVersion } from '../../utils/evolcore-version.js';
|
|
4
5
|
import { DEFAULT_FLUSH_DELAY_MS } from '../../types.js';
|
|
5
6
|
export class IMRenderer {
|
|
6
7
|
opts;
|
|
@@ -79,9 +80,9 @@ export class IMRenderer {
|
|
|
79
80
|
}
|
|
80
81
|
/** 是否有会抑制兜底错误消息的正文/过程内容;lifecycle 边界不算。 */
|
|
81
82
|
hasNonLifecycleContent() {
|
|
82
|
-
return this.textBuffer.length > 0 || this.itemsQueue.some(it => {
|
|
83
|
+
return this.textBuffer.trim().length > 0 || this.itemsQueue.some(it => {
|
|
83
84
|
if (it.kind === 'text')
|
|
84
|
-
return it.text.length > 0;
|
|
85
|
+
return it.text.trim().length > 0;
|
|
85
86
|
return it.kind !== 'started' && it.kind !== 'completed';
|
|
86
87
|
});
|
|
87
88
|
}
|
|
@@ -95,6 +96,21 @@ export class IMRenderer {
|
|
|
95
96
|
return;
|
|
96
97
|
if (this.textBuffer.length === 0)
|
|
97
98
|
return;
|
|
99
|
+
// 文件标记过滤后若只剩空白,应立即消费并告警;尤其避免 final-only
|
|
100
|
+
// 模式把工具调用前的空白继续带到最终回复。
|
|
101
|
+
const rawText = this.opts.fileMarkerPattern
|
|
102
|
+
? this.textBuffer.replace(this.opts.fileMarkerPattern, '')
|
|
103
|
+
: this.textBuffer;
|
|
104
|
+
if (!rawText.trim()) {
|
|
105
|
+
if (this.timer) {
|
|
106
|
+
clearTimeout(this.timer);
|
|
107
|
+
this.timer = undefined;
|
|
108
|
+
}
|
|
109
|
+
this.textBuffer = '';
|
|
110
|
+
this.itemsQueue = this.itemsQueue.filter(it => it.kind !== 'text');
|
|
111
|
+
this.hasSendableText(rawText, 'flushText');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
98
114
|
if (this.suppressIntermediateText()) {
|
|
99
115
|
this.itemsQueue = this.itemsQueue.filter(it => it.kind !== 'text');
|
|
100
116
|
return;
|
|
@@ -103,14 +119,8 @@ export class IMRenderer {
|
|
|
103
119
|
clearTimeout(this.timer);
|
|
104
120
|
this.timer = undefined;
|
|
105
121
|
}
|
|
106
|
-
// 文件标记过滤:tool_use 前的文本块也不能把 marker 暴露给用户
|
|
107
|
-
const rawText = this.opts.fileMarkerPattern
|
|
108
|
-
? this.textBuffer.replace(this.opts.fileMarkerPattern, '')
|
|
109
|
-
: this.textBuffer;
|
|
110
122
|
this.textBuffer = '';
|
|
111
|
-
|
|
112
|
-
return;
|
|
113
|
-
// 清掉 itemsQueue 中的 text items(已发出)
|
|
123
|
+
// 清掉已消费的 text items,包括被拦截的纯空白正文。
|
|
114
124
|
this.itemsQueue = this.itemsQueue.filter(it => it.kind !== 'text');
|
|
115
125
|
const payload = { kind: 'result.text', text: rawText, isFinal: false };
|
|
116
126
|
this.sentContent = true;
|
|
@@ -164,6 +174,7 @@ export class IMRenderer {
|
|
|
164
174
|
this.emitProgress('text', outputTokens, turn);
|
|
165
175
|
if (!text)
|
|
166
176
|
return;
|
|
177
|
+
// 保留流式片段之间的空格/换行;仅在发送完整正文时判定是否纯空白。
|
|
167
178
|
// 同一窗口内连续 text delta 合并到最后一个 text item
|
|
168
179
|
const last = this.itemsQueue[this.itemsQueue.length - 1];
|
|
169
180
|
if (last && last.kind === 'text') {
|
|
@@ -302,6 +313,8 @@ export class IMRenderer {
|
|
|
302
313
|
async sendOperationalNoticeAsText(text) {
|
|
303
314
|
if (!this.opts.operationalNoticesAsText || this.opts.envelope.chatmode === 'proactive' || !text)
|
|
304
315
|
return false;
|
|
316
|
+
if (!this.hasSendableText(text, 'operational-notice'))
|
|
317
|
+
return false;
|
|
305
318
|
// 保持与流式正文的到达顺序:先发出已缓冲的正文,再投影运行状态。
|
|
306
319
|
await this.flushText();
|
|
307
320
|
const payload = { kind: 'result.text', text, isFinal: false };
|
|
@@ -315,6 +328,17 @@ export class IMRenderer {
|
|
|
315
328
|
synthCallId() {
|
|
316
329
|
return `synth-${this.opts.envelope.taskId}-${++this.syntheticCallSeq}`;
|
|
317
330
|
}
|
|
331
|
+
/** Reject blank bodies before sending, without trimming meaningful formatting. */
|
|
332
|
+
hasSendableText(text, source) {
|
|
333
|
+
if (text.trim())
|
|
334
|
+
return true;
|
|
335
|
+
// An unused buffer is normal. A nonempty whitespace body is diagnostic evidence.
|
|
336
|
+
if (text.length > 0) {
|
|
337
|
+
const { envelope, agentAid } = this.opts;
|
|
338
|
+
logger.warn(`[IMRenderer] Attempted to send empty message, skipping: code=EMPTY_MESSAGE source=${source} task=${envelope.taskId} session=${envelope.sessionId ?? '<none>'} agent=${agentAid ?? envelope.agentName} textLength=${text.length} text=${JSON.stringify(text.slice(0, 80))}`);
|
|
339
|
+
}
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
318
342
|
/** Convert a structured failed receipt into the same error shape as a rejected sender. */
|
|
319
343
|
receiptError(receipt) {
|
|
320
344
|
return Object.assign(new Error(receipt.error), {
|
|
@@ -331,6 +355,18 @@ export class IMRenderer {
|
|
|
331
355
|
: undefined;
|
|
332
356
|
return value.code === 'OUTBOX_FULL' || cause?.code === 'OUTBOX_FULL';
|
|
333
357
|
}
|
|
358
|
+
isPermanentActivityError(error) {
|
|
359
|
+
const value = error && typeof error === 'object' ? error : {};
|
|
360
|
+
const cause = value.cause && typeof value.cause === 'object'
|
|
361
|
+
? value.cause
|
|
362
|
+
: undefined;
|
|
363
|
+
const code = String(value.code ?? cause?.code ?? '');
|
|
364
|
+
return value.permanent === true
|
|
365
|
+
|| value.status === 'failed'
|
|
366
|
+
|| code === 'AUN_SEND_FAILED'
|
|
367
|
+
|| code === '-1'
|
|
368
|
+
|| /payload is too large/i.test(String(value.message ?? value.error ?? ''));
|
|
369
|
+
}
|
|
334
370
|
/**
|
|
335
371
|
* Serialize durable sends while keeping the chain usable after a rejected
|
|
336
372
|
* operation. Activity queue saturation is best-effort: it is logged, but
|
|
@@ -344,9 +380,19 @@ export class IMRenderer {
|
|
|
344
380
|
}
|
|
345
381
|
});
|
|
346
382
|
const handled = operation.catch(error => {
|
|
347
|
-
if (payload.kind === 'activity.batch'
|
|
348
|
-
|
|
349
|
-
|
|
383
|
+
if (payload.kind === 'activity.batch') {
|
|
384
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
385
|
+
if (this.isOutboxFull(error)) {
|
|
386
|
+
logger.warn(`[IMRenderer] activity outbox full; continuing without activity batch: ${detail}`);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (this.isPermanentActivityError(error)) {
|
|
390
|
+
// Activity is best-effort. A permanent structured-send failure (for
|
|
391
|
+
// example an AUN payload-size rejection) must not requeue the same
|
|
392
|
+
// item indefinitely or prevent the final result.text from flushing.
|
|
393
|
+
logger.warn(`[IMRenderer] activity delivery failed; dropping activity batch and continuing: ${detail}`);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
350
396
|
}
|
|
351
397
|
throw error;
|
|
352
398
|
});
|
|
@@ -432,22 +478,25 @@ export class IMRenderer {
|
|
|
432
478
|
// 文件标记过滤:marker 任何时候都不该出现在用户文本里,必须在 *每次* flush
|
|
433
479
|
// (含非最终的定时 flush)执行。否则文本块若滞留 buffer 后被定时器触发,会走
|
|
434
480
|
// 下方非-final 的 result.text 路径,把 [SEND_FILE:...] 原样发给用户。
|
|
435
|
-
//
|
|
481
|
+
// 先保留空白,以便空正文告警仍能记录原长度。
|
|
436
482
|
if (this.opts.fileMarkerPattern) {
|
|
437
|
-
|
|
438
|
-
const replaced = s.replace(this.opts.fileMarkerPattern, '');
|
|
439
|
-
return isFinal ? replaced.trim() : replaced;
|
|
440
|
-
};
|
|
441
|
-
this.textBuffer = strip(this.textBuffer);
|
|
483
|
+
this.textBuffer = this.textBuffer.replace(this.opts.fileMarkerPattern, '');
|
|
442
484
|
for (const item of this.itemsQueue) {
|
|
443
485
|
if (item.kind === 'text')
|
|
444
486
|
item.text = item.text.replace(this.opts.fileMarkerPattern, '');
|
|
445
487
|
}
|
|
446
488
|
}
|
|
489
|
+
if (!this.hasSendableText(this.textBuffer, isFinal ? 'final' : 'flush')) {
|
|
490
|
+
this.textBuffer = '';
|
|
491
|
+
}
|
|
492
|
+
else if (isFinal && this.opts.fileMarkerPattern) {
|
|
493
|
+
// 保持既有最终文件标记过滤语义;中间文本的格式原样保留。
|
|
494
|
+
this.textBuffer = this.textBuffer.trim();
|
|
495
|
+
}
|
|
447
496
|
// 清掉空 text items
|
|
448
497
|
const items = this.itemsQueue.filter(it => {
|
|
449
498
|
if (it.kind === 'text')
|
|
450
|
-
return it.text.length > 0;
|
|
499
|
+
return it.text.trim().length > 0;
|
|
451
500
|
return true;
|
|
452
501
|
});
|
|
453
502
|
this.itemsQueue = [];
|
|
@@ -544,6 +593,8 @@ export class IMRenderer {
|
|
|
544
593
|
if (!item)
|
|
545
594
|
return;
|
|
546
595
|
if (item.kind === 'text') {
|
|
596
|
+
if (!this.hasSendableText(item.text, 'proactive'))
|
|
597
|
+
return;
|
|
547
598
|
this.hasEmittedText = true;
|
|
548
599
|
this.allText += item.text;
|
|
549
600
|
}
|
|
@@ -633,7 +684,7 @@ export class IMRenderer {
|
|
|
633
684
|
if (isContextTooLongText(event.error || ''))
|
|
634
685
|
return null;
|
|
635
686
|
const text = getErrorMessage(new Error(event.error || '任务执行失败'), undefined, false);
|
|
636
|
-
return { kind: 'notice', text, severity: 'warn' };
|
|
687
|
+
return { kind: 'notice', text: tagErrorTextWithEvolcoreVersion(text), severity: 'warn' };
|
|
637
688
|
}
|
|
638
689
|
case 'complete': {
|
|
639
690
|
if (event.queryFinal === false)
|
|
@@ -650,7 +701,7 @@ export class IMRenderer {
|
|
|
650
701
|
const text = getErrorMessage(new Error(errText), event.terminalReason, false);
|
|
651
702
|
const item = {
|
|
652
703
|
kind: 'summary',
|
|
653
|
-
text,
|
|
704
|
+
text: tagErrorTextWithEvolcoreVersion(text),
|
|
654
705
|
is_error: true,
|
|
655
706
|
};
|
|
656
707
|
if (event.subtype !== undefined)
|
|
@@ -25,7 +25,7 @@ import { createRootCausation, deriveCausation, normalizeCausation } from '../cau
|
|
|
25
25
|
import { recordCausationSpan } from '../causation/audit.js';
|
|
26
26
|
import { renderActionAsText } from '../interaction-router.js';
|
|
27
27
|
import { planApprovalRoute } from '../permission/approval-gateway.js';
|
|
28
|
-
import { parseFullAccessCommand } from '../command/slash-gate.js';
|
|
28
|
+
import { guardGroupSlashCommand, parseFullAccessCommand } from '../command/slash-gate.js';
|
|
29
29
|
import { isFullAccessEnabled } from '../../config-store.js';
|
|
30
30
|
import { auditFullAccessEvent } from '../auth/authorization-audit.js';
|
|
31
31
|
import { consumeAdmissionReplyBudget, clearAdmissionReplyBudgets, evaluateInboundAdmissionPreflight, evaluateOrdinaryInboundAdmission, } from './message-admission.js';
|
|
@@ -500,9 +500,31 @@ export class MessageBridge {
|
|
|
500
500
|
async sendAdmissionControlReply(context, msg, sendReply, text) {
|
|
501
501
|
if (!text || !consumeAdmissionReplyBudget(context))
|
|
502
502
|
return false;
|
|
503
|
-
|
|
503
|
+
if (context.chatType === 'group' && /^\s*\/(?:bind|request)(?:\s|$)/i.test(msg.content)) {
|
|
504
|
+
await this.sendSlashControlReply(context.channelKey, msg, sendReply, { kind: 'command.error', text });
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
await sendReply(msg.channelId, text, msg.replyContext);
|
|
508
|
+
}
|
|
504
509
|
return true;
|
|
505
510
|
}
|
|
511
|
+
/** Controls handled before the normal slash handler still need structured group feedback. */
|
|
512
|
+
async sendSlashControlReply(channel, msg, sendReply, payload, adapter = this.processor.getChannelInfo?.(channel)?.adapter) {
|
|
513
|
+
if (msg.chatType === 'group' && adapter?.send) {
|
|
514
|
+
await adapter.send(buildEnvelope({
|
|
515
|
+
taskId: `cmd-${randomBytes(5).toString('hex')}`,
|
|
516
|
+
channel,
|
|
517
|
+
channelId: msg.channelId,
|
|
518
|
+
chatmode: 'interactive',
|
|
519
|
+
replyContext: {
|
|
520
|
+
...msg.replyContext,
|
|
521
|
+
...(msg.threadId ? { threadId: msg.threadId } : {}),
|
|
522
|
+
},
|
|
523
|
+
}), payload);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
await sendReply(msg.channelId, payload.text, msg.replyContext);
|
|
527
|
+
}
|
|
506
528
|
admissionDeniedNotice(context, channelType) {
|
|
507
529
|
if (context.contactStatus === 'pending') {
|
|
508
530
|
return '联系人申请审核中;可再次发送 /request 更新说明。';
|
|
@@ -801,6 +823,16 @@ export class MessageBridge {
|
|
|
801
823
|
: { isMenu: false };
|
|
802
824
|
let menuResponseWarning;
|
|
803
825
|
if (menuControl.isMenu) {
|
|
826
|
+
// Menu is an AUN private control plane. Group messages must never
|
|
827
|
+
// execute Menu commands or participate in token issuance/rotation.
|
|
828
|
+
if (msg.chatType === 'group') {
|
|
829
|
+
this.logMenuDiagnostic('unsupported-chat-type', channelName, msg, menuControl, 'MENU_PRIVATE_ONLY');
|
|
830
|
+
logMenuRequestCompleted(menuControl.request, undefined, this.menuFlowContext(channelName, msg), {
|
|
831
|
+
delivery: 'dropped',
|
|
832
|
+
reason: 'unsupported-chat-type',
|
|
833
|
+
});
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
804
836
|
// AUN captures this mark at its adapter boundary. Legacy/test
|
|
805
837
|
// adapters fall back to the bridge entry mark captured above.
|
|
806
838
|
Object.assign(msg, menuTiming);
|
|
@@ -837,7 +869,10 @@ export class MessageBridge {
|
|
|
837
869
|
const tokenSupplied = Object.prototype.hasOwnProperty.call(menuControl.request, 'menu_token');
|
|
838
870
|
const tokenValid = (menuTokenRequired || tokenSupplied)
|
|
839
871
|
&& !!tokenOwnerAid
|
|
840
|
-
&& this.menuTokenStore.use(tokenOwnerAid, msg.peerId, menuControl.request.menu_token
|
|
872
|
+
&& this.menuTokenStore.use(tokenOwnerAid, msg.peerId, menuControl.request.menu_token, {
|
|
873
|
+
deviceId: msg.peerDeviceId,
|
|
874
|
+
slotId: msg.peerSlotId,
|
|
875
|
+
});
|
|
841
876
|
if (menuTokenRequired && !tokenValid) {
|
|
842
877
|
this.logMenuDiagnostic('token-required', channelName, msg, menuControl, 'MENU_TOKEN_REQUIRED');
|
|
843
878
|
await this.sendMenuResponse(adapter, channelName, msg, menuFailure(header, {
|
|
@@ -915,6 +950,11 @@ export class MessageBridge {
|
|
|
915
950
|
// internal per-call authorization carried into ResponseEngine.
|
|
916
951
|
const fullAccessCommand = parseFullAccessCommand(content);
|
|
917
952
|
if (fullAccessCommand.matched) {
|
|
953
|
+
const groupGuard = guardGroupSlashCommand(content, chatType);
|
|
954
|
+
if (groupGuard?.kind === 'command.error') {
|
|
955
|
+
await this.sendSlashControlReply(channelName, msg, sendReply, groupGuard, adapter);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
918
958
|
const reject = async (text) => {
|
|
919
959
|
logger.warn(`[MessageBridge] fullaccess command rejected: channel=${channelName} `
|
|
920
960
|
+ `actor=${authSubject.principalId ?? authSubject.actorId ?? '<none>'} reason=${text}`);
|
|
@@ -1002,6 +1042,13 @@ export class MessageBridge {
|
|
|
1002
1042
|
// 2. 命令快速路径(去除引用前缀后检查,兼容话题中引用上文的情况)
|
|
1003
1043
|
const contentForCmd = content.replace(/^(>[^\n]*\n)+\n?/, '').trim();
|
|
1004
1044
|
const cmdContent = contentForCmd || content;
|
|
1045
|
+
if (msg.source !== 'handoff' && !executionPermissionOverride) {
|
|
1046
|
+
const groupGuard = guardGroupSlashCommand(cmdContent, chatType);
|
|
1047
|
+
if (groupGuard?.kind === 'command.error') {
|
|
1048
|
+
await this.sendSlashControlReply(channelName, msg, sendReply, groupGuard, adapter);
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1005
1052
|
const isCmd = msg.source !== 'handoff'
|
|
1006
1053
|
// Once /fa has been accepted, its remainder is always model input.
|
|
1007
1054
|
// A prompt such as `/fa /status` must not be re-routed as the
|
|
@@ -1411,7 +1458,10 @@ export class MessageBridge {
|
|
|
1411
1458
|
}
|
|
1412
1459
|
}
|
|
1413
1460
|
const scope = msg.chatType === 'group' ? (msg.groupId || msg.channelId) : msg.peerId;
|
|
1414
|
-
|
|
1461
|
+
// Separate installations can generate identical request IDs. Token
|
|
1462
|
+
// issuance and replay must remain scoped to the authenticated requester.
|
|
1463
|
+
const dedupKey = [msg.selfAID || channel, channelType, msg.chatType || 'private', scope, msg.peerId,
|
|
1464
|
+
msg.peerDeviceId || '', msg.peerSlotId || '', msg.threadId || '', parsed.id].join('\u001f');
|
|
1415
1465
|
let afterResponse;
|
|
1416
1466
|
const deduped = await this.menuDeduper.execute(dedupKey, menuPayloadFingerprint(parsed.raw), () => isTokenRequest
|
|
1417
1467
|
? this.issueMenuTokenResponse(header, channel, msg)
|
|
@@ -1452,7 +1502,9 @@ export class MessageBridge {
|
|
|
1452
1502
|
case 'menu.list':
|
|
1453
1503
|
if (args?.view === 'catalog') {
|
|
1454
1504
|
validateMenuCatalogArgs(args);
|
|
1455
|
-
const data = await this.cmdHandler.getMenuCatalog(channel, msg.channelId, authSubject, args.context, msg.isControlChannel ? 'control' : 'agent'
|
|
1505
|
+
const data = await this.cmdHandler.getMenuCatalog(channel, msg.channelId, authSubject, args.context, msg.isControlChannel ? 'control' : 'agent', !msg.isControlChannel || (msg.encrypted === true
|
|
1506
|
+
&& msg.protectedHeaders?.auth_method !== 'remote-access-token'
|
|
1507
|
+
&& msg.protectedHeaders?.auth_method !== 'ecweb-token'));
|
|
1456
1508
|
return menuSuccess(header, data);
|
|
1457
1509
|
}
|
|
1458
1510
|
if (args?.view !== undefined) {
|
|
@@ -1615,6 +1667,9 @@ export class MessageBridge {
|
|
|
1615
1667
|
clientName: this.menuTokenHeaderValue(headers.client_name ?? headers.app_name),
|
|
1616
1668
|
clientVersion: this.menuTokenHeaderValue(headers.client_version ?? headers.app_version),
|
|
1617
1669
|
evolVersion: this.menuTokenHeaderValue(headers.evol_version),
|
|
1670
|
+
}, {
|
|
1671
|
+
deviceId: msg.peerDeviceId,
|
|
1672
|
+
slotId: msg.peerSlotId,
|
|
1618
1673
|
});
|
|
1619
1674
|
if (!issued) {
|
|
1620
1675
|
return menuFailure(header, { code: 'MENU_TOKEN_REJECTED', message: '授权申请未通过' });
|
|
@@ -1732,20 +1787,25 @@ export class MessageBridge {
|
|
|
1732
1787
|
logger.info(`[${channel}] ${channelId}: ${content}${source === 'card-trigger' ? ' [card]' : ''}`);
|
|
1733
1788
|
const adapter = this.processor.getChannelInfo?.(channel)?.adapter;
|
|
1734
1789
|
const cmdResult = await this.cmdHandler.handle(content, channel, channelId, async (_cid, text, opts, updatePayload) => {
|
|
1735
|
-
|
|
1790
|
+
const payload = updatePayload ?? (chatType === 'group' ? { kind: 'command.result', text } : undefined);
|
|
1791
|
+
if (payload && adapter?.send) {
|
|
1736
1792
|
const envelope = buildEnvelope({
|
|
1737
1793
|
taskId: `cmd-update-${randomBytes(5).toString('hex')}`,
|
|
1738
1794
|
channel,
|
|
1739
1795
|
channelId,
|
|
1740
1796
|
agentName: this.agentRegistry?.resolveByChannel(channel)?.name ?? '<unknown>',
|
|
1741
1797
|
chatmode: 'interactive',
|
|
1742
|
-
replyContext:
|
|
1798
|
+
replyContext: {
|
|
1799
|
+
...(opts ?? {}),
|
|
1800
|
+
...(replyContext ?? {}),
|
|
1801
|
+
metadata: { ...opts?.metadata, ...replyContext?.metadata },
|
|
1802
|
+
},
|
|
1743
1803
|
});
|
|
1744
|
-
await adapter.send(envelope,
|
|
1804
|
+
await adapter.send(envelope, payload);
|
|
1745
1805
|
return;
|
|
1746
1806
|
}
|
|
1747
1807
|
await sendReply(text, opts, updatePayload);
|
|
1748
|
-
}, userId, threadId, chatType, source, messageId, selfAID, authSubject?.identity, authSubject, replyContext);
|
|
1808
|
+
}, userId, threadId, chatType, source, messageId, selfAID, authSubject?.identity, authSubject, replyContext, true);
|
|
1749
1809
|
logger.debug(`[MessageBridge] handleCommand: result type=${typeof cmdResult}`);
|
|
1750
1810
|
if (cmdResult === undefined)
|
|
1751
1811
|
return false;
|
|
@@ -1275,6 +1275,8 @@ export class MessageQueue {
|
|
|
1275
1275
|
return false;
|
|
1276
1276
|
if (first.projectPath !== next.projectPath || first.agentName !== next.agentName)
|
|
1277
1277
|
return false;
|
|
1278
|
+
// Results from the same parent handoff are still mergeable. Their
|
|
1279
|
+
// resultRefs are retained and consumed individually after one turn.
|
|
1278
1280
|
const a = first.message.handoffDelivery?.originAuthorization;
|
|
1279
1281
|
const b = next.message.handoffDelivery?.originAuthorization;
|
|
1280
1282
|
if (!a || !b)
|
|
@@ -1323,6 +1325,10 @@ export class MessageQueue {
|
|
|
1323
1325
|
let hasMessagesAfterRestartResume = false;
|
|
1324
1326
|
const originHandoffIds = [];
|
|
1325
1327
|
const seenOriginHandoffIds = new Set();
|
|
1328
|
+
const originResultIds = [];
|
|
1329
|
+
const seenOriginResultIds = new Set();
|
|
1330
|
+
const originResultRefs = [];
|
|
1331
|
+
const seenOriginResultRefs = new Set();
|
|
1326
1332
|
const allOriginHandoffs = items.every(item => this.isOriginHandoff(item.message));
|
|
1327
1333
|
for (const item of items) {
|
|
1328
1334
|
const m = item.message;
|
|
@@ -1347,6 +1353,24 @@ export class MessageQueue {
|
|
|
1347
1353
|
originHandoffIds.push(id);
|
|
1348
1354
|
}
|
|
1349
1355
|
}
|
|
1356
|
+
const refs = m.handoffDelivery.resultRefs?.length
|
|
1357
|
+
? m.handoffDelivery.resultRefs
|
|
1358
|
+
: (m.handoffDelivery.resultIds?.length
|
|
1359
|
+
? m.handoffDelivery.resultIds.map(resultId => ({ handoffId: m.handoffDelivery.handoffId, resultId }))
|
|
1360
|
+
: (m.handoffDelivery.resultId
|
|
1361
|
+
? [{ handoffId: m.handoffDelivery.handoffId, resultId: m.handoffDelivery.resultId }]
|
|
1362
|
+
: []));
|
|
1363
|
+
for (const ref of refs) {
|
|
1364
|
+
const refKey = `${ref.handoffId}\u0000${ref.resultId}`;
|
|
1365
|
+
if (!seenOriginResultRefs.has(refKey)) {
|
|
1366
|
+
seenOriginResultRefs.add(refKey);
|
|
1367
|
+
originResultRefs.push(ref);
|
|
1368
|
+
}
|
|
1369
|
+
if (!seenOriginResultIds.has(ref.resultId)) {
|
|
1370
|
+
seenOriginResultIds.add(ref.resultId);
|
|
1371
|
+
originResultIds.push(ref.resultId);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1350
1374
|
}
|
|
1351
1375
|
for (const id of [...(m.sourceMessageIds ?? []), ...(m.messageId ? [m.messageId] : [])]) {
|
|
1352
1376
|
if (!seenSourceMessageIds.has(id)) {
|
|
@@ -1418,6 +1442,8 @@ export class MessageQueue {
|
|
|
1418
1442
|
...last.message.handoffDelivery,
|
|
1419
1443
|
handoffId: originHandoffIds[0],
|
|
1420
1444
|
handoffIds: originHandoffIds,
|
|
1445
|
+
...(originResultIds.length > 0 ? { resultIds: originResultIds } : {}),
|
|
1446
|
+
...(originResultRefs.length > 0 ? { resultRefs: originResultRefs } : {}),
|
|
1421
1447
|
}
|
|
1422
1448
|
: last.message.handoffDelivery,
|
|
1423
1449
|
};
|
|
@@ -101,6 +101,7 @@ export function deliveryTargetFromSession(session) {
|
|
|
101
101
|
export function replyContextFromSession(session, context) {
|
|
102
102
|
return {
|
|
103
103
|
...(session.metadata?.replyContext ?? {}),
|
|
104
|
+
...(session.threadId ? { threadId: session.threadId } : {}),
|
|
104
105
|
...(context ?? {}),
|
|
105
106
|
// Session chatType/groupId is the persisted routing authority. The nested
|
|
106
107
|
// reply context can outlive a route correction, so only an explicit
|
|
@@ -2,7 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import crypto from 'crypto';
|
|
5
|
-
import { BaseagentRunnerUnavailableError, hasCompact,
|
|
5
|
+
import { BaseagentRunnerUnavailableError, hasCompact, autoCompactWindowForModel, isClaudeContextUsageModel, numericToken } from '../../agents/runner-types.js';
|
|
6
6
|
import { buildTaskRuntimeEnv, ensureRuntimeLockDir, ensureSessionRuntimeDir } from '../../cli/task-context.js';
|
|
7
7
|
import { IMRenderer } from './im-renderer.js';
|
|
8
8
|
import { createSendFileMarkerPattern } from './file-markers.js';
|
|
@@ -11,7 +11,8 @@ import { StreamIdleMonitor } from './stream-idle-monitor.js';
|
|
|
11
11
|
import { logger } from '../../utils/logger.js';
|
|
12
12
|
import { isHostChinese } from '../../utils/locale.js';
|
|
13
13
|
import { getErrorMessage, classifyError, ErrorType, ERROR_PREFIX, isInfraError, isAbortTerminalReason, prefixErrorType, isRetryableError, isContextTooLongText } from '../../utils/error-utils.js';
|
|
14
|
-
import {
|
|
14
|
+
import { readEvolcoreRuntimeFlavor, tagErrorTextWithEvolcoreVersion } from '../../utils/evolcore-version.js';
|
|
15
|
+
import { describeProactiveSendCommandFailure, isExactEvolcoreSendCommandForSession } from '../permission/ec-command-parser.js';
|
|
15
16
|
import { summarizeToolInput } from '../../utils/tool-summary.js';
|
|
16
17
|
import { agentDir as resolveAgentDir, agentMdPath, getPackageRoot, resolveRoot, resolvePaths } from '../../paths.js';
|
|
17
18
|
import { renderKitSections } from '../../eck/kit-renderer.js';
|
|
@@ -485,9 +486,6 @@ export async function resolveGroupRulesForTurn(opts, sync = syncGroupRulesContex
|
|
|
485
486
|
}
|
|
486
487
|
return sync({ selfAid: opts.selfAid, groupId: opts.groupId, channel: opts.channel });
|
|
487
488
|
}
|
|
488
|
-
function autoCompactTokensFromMaxTokens(maxTokens) {
|
|
489
|
-
return autoCompactWindowForContextWindow(maxTokens);
|
|
490
|
-
}
|
|
491
489
|
/**
|
|
492
490
|
* 构造 OutboundEnvelope —— 出站三件套的信封部分。
|
|
493
491
|
*
|
|
@@ -915,6 +913,20 @@ export class ResponseEngine {
|
|
|
915
913
|
causation: runtime?.causation,
|
|
916
914
|
});
|
|
917
915
|
}
|
|
916
|
+
async recoverAuthorizedHandoffResult(params, selfAid) {
|
|
917
|
+
if (!this.handoffRuntime) {
|
|
918
|
+
return { ok: false, code: 'HANDOFF_NOT_FOUND', error: 'handoff runtime not configured' };
|
|
919
|
+
}
|
|
920
|
+
const runtime = this.activeTaskRuntimeContexts.get(params.sessionId);
|
|
921
|
+
return this.handoffRuntime.recoverReturnHandoff({
|
|
922
|
+
selfAid,
|
|
923
|
+
recoverySessionId: params.sessionId,
|
|
924
|
+
handoffId: params.handoffId,
|
|
925
|
+
content: params.content,
|
|
926
|
+
actorId: params.actorId,
|
|
927
|
+
causation: runtime?.causation,
|
|
928
|
+
});
|
|
929
|
+
}
|
|
918
930
|
agentRegistry;
|
|
919
931
|
setAgentRegistry(registry) {
|
|
920
932
|
this.agentRegistry = registry;
|
|
@@ -2132,6 +2144,7 @@ export class ResponseEngine {
|
|
|
2132
2144
|
modeConfig: resolvedMode.context.modeConfig,
|
|
2133
2145
|
state: modeState,
|
|
2134
2146
|
isSendCommand: (toolName, toolInput) => isExactEvolcoreSendCommandForSession(toolName, toolInput, session.channelId, chatType, selfAid),
|
|
2147
|
+
describeSendCommandFailure: describeProactiveSendCommandFailure,
|
|
2135
2148
|
logger,
|
|
2136
2149
|
} : null;
|
|
2137
2150
|
if (resolvedMode?.mode.beforeProcess && modeProcessCtx) {
|
|
@@ -2764,6 +2777,7 @@ export class ResponseEngine {
|
|
|
2764
2777
|
let previousFallbackState;
|
|
2765
2778
|
let agentModel;
|
|
2766
2779
|
let v2HandoffIds = [];
|
|
2780
|
+
let v2HandoffResultRefs = [];
|
|
2767
2781
|
let v2HandoffDirection;
|
|
2768
2782
|
let handoffPromptRendered = false;
|
|
2769
2783
|
let runtimeEnv;
|
|
@@ -3098,7 +3112,7 @@ export class ResponseEngine {
|
|
|
3098
3112
|
KITS_FRAGMENTS: path.join(pkgRoot, 'kits', 'templates', 'system-fragments'),
|
|
3099
3113
|
KITS_MESSAGE_FRAGMENTS: path.join(pkgRoot, 'kits', 'templates', 'message-fragments'),
|
|
3100
3114
|
// evolcore 运行模式:dev=源码仓库 | install=全局安装包
|
|
3101
|
-
evolcoreMode:
|
|
3115
|
+
evolcoreMode: readEvolcoreRuntimeFlavor(),
|
|
3102
3116
|
// 路径变量(用于 manifest 路径展开,resolvePath 用 ctx.vars 取真值)
|
|
3103
3117
|
PERSONAL_DIR: selfAid ? path.join(resolveRoot(), 'agents', selfAid, 'personal') : undefined,
|
|
3104
3118
|
RELATIONS_DIR: selfAid ? path.join(resolveRoot(), 'agents', selfAid, 'relations') : undefined,
|
|
@@ -3241,6 +3255,7 @@ export class ResponseEngine {
|
|
|
3241
3255
|
v2HandoffIds = Array.from(new Set(items.flatMap(item => (item.handoff?.handoffIds?.length
|
|
3242
3256
|
? item.handoff.handoffIds
|
|
3243
3257
|
: (item.handoff?.handoffId ? [item.handoff.handoffId] : [])))));
|
|
3258
|
+
v2HandoffResultRefs = items.flatMap(item => item.handoff?.resultRefs ?? []);
|
|
3244
3259
|
v2HandoffDirection = message.handoffDelivery.direction;
|
|
3245
3260
|
return items;
|
|
3246
3261
|
}
|
|
@@ -3314,11 +3329,18 @@ export class ResponseEngine {
|
|
|
3314
3329
|
return;
|
|
3315
3330
|
}
|
|
3316
3331
|
if (v2HandoffIds.length > 0 && handoffPromptRendered && this.handoffRuntime && selfAid) {
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
this.handoffRuntime.completeOriginContext(selfAid, handoffId);
|
|
3320
|
-
|
|
3321
|
-
|
|
3332
|
+
if (v2HandoffDirection === 'origin' && v2HandoffResultRefs.length > 0) {
|
|
3333
|
+
for (const ref of v2HandoffResultRefs) {
|
|
3334
|
+
this.handoffRuntime.completeOriginContext(selfAid, ref.handoffId, ref.resultId);
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
else {
|
|
3338
|
+
for (const handoffId of v2HandoffIds) {
|
|
3339
|
+
if (v2HandoffDirection === 'origin')
|
|
3340
|
+
this.handoffRuntime.completeOriginContext(selfAid, handoffId);
|
|
3341
|
+
else if (v2HandoffDirection === 'target')
|
|
3342
|
+
this.handoffRuntime.completeTargetContext(selfAid, handoffId);
|
|
3343
|
+
}
|
|
3322
3344
|
}
|
|
3323
3345
|
}
|
|
3324
3346
|
// The runner may already own a stronger per-session directory (Codex
|
|
@@ -4452,7 +4474,9 @@ export class ResponseEngine {
|
|
|
4452
4474
|
kind: 'activity.batch',
|
|
4453
4475
|
items: [{
|
|
4454
4476
|
kind: 'notice',
|
|
4455
|
-
|
|
4477
|
+
// activity.batch 载荷混合正常内容与错误,顶层出站包裹不整体打标;
|
|
4478
|
+
// 这里的 notice 是 proactive 下用户能看到的错误副本,单独打标。
|
|
4479
|
+
text: tagErrorTextWithEvolcoreVersion(userMessage),
|
|
4456
4480
|
severity: 'warn',
|
|
4457
4481
|
subtype: 'task-error',
|
|
4458
4482
|
}],
|
|
@@ -4567,12 +4591,12 @@ export class ResponseEngine {
|
|
|
4567
4591
|
return undefined;
|
|
4568
4592
|
const shouldClose = !writerDb;
|
|
4569
4593
|
try {
|
|
4570
|
-
const row = db.prepare(`SELECT model, input_tokens, cache_creation_tokens, cache_read_tokens,
|
|
4571
|
-
context_tokens
|
|
4572
|
-
FROM model_calls
|
|
4573
|
-
WHERE session_id = ?
|
|
4574
|
-
AND agent_session_id = ?
|
|
4575
|
-
ORDER BY ts DESC, call_index DESC
|
|
4594
|
+
const row = db.prepare(`SELECT model, input_tokens, cache_creation_tokens, cache_read_tokens,
|
|
4595
|
+
context_tokens
|
|
4596
|
+
FROM model_calls
|
|
4597
|
+
WHERE session_id = ?
|
|
4598
|
+
AND agent_session_id = ?
|
|
4599
|
+
ORDER BY ts DESC, call_index DESC
|
|
4576
4600
|
LIMIT 1`).get(sessionId, agentSessionId);
|
|
4577
4601
|
if (!row)
|
|
4578
4602
|
return undefined;
|
|
@@ -4590,16 +4614,11 @@ export class ResponseEngine {
|
|
|
4590
4614
|
}
|
|
4591
4615
|
if (totalTokens <= 0)
|
|
4592
4616
|
return undefined;
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
// Historic rows may contain the old fixed 350k threshold. Never let a
|
|
4599
|
-
// persisted value exceed the context window that accompanied it.
|
|
4600
|
-
const autoCompactTokens = inferredAutoCompactTokens
|
|
4601
|
-
? Math.min(candidateAutoCompactTokens, inferredAutoCompactTokens)
|
|
4602
|
-
: candidateAutoCompactTokens;
|
|
4617
|
+
// EvolCore 的自动压缩阈值固定为 650k,与模型上下文窗口无关:
|
|
4618
|
+
// 大窗口模型(1M)到 650k 由 EvolCore 压缩;小窗口模型(200k/128k)
|
|
4619
|
+
// 到不了该阈值,交给 base agent 自身的压缩机制处理。
|
|
4620
|
+
// 历史行里可能存着旧的 350k 阈值,这里一律忽略,只认当前常量。
|
|
4621
|
+
const autoCompactTokens = autoCompactWindowForModel(model);
|
|
4603
4622
|
return { totalTokens, autoCompactTokens };
|
|
4604
4623
|
}
|
|
4605
4624
|
finally {
|