evolcore 0.0.5 → 0.0.7
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 +49 -0
- package/README.md +4 -12
- package/dist/agents/baseagent.js +39 -0
- package/dist/agents/claude-runner.js +10 -2
- package/dist/agents/codex-runner.js +37 -8
- package/dist/agents/ecagent-runner.js +1159 -0
- package/dist/agents/gemini-runner.js +4 -1
- package/dist/agents/runner-types.js +20 -4
- package/dist/aun/msg/history.js +32 -9
- package/dist/aun/outbox.js +4 -9
- package/dist/channels/aun.js +32 -6
- package/dist/channels/daemon.js +7 -4
- package/dist/channels/dingtalk.js +3 -5
- package/dist/channels/feishu.js +16 -108
- package/dist/channels/wechat.js +4 -4
- package/dist/channels/wecom.js +4 -6
- package/dist/cli/agent-command.js +1 -1
- package/dist/cli/agent.js +42 -11
- package/dist/cli/aun-commands.js +50 -3
- package/dist/cli/daemon-commands.js +88 -8
- package/dist/cli/data-command.js +132 -0
- package/dist/cli/index.js +11 -3
- package/dist/cli/init.js +76 -17
- package/dist/cli/net-check.js +9 -20
- package/dist/cli/restart-monitor.js +25 -2
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg.js +12 -25
- package/dist/config/builtin-roles.js +3 -1
- package/dist/config/config-field-policy.js +1 -1
- package/dist/config/gateway-config.js +21 -4
- package/dist/config/resolved-config-op.js +10 -0
- package/dist/core/command/command-handler.js +2 -2
- package/dist/core/command/menu-handler.js +11 -9
- package/dist/core/command/role-menu.js +11 -0
- package/dist/core/command/slash-handler.js +18 -14
- package/dist/core/data-migration.js +1434 -0
- package/dist/core/handoff/store.js +14 -4
- package/dist/core/inference/text-inference.js +42 -1
- package/dist/core/message/pending-hints.js +1 -1
- package/dist/core/message/response-engine.js +406 -167
- package/dist/core/message/retry-scheduler.js +71 -0
- package/dist/core/model/model-catalog.js +7 -2
- package/dist/core/model/model-fallback.js +81 -0
- package/dist/core/protected-paths.js +41 -8
- package/dist/core/session/adapters/ecagent-session-file-adapter.js +112 -0
- package/dist/core/session/session-fs-store.js +283 -59
- package/dist/core/session/session-manager.js +19 -21
- package/dist/core/session/session-title.js +1 -0
- package/dist/core/session/session-turn-coordinator.js +8 -1
- package/dist/core/system-channels.js +1 -0
- package/dist/index.js +13 -10
- package/dist/paths.js +35 -27
- package/dist/trigger/feedback.js +16 -0
- package/dist/trigger/legacy-session-history.js +19 -0
- package/dist/trigger/manager.js +12 -1
- package/dist/trigger/parser.js +4 -2
- package/dist/trigger/scheduler.js +185 -15
- package/dist/trigger/session-lock.js +62 -0
- package/dist/trigger/state.js +64 -0
- package/dist/trigger/validation.js +32 -2
- package/dist/utils/aid-bind.js +1 -1
- package/dist/utils/error-utils.js +9 -0
- package/dist/utils/instance-registry.js +2 -2
- package/dist/utils/welcome.js +2 -3
- package/ecagent/LICENSE +21 -0
- package/ecagent/NOTICE +11 -0
- package/ecagent/README.md +61 -0
- package/ecagent/dist/agent-loop.d.ts +24 -0
- package/ecagent/dist/agent-loop.d.ts.map +1 -0
- package/ecagent/dist/agent-loop.js +547 -0
- package/ecagent/dist/agent-loop.js.map +1 -0
- package/ecagent/dist/agent.d.ts +127 -0
- package/ecagent/dist/agent.d.ts.map +1 -0
- package/ecagent/dist/agent.js +386 -0
- package/ecagent/dist/agent.js.map +1 -0
- package/ecagent/dist/harness/agent-harness.d.ts +95 -0
- package/ecagent/dist/harness/agent-harness.d.ts.map +1 -0
- package/ecagent/dist/harness/agent-harness.js +926 -0
- package/ecagent/dist/harness/agent-harness.js.map +1 -0
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts +51 -0
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +1 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js +174 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js.map +1 -0
- package/ecagent/dist/harness/compaction/compaction.d.ts +95 -0
- package/ecagent/dist/harness/compaction/compaction.d.ts.map +1 -0
- package/ecagent/dist/harness/compaction/compaction.js +528 -0
- package/ecagent/dist/harness/compaction/compaction.js.map +1 -0
- package/ecagent/dist/harness/compaction/utils.d.ts +25 -0
- package/ecagent/dist/harness/compaction/utils.d.ts.map +1 -0
- package/ecagent/dist/harness/compaction/utils.js +131 -0
- package/ecagent/dist/harness/compaction/utils.js.map +1 -0
- package/ecagent/dist/harness/env/nodejs.d.ts +51 -0
- package/ecagent/dist/harness/env/nodejs.d.ts.map +1 -0
- package/ecagent/dist/harness/env/nodejs.js +513 -0
- package/ecagent/dist/harness/env/nodejs.js.map +1 -0
- package/ecagent/dist/harness/messages.d.ts +51 -0
- package/ecagent/dist/harness/messages.d.ts.map +1 -0
- package/ecagent/dist/harness/messages.js +102 -0
- package/ecagent/dist/harness/messages.js.map +1 -0
- package/ecagent/dist/harness/prompt-templates.d.ts +48 -0
- package/ecagent/dist/harness/prompt-templates.d.ts.map +1 -0
- package/ecagent/dist/harness/prompt-templates.js +230 -0
- package/ecagent/dist/harness/prompt-templates.js.map +1 -0
- package/ecagent/dist/harness/session/jsonl-repo.d.ts +26 -0
- package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +1 -0
- package/ecagent/dist/harness/session/jsonl-repo.js +100 -0
- package/ecagent/dist/harness/session/jsonl-repo.js.map +1 -0
- package/ecagent/dist/harness/session/jsonl-storage.d.ts +34 -0
- package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +1 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +234 -0
- package/ecagent/dist/harness/session/jsonl-storage.js.map +1 -0
- package/ecagent/dist/harness/session/memory-repo.d.ts +18 -0
- package/ecagent/dist/harness/session/memory-repo.d.ts.map +1 -0
- package/ecagent/dist/harness/session/memory-repo.js +44 -0
- package/ecagent/dist/harness/session/memory-repo.js.map +1 -0
- package/ecagent/dist/harness/session/memory-storage.d.ts +25 -0
- package/ecagent/dist/harness/session/memory-storage.d.ts.map +1 -0
- package/ecagent/dist/harness/session/memory-storage.js +111 -0
- package/ecagent/dist/harness/session/memory-storage.js.map +1 -0
- package/ecagent/dist/harness/session/repo-utils.d.ts +11 -0
- package/ecagent/dist/harness/session/repo-utils.d.ts.map +1 -0
- package/ecagent/dist/harness/session/repo-utils.js +39 -0
- package/ecagent/dist/harness/session/repo-utils.js.map +1 -0
- package/ecagent/dist/harness/session/session.d.ts +47 -0
- package/ecagent/dist/harness/session/session.d.ts.map +1 -0
- package/ecagent/dist/harness/session/session.js +245 -0
- package/ecagent/dist/harness/session/session.js.map +1 -0
- package/ecagent/dist/harness/session/uuid.d.ts +2 -0
- package/ecagent/dist/harness/session/uuid.d.ts.map +1 -0
- package/ecagent/dist/harness/session/uuid.js +50 -0
- package/ecagent/dist/harness/session/uuid.js.map +1 -0
- package/ecagent/dist/harness/skills.d.ts +44 -0
- package/ecagent/dist/harness/skills.d.ts.map +1 -0
- package/ecagent/dist/harness/skills.js +311 -0
- package/ecagent/dist/harness/skills.js.map +1 -0
- package/ecagent/dist/harness/system-prompt.d.ts +3 -0
- package/ecagent/dist/harness/system-prompt.d.ts.map +1 -0
- package/ecagent/dist/harness/system-prompt.js +30 -0
- package/ecagent/dist/harness/system-prompt.js.map +1 -0
- package/ecagent/dist/harness/types.d.ts +619 -0
- package/ecagent/dist/harness/types.d.ts.map +1 -0
- package/ecagent/dist/harness/types.js +81 -0
- package/ecagent/dist/harness/types.js.map +1 -0
- package/ecagent/dist/harness/utils/shell-output.d.ts +14 -0
- package/ecagent/dist/harness/utils/shell-output.d.ts.map +1 -0
- package/ecagent/dist/harness/utils/shell-output.js +126 -0
- package/ecagent/dist/harness/utils/shell-output.js.map +1 -0
- package/ecagent/dist/harness/utils/truncate.d.ts +70 -0
- package/ecagent/dist/harness/utils/truncate.d.ts.map +1 -0
- package/ecagent/dist/harness/utils/truncate.js +290 -0
- package/ecagent/dist/harness/utils/truncate.js.map +1 -0
- package/ecagent/dist/index.d.ts +22 -0
- package/ecagent/dist/index.d.ts.map +1 -0
- package/ecagent/dist/index.js +27 -0
- package/ecagent/dist/index.js.map +1 -0
- package/ecagent/dist/node.d.ts +3 -0
- package/ecagent/dist/node.d.ts.map +1 -0
- package/ecagent/dist/node.js +3 -0
- package/ecagent/dist/node.js.map +1 -0
- package/ecagent/dist/proxy.d.ts +69 -0
- package/ecagent/dist/proxy.d.ts.map +1 -0
- package/ecagent/dist/proxy.js +278 -0
- package/ecagent/dist/proxy.js.map +1 -0
- package/ecagent/dist/runtime/api/lazy.d.ts +15 -0
- package/ecagent/dist/runtime/api/lazy.d.ts.map +1 -0
- package/ecagent/dist/runtime/api/lazy.js +59 -0
- package/ecagent/dist/runtime/api/lazy.js.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.d.ts +97 -0
- package/ecagent/dist/runtime/api/pi-messages.d.ts.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.js +307 -0
- package/ecagent/dist/runtime/api/pi-messages.js.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts +3 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.js +3 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +1 -0
- package/ecagent/dist/runtime/auth/context.d.ts +7 -0
- package/ecagent/dist/runtime/auth/context.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/context.js +42 -0
- package/ecagent/dist/runtime/auth/context.js.map +1 -0
- package/ecagent/dist/runtime/auth/credential-store.d.ts +16 -0
- package/ecagent/dist/runtime/auth/credential-store.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/credential-store.js +39 -0
- package/ecagent/dist/runtime/auth/credential-store.js.map +1 -0
- package/ecagent/dist/runtime/auth/helpers.d.ts +20 -0
- package/ecagent/dist/runtime/auth/helpers.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/helpers.js +46 -0
- package/ecagent/dist/runtime/auth/helpers.js.map +1 -0
- package/ecagent/dist/runtime/auth/resolve.d.ts +26 -0
- package/ecagent/dist/runtime/auth/resolve.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/resolve.js +100 -0
- package/ecagent/dist/runtime/auth/resolve.js.map +1 -0
- package/ecagent/dist/runtime/auth/types.d.ts +180 -0
- package/ecagent/dist/runtime/auth/types.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/types.js +2 -0
- package/ecagent/dist/runtime/auth/types.js.map +1 -0
- package/ecagent/dist/runtime/compat.d.ts +28 -0
- package/ecagent/dist/runtime/compat.d.ts.map +1 -0
- package/ecagent/dist/runtime/compat.js +86 -0
- package/ecagent/dist/runtime/compat.js.map +1 -0
- package/ecagent/dist/runtime/index.d.ts +20 -0
- package/ecagent/dist/runtime/index.d.ts.map +1 -0
- package/ecagent/dist/runtime/index.js +17 -0
- package/ecagent/dist/runtime/index.js.map +1 -0
- package/ecagent/dist/runtime/models.d.ts +142 -0
- package/ecagent/dist/runtime/models.d.ts.map +1 -0
- package/ecagent/dist/runtime/models.js +245 -0
- package/ecagent/dist/runtime/models.js.map +1 -0
- package/ecagent/dist/runtime/oauth.d.ts +2 -0
- package/ecagent/dist/runtime/oauth.d.ts.map +1 -0
- package/ecagent/dist/runtime/oauth.js +2 -0
- package/ecagent/dist/runtime/oauth.js.map +1 -0
- package/ecagent/dist/runtime/providers/faux.d.ts +97 -0
- package/ecagent/dist/runtime/providers/faux.d.ts.map +1 -0
- package/ecagent/dist/runtime/providers/faux.js +395 -0
- package/ecagent/dist/runtime/providers/faux.js.map +1 -0
- package/ecagent/dist/runtime/types.d.ts +607 -0
- package/ecagent/dist/runtime/types.d.ts.map +1 -0
- package/ecagent/dist/runtime/types.js +2 -0
- package/ecagent/dist/runtime/types.js.map +1 -0
- package/ecagent/dist/runtime/utils/diagnostics.d.ts +19 -0
- package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/diagnostics.js +25 -0
- package/ecagent/dist/runtime/utils/diagnostics.js.map +1 -0
- package/ecagent/dist/runtime/utils/event-stream.d.ts +21 -0
- package/ecagent/dist/runtime/utils/event-stream.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/event-stream.js +77 -0
- package/ecagent/dist/runtime/utils/event-stream.js.map +1 -0
- package/ecagent/dist/runtime/utils/headers.d.ts +4 -0
- package/ecagent/dist/runtime/utils/headers.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/headers.js +18 -0
- package/ecagent/dist/runtime/utils/headers.js.map +1 -0
- package/ecagent/dist/runtime/utils/json-parse.d.ts +16 -0
- package/ecagent/dist/runtime/utils/json-parse.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/json-parse.js +113 -0
- package/ecagent/dist/runtime/utils/json-parse.js.map +1 -0
- package/ecagent/dist/runtime/utils/oauth/types.d.ts +64 -0
- package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/oauth/types.js +2 -0
- package/ecagent/dist/runtime/utils/oauth/types.js.map +1 -0
- package/ecagent/dist/runtime/utils/overflow.d.ts +58 -0
- package/ecagent/dist/runtime/utils/overflow.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/overflow.js +158 -0
- package/ecagent/dist/runtime/utils/overflow.js.map +1 -0
- package/ecagent/dist/runtime/utils/provider-env.d.ts +7 -0
- package/ecagent/dist/runtime/utils/provider-env.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/provider-env.js +44 -0
- package/ecagent/dist/runtime/utils/provider-env.js.map +1 -0
- package/ecagent/dist/runtime/utils/retry.d.ts +12 -0
- package/ecagent/dist/runtime/utils/retry.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/retry.js +90 -0
- package/ecagent/dist/runtime/utils/retry.js.map +1 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts +17 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.js +21 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.js.map +1 -0
- package/ecagent/dist/runtime/utils/validation.d.ts +18 -0
- package/ecagent/dist/runtime/utils/validation.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/validation.js +269 -0
- package/ecagent/dist/runtime/utils/validation.js.map +1 -0
- package/ecagent/dist/types.d.ts +401 -0
- package/ecagent/dist/types.d.ts.map +1 -0
- package/ecagent/dist/types.js +2 -0
- package/ecagent/dist/types.js.map +1 -0
- package/ecagent/package.json +93 -0
- package/ecagent/src/agent-loop.ts +792 -0
- package/ecagent/src/agent.ts +575 -0
- package/ecagent/src/harness/agent-harness.ts +1029 -0
- package/ecagent/src/harness/compaction/branch-summarization.ts +261 -0
- package/ecagent/src/harness/compaction/compaction.ts +753 -0
- package/ecagent/src/harness/compaction/utils.ts +144 -0
- package/ecagent/src/harness/env/nodejs.ts +569 -0
- package/ecagent/src/harness/messages.ts +164 -0
- package/ecagent/src/harness/prompt-templates.ts +267 -0
- package/ecagent/src/harness/session/jsonl-repo.ts +179 -0
- package/ecagent/src/harness/session/jsonl-storage.ts +314 -0
- package/ecagent/src/harness/session/memory-repo.ts +50 -0
- package/ecagent/src/harness/session/memory-storage.ts +133 -0
- package/ecagent/src/harness/session/repo-utils.ts +51 -0
- package/ecagent/src/harness/session/session.ts +338 -0
- package/ecagent/src/harness/session/uuid.ts +54 -0
- package/ecagent/src/harness/skills.ts +375 -0
- package/ecagent/src/harness/system-prompt.ts +34 -0
- package/ecagent/src/harness/types.ts +838 -0
- package/ecagent/src/harness/utils/shell-output.ts +135 -0
- package/ecagent/src/harness/utils/truncate.ts +344 -0
- package/ecagent/src/index.ts +46 -0
- package/ecagent/src/node.ts +2 -0
- package/ecagent/src/proxy.ts +367 -0
- package/ecagent/src/runtime/api/lazy.ts +70 -0
- package/ecagent/src/runtime/api/pi-messages.lazy.ts +4 -0
- package/ecagent/src/runtime/api/pi-messages.ts +436 -0
- package/ecagent/src/runtime/auth/context.ts +45 -0
- package/ecagent/src/runtime/auth/credential-store.ts +47 -0
- package/ecagent/src/runtime/auth/helpers.ts +46 -0
- package/ecagent/src/runtime/auth/resolve.ts +141 -0
- package/ecagent/src/runtime/auth/types.ts +182 -0
- package/ecagent/src/runtime/compat.ts +158 -0
- package/ecagent/src/runtime/index.ts +31 -0
- package/ecagent/src/runtime/models.ts +452 -0
- package/ecagent/src/runtime/oauth.ts +1 -0
- package/ecagent/src/runtime/providers/faux.ts +538 -0
- package/ecagent/src/runtime/types.ts +718 -0
- package/ecagent/src/runtime/utils/diagnostics.ts +45 -0
- package/ecagent/src/runtime/utils/event-stream.ts +88 -0
- package/ecagent/src/runtime/utils/headers.ts +18 -0
- package/ecagent/src/runtime/utils/json-parse.ts +124 -0
- package/ecagent/src/runtime/utils/oauth/types.ts +79 -0
- package/ecagent/src/runtime/utils/overflow.ts +165 -0
- package/ecagent/src/runtime/utils/provider-env.ts +52 -0
- package/ecagent/src/runtime/utils/retry.ts +101 -0
- package/ecagent/src/runtime/utils/typebox-helpers.ts +24 -0
- package/ecagent/src/runtime/utils/validation.ts +310 -0
- package/ecagent/src/types.ts +430 -0
- package/ecagent/tsconfig.build.json +32 -0
- package/kits/schemas/_meta.json +7 -4
- package/kits/schemas/agent-config.schema.10.json +370 -0
- package/kits/schemas/defaults.schema.4.json +93 -0
- package/kits/schemas/relation-config.schema.8.json +69 -0
- package/kits/templates/roles/admin.json +1 -1
- package/package.json +22 -6
- package/skills/eclink/SKILL.md +70 -0
- package/skills/eclink/agents/openai.yaml +4 -0
- package/assets/.env.template +0 -4
package/dist/paths.js
CHANGED
|
@@ -25,15 +25,19 @@ export function _resetRoot() {
|
|
|
25
25
|
}
|
|
26
26
|
export function resolvePaths() {
|
|
27
27
|
const root = resolveRoot();
|
|
28
|
+
const agentsDir = path.join(root, 'agents');
|
|
28
29
|
return {
|
|
29
30
|
root,
|
|
30
|
-
|
|
31
|
+
// Session storage is partitioned by owning Agent. Keep the historical
|
|
32
|
+
// location separately so the explicit data migration can inventory it.
|
|
33
|
+
sessionsDir: agentsDir,
|
|
34
|
+
legacySessionsDir: path.join(root, 'data', 'sessions'),
|
|
31
35
|
instanceDir: path.join(root, 'data', 'instance'),
|
|
32
36
|
outboxDir: path.join(root, 'data', 'outbox'),
|
|
33
37
|
dataDir: path.join(root, 'data'),
|
|
34
38
|
claudeModelCache: path.join(root, 'data', 'claude-model-cache.json'),
|
|
35
39
|
logs: path.join(root, 'logs'),
|
|
36
|
-
agentsDir
|
|
40
|
+
agentsDir,
|
|
37
41
|
lineStats: path.join(root, 'logs', 'line-stats.log'),
|
|
38
42
|
readySignal: path.join(root, 'data', 'instance', 'ready.signal'),
|
|
39
43
|
controlToken: path.join(root, 'data', 'instance', 'control.token'),
|
|
@@ -126,8 +130,36 @@ export function agentDataDir(aid) {
|
|
|
126
130
|
export function agentDataCacheDir(aid) {
|
|
127
131
|
return path.join(agentDataDir(aid), 'cache');
|
|
128
132
|
}
|
|
133
|
+
export function agentHandoffDir(aid) {
|
|
134
|
+
return path.join(agentDataDir(aid), 'handoff');
|
|
135
|
+
}
|
|
136
|
+
export function agentOutboxPath(aid) {
|
|
137
|
+
return path.join(agentDataDir(aid), 'outbox.jsonl');
|
|
138
|
+
}
|
|
139
|
+
/** Directory-safe channel instance key used by connector runtime state. */
|
|
140
|
+
function encodePathKey(value) {
|
|
141
|
+
return encodeURIComponent(value);
|
|
142
|
+
}
|
|
143
|
+
export function daemonDataDir() {
|
|
144
|
+
return path.join(resolveRoot(), 'data', 'daemon');
|
|
145
|
+
}
|
|
146
|
+
export function daemonControlDir() {
|
|
147
|
+
return path.join(daemonDataDir(), 'control');
|
|
148
|
+
}
|
|
149
|
+
export function daemonQueuePath() {
|
|
150
|
+
return path.join(daemonDataDir(), 'message-queue.json');
|
|
151
|
+
}
|
|
152
|
+
export function channelStateDir(channelKey) {
|
|
153
|
+
if (!channelKey || channelKey === '.' || channelKey === '..') {
|
|
154
|
+
throw new Error('channelKey is required');
|
|
155
|
+
}
|
|
156
|
+
return path.join(resolveRoot(), 'data', 'channel-state', encodePathKey(channelKey));
|
|
157
|
+
}
|
|
158
|
+
export function channelStatePath(channelKey, ...parts) {
|
|
159
|
+
return path.join(channelStateDir(channelKey), ...parts);
|
|
160
|
+
}
|
|
129
161
|
export function agentTriggersDir(aid) {
|
|
130
|
-
return path.join(
|
|
162
|
+
return path.join(agentDir(aid), 'triggers');
|
|
131
163
|
}
|
|
132
164
|
function resolveInstanceSocketPath(root) {
|
|
133
165
|
if (isWindows) {
|
|
@@ -147,7 +179,6 @@ export function ensureDataDirs() {
|
|
|
147
179
|
fs.mkdirSync(p.outboxDir, { recursive: true });
|
|
148
180
|
fs.mkdirSync(p.eckDir, { recursive: true });
|
|
149
181
|
fs.mkdirSync(aidsDir(), { recursive: true });
|
|
150
|
-
seedConfigTemplates();
|
|
151
182
|
migrateFromAun();
|
|
152
183
|
}
|
|
153
184
|
const MIGRATION_MARKER = '.migrated-from-aun';
|
|
@@ -211,29 +242,6 @@ function migrateFromAun() {
|
|
|
211
242
|
}
|
|
212
243
|
catch { }
|
|
213
244
|
}
|
|
214
|
-
/**
|
|
215
|
-
* 首次运行时从 assets/ 模板拷贝 .env 到 $EVOLCORE_HOME。
|
|
216
|
-
* 已存在则跳过,不覆盖用户修改。
|
|
217
|
-
*/
|
|
218
|
-
function seedConfigTemplates() {
|
|
219
|
-
const root = resolveRoot();
|
|
220
|
-
const assetsDir = path.join(getPackageRoot(), 'assets');
|
|
221
|
-
const templates = [
|
|
222
|
-
{ src: '.env.template', dst: '.env' },
|
|
223
|
-
];
|
|
224
|
-
for (const { src, dst } of templates) {
|
|
225
|
-
const dstPath = path.join(root, dst);
|
|
226
|
-
if (fs.existsSync(dstPath))
|
|
227
|
-
continue;
|
|
228
|
-
const srcPath = path.join(assetsDir, src);
|
|
229
|
-
if (!fs.existsSync(srcPath))
|
|
230
|
-
continue;
|
|
231
|
-
try {
|
|
232
|
-
fs.copyFileSync(srcPath, dstPath);
|
|
233
|
-
}
|
|
234
|
-
catch { /* best-effort */ }
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
245
|
// ── kits 路径(始终从包内读取,不复制到 EVOLCORE_HOME)──
|
|
238
246
|
export function kitsDir() {
|
|
239
247
|
return path.join(getPackageRoot(), 'kits');
|
package/dist/trigger/feedback.js
CHANGED
|
@@ -69,6 +69,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
69
69
|
const deadlineTimer = setTimeout(() => abortDelivery('timeout', new Error(`target session timed out after ${TARGET_SESSION_DEADLINE_MS}ms`)), TARGET_SESSION_DEADLINE_MS);
|
|
70
70
|
deadlineTimer.unref?.();
|
|
71
71
|
let outcome;
|
|
72
|
+
let releaseSessionLock;
|
|
72
73
|
try {
|
|
73
74
|
if (delivery.signal.aborted) {
|
|
74
75
|
const aborted = targetSessionCancellationError(abortKind, delivery.signal.reason, false);
|
|
@@ -128,6 +129,20 @@ export class TriggerFeedbackDispatcher {
|
|
|
128
129
|
}
|
|
129
130
|
return this.failed(feedback, [], 'session_error', err?.message || String(err));
|
|
130
131
|
}
|
|
132
|
+
if (input.onSessionResolved) {
|
|
133
|
+
const access = await input.onSessionResolved(session);
|
|
134
|
+
if (access.kind === 'conflict') {
|
|
135
|
+
return {
|
|
136
|
+
status: 'skipped',
|
|
137
|
+
reason: 'concurrency_forbid',
|
|
138
|
+
conflictRunId: access.conflictRunId,
|
|
139
|
+
feedback,
|
|
140
|
+
effects: [],
|
|
141
|
+
error: null,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
releaseSessionLock = access.release;
|
|
145
|
+
}
|
|
131
146
|
const message = {
|
|
132
147
|
channel: target.channelKey,
|
|
133
148
|
channelType,
|
|
@@ -241,6 +256,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
258
|
finally {
|
|
259
|
+
releaseSessionLock?.();
|
|
244
260
|
clearTimeout(deadlineTimer);
|
|
245
261
|
input.signal?.removeEventListener('abort', onInputAbort);
|
|
246
262
|
outcome?.cancel();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const HISTORY_CHANNELS = new Set(['aun', 'feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom']);
|
|
2
|
+
/**
|
|
3
|
+
* Turns legacy raw session-file references into the controlled history CLI.
|
|
4
|
+
* The replacement deliberately keeps the explicit peer/channel scope but
|
|
5
|
+
* never carries a filesystem location into a Trigger prompt.
|
|
6
|
+
*/
|
|
7
|
+
export function rewriteLegacyTriggerSessionPaths(prompt, triggerAid) {
|
|
8
|
+
const legacyPath = /data\/sessions\/([A-Za-z0-9_-]+)\/([^/\s`"'<>]+)(?:\/([^/\s`"'<>]+))?\/messages\.jsonl/g;
|
|
9
|
+
return prompt.replace(legacyPath, (match, channel, first, second) => {
|
|
10
|
+
if (!HISTORY_CHANNELS.has(channel))
|
|
11
|
+
return match;
|
|
12
|
+
const isAun = channel === 'aun';
|
|
13
|
+
const target = isAun ? second : first;
|
|
14
|
+
const selfAid = triggerAid ?? (isAun ? first : undefined);
|
|
15
|
+
if (!selfAid || !target)
|
|
16
|
+
return match;
|
|
17
|
+
return `ec msg history ${selfAid} ${target} --channel ${channel} --session all --direction in --format json`;
|
|
18
|
+
});
|
|
19
|
+
}
|
package/dist/trigger/manager.js
CHANGED
|
@@ -4,6 +4,7 @@ import { agentTriggersDir } from '../paths.js';
|
|
|
4
4
|
import { definitionRevision, normalizeTriggerDefinition, resolveScriptPath, safeRelativePath, } from './validation.js';
|
|
5
5
|
import { atomicWriteJson } from '../core/session/session-fs-store.js';
|
|
6
6
|
import { TriggerHistoryStore } from './history.js';
|
|
7
|
+
import { rewriteLegacyTriggerSessionPaths } from './legacy-session-history.js';
|
|
7
8
|
export class TriggerDefinitionManager {
|
|
8
9
|
agentAid;
|
|
9
10
|
rootDir;
|
|
@@ -34,7 +35,17 @@ export class TriggerDefinitionManager {
|
|
|
34
35
|
if (!fs.existsSync(file))
|
|
35
36
|
return undefined;
|
|
36
37
|
const raw = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
37
|
-
|
|
38
|
+
const definition = normalizeTriggerDefinition(raw);
|
|
39
|
+
if (typeof definition.execution.prompt === 'string') {
|
|
40
|
+
const rewritten = rewriteLegacyTriggerSessionPaths(definition.execution.prompt, definition.agentAid);
|
|
41
|
+
if (rewritten !== definition.execution.prompt) {
|
|
42
|
+
definition.execution = { ...definition.execution, prompt: rewritten };
|
|
43
|
+
definition.updatedAt = Date.now();
|
|
44
|
+
this.writeDefinition(definition);
|
|
45
|
+
this.history.recordDefinition('trigger.updated', definition, { reason: 'legacy-session-history-paths' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return definition;
|
|
38
49
|
}
|
|
39
50
|
require(triggerId) {
|
|
40
51
|
const def = this.get(triggerId);
|
package/dist/trigger/parser.js
CHANGED
|
@@ -210,11 +210,13 @@ function parseTriggerThread(flags) {
|
|
|
210
210
|
return { ok: false, error: '--trigger-thread 不能为空' };
|
|
211
211
|
if (raw === 'per-run')
|
|
212
212
|
return { ok: true, value: 'per_run' };
|
|
213
|
+
if (raw === 'by-run')
|
|
214
|
+
return { ok: true, value: 'by_run' };
|
|
213
215
|
if (raw === 'by-trigger')
|
|
214
216
|
return { ok: true, value: 'by_trigger' };
|
|
215
|
-
if (raw === 'per_run' || raw === 'by_trigger')
|
|
217
|
+
if (raw === 'per_run' || raw === 'by_run' || raw === 'by_trigger')
|
|
216
218
|
return { ok: true, value: raw };
|
|
217
|
-
return { ok: false, error: '--trigger-thread 只接受
|
|
219
|
+
return { ok: false, error: '--trigger-thread 只接受 by-run 或 by-trigger(兼容 per-run)' };
|
|
218
220
|
}
|
|
219
221
|
function parseTargetSession(flags) {
|
|
220
222
|
if (!flags.has('target-session'))
|
|
@@ -3,7 +3,8 @@ 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, } from './validation.js';
|
|
6
|
+
import { definitionRevision, parseDurationMs, previewText, renderTemplate, resolveScriptPath, sha256, validateConcurrencyCombination, } from './validation.js';
|
|
7
|
+
import { TargetSessionLockRegistry } from './session-lock.js';
|
|
7
8
|
import { enterTrigger, formatTriggerPath } from '../core/causation/context.js';
|
|
8
9
|
import { createRootCausation } from '../core/causation/context.js';
|
|
9
10
|
import { recordCausationSpan } from '../core/causation/audit.js';
|
|
@@ -21,6 +22,7 @@ export class TriggerRuntimeScheduler {
|
|
|
21
22
|
daemonChannel;
|
|
22
23
|
runtime;
|
|
23
24
|
eventBus;
|
|
25
|
+
targetSessionLocks;
|
|
24
26
|
timers = new Map();
|
|
25
27
|
running = new Map();
|
|
26
28
|
runStartLocks = new Map();
|
|
@@ -28,7 +30,7 @@ export class TriggerRuntimeScheduler {
|
|
|
28
30
|
eventSource;
|
|
29
31
|
initialized = false;
|
|
30
32
|
stopping = false;
|
|
31
|
-
constructor(manager, state, audit, scriptExecutor, feedback, daemonChannel, runtime, eventBus) {
|
|
33
|
+
constructor(manager, state, audit, scriptExecutor, feedback, daemonChannel, runtime, eventBus, targetSessionLocks = new TargetSessionLockRegistry()) {
|
|
32
34
|
this.manager = manager;
|
|
33
35
|
this.state = state;
|
|
34
36
|
this.audit = audit;
|
|
@@ -37,6 +39,7 @@ export class TriggerRuntimeScheduler {
|
|
|
37
39
|
this.daemonChannel = daemonChannel;
|
|
38
40
|
this.runtime = runtime;
|
|
39
41
|
this.eventBus = eventBus;
|
|
42
|
+
this.targetSessionLocks = targetSessionLocks;
|
|
40
43
|
if (eventBus) {
|
|
41
44
|
this.eventSource = new TriggerEventSource(eventBus, (triggerId, event) => {
|
|
42
45
|
void this.fireEventTrigger(triggerId, event);
|
|
@@ -391,6 +394,31 @@ export class TriggerRuntimeScheduler {
|
|
|
391
394
|
return { ok: false, runId, triggerId: definition.id, status: 'failed', reason: 'stopped' };
|
|
392
395
|
}
|
|
393
396
|
const source = this.buildSourceInfo(definition.source, firedAt, payload.scheduledAt, payload.payload);
|
|
397
|
+
try {
|
|
398
|
+
validateConcurrencyCombination(definition.execution, definition.reliability);
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
402
|
+
const audit = this.buildAudit({
|
|
403
|
+
definition,
|
|
404
|
+
runId,
|
|
405
|
+
startedAt: firedAt,
|
|
406
|
+
status: 'failed',
|
|
407
|
+
reason: 'invalid_execution_configuration',
|
|
408
|
+
source,
|
|
409
|
+
script: null,
|
|
410
|
+
reply: null,
|
|
411
|
+
feedback: null,
|
|
412
|
+
effects: [],
|
|
413
|
+
error: { code: 'invalid_execution_configuration', message },
|
|
414
|
+
causation: payload.causation,
|
|
415
|
+
});
|
|
416
|
+
if (!payload.dryRun) {
|
|
417
|
+
this.audit.write(audit);
|
|
418
|
+
this.publishTriggerRunOutcome(definition, audit);
|
|
419
|
+
}
|
|
420
|
+
return { ok: false, runId, triggerId: definition.id, status: 'failed', reason: 'invalid_execution_configuration', audit, error: message };
|
|
421
|
+
}
|
|
394
422
|
const executionAuthorization = this.runtime.authorizeExecution?.(definition);
|
|
395
423
|
if (executionAuthorization && !executionAuthorization.allowed) {
|
|
396
424
|
const reason = executionAuthorization.reason || 'execution_authorization_denied';
|
|
@@ -455,6 +483,7 @@ export class TriggerRuntimeScheduler {
|
|
|
455
483
|
definitionRevision: definitionRevision(definition),
|
|
456
484
|
source,
|
|
457
485
|
resumeCount: 0,
|
|
486
|
+
attempts: [],
|
|
458
487
|
events: [{ seq: 0, event: 'run.started', ts: startedAt }],
|
|
459
488
|
};
|
|
460
489
|
if (!payload.dryRun) {
|
|
@@ -597,6 +626,7 @@ export class TriggerRuntimeScheduler {
|
|
|
597
626
|
anomalies: executionAnomalies,
|
|
598
627
|
effects: feedbackResult.effects,
|
|
599
628
|
error: feedbackResult.error,
|
|
629
|
+
conflictRunId: feedbackResult.conflictRunId,
|
|
600
630
|
causation,
|
|
601
631
|
});
|
|
602
632
|
if (!payload.dryRun) {
|
|
@@ -680,7 +710,7 @@ export class TriggerRuntimeScheduler {
|
|
|
680
710
|
let attempt = 1;
|
|
681
711
|
let anomalies = [];
|
|
682
712
|
try {
|
|
683
|
-
let execution = await this.
|
|
713
|
+
let execution = await this.runRecordedExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt);
|
|
684
714
|
anomalies = accumulateTriggerExecutionAnomalies(anomalies, mergeTriggerExecutionAnomalies(execution.reply?.anomalies, drainTriggerExecutionAnomalies(runId)));
|
|
685
715
|
onAnomalies?.(anomalies);
|
|
686
716
|
for (let retryCount = 0; shouldRetryExecutionResult(execution) && retryCount < maxAttempts && !signal.aborted; retryCount++) {
|
|
@@ -688,7 +718,7 @@ export class TriggerRuntimeScheduler {
|
|
|
688
718
|
if (!backoffCompleted || signal.aborted)
|
|
689
719
|
break;
|
|
690
720
|
attempt += 1;
|
|
691
|
-
execution = await this.
|
|
721
|
+
execution = await this.runRecordedExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt, retryContextFromExecution(attempt - 1, `${runId}:attempt:${attempt - 1}`, execution));
|
|
692
722
|
anomalies = accumulateTriggerExecutionAnomalies(anomalies, mergeTriggerExecutionAnomalies(execution.reply?.anomalies, drainTriggerExecutionAnomalies(runId)));
|
|
693
723
|
onAnomalies?.(anomalies);
|
|
694
724
|
}
|
|
@@ -703,7 +733,34 @@ export class TriggerRuntimeScheduler {
|
|
|
703
733
|
throw new TriggerExecutionFailure(error, anomalies);
|
|
704
734
|
}
|
|
705
735
|
}
|
|
706
|
-
async
|
|
736
|
+
async runRecordedExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt, previousAttempt) {
|
|
737
|
+
const attemptId = `${runId}:attempt:${attempt}`;
|
|
738
|
+
if (!dryRun) {
|
|
739
|
+
this.state.startExecutionAttempt?.(definition.id, runId, {
|
|
740
|
+
attempt,
|
|
741
|
+
attemptId,
|
|
742
|
+
startedAt: Date.now(),
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
try {
|
|
746
|
+
const execution = await this.runExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt, previousAttempt);
|
|
747
|
+
if (!dryRun) {
|
|
748
|
+
const summary = attemptSummaryFromExecution(attempt, attemptId, execution);
|
|
749
|
+
this.state.completeExecutionAttempt?.(definition.id, runId, attemptId, summary);
|
|
750
|
+
}
|
|
751
|
+
return execution;
|
|
752
|
+
}
|
|
753
|
+
catch (error) {
|
|
754
|
+
if (!dryRun) {
|
|
755
|
+
this.state.completeExecutionAttempt?.(definition.id, runId, attemptId, {
|
|
756
|
+
status: 'failed',
|
|
757
|
+
error: errorSummary(error, 'execution_exception'),
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
throw error;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
async runExecutionAttempt(definition, runId, firedAt, sourcePayload, signal, dryRun, causation, attempt = 1, previousAttempt) {
|
|
707
764
|
if (signal.aborted) {
|
|
708
765
|
return {
|
|
709
766
|
script: null,
|
|
@@ -735,12 +792,15 @@ export class TriggerRuntimeScheduler {
|
|
|
735
792
|
reply,
|
|
736
793
|
};
|
|
737
794
|
}
|
|
738
|
-
const
|
|
795
|
+
const originalPrompt = renderTemplate(definition.execution.prompt ?? '', {
|
|
739
796
|
trigger: definition,
|
|
740
797
|
timestamp: firedAt,
|
|
741
798
|
event: sourcePayload,
|
|
742
799
|
source: { type: definition.source.type, payload: sourcePayload },
|
|
743
800
|
});
|
|
801
|
+
const prompt = previousAttempt
|
|
802
|
+
? renderRetryContinuationPrompt(originalPrompt, previousAttempt)
|
|
803
|
+
: originalPrompt;
|
|
744
804
|
const processing = {
|
|
745
805
|
mode: definition.execution.type,
|
|
746
806
|
renderedTextHash: sha256(prompt),
|
|
@@ -756,6 +816,20 @@ export class TriggerRuntimeScheduler {
|
|
|
756
816
|
dryRun,
|
|
757
817
|
causation,
|
|
758
818
|
signal,
|
|
819
|
+
onSessionResolved: async (session) => {
|
|
820
|
+
this.state.startExecutionAttempt?.(definition.id, runId, {
|
|
821
|
+
attempt,
|
|
822
|
+
attemptId: `${runId}:attempt:${attempt}`,
|
|
823
|
+
startedAt: Date.now(),
|
|
824
|
+
executionSessionId: session.id,
|
|
825
|
+
});
|
|
826
|
+
// runExecution is also used by focused unit tests without a live
|
|
827
|
+
// scheduler runtime. Production calls always have a RunningRun.
|
|
828
|
+
if (!this.running.get(definition.id)?.has(runId)) {
|
|
829
|
+
return { kind: 'acquired', release: () => undefined };
|
|
830
|
+
}
|
|
831
|
+
return await this.acquireTargetSessionLock(definition, runId, session.id);
|
|
832
|
+
},
|
|
759
833
|
});
|
|
760
834
|
return {
|
|
761
835
|
script: null,
|
|
@@ -792,19 +866,13 @@ export class TriggerRuntimeScheduler {
|
|
|
792
866
|
const attemptId = `${runId}:attempt:${attempt}`;
|
|
793
867
|
const executionDeadlineAt = this.daemonExecutionDeadlineAt(Date.now());
|
|
794
868
|
const executionSession = await this.daemonChannel.getOrCreateConversationSession(definition, this.runtime.projectPath, runtimeBaseagent, runId, attemptId);
|
|
795
|
-
const activeRun = this.state.
|
|
869
|
+
const activeRun = this.state.startExecutionAttempt?.(definition.id, runId, {
|
|
796
870
|
attempt,
|
|
797
871
|
attemptId,
|
|
872
|
+
startedAt: Date.now(),
|
|
798
873
|
executionSessionId: executionSession.id,
|
|
799
874
|
executionDeadlineAt,
|
|
800
875
|
});
|
|
801
|
-
this.state.appendEvent?.(definition.id, runId, {
|
|
802
|
-
event: 'execution.attempt.started',
|
|
803
|
-
ts: Date.now(),
|
|
804
|
-
attempt,
|
|
805
|
-
attemptId,
|
|
806
|
-
executionSessionId: executionSession.id,
|
|
807
|
-
});
|
|
808
876
|
const daemonReply = await this.daemonChannel.converse(prompt, {
|
|
809
877
|
trigger: definition,
|
|
810
878
|
runId,
|
|
@@ -869,6 +937,26 @@ export class TriggerRuntimeScheduler {
|
|
|
869
937
|
signal,
|
|
870
938
|
});
|
|
871
939
|
}
|
|
940
|
+
async acquireTargetSessionLock(definition, runId, sessionId) {
|
|
941
|
+
const concurrency = definition.reliability.concurrency;
|
|
942
|
+
if (concurrency === 'allow') {
|
|
943
|
+
throw new Error('target_session concurrency=allow must be rejected before session dispatch');
|
|
944
|
+
}
|
|
945
|
+
const runtime = this.running.get(definition.id)?.get(runId);
|
|
946
|
+
if (!runtime) {
|
|
947
|
+
throw new Error(`target session lock requested for non-running Trigger run: ${definition.id}/${runId}`);
|
|
948
|
+
}
|
|
949
|
+
return await this.targetSessionLocks.acquire(sessionId, concurrency, {
|
|
950
|
+
triggerId: definition.id,
|
|
951
|
+
runId,
|
|
952
|
+
replace: async () => {
|
|
953
|
+
await this.terminateRun(runId, runtime, {
|
|
954
|
+
reason: 'replaced',
|
|
955
|
+
message: `target session run replaced: trigger=${definition.id} run=${runId}`,
|
|
956
|
+
});
|
|
957
|
+
},
|
|
958
|
+
});
|
|
959
|
+
}
|
|
872
960
|
async checkConcurrency(definition, nextRunId, source) {
|
|
873
961
|
const runs = this.running.get(definition.id);
|
|
874
962
|
if (!runs || runs.size === 0 || definition.reliability.concurrency === 'allow')
|
|
@@ -1118,7 +1206,16 @@ export class TriggerRuntimeScheduler {
|
|
|
1118
1206
|
async runRecoveredExecution(definition, runtime, session) {
|
|
1119
1207
|
const { run, source, controller, causation } = runtime;
|
|
1120
1208
|
let attempt = run.attempt;
|
|
1209
|
+
const attemptId = run.attemptId ?? `${run.runId}:attempt:${attempt}`;
|
|
1210
|
+
this.state.startExecutionAttempt(definition.id, run.runId, {
|
|
1211
|
+
attempt,
|
|
1212
|
+
attemptId,
|
|
1213
|
+
startedAt: run.startedAt,
|
|
1214
|
+
executionSessionId: session.id,
|
|
1215
|
+
executionDeadlineAt: run.executionDeadlineAt,
|
|
1216
|
+
});
|
|
1121
1217
|
let execution = await this.runRecoveredExecutionAttempt(definition, runtime, session);
|
|
1218
|
+
this.state.completeExecutionAttempt(definition.id, run.runId, attemptId, attemptSummaryFromExecution(attempt, attemptId, execution));
|
|
1122
1219
|
let anomalies = accumulateTriggerExecutionAnomalies([], mergeTriggerExecutionAnomalies(execution.reply?.anomalies, drainTriggerExecutionAnomalies(run.runId)));
|
|
1123
1220
|
runtime.anomalies = anomalies;
|
|
1124
1221
|
const maxAttempt = 1 + (definition.execution.onError === 'retry'
|
|
@@ -1129,7 +1226,7 @@ export class TriggerRuntimeScheduler {
|
|
|
1129
1226
|
if (!backoffCompleted || controller.signal.aborted)
|
|
1130
1227
|
break;
|
|
1131
1228
|
attempt += 1;
|
|
1132
|
-
execution = await this.
|
|
1229
|
+
execution = await this.runRecordedExecutionAttempt(definition, run.runId, source.firedAt, source.payload, controller.signal, false, causation, attempt, retryContextFromExecution(attempt - 1, `${run.runId}:attempt:${attempt - 1}`, execution));
|
|
1133
1230
|
anomalies = accumulateTriggerExecutionAnomalies(anomalies, mergeTriggerExecutionAnomalies(execution.reply?.anomalies, drainTriggerExecutionAnomalies(run.runId)));
|
|
1134
1231
|
runtime.anomalies = anomalies;
|
|
1135
1232
|
}
|
|
@@ -1356,6 +1453,12 @@ export class TriggerRuntimeScheduler {
|
|
|
1356
1453
|
}
|
|
1357
1454
|
buildAudit(input) {
|
|
1358
1455
|
const reply = summarizeReply(input.reply, { omitText: input.script?.result !== undefined });
|
|
1456
|
+
const activeRun = this.state.list?.(input.definition.id).find(run => run.runId === input.runId);
|
|
1457
|
+
const attempts = activeRun?.attempts?.map(attempt => ({
|
|
1458
|
+
...attempt,
|
|
1459
|
+
...(attempt.error ? { error: { ...attempt.error } } : {}),
|
|
1460
|
+
}));
|
|
1461
|
+
const finalAttempt = attempts?.at(-1);
|
|
1359
1462
|
return {
|
|
1360
1463
|
runId: input.runId,
|
|
1361
1464
|
triggerId: input.definition.id,
|
|
@@ -1365,6 +1468,9 @@ export class TriggerRuntimeScheduler {
|
|
|
1365
1468
|
status: input.status,
|
|
1366
1469
|
reason: input.reason,
|
|
1367
1470
|
conflictRunId: input.conflictRunId,
|
|
1471
|
+
...(activeRun?.executionSessionId ? { executionSessionId: activeRun.executionSessionId } : {}),
|
|
1472
|
+
...(attempts?.length ? { attempts } : {}),
|
|
1473
|
+
...(finalAttempt ? { finalAttempt: finalAttempt.attempt } : {}),
|
|
1368
1474
|
definition: {
|
|
1369
1475
|
schemaVersion: input.definition.$schema_version,
|
|
1370
1476
|
revision: definitionRevision(input.definition),
|
|
@@ -1522,6 +1628,10 @@ export class TriggerRuntimeScheduler {
|
|
|
1522
1628
|
this.removeRunning(triggerId, runId);
|
|
1523
1629
|
return;
|
|
1524
1630
|
}
|
|
1631
|
+
// terminateRun owns the terminal audit and must retain active attempt
|
|
1632
|
+
// snapshots until its completion barrier has settled.
|
|
1633
|
+
if (runtime?.termination)
|
|
1634
|
+
return;
|
|
1525
1635
|
this.finishRun(triggerId, runId);
|
|
1526
1636
|
}
|
|
1527
1637
|
suspendedRuntimeResult(runtime, triggerId, runId) {
|
|
@@ -1787,6 +1897,65 @@ function errorReply(runId, durationMs, reason, text) {
|
|
|
1787
1897
|
},
|
|
1788
1898
|
};
|
|
1789
1899
|
}
|
|
1900
|
+
function attemptSummaryFromExecution(attempt, attemptId, execution) {
|
|
1901
|
+
if (execution.feedbackResult) {
|
|
1902
|
+
const failed = execution.feedbackResult.status !== 'completed';
|
|
1903
|
+
return {
|
|
1904
|
+
status: failed ? 'failed' : 'completed',
|
|
1905
|
+
...(execution.feedbackResult.error
|
|
1906
|
+
? { error: execution.feedbackResult.error }
|
|
1907
|
+
: failed
|
|
1908
|
+
? { error: {
|
|
1909
|
+
code: execution.feedbackResult.reason ?? 'target_session_failed',
|
|
1910
|
+
message: execution.feedbackResult.reason ?? 'target session execution did not start',
|
|
1911
|
+
} }
|
|
1912
|
+
: {}),
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
const reply = execution.reply;
|
|
1916
|
+
if (!reply) {
|
|
1917
|
+
return { status: 'failed', error: { code: 'execution_missing_reply', message: 'execution completed without a reply' } };
|
|
1918
|
+
}
|
|
1919
|
+
switch (reply.outcome) {
|
|
1920
|
+
case 'success': return { status: 'completed' };
|
|
1921
|
+
case 'noop': return { status: 'noop' };
|
|
1922
|
+
case 'interrupted': return { status: 'interrupted', error: replyErrorSummary(reply, 'interrupted') };
|
|
1923
|
+
case 'timeout': return { status: 'timeout', error: replyErrorSummary(reply, 'timeout') };
|
|
1924
|
+
case 'error': return { status: 'failed', error: replyErrorSummary(reply, 'execution_error') };
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
function retryContextFromExecution(attempt, attemptId, execution) {
|
|
1928
|
+
return {
|
|
1929
|
+
attempt,
|
|
1930
|
+
attemptId,
|
|
1931
|
+
...attemptSummaryFromExecution(attempt, attemptId, execution),
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
function replyErrorSummary(reply, fallbackCode) {
|
|
1935
|
+
return {
|
|
1936
|
+
code: reply.error?.reason || fallbackCode,
|
|
1937
|
+
message: previewText(reply.error?.text || `Trigger attempt ${fallbackCode}`, 600),
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
function errorSummary(error, fallbackCode) {
|
|
1941
|
+
const cause = error instanceof TriggerExecutionFailure ? error.cause : error;
|
|
1942
|
+
return {
|
|
1943
|
+
code: fallbackCode,
|
|
1944
|
+
message: previewText(cause instanceof Error ? cause.message : String(cause), 600),
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
function renderRetryContinuationPrompt(originalPrompt, previous) {
|
|
1948
|
+
const error = previous.error
|
|
1949
|
+
? `${previous.error.code}: ${previous.error.message}`
|
|
1950
|
+
: previous.status;
|
|
1951
|
+
return [
|
|
1952
|
+
'这是同一个 Trigger run 的恢复执行,不是新任务。',
|
|
1953
|
+
`上一 attempt 为 ${previous.attempt}(${previous.attemptId}),结果:${error}。`,
|
|
1954
|
+
'请先检查当前会话已有上下文、工具结果和已完成步骤,只继续未完成的工作。',
|
|
1955
|
+
'原始任务:',
|
|
1956
|
+
originalPrompt,
|
|
1957
|
+
].join('\n');
|
|
1958
|
+
}
|
|
1790
1959
|
function summarizeScript(script) {
|
|
1791
1960
|
if (!script)
|
|
1792
1961
|
return null;
|
|
@@ -1833,6 +2002,7 @@ function summarizeReply(reply, opts = {}) {
|
|
|
1833
2002
|
durationMs: reply.meta.durationMs,
|
|
1834
2003
|
numTurns: reply.meta.numTurns,
|
|
1835
2004
|
tokenUsage: reply.meta.tokenUsage,
|
|
2005
|
+
contextRecoveryAttempts: reply.meta.contextRecoveryAttempts,
|
|
1836
2006
|
toolCallCount: reply.meta.toolCallCount,
|
|
1837
2007
|
};
|
|
1838
2008
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-wide ownership for target sessions. Schedulers are created per
|
|
3
|
+
* agent, so per-scheduler maps cannot protect a session shared by triggers.
|
|
4
|
+
*/
|
|
5
|
+
export class TargetSessionLockRegistry {
|
|
6
|
+
owners = new Map();
|
|
7
|
+
mutations = new Map();
|
|
8
|
+
async acquire(sessionId, concurrency, owner) {
|
|
9
|
+
return await this.withMutation(sessionId, async () => {
|
|
10
|
+
const current = this.owners.get(sessionId);
|
|
11
|
+
if (!current)
|
|
12
|
+
return this.claim(sessionId, owner);
|
|
13
|
+
if (concurrency === 'forbid') {
|
|
14
|
+
return {
|
|
15
|
+
kind: 'conflict',
|
|
16
|
+
conflictTriggerId: current.triggerId,
|
|
17
|
+
conflictRunId: current.runId,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
await current.replace();
|
|
21
|
+
const remaining = this.owners.get(sessionId);
|
|
22
|
+
if (remaining) {
|
|
23
|
+
return {
|
|
24
|
+
kind: 'conflict',
|
|
25
|
+
conflictTriggerId: remaining.triggerId,
|
|
26
|
+
conflictRunId: remaining.runId,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return this.claim(sessionId, owner);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
claim(sessionId, owner) {
|
|
33
|
+
this.owners.set(sessionId, owner);
|
|
34
|
+
let released = false;
|
|
35
|
+
return {
|
|
36
|
+
kind: 'acquired',
|
|
37
|
+
release: () => {
|
|
38
|
+
if (released)
|
|
39
|
+
return;
|
|
40
|
+
released = true;
|
|
41
|
+
if (this.owners.get(sessionId) === owner)
|
|
42
|
+
this.owners.delete(sessionId);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async withMutation(sessionId, action) {
|
|
47
|
+
const previous = this.mutations.get(sessionId) ?? Promise.resolve();
|
|
48
|
+
let releaseCurrent;
|
|
49
|
+
const current = new Promise(resolve => { releaseCurrent = resolve; });
|
|
50
|
+
const tail = previous.then(() => current);
|
|
51
|
+
this.mutations.set(sessionId, tail);
|
|
52
|
+
await previous;
|
|
53
|
+
try {
|
|
54
|
+
return await action();
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
releaseCurrent();
|
|
58
|
+
if (this.mutations.get(sessionId) === tail)
|
|
59
|
+
this.mutations.delete(sessionId);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|