evolcore 0.0.32 → 0.0.34
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 +61 -0
- package/bin/ec.js +3 -2
- package/bin/install-codex-managed-hooks.mjs +135 -37
- package/dist/agents/baseagent-availability.js +20 -36
- package/dist/agents/claude-runner.js +111 -15
- package/dist/agents/codex/app-server-client.js +3 -0
- package/dist/agents/codex/diagnostics.js +112 -54
- package/dist/agents/codex-runner.js +241 -63
- package/dist/agents/ecagent-runner.js +78 -33
- package/dist/agents/runner-types.js +5 -6
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/group/operations.js +0 -1
- package/dist/aun/msg/history.js +1 -0
- package/dist/aun/msg/p2p.js +0 -1
- package/dist/aun/outbox.js +50 -1
- package/dist/channels/aun.js +44 -8
- package/dist/channels/daemon.js +261 -3
- package/dist/cli/agent-command.js +58 -24
- package/dist/cli/agent.js +1 -1
- package/dist/cli/aun-commands.js +368 -31
- package/dist/cli/contact.js +8 -2
- package/dist/cli/ctl-command.js +3 -1
- package/dist/cli/daemon-commands.js +197 -27
- package/dist/cli/debug-mode.js +154 -0
- package/dist/cli/fs-command.js +2 -1
- package/dist/cli/handoff-command.js +3 -0
- package/dist/cli/index.js +98 -67
- package/dist/cli/init.js +2 -2
- package/dist/cli/integrity-command.js +196 -0
- package/dist/cli/managed-command-guard.js +5 -0
- package/dist/cli/memory-command.js +166 -146
- package/dist/cli/queue-command.js +9 -4
- package/dist/cli/session-command.js +194 -0
- package/dist/cli/skill-command.js +78 -2
- package/dist/cli/task-context.js +1 -0
- package/dist/cli/thread-command.js +622 -0
- package/dist/cli/trigger-command.js +10 -3
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-field-policy.js +6 -3
- package/dist/config/config-manager.js +26 -2
- package/dist/config/contact-book-store.js +5 -0
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config/role-service.js +13 -0
- package/dist/config/runtime-env.js +16 -0
- package/dist/config-store.js +45 -0
- package/dist/core/audit/log-integrity.js +3 -1
- package/dist/core/auth/agent-delegation.js +133 -36
- package/dist/core/auth/debug-context.js +139 -0
- package/dist/core/auth/delegation-diagnostics.js +414 -0
- package/dist/core/auth/operation-authorizer.js +25 -2
- package/dist/core/auth/operation-catalog.js +49 -0
- package/dist/core/background-session/session-cleanup.js +212 -0
- package/dist/core/background-session/types.js +10 -0
- package/dist/core/bootstrap-messages.js +1 -1
- package/dist/core/bootstrap-service.js +6 -3
- package/dist/core/command/agent-control.js +18 -26
- package/dist/core/command/command-handler.js +197 -27
- package/dist/core/command/daemon-diagnostics.js +1 -0
- package/dist/core/command/memory-slash.js +6 -2
- package/dist/core/command/menu-catalog.js +51 -1
- package/dist/core/command/menu-handler.js +114 -23
- package/dist/core/command/menu-protocol.js +25 -1
- package/dist/core/command/skill-slash.js +322 -0
- package/dist/core/command/slash-gate.js +6 -4
- package/dist/core/command/slash-handler.js +195 -13
- package/dist/core/command/topic-slash.js +528 -0
- package/dist/core/daemon-bootstrap.js +4 -7
- package/dist/core/evolagent-registry.js +20 -5
- package/dist/core/file-integrity/read.js +61 -0
- package/dist/core/file-integrity/store.js +262 -0
- package/dist/core/handoff/runtime.js +5 -11
- package/dist/core/handoff/store.js +5 -0
- package/dist/core/ipc-registration.js +175 -3
- package/dist/core/memory/batch-meta.js +132 -0
- package/dist/core/memory/consolidation-context.js +83 -29
- package/dist/core/memory/consolidation-ops-records.js +49 -16
- package/dist/core/memory/consolidation-queue-format.js +21 -0
- package/dist/core/memory/consolidation.js +264 -205
- package/dist/core/memory/index-manager.js +19 -28
- package/dist/core/memory/memory-admin.js +19 -14
- package/dist/core/memory/memory-document.js +53 -9
- package/dist/core/memory/memory-writer.js +30 -15
- package/dist/core/message/aun-ipc-sender.js +161 -6
- package/dist/core/message/im-renderer.js +169 -10
- package/dist/core/message/message-bridge.js +15 -4
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/peer-mode.js +6 -1
- package/dist/core/message/response-engine.js +929 -110
- package/dist/core/message/subtask-tool-projection.js +140 -0
- package/dist/core/model/catalog-service.js +17 -12
- package/dist/core/permission/ec-command-parser.js +217 -9
- package/dist/core/permission/protected-paths.js +5 -1
- package/dist/core/permission/readonly-shell-query.js +43 -5
- package/dist/core/permission/session-path-grants.js +334 -0
- package/dist/core/permission/tool-canonical.js +226 -0
- package/dist/core/permission/tool-policy.js +30 -62
- package/dist/core/role/runtime-policy.js +21 -10
- package/dist/core/session/session-fs-store.js +123 -8
- package/dist/core/session/session-idle-monitor.js +249 -22
- package/dist/core/session/session-manager.js +129 -14
- package/dist/core/skill/command-parser.js +13 -0
- package/dist/core/skill/index-generator.js +21 -4
- package/dist/core/skill/startup.js +41 -0
- package/dist/core/skill/switch-resolver.js +55 -29
- package/dist/core/system-session/grants.js +40 -0
- package/dist/core/system-session/memory.js +222 -0
- package/dist/core/system-session/registry.js +74 -0
- package/dist/core/system-session/types.js +14 -0
- package/dist/core/thread/command-parser.js +125 -0
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +95 -0
- package/dist/core/thread/thread-context-storage.js +131 -0
- package/dist/core/thread/thread-operation.js +258 -0
- package/dist/core/thread/thread-route.js +33 -0
- package/dist/core/thread/thread-service.js +770 -0
- package/dist/core/thread/types.js +1 -0
- package/dist/eck/kit-renderer.js +7 -2
- package/dist/eck/manifest-engine.js +24 -4
- package/dist/eck/message-renderer.js +35 -0
- package/dist/index.js +19 -7
- package/dist/ipc.js +140 -50
- package/dist/paths.js +93 -0
- package/dist/response-system/engines/v1/proactive-flow.js +169 -80
- package/dist/stats/billing.js +20 -8
- package/dist/trigger/authorization.js +57 -28
- package/dist/trigger/feedback.js +13 -2
- package/dist/trigger/parser.js +70 -1
- package/dist/trigger/system-definitions.js +3 -3
- package/dist/trigger/validation.js +14 -0
- package/dist/utils/cross-platform.js +11 -2
- package/dist/utils/error-dict.json +18 -4
- package/dist/utils/error-utils.js +143 -1
- package/dist/utils/instance-registry.js +13 -8
- package/dist/utils/log-writer.js +12 -0
- package/dist/utils/process-introspect.js +11 -0
- package/kits/docs/context-assembly.md +1 -1
- package/kits/docs/evolcore/INDEX.md +1 -0
- package/kits/docs/evolcore/agent-create.md +40 -28
- package/kits/docs/evolcore/agent.md +21 -6
- package/kits/docs/evolcore/config.md +2 -2
- package/kits/docs/evolcore/ctl.md +2 -2
- package/kits/docs/evolcore/ec-capabilities.md +5 -1
- package/kits/docs/evolcore/fs-architecture.md +4 -5
- package/kits/docs/evolcore/fs.md +1 -1
- package/kits/docs/evolcore/group-collaboration.md +4 -6
- package/kits/docs/evolcore/group.md +11 -12
- package/kits/docs/evolcore/memory-architecture.md +4 -5
- package/kits/docs/evolcore/memory-consolidation.md +19 -15
- package/kits/docs/evolcore/memory-tags.md +3 -1
- package/kits/docs/evolcore/memory.md +24 -12
- package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
- package/kits/docs/evolcore/menu-protocol.md +7 -0
- package/kits/docs/evolcore/model.md +16 -0
- package/kits/docs/evolcore/msg.md +8 -11
- package/kits/docs/evolcore/thread-chain.md +267 -0
- package/kits/docs/prompt-loading-architecture.md +1 -1
- package/kits/eck_manifest.json +55 -40
- package/kits/eck_manifest.memory.json +0 -12
- package/kits/eck_message_manifest.json +169 -10
- package/kits/rules/01-overview.md +11 -0
- package/kits/rules/03-identity.md +6 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +1 -1
- package/kits/rules/07-memory-and-thread.md +199 -0
- package/kits/schemas/_meta.json +7 -1
- package/kits/schemas/agent-config.schema.13.json +1 -1
- package/kits/schemas/daemon.schema.7.json +140 -0
- package/kits/schemas/relation-config.schema.9.json +18 -3
- package/kits/schemas/role-config.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.2.json +6 -6
- package/kits/schemas/single-session.schema.3.json +6 -6
- package/kits/skills/.switches.json +12 -1
- package/kits/skills/ec-group/SKILL.md +234 -0
- package/kits/skills/ec-skill/SKILL.md +10 -1
- package/kits/skills/ec-skill/scripts/cli.mjs +16 -2
- package/kits/skills/ec-skill/scripts/skill.mjs +1 -1
- package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
- package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
- package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
- package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
- package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
- package/kits/skills/thread-ops/SKILL.md +492 -0
- package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
- package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
- package/kits/skills/wechat-article-reader/SKILL.md +97 -0
- package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
- package/kits/templates/bootstrap-welcome.md +7 -7
- package/kits/templates/memory-consolidation/forget.md +7 -2
- package/kits/templates/memory-consolidation/generalize.md +9 -4
- package/kits/templates/memory-consolidation/notes.md +11 -11
- package/kits/templates/memory-consolidation/profile.md +8 -3
- package/kits/templates/memory-consolidation/promote.md +8 -3
- package/kits/templates/memory-consolidation/workflow.md +6 -6
- package/kits/templates/message-fragments/handoff-request-to-target.md +1 -1
- package/kits/templates/message-fragments/item.md +2 -1
- package/kits/templates/message-fragments/thread-context.md +6 -0
- package/kits/templates/message-fragments/trigger-session.md +2 -0
- package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
- package/kits/templates/roles/member.json +2 -0
- package/kits/templates/roles/visitor.json +2 -0
- package/kits/templates/system-fragments/bootstrap.md +67 -72
- package/kits/templates/system-fragments/channel.md +3 -6
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/managed-runtime.md +15 -0
- package/kits/templates/system-fragments/memory.md +16 -9
- package/kits/templates/system-fragments/reply.md +7 -6
- package/kits/templates/system-fragments/session.md +5 -14
- package/package.json +6 -3
- package/dist/core/memory/memory-session-policy.js +0 -41
- package/dist/core/memory/memory-signature.js +0 -257
- package/kits/docs/evolcore/group-fs.md +0 -17
- package/kits/docs/venues/aun-group.md +0 -45
- package/kits/docs/venues/group.md +0 -43
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getRunnerCatalog, catalogEfforts, assertCatalogSelectable,
|
|
1
|
+
import { getRunnerCatalog, catalogEfforts, assertCatalogSelectable, } from '../core/model/model-catalog.js';
|
|
2
2
|
// Ecagent/OpenAI API 不认识 Claude Code SDK 的窗口后缀,必须传入基础模型 ID。
|
|
3
3
|
import { stripContextWindowSuffix } from '../core/model/context-window-suffix.js';
|
|
4
4
|
import fs from 'fs';
|
|
@@ -18,6 +18,7 @@ import { auditToolPreflightDenial } from '../core/auth/authorization-audit.js';
|
|
|
18
18
|
import { resolveEcagentConfig } from './baseagent.js';
|
|
19
19
|
import { buildModelRequestHeaders } from './request-identity.js';
|
|
20
20
|
import { appendRequestPath } from './request-identity.js';
|
|
21
|
+
import { resolveModelSpec } from '../stats/billing.js';
|
|
21
22
|
import { getManagedTaskTempDir } from '../cli/task-context.js';
|
|
22
23
|
import { unsettledInterruptError, withInterruptDeadline, hasTrustedFullAccessContext } from './runner-types.js';
|
|
23
24
|
const PROVIDER_ID = 'evolcore-gateway';
|
|
@@ -436,18 +437,23 @@ async function consumeOpenAiStream(output, body, model) {
|
|
|
436
437
|
throw new Error('[network] Gateway stream ended without a terminal event');
|
|
437
438
|
}
|
|
438
439
|
function createModel(id, baseUrl) {
|
|
439
|
-
const
|
|
440
|
+
const modelId = stripContextWindowSuffix(id);
|
|
441
|
+
const isClaude = modelId.toLowerCase().startsWith('claude-');
|
|
442
|
+
const fallback = isClaude
|
|
443
|
+
? { context_window: 200_000, max_output_tokens: 8_192 }
|
|
444
|
+
: { context_window: 128_000, max_output_tokens: 16_384 };
|
|
445
|
+
const spec = resolveModelSpec(resolveRoot(), id, undefined, fallback);
|
|
440
446
|
return {
|
|
441
|
-
id,
|
|
442
|
-
name:
|
|
447
|
+
id: modelId,
|
|
448
|
+
name: modelId,
|
|
443
449
|
api: 'openai-completions',
|
|
444
450
|
provider: PROVIDER_ID,
|
|
445
451
|
baseUrl,
|
|
446
452
|
reasoning: true,
|
|
447
453
|
input: ['text', 'image'],
|
|
448
454
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
449
|
-
contextWindow:
|
|
450
|
-
maxTokens:
|
|
455
|
+
contextWindow: spec.context_window,
|
|
456
|
+
maxTokens: spec.max_output_tokens,
|
|
451
457
|
compat: {
|
|
452
458
|
maxTokensField: 'max_tokens',
|
|
453
459
|
supportsUsageInStreaming: true,
|
|
@@ -464,7 +470,11 @@ function isWithin(root, candidate) {
|
|
|
464
470
|
const relative = path.relative(root, candidate);
|
|
465
471
|
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
466
472
|
}
|
|
467
|
-
|
|
473
|
+
/** 路径是否落在任一显式声明的根之下(含根本身)。 */
|
|
474
|
+
function isWithinAny(candidate, roots) {
|
|
475
|
+
return roots.some(root => isWithin(path.resolve(root), candidate));
|
|
476
|
+
}
|
|
477
|
+
export function resolveEcagentToolPath(projectPath, candidate, forWrite = false, bootstrapAgentMdPath, fullaccess = false, personalMdPath, sessionGrants) {
|
|
468
478
|
const root = fs.realpathSync(projectPath);
|
|
469
479
|
const resolved = path.resolve(root, candidate || '.');
|
|
470
480
|
const allowedBootstrapFile = bootstrapAgentMdPath
|
|
@@ -472,7 +482,15 @@ export function resolveEcagentToolPath(projectPath, candidate, forWrite = false,
|
|
|
472
482
|
: undefined;
|
|
473
483
|
const allowedPersonalFile = personalMdPath ? path.resolve(personalMdPath) : undefined;
|
|
474
484
|
const isManagedIdentityFile = resolved === allowedBootstrapFile || resolved === allowedPersonalFile;
|
|
475
|
-
|
|
485
|
+
// 系统会话:模块声明的可读根整体放行,可写文件逐个精确匹配(不含目录)。
|
|
486
|
+
// 声明之外、项目之外的路径仍然拒绝。声明里的路径可能在多个根之间借符号链接互串,
|
|
487
|
+
// 所以放行前统一按真实路径复核,确认真实位置仍落在同一个被授予的边界内。
|
|
488
|
+
// 写只看可写文件(逐个精确匹配),绝不由可读根推导;读只看可读根。
|
|
489
|
+
const sessionWrites = forWrite && (sessionGrants?.writeFiles ?? [])
|
|
490
|
+
.some(file => path.resolve(file) === resolved);
|
|
491
|
+
const sessionReads = !forWrite && isWithinAny(resolved, sessionGrants?.readRoots ?? []);
|
|
492
|
+
const isSessionTarget = sessionReads || sessionWrites;
|
|
493
|
+
if (!fullaccess && !isWithin(root, resolved) && !isManagedIdentityFile && !isSessionTarget) {
|
|
476
494
|
throw new Error(`Path is outside the project: ${candidate}`);
|
|
477
495
|
}
|
|
478
496
|
if (isManagedIdentityFile) {
|
|
@@ -494,7 +512,34 @@ export function resolveEcagentToolPath(projectPath, candidate, forWrite = false,
|
|
|
494
512
|
while (!fs.existsSync(cursor) && cursor !== path.dirname(cursor))
|
|
495
513
|
cursor = path.dirname(cursor);
|
|
496
514
|
const canonical = fs.realpathSync(cursor);
|
|
497
|
-
if (
|
|
515
|
+
if (fullaccess)
|
|
516
|
+
return resolved;
|
|
517
|
+
// 系统会话的写入目标与判定层一致:必须是普通文件,链接一律拒绝。
|
|
518
|
+
// 链接会让 resolved 与真实位置分离,放行等于把洞开到声明之外。
|
|
519
|
+
if (sessionWrites && fs.existsSync(resolved) && fs.lstatSync(resolved).isSymbolicLink()) {
|
|
520
|
+
throw new Error(`Refusing to write through a symbolic link: ${candidate}`);
|
|
521
|
+
}
|
|
522
|
+
// 可写文件尚未创建时,以父目录的真实路径为准;已存在时以文件自身的真实路径为准。
|
|
523
|
+
const canonicalSelf = fs.existsSync(resolved) ? fs.realpathSync(resolved) : canonical;
|
|
524
|
+
if (isSessionTarget) {
|
|
525
|
+
const grantedRoots = [
|
|
526
|
+
...(sessionReads ? sessionGrants?.readRoots ?? [] : []),
|
|
527
|
+
...(sessionWrites ? (sessionGrants?.writeFiles ?? []).filter(file => path.resolve(file) === resolved) : []),
|
|
528
|
+
];
|
|
529
|
+
const canonicalRoots = grantedRoots.flatMap(granted => {
|
|
530
|
+
const inside = fs.existsSync(granted) ? [fs.realpathSync(granted)] : [];
|
|
531
|
+
// 根自身可能尚未创建,或者位于尚未创建的上层目录中;先归到存在的祖先再比。
|
|
532
|
+
let ancestor = granted;
|
|
533
|
+
while (!fs.existsSync(ancestor) && ancestor !== path.dirname(ancestor))
|
|
534
|
+
ancestor = path.dirname(ancestor);
|
|
535
|
+
return [...inside, fs.realpathSync(ancestor)];
|
|
536
|
+
});
|
|
537
|
+
if (!canonicalRoots.some(granted => isWithin(granted, canonical) && isWithin(granted, canonicalSelf))) {
|
|
538
|
+
throw new Error(`Path resolves outside its declared grant: ${candidate}`);
|
|
539
|
+
}
|
|
540
|
+
return resolved;
|
|
541
|
+
}
|
|
542
|
+
if (!isWithin(root, canonical))
|
|
498
543
|
throw new Error(`Path resolves outside the project: ${candidate}`);
|
|
499
544
|
return resolved;
|
|
500
545
|
}
|
|
@@ -547,7 +592,7 @@ async function walkFiles(root, signal) {
|
|
|
547
592
|
function textResult(text, details = {}) {
|
|
548
593
|
return { content: [{ type: 'text', text: truncate(text) }], details };
|
|
549
594
|
}
|
|
550
|
-
function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullaccess = false, personalMdPath) {
|
|
595
|
+
function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullaccess = false, personalMdPath, sessionGrants) {
|
|
551
596
|
const read = {
|
|
552
597
|
name: 'Read', label: 'Read', description: 'Read a UTF-8 text file from the project.',
|
|
553
598
|
parameters: Type.Object({
|
|
@@ -556,7 +601,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
556
601
|
limit: Type.Optional(Type.Number({ minimum: 1 })),
|
|
557
602
|
}),
|
|
558
603
|
async execute(_id, params, signal) {
|
|
559
|
-
const file = resolveEcagentToolPath(projectPath, params.file_path, false, bootstrapAgentMdPath, fullaccess, personalMdPath);
|
|
604
|
+
const file = resolveEcagentToolPath(projectPath, params.file_path, false, bootstrapAgentMdPath, fullaccess, personalMdPath, sessionGrants);
|
|
560
605
|
const stat = await fs.promises.stat(file);
|
|
561
606
|
if (stat.size > MAX_READ_BYTES)
|
|
562
607
|
throw new Error(`File exceeds ${MAX_READ_BYTES} byte read limit`);
|
|
@@ -573,7 +618,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
573
618
|
name: 'Glob', label: 'Glob', description: 'Find project files matching a glob pattern.',
|
|
574
619
|
parameters: Type.Object({ pattern: Type.String(), path: Type.Optional(Type.String()) }),
|
|
575
620
|
async execute(_id, params, signal) {
|
|
576
|
-
const root = resolveEcagentToolPath(projectPath, params.path ?? '.', false, undefined, fullaccess);
|
|
621
|
+
const root = resolveEcagentToolPath(projectPath, params.path ?? '.', false, undefined, fullaccess, undefined, sessionGrants);
|
|
577
622
|
const matcher = globRegex(params.pattern.replaceAll('\\', '/'));
|
|
578
623
|
const files = (await walkFiles(root, signal))
|
|
579
624
|
.map(file => path.relative(root, file).replaceAll(path.sep, '/'))
|
|
@@ -589,7 +634,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
589
634
|
case_insensitive: Type.Optional(Type.Boolean()), literal: Type.Optional(Type.Boolean()),
|
|
590
635
|
}),
|
|
591
636
|
async execute(_id, params, signal) {
|
|
592
|
-
const root = resolveEcagentToolPath(projectPath, params.path ?? '.', false, undefined, fullaccess);
|
|
637
|
+
const root = resolveEcagentToolPath(projectPath, params.path ?? '.', false, undefined, fullaccess, undefined, sessionGrants);
|
|
593
638
|
const files = (await fs.promises.stat(root)).isFile() ? [root] : await walkFiles(root, signal);
|
|
594
639
|
const fileMatcher = params.glob ? globRegex(params.glob.replaceAll('\\', '/')) : undefined;
|
|
595
640
|
const flags = params.case_insensitive ? 'i' : '';
|
|
@@ -622,7 +667,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
622
667
|
name: 'Write', label: 'Write', description: 'Create or completely overwrite a project file.',
|
|
623
668
|
parameters: Type.Object({ file_path: Type.String(), content: Type.String() }), executionMode: 'sequential',
|
|
624
669
|
async execute(_id, params, signal) {
|
|
625
|
-
const file = resolveEcagentToolPath(projectPath, params.file_path, true, bootstrapAgentMdPath, fullaccess, personalMdPath);
|
|
670
|
+
const file = resolveEcagentToolPath(projectPath, params.file_path, true, bootstrapAgentMdPath, fullaccess, personalMdPath, sessionGrants);
|
|
626
671
|
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
627
672
|
await fs.promises.writeFile(file, params.content, { encoding: 'utf8', signal });
|
|
628
673
|
return textResult(`Wrote ${Buffer.byteLength(params.content)} bytes to ${path.relative(projectPath, file)}`, { file });
|
|
@@ -635,7 +680,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
635
680
|
replace_all: Type.Optional(Type.Boolean()),
|
|
636
681
|
}), executionMode: 'sequential',
|
|
637
682
|
async execute(_id, params, signal) {
|
|
638
|
-
const file = resolveEcagentToolPath(projectPath, params.file_path,
|
|
683
|
+
const file = resolveEcagentToolPath(projectPath, params.file_path, true, bootstrapAgentMdPath, fullaccess, personalMdPath, sessionGrants);
|
|
639
684
|
const value = await fs.promises.readFile(file, { encoding: 'utf8', signal });
|
|
640
685
|
if (!params.old_string)
|
|
641
686
|
throw new Error('old_string must not be empty');
|
|
@@ -724,7 +769,7 @@ export class EcagentRunner {
|
|
|
724
769
|
configuredHeaders: config.headers,
|
|
725
770
|
}),
|
|
726
771
|
};
|
|
727
|
-
this.model =
|
|
772
|
+
this.model = config.model;
|
|
728
773
|
this.effort = config.effort;
|
|
729
774
|
this.agentAid = runtime?.agentAid;
|
|
730
775
|
this.onSessionIdUpdate = callbacks?.onSessionIdUpdate;
|
|
@@ -734,8 +779,8 @@ export class EcagentRunner {
|
|
|
734
779
|
throw new Error('ecagent requires an EvolCore Agent AID');
|
|
735
780
|
return agentSessionsDir(this.agentAid);
|
|
736
781
|
}
|
|
737
|
-
setModel(model) { this.model =
|
|
738
|
-
getModel() { return this.model; }
|
|
782
|
+
setModel(model) { this.model = model; }
|
|
783
|
+
getModel() { return stripContextWindowSuffix(this.model); }
|
|
739
784
|
resolveModelId(model) { return model; }
|
|
740
785
|
setEffort(effort) { this.effort = effort; }
|
|
741
786
|
getEffort() { return this.effort; }
|
|
@@ -762,15 +807,7 @@ export class EcagentRunner {
|
|
|
762
807
|
return catalog.models.map(m => m.id);
|
|
763
808
|
}
|
|
764
809
|
async getAvailableEfforts(model) {
|
|
765
|
-
|
|
766
|
-
const efforts = catalogEfforts(catalog, model, 'ecagent');
|
|
767
|
-
if (efforts.length > 0)
|
|
768
|
-
return efforts;
|
|
769
|
-
// The embedded transport advertises reasoning support for every model it
|
|
770
|
-
// constructs. Older gateways may omit reasoningLevels from /models; keep
|
|
771
|
-
// menu.options aligned with the actual runner capability in that case.
|
|
772
|
-
const entry = catalog.models.find(item => item.id === resolveCatalogModel(catalog, model));
|
|
773
|
-
return entry && entry.reasoningLevels === undefined ? [...TRANSPORT_EFFORTS.ecagent] : efforts;
|
|
810
|
+
return catalogEfforts(await this.getModelCatalog(), model, 'ecagent');
|
|
774
811
|
}
|
|
775
812
|
registerStream(key, stream) { this.activeStreams.set(key, stream); }
|
|
776
813
|
cleanupStream(key) {
|
|
@@ -893,7 +930,7 @@ export class EcagentRunner {
|
|
|
893
930
|
models,
|
|
894
931
|
model,
|
|
895
932
|
thinkingLevel: normalizeThinkingLevel(effort),
|
|
896
|
-
tools: createTools(nodeEnv, request.projectPath, request.runtimeEnv, request.modelOverride?.bootstrapAgentMdPath, fullaccess, request.modelOverride?.personalMdPath),
|
|
933
|
+
tools: createTools(nodeEnv, request.projectPath, request.runtimeEnv, request.modelOverride?.bootstrapAgentMdPath, fullaccess, request.modelOverride?.personalMdPath, this.permissionContexts.get(request.sessionId)?.systemSessionGrants),
|
|
897
934
|
systemPrompt: [DEFAULT_SYSTEM_PROMPT, request.systemPromptAppend].filter(Boolean).join('\n\n'),
|
|
898
935
|
streamOptions: {
|
|
899
936
|
timeoutMs: this.config.timeoutMs,
|
|
@@ -917,7 +954,7 @@ export class EcagentRunner {
|
|
|
917
954
|
if (pauseResult === 'cancelled')
|
|
918
955
|
return { block: true, reason: '工具调用已取消' };
|
|
919
956
|
}
|
|
920
|
-
const decision = await this.authorizeTool(request.sessionId, request.projectPath, permissionMode, event.toolName, event.input);
|
|
957
|
+
const decision = await this.authorizeTool(request.sessionId, request.projectPath, permissionMode, event.toolName, event.input, stats.numTurns + 1);
|
|
921
958
|
return lifecycle.cancelled || signal?.aborted ? { block: true, reason: '工具调用已取消' } : decision;
|
|
922
959
|
});
|
|
923
960
|
const unsubscribe = harness.subscribe(event => this.mapHarnessEvent(queue, event, stats, model, effort));
|
|
@@ -1175,7 +1212,7 @@ export class EcagentRunner {
|
|
|
1175
1212
|
model: model.id, effort,
|
|
1176
1213
|
};
|
|
1177
1214
|
}
|
|
1178
|
-
async authorizeTool(sessionId, projectPath, mode, toolName, input) {
|
|
1215
|
+
async authorizeTool(sessionId, projectPath, mode, toolName, input, turn) {
|
|
1179
1216
|
const permissionContext = this.permissionContexts.get(sessionId);
|
|
1180
1217
|
if (mode === 'fullaccess') {
|
|
1181
1218
|
return hasTrustedFullAccessContext(permissionContext)
|
|
@@ -1220,7 +1257,15 @@ export class EcagentRunner {
|
|
|
1220
1257
|
logger.warn(`[EcagentRunner] failed to record blocked operation: session=${sessionId} tool=${toolName} code=${policyCode} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1221
1258
|
}
|
|
1222
1259
|
};
|
|
1223
|
-
|
|
1260
|
+
// 系统会话:模块判定即最终结论,不进入 preflight / permissionMode 分支
|
|
1261
|
+
if (permissionContext?.systemSessionCheck) {
|
|
1262
|
+
const decision = permissionContext.systemSessionCheck(toolName, input);
|
|
1263
|
+
if (decision.allow)
|
|
1264
|
+
return {};
|
|
1265
|
+
await recordBlockedOperation(decision.code);
|
|
1266
|
+
return { block: true, reason: decision.reason };
|
|
1267
|
+
}
|
|
1268
|
+
const policy = permissionContext?.policyHook?.(toolName, input, { turn });
|
|
1224
1269
|
if (policy?.block) {
|
|
1225
1270
|
await recordBlockedOperation(policy.policyCode ?? 'session_policy_hook');
|
|
1226
1271
|
return { block: true, reason: policy.reason || '当前会话策略拒绝此工具调用' };
|
|
@@ -1247,7 +1292,7 @@ export class EcagentRunner {
|
|
|
1247
1292
|
const checkedInput = preflight.input;
|
|
1248
1293
|
if (mode === 'readonly') {
|
|
1249
1294
|
const decision = checkReadonly(toolName, checkedInput, projectPath, {
|
|
1250
|
-
sessionId, managedTempDir: permissionContext?.managedTempDir, channel: permissionContext?.channel, peerId: permissionContext?.userId, role: permissionContext?.role,
|
|
1295
|
+
sessionId, managedTempDir: permissionContext?.managedTempDir, grantedReadRoots: permissionContext?.grantedReadRoots, channel: permissionContext?.channel, peerId: permissionContext?.userId, role: permissionContext?.role,
|
|
1251
1296
|
allowReadonlySourceDiagnostics: permissionContext?.allowReadonlySourceDiagnostics === true,
|
|
1252
1297
|
});
|
|
1253
1298
|
if (decision.behavior === 'deny') {
|
|
@@ -1359,7 +1404,7 @@ export class EcagentRunner {
|
|
|
1359
1404
|
? cached
|
|
1360
1405
|
: await this.openExistingRuntime(agentSessionId, cwd);
|
|
1361
1406
|
this.onCompactStart?.(sessionId);
|
|
1362
|
-
const compactModel =
|
|
1407
|
+
const compactModel = modelOverride?.model || this.model;
|
|
1363
1408
|
const compactEffort = modelOverride?.effortMode === 'model_default'
|
|
1364
1409
|
? undefined
|
|
1365
1410
|
: modelOverride?.effort ?? this.effort;
|
|
@@ -136,10 +136,9 @@ export function isOneMillionContextModel(model) {
|
|
|
136
136
|
return ONE_M_CONTEXT_MODEL_PREFIXES.some(prefix => base === prefix || base.startsWith(`${prefix}-`));
|
|
137
137
|
}
|
|
138
138
|
/**
|
|
139
|
-
*
|
|
140
|
-
* every other model falls back to 200,000
|
|
141
|
-
* This is an operational guardrail, not a claim about
|
|
142
|
-
* advertised capacity.
|
|
139
|
+
* Hardcoded context-window fallback for models missing from the parameter table:
|
|
140
|
+
* known 1M models use 1,000,000; every other model falls back to 200,000.
|
|
141
|
+
* This is an operational guardrail, not a claim about advertised capacity.
|
|
143
142
|
*/
|
|
144
143
|
export function realContextWindowForModel(model) {
|
|
145
144
|
return isOneMillionContextModel(model) ? 1000000 : 200000;
|
|
@@ -159,8 +158,8 @@ export function autoCompactWindowForModel(_model) {
|
|
|
159
158
|
* at the right point for small-context models (200k/128k), where EvolCore's
|
|
160
159
|
* fixed 650k threshold would never trigger.
|
|
161
160
|
*/
|
|
162
|
-
export function sdkAutoCompactWindowForModel(model) {
|
|
163
|
-
const contextWindow = realContextWindowForModel(model);
|
|
161
|
+
export function sdkAutoCompactWindowForModel(model, resolvedContextWindow) {
|
|
162
|
+
const contextWindow = resolvedContextWindow ?? realContextWindowForModel(model);
|
|
164
163
|
const reserve = Math.min(10_000, Math.floor(contextWindow * 0.05));
|
|
165
164
|
return Math.min(650_000, Math.max(1, contextWindow - reserve));
|
|
166
165
|
}
|
package/dist/aun/aid/identity.js
CHANGED
|
@@ -224,7 +224,7 @@ export async function aidCreate(aid, opts) {
|
|
|
224
224
|
// 新注册流程:AIDStore.register → downloadCaRoot → load → authenticate
|
|
225
225
|
const store = await getAidStore({ slotId: SLOT.cli, aunPath });
|
|
226
226
|
try {
|
|
227
|
-
const regResult = await store.register(aid);
|
|
227
|
+
const regResult = await store.register(aid, { type: 'agent' });
|
|
228
228
|
if (!regResult.ok) {
|
|
229
229
|
const e = new Error(regResult.error.message);
|
|
230
230
|
e.code = regResult.error.code;
|
|
@@ -117,7 +117,6 @@ async function tryDaemonGroupSend(args, payload, runtimeContext, file) {
|
|
|
117
117
|
mentions: args.mentions,
|
|
118
118
|
encrypt: args.encrypt,
|
|
119
119
|
thread,
|
|
120
|
-
returnPolicy: args.returnPolicy,
|
|
121
120
|
originSessionId: runtimeContext.sessionId,
|
|
122
121
|
originMessageId: runtimeContext.messageId,
|
|
123
122
|
delegationToken: readDelegationCredential(),
|
package/dist/aun/msg/history.js
CHANGED
|
@@ -171,6 +171,7 @@ function readHistoryScopes(input) {
|
|
|
171
171
|
.filter(({ entry, sessionIds }) => sessionIds === undefined
|
|
172
172
|
|| (typeof entry.sessionId === 'string' && sessionIds.has(entry.sessionId)))
|
|
173
173
|
.filter(({ entry }) => input.direction === 'all' || entry.dir === input.direction)
|
|
174
|
+
.filter(({ entry }) => input.args.threadId === undefined || entry.threadId === input.args.threadId)
|
|
174
175
|
.filter(({ entry }) => input.args.after === undefined || entry.ts > input.args.after)
|
|
175
176
|
.filter(({ entry }) => input.args.before === undefined || entry.ts < input.args.before)
|
|
176
177
|
.sort((left, right) => left.entry.ts - right.entry.ts || left.scope - right.scope)
|
package/dist/aun/msg/p2p.js
CHANGED
|
@@ -134,7 +134,6 @@ async function tryDaemonMsgSend(args, payload, runtimeContext, file) {
|
|
|
134
134
|
...(payload ? { payload } : { file }),
|
|
135
135
|
encrypt: args.encrypt,
|
|
136
136
|
thread,
|
|
137
|
-
returnPolicy: args.returnPolicy,
|
|
138
137
|
handoffContext: args.handoffContext,
|
|
139
138
|
originSessionId: runtimeContext.sessionId,
|
|
140
139
|
originMessageId: runtimeContext.messageId,
|
package/dist/aun/outbox.js
CHANGED
|
@@ -64,6 +64,24 @@ function isExpired(entry) {
|
|
|
64
64
|
return false;
|
|
65
65
|
return Date.now() - entry.ts > entry.ttl;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* A process-scoped entry whose enqueuing process is gone. Replaying it would
|
|
69
|
+
* deliver stale live feedback — typically the "restarting, back in ~5s" notice
|
|
70
|
+
* that a successful restart has already superseded with its own confirmation.
|
|
71
|
+
*
|
|
72
|
+
* A stale entry is not `isExpired()`: it needs `drainOnce` to retire it with a
|
|
73
|
+
* reason of its own, otherwise the send log would report a semantic drop as a
|
|
74
|
+
* timeout.
|
|
75
|
+
*/
|
|
76
|
+
export function isStaleProcessScoped(entry) {
|
|
77
|
+
if (!entry.processScoped)
|
|
78
|
+
return false;
|
|
79
|
+
// A record without a pid cannot prove same-process ownership. Treat it as
|
|
80
|
+
// replayable so the ordinary route/expiry rules stay in charge.
|
|
81
|
+
if (typeof entry.enqueuedByPid !== 'number')
|
|
82
|
+
return false;
|
|
83
|
+
return entry.enqueuedByPid !== process.pid;
|
|
84
|
+
}
|
|
67
85
|
export function isDeliveryForChannel(value, channelId) {
|
|
68
86
|
return isDeliveryTargetForChannel(value, channelId);
|
|
69
87
|
}
|
|
@@ -129,6 +147,7 @@ export function enqueue(aid, opts) {
|
|
|
129
147
|
delivery,
|
|
130
148
|
dedupeKey: opts.dedupeKey,
|
|
131
149
|
critical: opts.critical,
|
|
150
|
+
...(opts.processScoped ? { processScoped: true, enqueuedByPid: process.pid } : {}),
|
|
132
151
|
type: opts.type,
|
|
133
152
|
contentKind: opts.contentKind,
|
|
134
153
|
payload: opts.payload,
|
|
@@ -273,6 +292,19 @@ function markExpired(entry) {
|
|
|
273
292
|
code: entry.lastErrorCode,
|
|
274
293
|
};
|
|
275
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Drop a process-scoped entry left behind by a previous process. The terminal
|
|
297
|
+
* record is retained so the send log still shows why it never went out.
|
|
298
|
+
*/
|
|
299
|
+
function markSupersededProcessScoped(entry) {
|
|
300
|
+
entry.lastError = 'process-scoped delivery superseded by a new daemon process';
|
|
301
|
+
entry.lastErrorCode = 'OUTBOX_PROCESS_SUPERSEDED';
|
|
302
|
+
entry.terminal = {
|
|
303
|
+
at: Date.now(),
|
|
304
|
+
error: entry.lastError,
|
|
305
|
+
code: entry.lastErrorCode,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
276
308
|
/** Mark a durable entry terminal while keeping its reason for diagnostics. */
|
|
277
309
|
export function markTerminal(aid, id, failure, submitted, queue = submitted ? entryQueue(submitted) : 'default') {
|
|
278
310
|
const entries = readEntries(aid, queue);
|
|
@@ -336,6 +368,7 @@ async function drainOnce(aid, sender, queue) {
|
|
|
336
368
|
let expired = 0;
|
|
337
369
|
let failed = 0;
|
|
338
370
|
let permanent = 0;
|
|
371
|
+
let superseded = 0;
|
|
339
372
|
const remaining = [];
|
|
340
373
|
for (const entry of entries) {
|
|
341
374
|
// Cancellation or another sender may have changed an
|
|
@@ -350,6 +383,16 @@ async function drainOnce(aid, sender, queue) {
|
|
|
350
383
|
}
|
|
351
384
|
Object.assign(entry, currentEntry);
|
|
352
385
|
}
|
|
386
|
+
if (isStaleProcessScoped(entry)) {
|
|
387
|
+
// Deliberately not counted as `expired`: this is a semantic drop, not a
|
|
388
|
+
// timeout, and the drained-line diagnostic should not conflate them.
|
|
389
|
+
// The terminal record also retires the entry from `hasPending()`, so a
|
|
390
|
+
// later drain does not rediscover it.
|
|
391
|
+
superseded++;
|
|
392
|
+
markSupersededProcessScoped(entry);
|
|
393
|
+
remaining.push(entry);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
353
396
|
if (isExpired(entry)) {
|
|
354
397
|
expired++;
|
|
355
398
|
markExpired(entry);
|
|
@@ -457,7 +500,13 @@ async function drainOnce(aid, sender, queue) {
|
|
|
457
500
|
}];
|
|
458
501
|
});
|
|
459
502
|
writeEntries(aid, retained, queue);
|
|
460
|
-
return {
|
|
503
|
+
return {
|
|
504
|
+
sent,
|
|
505
|
+
expired,
|
|
506
|
+
failed,
|
|
507
|
+
...(permanent > 0 ? { permanent } : {}),
|
|
508
|
+
...(superseded > 0 ? { superseded } : {}),
|
|
509
|
+
};
|
|
461
510
|
}
|
|
462
511
|
export async function drain(aid, sender, queue = 'default') {
|
|
463
512
|
const drainKey = `${queue}:${aid}`;
|
package/dist/channels/aun.js
CHANGED
|
@@ -557,6 +557,11 @@ function setIfDefined(target, key, value) {
|
|
|
557
557
|
if (value !== undefined)
|
|
558
558
|
target[key] = value;
|
|
559
559
|
}
|
|
560
|
+
function appendRawErrorText(text, raw) {
|
|
561
|
+
if (typeof raw !== 'string' || !raw.trim() || text.includes(raw))
|
|
562
|
+
return text;
|
|
563
|
+
return `${text}\n原因:${raw}`;
|
|
564
|
+
}
|
|
560
565
|
/**
|
|
561
566
|
* 把 AUNChannel 投递的 opts 映射成渠道无关的 InboundMessage。
|
|
562
567
|
*
|
|
@@ -4413,6 +4418,9 @@ export class AUNChannel {
|
|
|
4413
4418
|
};
|
|
4414
4419
|
if (evolCommand)
|
|
4415
4420
|
base.ext = { evolCommand };
|
|
4421
|
+
// Same diagnostic dictionary as text payloads (sessionId/agentSessionId/model).
|
|
4422
|
+
if (context?.debug)
|
|
4423
|
+
base.debug = { ...context.debug, sentAt: localTimestamp() };
|
|
4416
4424
|
return withAunAttention(base);
|
|
4417
4425
|
}
|
|
4418
4426
|
async sendReliableStructured(channelId, payload, context, logText) {
|
|
@@ -4496,6 +4504,9 @@ export class AUNChannel {
|
|
|
4496
4504
|
delivery,
|
|
4497
4505
|
dedupeKey: operationId,
|
|
4498
4506
|
critical: routedContext.metadata?.criticalDelivery === true,
|
|
4507
|
+
// Live feedback about the running process (for example the pre-restart
|
|
4508
|
+
// notice) must never be replayed by the process that replaces it.
|
|
4509
|
+
processScoped: routedContext.metadata?.processScopedDelivery === true,
|
|
4499
4510
|
type: 'text',
|
|
4500
4511
|
text: finalText,
|
|
4501
4512
|
context: routedContext,
|
|
@@ -4565,6 +4576,16 @@ export class AUNChannel {
|
|
|
4565
4576
|
};
|
|
4566
4577
|
}
|
|
4567
4578
|
/** Daemon-side transport for `ec msg send` running inside an agent task. */
|
|
4579
|
+
/**
|
|
4580
|
+
* Agent 经 CLI 委托发送(ec msg send / ec group send)时占用本轮序号,
|
|
4581
|
+
* 与回复路径共用 sentCount,保证同一轮内 seqInTurn 连续。
|
|
4582
|
+
*/
|
|
4583
|
+
nextSeqInTurn(channelId, threadId) {
|
|
4584
|
+
const turnKey = `${channelId}\0${threadId ?? ''}`;
|
|
4585
|
+
const seqInTurn = (this.sentCount.get(turnKey) || 0) + 1;
|
|
4586
|
+
this.sentCount.set(turnKey, seqInTurn);
|
|
4587
|
+
return seqInTurn;
|
|
4588
|
+
}
|
|
4568
4589
|
async sendDaemonMsg(args) {
|
|
4569
4590
|
if (!args.to) {
|
|
4570
4591
|
return { ok: false, error: 'aun-msg-send requires a private target', code: 'UNSUPPORTED_TARGET' };
|
|
@@ -5271,6 +5292,9 @@ export class AUNChannel {
|
|
|
5271
5292
|
delete payloadWithChatmode.thread_id;
|
|
5272
5293
|
if (context?.threadId && !payloadWithChatmode.thread_id)
|
|
5273
5294
|
payloadWithChatmode.thread_id = context.threadId;
|
|
5295
|
+
// Same diagnostic dictionary as text payloads (sessionId/agentSessionId/model).
|
|
5296
|
+
if (context?.debug)
|
|
5297
|
+
payloadWithChatmode.debug = { ...context.debug, sentAt: localTimestamp() };
|
|
5274
5298
|
const params = {
|
|
5275
5299
|
context: { type: 'task', id: taskId },
|
|
5276
5300
|
payload: this.limitThoughtPayload(payloadWithChatmode),
|
|
@@ -5847,8 +5871,12 @@ export class AUNChannel {
|
|
|
5847
5871
|
}
|
|
5848
5872
|
return { status: 'permanent', error: `unsupported outbox entry type: ${entry.type}`, code: 'UNSUPPORTED_OUTBOX_TYPE' };
|
|
5849
5873
|
}, queue);
|
|
5850
|
-
if (result.sent > 0 || result.expired > 0 || result.permanent) {
|
|
5851
|
-
|
|
5874
|
+
if (result.sent > 0 || result.expired > 0 || result.permanent || result.superseded) {
|
|
5875
|
+
const superseded = result.superseded ? ` superseded=${result.superseded}` : '';
|
|
5876
|
+
logger.info(`${this.logPrefix()} ${queue} outbox drained: sent=${result.sent} expired=${result.expired} failed=${result.failed} permanent=${result.permanent ?? 0}${superseded}`);
|
|
5877
|
+
}
|
|
5878
|
+
if (result.superseded) {
|
|
5879
|
+
logger.info(`${this.logPrefix()} ${queue} outbox: dropped ${result.superseded} process-scoped entr${result.superseded === 1 ? 'y' : 'ies'} left by a previous daemon process`);
|
|
5852
5880
|
}
|
|
5853
5881
|
};
|
|
5854
5882
|
await drainQueue('default');
|
|
@@ -5962,6 +5990,9 @@ export class AUNChannel {
|
|
|
5962
5990
|
statusPayload.chatmode = context.metadata.chatmode;
|
|
5963
5991
|
if (context?.replyToMessageId)
|
|
5964
5992
|
statusPayload.ref_message_id = context.replyToMessageId;
|
|
5993
|
+
// Same diagnostic dictionary as text payloads (sessionId/agentSessionId/model).
|
|
5994
|
+
if (context?.debug)
|
|
5995
|
+
statusPayload.debug = { ...context.debug, sentAt: localTimestamp() };
|
|
5965
5996
|
const notifyOptions = { ttlMs: 60_000 };
|
|
5966
5997
|
if (delivery.chatType === 'group')
|
|
5967
5998
|
notifyOptions.groupId = delivery.groupId;
|
|
@@ -6389,6 +6420,7 @@ export class AUNChannelPlugin {
|
|
|
6389
6420
|
text: payload.text,
|
|
6390
6421
|
severity: 'info',
|
|
6391
6422
|
};
|
|
6423
|
+
setIfDefined(noticePayload, 'raw', payload.raw);
|
|
6392
6424
|
setIfDefined(noticePayload, 'subtype', payload.subtype);
|
|
6393
6425
|
await channel.sendReliableStructured(channelId, noticePayload, replyCtx, payload.text);
|
|
6394
6426
|
return;
|
|
@@ -6398,10 +6430,14 @@ export class AUNChannelPlugin {
|
|
|
6398
6430
|
type: payload.recoverable === true ? 'notice' : 'error',
|
|
6399
6431
|
...taskBase(),
|
|
6400
6432
|
subtype: payload.subtype,
|
|
6401
|
-
text: payload.
|
|
6433
|
+
text: payload.recoverable === true
|
|
6434
|
+
? payload.text
|
|
6435
|
+
: appendRawErrorText(payload.text, payload.raw),
|
|
6436
|
+
...(payload.raw !== undefined ? { raw: payload.raw } : {}),
|
|
6437
|
+
...(payload.reason !== undefined ? { reason: payload.reason } : {}),
|
|
6402
6438
|
...(payload.recoverable === true
|
|
6403
6439
|
? { severity: 'warn' }
|
|
6404
|
-
: {
|
|
6440
|
+
: { recoverable: false }),
|
|
6405
6441
|
};
|
|
6406
6442
|
await channel.sendReliableStructured(channelId, errorPayload, { ...(replyCtx ?? {}), suppressPeerMention: true }, payload.text);
|
|
6407
6443
|
return;
|
|
@@ -6410,11 +6446,11 @@ export class AUNChannelPlugin {
|
|
|
6410
6446
|
const errorPayload = {
|
|
6411
6447
|
type: 'error',
|
|
6412
6448
|
...taskBase(),
|
|
6413
|
-
|
|
6414
|
-
text: payload.text,
|
|
6415
|
-
message: payload.text,
|
|
6416
|
-
user_message: payload.text,
|
|
6449
|
+
text: appendRawErrorText(payload.text, payload.raw),
|
|
6417
6450
|
};
|
|
6451
|
+
setIfDefined(errorPayload, 'subtype', payload.subtype);
|
|
6452
|
+
setIfDefined(errorPayload, 'reason', payload.reason);
|
|
6453
|
+
setIfDefined(errorPayload, 'raw', payload.raw);
|
|
6418
6454
|
await channel.sendReliableStructured(channelId, errorPayload, { ...(replyCtx ?? {}), suppressPeerMention: true }, payload.text);
|
|
6419
6455
|
return;
|
|
6420
6456
|
}
|