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
|
@@ -3,7 +3,7 @@ import fs from 'fs';
|
|
|
3
3
|
import { CronExpressionParser } from 'cron-parser';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { matchTriggerEvent, TriggerEventSource } from './event-source.js';
|
|
6
|
-
import { definitionRevision, parseDurationMs, previewText, renderTemplate, resolveScriptPath, sha256, validateConcurrencyCombination, } from './validation.js';
|
|
6
|
+
import { definitionRevision, executionTimeoutMs, parseDurationMs, previewText, renderTemplate, resolveScriptPath, sha256, validateConcurrencyCombination, } from './validation.js';
|
|
7
7
|
import { TargetSessionLockRegistry } from './session-lock.js';
|
|
8
8
|
import { enterTrigger, formatTriggerPath } from '../core/causation/context.js';
|
|
9
9
|
import { createRootCausation } from '../core/causation/context.js';
|
|
@@ -13,6 +13,13 @@ const MAX_TIMER_MS = 2_147_483_647;
|
|
|
13
13
|
const RUN_ABORT_SETTLE_GRACE_MS = 1_000;
|
|
14
14
|
const RUN_COMPLETION_BARRIER_MS = 1_500;
|
|
15
15
|
const TRIGGER_RESTART_RESUME_PROMPT = 'EvolCore 服务已重启。请基于当前会话记录继续完成刚才被中断的 Trigger 任务;不要重新从头执行已经完成的步骤。';
|
|
16
|
+
function eventSessionKey(payload, fallbackAgentAid) {
|
|
17
|
+
const agentAid = typeof payload.agentAid === 'string' && payload.agentAid.trim()
|
|
18
|
+
? payload.agentAid.trim()
|
|
19
|
+
: fallbackAgentAid;
|
|
20
|
+
const sessionId = typeof payload.sessionId === 'string' ? payload.sessionId : '';
|
|
21
|
+
return `${agentAid}:${sessionId}`;
|
|
22
|
+
}
|
|
16
23
|
export class TriggerRuntimeScheduler {
|
|
17
24
|
manager;
|
|
18
25
|
state;
|
|
@@ -818,6 +825,7 @@ export class TriggerRuntimeScheduler {
|
|
|
818
825
|
attemptId: `${runId}:attempt:${attempt}`,
|
|
819
826
|
firedAt,
|
|
820
827
|
prompt,
|
|
828
|
+
sourcePayload,
|
|
821
829
|
dryRun,
|
|
822
830
|
causation,
|
|
823
831
|
signal,
|
|
@@ -869,7 +877,17 @@ export class TriggerRuntimeScheduler {
|
|
|
869
877
|
+ ` model=${definition.execution.model ?? '<agent-default>'}`
|
|
870
878
|
+ ` effort=${definition.execution.effort ?? '<agent-default>'}`);
|
|
871
879
|
const attemptId = `${runId}:attempt:${attempt}`;
|
|
872
|
-
const
|
|
880
|
+
const executionStartedAt = Date.now();
|
|
881
|
+
const configuredExecutionTimeout = executionTimeoutMs(definition.execution);
|
|
882
|
+
const daemonExecutionDeadlineAt = this.daemonExecutionDeadlineAt(executionStartedAt);
|
|
883
|
+
const configuredExecutionDeadlineAt = configuredExecutionTimeout === undefined
|
|
884
|
+
? undefined
|
|
885
|
+
: executionStartedAt + configuredExecutionTimeout;
|
|
886
|
+
const executionDeadlineAt = daemonExecutionDeadlineAt === undefined
|
|
887
|
+
? configuredExecutionDeadlineAt
|
|
888
|
+
: configuredExecutionDeadlineAt === undefined
|
|
889
|
+
? daemonExecutionDeadlineAt
|
|
890
|
+
: Math.min(daemonExecutionDeadlineAt, configuredExecutionDeadlineAt);
|
|
873
891
|
const executionSession = await this.daemonChannel.getOrCreateConversationSession(definition, this.runtime.projectPath, runtimeBaseagent, runId, attemptId);
|
|
874
892
|
const activeRun = this.state.startExecutionAttempt?.(definition.id, runId, {
|
|
875
893
|
attempt,
|
|
@@ -963,7 +981,13 @@ export class TriggerRuntimeScheduler {
|
|
|
963
981
|
});
|
|
964
982
|
}
|
|
965
983
|
async checkConcurrency(definition, nextRunId, source) {
|
|
966
|
-
const
|
|
984
|
+
const allRuns = this.running.get(definition.id);
|
|
985
|
+
// An event-session trigger owns many independent sessions. Forbid/replace
|
|
986
|
+
// applies within the source session, so one failure cannot suppress another.
|
|
987
|
+
const runs = definition.feedback.strategy === 'event_session' && allRuns
|
|
988
|
+
? new Map([...allRuns].filter(([, runtime]) => eventSessionKey(runtime.source.payload, definition.agentAid)
|
|
989
|
+
=== eventSessionKey(source.payload, definition.agentAid)))
|
|
990
|
+
: allRuns;
|
|
967
991
|
if (!runs || runs.size === 0 || definition.reliability.concurrency === 'allow')
|
|
968
992
|
return undefined;
|
|
969
993
|
const first = runs.values().next().value;
|
|
@@ -1753,7 +1777,7 @@ export class TriggerRuntimeScheduler {
|
|
|
1753
1777
|
publishTriggerRunOutcome(definition, audit) {
|
|
1754
1778
|
if (!this.eventBus || audit.status === 'dry-run')
|
|
1755
1779
|
return;
|
|
1756
|
-
const target = primaryTarget(definition);
|
|
1780
|
+
const target = audit.feedback?.target ?? primaryTarget(definition);
|
|
1757
1781
|
const targetChannel = target?.channelKey ?? 'daemon';
|
|
1758
1782
|
const targetChannelId = target?.channelId ?? definition.agentAid;
|
|
1759
1783
|
const base = {
|
|
@@ -2027,6 +2051,8 @@ function summarizeReply(reply, opts = {}) {
|
|
|
2027
2051
|
function primaryTarget(definition) {
|
|
2028
2052
|
if (definition.feedback.strategy === 'target')
|
|
2029
2053
|
return definition.feedback.target;
|
|
2054
|
+
if (definition.feedback.strategy === 'event_session')
|
|
2055
|
+
return undefined;
|
|
2030
2056
|
if (!definition.origin)
|
|
2031
2057
|
return undefined;
|
|
2032
2058
|
return {
|
|
@@ -3,6 +3,8 @@ import crypto from 'crypto';
|
|
|
3
3
|
import { normalizePermissionMode as normalizePermissionModeContract } from '../core/permission/mode.js';
|
|
4
4
|
import { formatChannelKey } from '../core/channel-loader.js';
|
|
5
5
|
const MAX_SCRIPT_TIMEOUT_MS = 900_000;
|
|
6
|
+
const TRIGGER_SESSION_TIMEOUT_MS = 30 * 60_000;
|
|
7
|
+
const MAX_EXECUTION_TIMEOUT_MS = 2_147_483_647;
|
|
6
8
|
export const TRIGGER_SCHEMA_VERSION = 3.1;
|
|
7
9
|
const LEGACY_TRIGGER_SCHEMA_VERSION = 4;
|
|
8
10
|
const DEFAULT_NOOP_SENTINEL = '[[NOOP]]';
|
|
@@ -35,7 +37,7 @@ export function normalizeTriggerDefinition(input, opts = {}) {
|
|
|
35
37
|
* channelId shape inference at runtime.
|
|
36
38
|
*/
|
|
37
39
|
export function assertExplicitAunDeliveryRoutes(definition) {
|
|
38
|
-
if (definition.feedback.strategy === 'silent')
|
|
40
|
+
if (definition.feedback.strategy === 'silent' || definition.feedback.strategy === 'event_session')
|
|
39
41
|
return;
|
|
40
42
|
const target = definition.feedback.strategy === 'target'
|
|
41
43
|
? definition.feedback.target
|
|
@@ -58,6 +60,11 @@ export function assertExplicitAunDeliveryRoutes(definition) {
|
|
|
58
60
|
export function validateTriggerDefinition(definition) {
|
|
59
61
|
normalizeTriggerDefinition(definition);
|
|
60
62
|
}
|
|
63
|
+
/** Resolve a model-backed attempt's deadline; target sessions are unlimited by default. */
|
|
64
|
+
export function executionTimeoutMs(execution) {
|
|
65
|
+
return execution.timeoutMs ?? (execution.type === 'target_session'
|
|
66
|
+
? undefined : TRIGGER_SESSION_TIMEOUT_MS);
|
|
67
|
+
}
|
|
61
68
|
/**
|
|
62
69
|
* Keep legacy `per_run` definitions byte-stable while giving runtime code one
|
|
63
70
|
* canonical representation for session selection and validation.
|
|
@@ -428,8 +435,14 @@ function normalizeExecution(value, _opts) {
|
|
|
428
435
|
throw new Error('execution.type must be script, trigger_session, or target_session');
|
|
429
436
|
}
|
|
430
437
|
const thread = normalizeExecutionThread(raw.thread);
|
|
438
|
+
if (raw.timeoutMs !== undefined && (type === 'script'
|
|
439
|
+
|| typeof raw.timeoutMs !== 'number' || !Number.isSafeInteger(raw.timeoutMs)
|
|
440
|
+
|| raw.timeoutMs <= 0 || raw.timeoutMs > MAX_EXECUTION_TIMEOUT_MS)) {
|
|
441
|
+
throw new Error('execution.timeoutMs must be an integer between 1 and 2147483647 for a model-backed Trigger');
|
|
442
|
+
}
|
|
431
443
|
const execution = {
|
|
432
444
|
type,
|
|
445
|
+
...(raw.timeoutMs !== undefined ? { timeoutMs: raw.timeoutMs } : {}),
|
|
433
446
|
prompt: type === 'script' ? optionalString(raw.prompt) : requiredString(raw.prompt, 'execution.prompt'),
|
|
434
447
|
script: type === 'script' ? normalizeScript(raw.script) : undefined,
|
|
435
448
|
thread: type === 'trigger_session' ? (thread ?? 'by_trigger') : thread,
|
|
@@ -511,8 +524,8 @@ function normalizeFeedback(value, agentAid) {
|
|
|
511
524
|
throw new Error('feedback must be an object');
|
|
512
525
|
const raw = value;
|
|
513
526
|
const strategy = requiredString(raw.strategy, 'feedback.strategy');
|
|
514
|
-
if (strategy !== 'origin' && strategy !== 'target' && strategy !== 'silent') {
|
|
515
|
-
throw new Error('feedback.strategy must be origin, target, or silent');
|
|
527
|
+
if (strategy !== 'origin' && strategy !== 'target' && strategy !== 'event_session' && strategy !== 'silent') {
|
|
528
|
+
throw new Error('feedback.strategy must be origin, target, event_session, or silent');
|
|
516
529
|
}
|
|
517
530
|
return {
|
|
518
531
|
strategy,
|
|
@@ -630,6 +643,10 @@ function normalizeOnError(value) {
|
|
|
630
643
|
}
|
|
631
644
|
function validateTriggerSemantics(definition) {
|
|
632
645
|
const execution = definition.execution;
|
|
646
|
+
if (definition.feedback.strategy === 'event_session'
|
|
647
|
+
&& (definition.source.type !== 'event' || execution.type !== 'target_session')) {
|
|
648
|
+
throw new Error('feedback.strategy=event_session requires an event source and target_session execution');
|
|
649
|
+
}
|
|
633
650
|
if (execution.type === 'script') {
|
|
634
651
|
if (!execution.script)
|
|
635
652
|
throw new Error('execution.script is required when execution.type=script');
|
|
@@ -449,7 +449,10 @@ export function resolveCliEntry(packageRoot) {
|
|
|
449
449
|
try {
|
|
450
450
|
const require = createRequire(path.join(packageRoot, 'package.json'));
|
|
451
451
|
const tsxUrl = pathToFileURL(require.resolve('tsx')).href;
|
|
452
|
-
|
|
452
|
+
const imports = process.platform === 'win32'
|
|
453
|
+
? ['--import', 'data:text/javascript,globalThis.process.geteuid=()=>-1', '--import', tsxUrl]
|
|
454
|
+
: ['--import', tsxUrl];
|
|
455
|
+
return { args: [...imports, sourceEntry], usingSource: true, entry: sourceEntry };
|
|
453
456
|
}
|
|
454
457
|
catch {
|
|
455
458
|
// tsx missing (e.g. `npm prune --production`): fall through to dist.
|
|
@@ -488,11 +491,37 @@ export function encodePath(projectPath) {
|
|
|
488
491
|
/**
|
|
489
492
|
* Cross-platform process liveness check.
|
|
490
493
|
*/
|
|
494
|
+
function readLinuxProcessState(pid) {
|
|
495
|
+
if (process.platform !== 'linux')
|
|
496
|
+
return null;
|
|
497
|
+
try {
|
|
498
|
+
const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
|
|
499
|
+
// The comm field may contain ')', so use the final closing parenthesis.
|
|
500
|
+
const closeParen = stat.lastIndexOf(')');
|
|
501
|
+
if (closeParen < 0)
|
|
502
|
+
return null;
|
|
503
|
+
return stat.slice(closeParen + 2, closeParen + 3) || null;
|
|
504
|
+
}
|
|
505
|
+
catch {
|
|
506
|
+
// Keep the kill(0) fallback below for permission and procfs races.
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/** Return the Linux proc state (for example Z, D, S, or R), when available. */
|
|
511
|
+
export function getProcessState(pid) {
|
|
512
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
513
|
+
return null;
|
|
514
|
+
return readLinuxProcessState(pid);
|
|
515
|
+
}
|
|
491
516
|
export function isProcessRunning(pid) {
|
|
492
517
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
493
518
|
return false;
|
|
494
519
|
if (isWindows)
|
|
495
520
|
return isWindowsProcessRunning(pid);
|
|
521
|
+
// A zombie has exited; only its unreaped process-table entry remains. A
|
|
522
|
+
// kill(pid, 0) probe alone reports such an entry as alive on Linux.
|
|
523
|
+
if (readLinuxProcessState(pid) === 'Z')
|
|
524
|
+
return false;
|
|
496
525
|
try {
|
|
497
526
|
process.kill(pid, 0);
|
|
498
527
|
return true;
|
|
@@ -70,6 +70,7 @@ export async function fetchRemotePairingCode(authorizedBy) {
|
|
|
70
70
|
try {
|
|
71
71
|
const response = await ipcQuery(resolvePaths().socket, {
|
|
72
72
|
type: 'remote-auth.pair-code',
|
|
73
|
+
source: 'host-cli',
|
|
73
74
|
...(authorizedBy?.trim() ? { authorizedBy: authorizedBy.trim() } : {}),
|
|
74
75
|
}, 2_000);
|
|
75
76
|
if (!response?.ok || typeof response.code !== 'string' || typeof response.expiresAt !== 'number')
|
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
{
|
|
2
|
-
"rules": [
|
|
3
|
-
{
|
|
4
|
-
"id": "context-too-long-cn",
|
|
5
|
-
"match": "上下文过长",
|
|
6
|
-
"action": "stop",
|
|
7
|
-
"type": "context_too_long",
|
|
8
|
-
"message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"id": "context-too-long-en",
|
|
12
|
-
"match": "context too long",
|
|
13
|
-
"action": "stop",
|
|
14
|
-
"type": "context_too_long",
|
|
15
|
-
"message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"id": "prompt-too-long",
|
|
19
|
-
"match": "prompt is too long",
|
|
20
|
-
"action": "stop",
|
|
21
|
-
"type": "context_too_long",
|
|
22
|
-
"message": "⚠️ 输入过长,请精简提问或使用 /compact 压缩上下文"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "invalid-api-key",
|
|
26
|
-
"match": "invalid api key",
|
|
27
|
-
"action": "stop",
|
|
28
|
-
"type": "auth_error",
|
|
29
|
-
"message": "❌ API Key 无效,请检查密钥配置。使用 /status 查看当前配置"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"id": "key-not-found",
|
|
33
|
-
"match": "key_not_found",
|
|
34
|
-
"action": "stop",
|
|
35
|
-
"type": "auth_error",
|
|
36
|
-
"message": "❌ API Key 未找到,请检查密钥配置"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"id": "api-key-verifier-too-many-connections",
|
|
40
|
-
"match": "error 1040 (08004): too many connections",
|
|
41
|
-
"action": "retry",
|
|
42
|
-
"type": "api_error",
|
|
43
|
-
"message": "⚠️ API 服务繁忙,请稍后重试"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"id": "credit-query-timeout",
|
|
47
|
-
"match": "积分查询超时",
|
|
48
|
-
"action": "retry",
|
|
49
|
-
"type": "api_error",
|
|
50
|
-
"message": "⚠️ 积分查询超时,请稍后重试"
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
"id": "capacity-pool-switching-cn",
|
|
54
|
-
"match": "算力池切换",
|
|
55
|
-
"action": "retry",
|
|
56
|
-
"type": "api_error",
|
|
57
|
-
"message": "⚠️ 当前算力池切换中,请稍后重试"
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"id": "retry-attempt-stalled",
|
|
61
|
-
"match": "retry_attempt_stalled",
|
|
62
|
-
"action": "retry",
|
|
63
|
-
"type": "api_error",
|
|
64
|
-
"message": "⚠️ API 重试调用长时间无响应"
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"id": "selected-model-at-capacity",
|
|
68
|
-
"match": "selected model is at capacity",
|
|
69
|
-
"action": "retry",
|
|
70
|
-
"type": "api_error",
|
|
71
|
-
"message": "⚠️ 当前模型繁忙,请稍后重试"
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"id": "api-error-400",
|
|
75
|
-
"match": "api error: 400",
|
|
76
|
-
"action": "stop",
|
|
77
|
-
"type": "api_error",
|
|
78
|
-
"message": "❌ 请求格式错误,请检查输入内容"
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
"id": "model-not-supported-403",
|
|
82
|
-
"match": "api error: 403 不支持该模型",
|
|
83
|
-
"action": "stop",
|
|
84
|
-
"type": "model_unavailable",
|
|
85
|
-
"message": "❌ 当前模型不受支持,请正确配置模型后重试"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"id": "api-error-403",
|
|
89
|
-
"match": "api error: 403",
|
|
90
|
-
"action": "retry",
|
|
91
|
-
"type": "api_error",
|
|
92
|
-
"message": "⚠️ API 访问受限,请稍后重试"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"id": "api-error-429",
|
|
96
|
-
"match": "api error: 429",
|
|
97
|
-
"action": "retry",
|
|
98
|
-
"type": "api_error",
|
|
99
|
-
"message": "⚠️ 请求过于频繁,请稍后重试"
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
"id": "api-error-500",
|
|
103
|
-
"match": "api error: 500",
|
|
104
|
-
"action": "retry",
|
|
105
|
-
"type": "api_error",
|
|
106
|
-
"message": "❌ API 服务暂时不可用,请稍后重试"
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"id": "api-error-502",
|
|
110
|
-
"match": "api error: 502",
|
|
111
|
-
"action": "retry",
|
|
112
|
-
"type": "api_error"
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
"id": "api-error-503",
|
|
116
|
-
"match": "api error: 503",
|
|
117
|
-
"action": "retry",
|
|
118
|
-
"type": "api_error"
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"id": "api-error-504",
|
|
122
|
-
"match": "api error: 504",
|
|
123
|
-
"action": "retry",
|
|
124
|
-
"type": "api_error"
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
"id": "not-valid-json",
|
|
128
|
-
"match": "is not valid json",
|
|
129
|
-
"action": "retry",
|
|
130
|
-
"type": "api_error",
|
|
131
|
-
"message": "⚠️ API 返回异常响应,请稍后重试"
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
"id": "json-parse-error",
|
|
135
|
-
"match": "json parse error",
|
|
136
|
-
"action": "retry",
|
|
137
|
-
"type": "api_error",
|
|
138
|
-
"message": "⚠️ API 返回 JSON 解析异常,请稍后重试"
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
"id": "feishu-permission",
|
|
142
|
-
"match": "im:resource",
|
|
143
|
-
"action": "stop",
|
|
144
|
-
"type": "unknown",
|
|
145
|
-
"message": "❌ 权限不足,请联系管理员配置应用权限"
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
"id": "stream-error",
|
|
149
|
-
"match": "stream",
|
|
150
|
-
"action": "retry",
|
|
151
|
-
"type": "stream_error"
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"id": "request-aborted",
|
|
155
|
-
"match": "request was aborted",
|
|
156
|
-
"action": "ignore",
|
|
157
|
-
"type": "stream_error"
|
|
158
|
-
}
|
|
159
|
-
]
|
|
160
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"rules": [
|
|
3
|
+
{
|
|
4
|
+
"id": "context-too-long-cn",
|
|
5
|
+
"match": "上下文过长",
|
|
6
|
+
"action": "stop",
|
|
7
|
+
"type": "context_too_long",
|
|
8
|
+
"message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": "context-too-long-en",
|
|
12
|
+
"match": "context too long",
|
|
13
|
+
"action": "stop",
|
|
14
|
+
"type": "context_too_long",
|
|
15
|
+
"message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "prompt-too-long",
|
|
19
|
+
"match": "prompt is too long",
|
|
20
|
+
"action": "stop",
|
|
21
|
+
"type": "context_too_long",
|
|
22
|
+
"message": "⚠️ 输入过长,请精简提问或使用 /compact 压缩上下文"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "invalid-api-key",
|
|
26
|
+
"match": "invalid api key",
|
|
27
|
+
"action": "stop",
|
|
28
|
+
"type": "auth_error",
|
|
29
|
+
"message": "❌ API Key 无效,请检查密钥配置。使用 /status 查看当前配置"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "key-not-found",
|
|
33
|
+
"match": "key_not_found",
|
|
34
|
+
"action": "stop",
|
|
35
|
+
"type": "auth_error",
|
|
36
|
+
"message": "❌ API Key 未找到,请检查密钥配置"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "api-key-verifier-too-many-connections",
|
|
40
|
+
"match": "error 1040 (08004): too many connections",
|
|
41
|
+
"action": "retry",
|
|
42
|
+
"type": "api_error",
|
|
43
|
+
"message": "⚠️ API 服务繁忙,请稍后重试"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "credit-query-timeout",
|
|
47
|
+
"match": "积分查询超时",
|
|
48
|
+
"action": "retry",
|
|
49
|
+
"type": "api_error",
|
|
50
|
+
"message": "⚠️ 积分查询超时,请稍后重试"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "capacity-pool-switching-cn",
|
|
54
|
+
"match": "算力池切换",
|
|
55
|
+
"action": "retry",
|
|
56
|
+
"type": "api_error",
|
|
57
|
+
"message": "⚠️ 当前算力池切换中,请稍后重试"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "retry-attempt-stalled",
|
|
61
|
+
"match": "retry_attempt_stalled",
|
|
62
|
+
"action": "retry",
|
|
63
|
+
"type": "api_error",
|
|
64
|
+
"message": "⚠️ API 重试调用长时间无响应"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "selected-model-at-capacity",
|
|
68
|
+
"match": "selected model is at capacity",
|
|
69
|
+
"action": "retry",
|
|
70
|
+
"type": "api_error",
|
|
71
|
+
"message": "⚠️ 当前模型繁忙,请稍后重试"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "api-error-400",
|
|
75
|
+
"match": "api error: 400",
|
|
76
|
+
"action": "stop",
|
|
77
|
+
"type": "api_error",
|
|
78
|
+
"message": "❌ 请求格式错误,请检查输入内容"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "model-not-supported-403",
|
|
82
|
+
"match": "api error: 403 不支持该模型",
|
|
83
|
+
"action": "stop",
|
|
84
|
+
"type": "model_unavailable",
|
|
85
|
+
"message": "❌ 当前模型不受支持,请正确配置模型后重试"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "api-error-403",
|
|
89
|
+
"match": "api error: 403",
|
|
90
|
+
"action": "retry",
|
|
91
|
+
"type": "api_error",
|
|
92
|
+
"message": "⚠️ API 访问受限,请稍后重试"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "api-error-429",
|
|
96
|
+
"match": "api error: 429",
|
|
97
|
+
"action": "retry",
|
|
98
|
+
"type": "api_error",
|
|
99
|
+
"message": "⚠️ 请求过于频繁,请稍后重试"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "api-error-500",
|
|
103
|
+
"match": "api error: 500",
|
|
104
|
+
"action": "retry",
|
|
105
|
+
"type": "api_error",
|
|
106
|
+
"message": "❌ API 服务暂时不可用,请稍后重试"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"id": "api-error-502",
|
|
110
|
+
"match": "api error: 502",
|
|
111
|
+
"action": "retry",
|
|
112
|
+
"type": "api_error"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "api-error-503",
|
|
116
|
+
"match": "api error: 503",
|
|
117
|
+
"action": "retry",
|
|
118
|
+
"type": "api_error"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": "api-error-504",
|
|
122
|
+
"match": "api error: 504",
|
|
123
|
+
"action": "retry",
|
|
124
|
+
"type": "api_error"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"id": "not-valid-json",
|
|
128
|
+
"match": "is not valid json",
|
|
129
|
+
"action": "retry",
|
|
130
|
+
"type": "api_error",
|
|
131
|
+
"message": "⚠️ API 返回异常响应,请稍后重试"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "json-parse-error",
|
|
135
|
+
"match": "json parse error",
|
|
136
|
+
"action": "retry",
|
|
137
|
+
"type": "api_error",
|
|
138
|
+
"message": "⚠️ API 返回 JSON 解析异常,请稍后重试"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"id": "feishu-permission",
|
|
142
|
+
"match": "im:resource",
|
|
143
|
+
"action": "stop",
|
|
144
|
+
"type": "unknown",
|
|
145
|
+
"message": "❌ 权限不足,请联系管理员配置应用权限"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "stream-error",
|
|
149
|
+
"match": "stream",
|
|
150
|
+
"action": "retry",
|
|
151
|
+
"type": "stream_error"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"id": "request-aborted",
|
|
155
|
+
"match": "request was aborted",
|
|
156
|
+
"action": "ignore",
|
|
157
|
+
"type": "stream_error"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
}
|
|
@@ -3,7 +3,36 @@ import path from 'path';
|
|
|
3
3
|
import { getPackageRoot, resolvePaths } from '../paths.js';
|
|
4
4
|
import { logger } from './logger.js';
|
|
5
5
|
import { isSandboxInitializationFailure } from '../core/permission/sandbox-runtime.js';
|
|
6
|
+
/** A deadline imposed by an outer executor, handled by the ordinary task timeout path. */
|
|
7
|
+
export class ExecutionTimeoutError extends Error {
|
|
8
|
+
reason;
|
|
9
|
+
timeoutMs;
|
|
10
|
+
constructor(reason, timeoutMs) {
|
|
11
|
+
super('TOTAL_EXECUTION_TIMEOUT');
|
|
12
|
+
this.reason = reason;
|
|
13
|
+
this.timeoutMs = timeoutMs;
|
|
14
|
+
this.name = 'ExecutionTimeoutError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class OrphanedTargetSessionError extends Error {
|
|
18
|
+
reason = 'orphaned_target_session';
|
|
19
|
+
constructor() {
|
|
20
|
+
super('ORPHANED_TARGET_SESSION');
|
|
21
|
+
this.name = 'OrphanedTargetSessionError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function isExecutionFailure(error) {
|
|
25
|
+
return error instanceof ExecutionTimeoutError || error instanceof OrphanedTargetSessionError;
|
|
26
|
+
}
|
|
6
27
|
export const CLAUDE_STARTUP_ARGUMENTS_TOO_LONG = 'claude_startup_arguments_too_long';
|
|
28
|
+
/** A completed provider response exhausted its output budget, rather than a transport failure. */
|
|
29
|
+
export function isOutputTokenLimitError(error) {
|
|
30
|
+
const record = error && typeof error === 'object' ? error : undefined;
|
|
31
|
+
const message = String(record?.message ?? error ?? '');
|
|
32
|
+
return record?.code === 'max_output_tokens'
|
|
33
|
+
|| /^\s*max_output_tokens\s*$/i.test(message)
|
|
34
|
+
|| /\breason["']?\s*[:=]\s*["']?max_output_tokens\b/i.test(message);
|
|
35
|
+
}
|
|
7
36
|
/** Identify a Claude process-start failure without treating ordinary tool errors as startup failures. */
|
|
8
37
|
export function isClaudeStartupArgumentsTooLong(error) {
|
|
9
38
|
const code = error && typeof error === 'object' && 'code' in error
|
|
@@ -36,6 +65,7 @@ export var ErrorType;
|
|
|
36
65
|
ErrorType["AUTH_ERROR"] = "auth_error";
|
|
37
66
|
ErrorType["FILE_CORRUPT"] = "file_corrupt";
|
|
38
67
|
ErrorType["STREAM_ERROR"] = "stream_error";
|
|
68
|
+
ErrorType["MAX_OUTPUT_TOKENS"] = "max_output_tokens";
|
|
39
69
|
ErrorType["CONTEXT_TOO_LONG"] = "context_too_long";
|
|
40
70
|
ErrorType["MODEL_UNAVAILABLE"] = "model_unavailable";
|
|
41
71
|
ErrorType["SESSION_UNAVAILABLE"] = "session_unavailable";
|
|
@@ -78,6 +108,7 @@ const NON_INFRA_SUBTYPES = new Set([
|
|
|
78
108
|
'stop',
|
|
79
109
|
]);
|
|
80
110
|
const NON_INFRA_TERMINAL_REASONS = new Set([
|
|
111
|
+
'max_output_tokens',
|
|
81
112
|
'rapid_refill_breaker',
|
|
82
113
|
'tool_deferred',
|
|
83
114
|
'stop_hook_prevented',
|
|
@@ -278,7 +309,18 @@ function hasRetryableHttpStatus(text) {
|
|
|
278
309
|
return RETRYABLE_HTTP_STATUS_PATTERN.test(text);
|
|
279
310
|
}
|
|
280
311
|
export function classifyError(error) {
|
|
312
|
+
if (error?.code === 'RUNNER_INTERRUPT_UNCONFIRMED')
|
|
313
|
+
return ErrorType.SESSION_UNAVAILABLE;
|
|
281
314
|
const msg = (error?.message || '').toLowerCase();
|
|
315
|
+
// A damaged ecagent JSONL transcript is deterministic local state. Retrying
|
|
316
|
+
// the provider request cannot repair it and can append more entries to the
|
|
317
|
+
// same unusable file.
|
|
318
|
+
if (msg.includes('invalid jsonl session file') || msg.includes('invalid session file')) {
|
|
319
|
+
return ErrorType.SESSION_UNAVAILABLE;
|
|
320
|
+
}
|
|
321
|
+
// The broad dictionary rule for "stream" must not hide a provider budget limit.
|
|
322
|
+
if (isOutputTokenLimitError(error))
|
|
323
|
+
return ErrorType.MAX_OUTPUT_TOKENS;
|
|
282
324
|
if (error?.code === 'TOPIC_BACKEND_UNAVAILABLE') {
|
|
283
325
|
return ErrorType.SESSION_UNAVAILABLE;
|
|
284
326
|
}
|
|
@@ -333,8 +375,15 @@ export function classifyError(error) {
|
|
|
333
375
|
* 注意:401 认证错误不可重试(API Key 无效不会因重试恢复)
|
|
334
376
|
*/
|
|
335
377
|
export function isRetryableError(error) {
|
|
378
|
+
if (error?.code === 'RUNNER_INTERRUPT_UNCONFIRMED')
|
|
379
|
+
return false;
|
|
380
|
+
// Replaying the same request does not increase its output budget.
|
|
381
|
+
if (isOutputTokenLimitError(error))
|
|
382
|
+
return false;
|
|
336
383
|
const msg = error?.message || String(error);
|
|
337
384
|
const lower = msg.toLowerCase();
|
|
385
|
+
if (lower.includes('invalid jsonl session file') || lower.includes('invalid session file'))
|
|
386
|
+
return false;
|
|
338
387
|
// 字典优先 — 命中则直接返回
|
|
339
388
|
const rule = matchErrorRule(lower);
|
|
340
389
|
if (rule)
|
|
@@ -350,6 +399,13 @@ export function isRetryableError(error) {
|
|
|
350
399
|
return false;
|
|
351
400
|
}
|
|
352
401
|
export function getErrorMessage(error, terminalReason, includeEmoji = true) {
|
|
402
|
+
if (error?.code === 'RUNNER_INTERRUPT_UNCONFIRMED')
|
|
403
|
+
return `${includeEmoji ? '⚠️ ' : ''}${error.message}`;
|
|
404
|
+
if (terminalReason === 'max_output_tokens' || isOutputTokenLimitError(error)) {
|
|
405
|
+
const prefix = includeEmoji ? '⚠️ ' : '';
|
|
406
|
+
return `${prefix}模型响应达到输出上限(max_output_tokens),本轮未完成。`
|
|
407
|
+
+ '请降低推理强度或提高模型服务的输出预算,然后在原会话发送“继续,先核对已完成操作,只完成剩余工作”;无需重发原任务。';
|
|
408
|
+
}
|
|
353
409
|
if (isClaudeStartupArgumentsTooLong(error)) {
|
|
354
410
|
const prefix = includeEmoji ? '⚠️ ' : '';
|
|
355
411
|
return `${prefix}当前 Claude 启动参数过长,任务未执行`;
|
|
@@ -374,7 +430,7 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
|
|
|
374
430
|
case 'permission_denied':
|
|
375
431
|
return `${prefix}权限被拒绝,操作已取消`;
|
|
376
432
|
case 'sandbox_initialization_failed':
|
|
377
|
-
return `${warnPrefix}
|
|
433
|
+
return `${warnPrefix}执行沙箱启动失败(sandbox_initialization_failed),当前操作未执行;请检查文件系统挂载规则及 user namespace/seccomp 配置`;
|
|
378
434
|
case 'claude_startup_arguments_too_long':
|
|
379
435
|
return `${warnPrefix}当前 Claude 启动参数过长,任务未执行`;
|
|
380
436
|
case 'aborted_streaming':
|
|
@@ -386,6 +442,9 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
|
|
|
386
442
|
const msg = error?.message || String(error);
|
|
387
443
|
const warnPrefix = includeEmoji ? '⚠️ ' : '';
|
|
388
444
|
const errPrefix = includeEmoji ? '❌ ' : '';
|
|
445
|
+
if (/invalid (?:jsonl )?session file/i.test(msg)) {
|
|
446
|
+
return `${errPrefix}ecagent 会话文件损坏,已停止自动重试;请使用 /repair 或 /new 恢复会话`;
|
|
447
|
+
}
|
|
389
448
|
// Codex app-server reports this when another app-server still owns the
|
|
390
449
|
// thread writer. Surface the handoff condition instead of hiding it behind
|
|
391
450
|
// the generic "processing failed" message.
|
|
@@ -408,7 +467,7 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
|
|
|
408
467
|
: `${warnPrefix}上下文过长,自动压缩失败,请手动输入 /compact 重试`;
|
|
409
468
|
}
|
|
410
469
|
if (isSandboxInitializationFailure(error)) {
|
|
411
|
-
return `${warnPrefix}
|
|
470
|
+
return `${warnPrefix}执行沙箱启动失败(sandbox_initialization_failed),当前操作未执行;请检查文件系统挂载规则及 user namespace/seccomp 配置`;
|
|
412
471
|
}
|
|
413
472
|
if (msg.includes('401') || msg.includes('authentication_error') || msg.toLowerCase().includes('unauthorized')) {
|
|
414
473
|
return `${errPrefix}API Key 无效,请检查密钥配置。使用 /status 查看当前配置`;
|