evolcore 0.0.26 → 0.0.28
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 +36 -0
- package/bin/codex-managed-acl.ps1 +43 -0
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +10 -5
- package/dist/agents/claude-runner.js +123 -22
- package/dist/agents/codex/app-server-client.js +70 -26
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex-runner.js +363 -421
- package/dist/agents/ecagent-runner.js +170 -25
- package/dist/agents/gemini-runner.js +6 -0
- package/dist/agents/runner-types.js +50 -2
- package/dist/aun/aid/agentmd.js +73 -31
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +3 -3
- 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} +161 -38
- package/dist/aun/{menu-client.js → menu/client.js} +13 -7
- 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 +84 -18
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +13 -8
- package/dist/aun/msg/upload.js +43 -88
- 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 +544 -239
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +108 -6
- package/dist/cli/agent-create.js +515 -2
- package/dist/cli/agent.js +109 -8
- package/dist/cli/aun-commands.js +191 -42
- package/dist/cli/config.js +8 -5
- package/dist/cli/contact.js +2 -2
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +111 -162
- package/dist/cli/diag.js +3 -3
- package/dist/cli/fs-command.js +3 -3
- package/dist/cli/handoff-command.js +6 -6
- package/dist/cli/index.js +8 -2
- package/dist/cli/init.js +34 -1
- package/dist/cli/managed-command-guard.js +2 -1
- package/dist/cli/menu-client.js +13 -5
- package/dist/cli/model.js +3 -3
- package/dist/cli/queue-command.js +2 -2
- package/dist/cli/response.js +2 -2
- package/dist/cli/restart-monitor.js +81 -19
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +20 -10
- package/dist/config/builtin-roles.js +10 -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 +20 -5
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +1 -1
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +5 -0
- 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 +34 -38
- package/dist/core/auth/operation-authorizer.js +67 -5
- package/dist/core/auth/operation-catalog.js +110 -0
- package/dist/core/auth/remote-access-store.js +115 -9
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +110 -19
- 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 +105 -40
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +34 -4
- package/dist/core/command/menu-handler.js +364 -96
- package/dist/core/command/menu-protocol.js +43 -6
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-handler.js +61 -37
- 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/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +94 -16
- package/dist/core/message/message-bridge.js +140 -13
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +73 -41
- package/dist/core/message/response-engine.js +729 -118
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +76 -36
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +72 -3
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +8 -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 +38 -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 +322 -207
- package/dist/ipc.js +141 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +3 -0
- 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/atomic-write.js +98 -0
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-utils.js +40 -2
- package/dist/utils/logger.js +23 -13
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +174 -1
- package/dist/utils/windows-shell-trust.js +37 -0
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/INDEX.md +0 -6
- package/kits/docs/channels/aun.md +23 -2
- package/kits/docs/channels/feishu.md +1 -1
- package/kits/docs/context-assembly.md +29 -17
- package/kits/docs/evolcore/INDEX.md +8 -3
- package/kits/docs/evolcore/agent-create.md +39 -7
- package/kits/docs/evolcore/agent.md +33 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/config.md +40 -1
- package/kits/docs/evolcore/group-collaboration.md +1 -1
- package/kits/docs/evolcore/group.md +117 -2
- package/kits/docs/evolcore/menu-client.md +16 -0
- package/kits/docs/evolcore/msg.md +3 -0
- package/kits/docs/evolcore/storage.md +3 -0
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +51 -3
- package/kits/docs/venues/group.md +5 -0
- package/kits/eck_manifest.json +27 -0
- package/kits/rules/01-overview.md +11 -7
- package/kits/rules/04-relation.md +2 -1
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +6 -4
- package/kits/schemas/agent-config.schema.12.json +25 -1
- package/kits/schemas/daemon.schema.6.json +2 -2
- package/kits/schemas/defaults.schema.5.json +1 -1
- package/kits/schemas/relation-config.schema.1.json +1 -1
- package/kits/schemas/relation-config.schema.5.json +1 -1
- package/kits/schemas/role-config.schema.1.json +14 -0
- package/kits/templates/roles/member.json +5 -0
- package/kits/templates/roles/visitor.json +5 -0
- package/kits/templates/system-fragments/baseagent.md +1 -1
- package/kits/templates/system-fragments/bootstrap.md +26 -9
- package/kits/templates/system-fragments/channel.md +8 -44
- package/kits/templates/system-fragments/commands.md +10 -2
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/reply.md +56 -0
- package/package.json +7 -3
- 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
package/dist/trigger/feedback.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { buildEnvelope } from '../core/message/message-utils.js';
|
|
2
|
-
import { renderTemplate, previewText, sha256 } from './validation.js';
|
|
2
|
+
import { executionTimeoutMs, renderTemplate, previewText, sha256 } from './validation.js';
|
|
3
|
+
import { isDaemonEventSessionTrigger } from './event-source.js';
|
|
4
|
+
import { TASK_RECOVERY_PROMPT } from '../core/task/task-recovery-service.js';
|
|
5
|
+
import { ExecutionTimeoutError, OrphanedTargetSessionError } from '../utils/error-utils.js';
|
|
3
6
|
const FEEDBACK_DEADLINE_MS = 30_000;
|
|
4
|
-
const TARGET_SESSION_DEADLINE_MS = 30 * 60_000;
|
|
5
7
|
const TARGET_SESSION_CANCEL_GRACE_MS = 1_000;
|
|
8
|
+
const TARGET_SESSION_OUTCOME_GRACE_MS = 5_000;
|
|
9
|
+
const TARGET_SESSION_PROBE_MS = 30_000;
|
|
10
|
+
const TARGET_SESSION_ORPHAN_GRACE_MS = 120_000;
|
|
6
11
|
export class TriggerFeedbackDispatcher {
|
|
7
12
|
deps;
|
|
8
13
|
constructor(deps) {
|
|
@@ -50,20 +55,72 @@ export class TriggerFeedbackDispatcher {
|
|
|
50
55
|
}
|
|
51
56
|
async dispatchTargetSession(input) {
|
|
52
57
|
const feedback = this.auditFeedback(input.trigger);
|
|
53
|
-
|
|
58
|
+
let eventSession;
|
|
59
|
+
let eventAgentAid;
|
|
60
|
+
let unresolvedTarget = this.resolveDeliveryTarget(input.trigger);
|
|
61
|
+
if (input.trigger.feedback.strategy === 'event_session') {
|
|
62
|
+
const payload = input.sourcePayload;
|
|
63
|
+
eventAgentAid = typeof payload?.agentAid === 'string' && payload.agentAid.trim()
|
|
64
|
+
? payload.agentAid.trim()
|
|
65
|
+
: undefined;
|
|
66
|
+
if (input.trigger.source.type !== 'event' || !payload || !eventAgentAid
|
|
67
|
+
|| (!isDaemonEventSessionTrigger(input.trigger) && eventAgentAid !== input.trigger.agentAid)
|
|
68
|
+
|| typeof payload.sessionId !== 'string' || !/^[A-Za-z0-9_-]+$/.test(payload.sessionId)
|
|
69
|
+
|| typeof payload.peerId !== 'string' || !payload.peerId.trim()) {
|
|
70
|
+
return this.failed(feedback, [], 'event_session_invalid', 'event must identify the owning agent, session, and original actor');
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
eventSession = await targetSessionLookup(this.deps.sessionManager.getSessionById(payload.sessionId));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
return this.failed(feedback, [], 'target_session_setup_failed', String(error));
|
|
77
|
+
}
|
|
78
|
+
if (!eventSession || eventSession.deletedAt) {
|
|
79
|
+
return this.failed(feedback, [], 'event_session_missing', 'event source session no longer exists');
|
|
80
|
+
}
|
|
81
|
+
if (eventSession.selfAID !== eventAgentAid
|
|
82
|
+
|| (!isDaemonEventSessionTrigger(input.trigger) && eventSession.selfAID !== input.trigger.agentAid)) {
|
|
83
|
+
return this.failed(feedback, [], 'event_session_agent_mismatch', 'event source session belongs to another agent');
|
|
84
|
+
}
|
|
85
|
+
const channelKey = eventSession.metadata?.channelKey ?? eventSession.channel;
|
|
86
|
+
if (!['private', 'group'].includes(eventSession.chatType) || channelTypeFromKey(channelKey) === 'daemon') {
|
|
87
|
+
return this.failed(feedback, [], 'event_session_route_invalid', 'event source is not a channel conversation');
|
|
88
|
+
}
|
|
89
|
+
if (channelTypeFromKey(channelKey) === 'aun' && typeof payload.encrypted !== 'boolean') {
|
|
90
|
+
return this.failed(feedback, [], 'event_session_encryption_missing', 'AUN event source must preserve the original encryption mode');
|
|
91
|
+
}
|
|
92
|
+
unresolvedTarget = {
|
|
93
|
+
channelKey,
|
|
94
|
+
channelId: eventSession.channelId,
|
|
95
|
+
chatType: eventSession.chatType,
|
|
96
|
+
session: eventSession.threadId ? 'thread' : 'main',
|
|
97
|
+
...(eventSession.threadId ? { threadId: eventSession.threadId } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
54
100
|
if (!unresolvedTarget)
|
|
55
101
|
return this.failed(feedback, [], 'target_missing', 'target_session feedback target is missing');
|
|
56
102
|
const target = unresolvedTarget;
|
|
57
103
|
if (channelTypeFromKey(target.channelKey) === 'aun' && !targetChatType(target)) {
|
|
58
104
|
return this.failed(feedback, [], 'route_missing', 'AUN target_session has no explicit delivery route');
|
|
59
105
|
}
|
|
106
|
+
const isTaskErrorRecovery = !!eventSession && input.sourcePayload?.type === 'task:error';
|
|
107
|
+
if (isTaskErrorRecovery && (typeof input.sourcePayload?.taskId !== 'string' || !input.sourcePayload.taskId
|
|
108
|
+
|| !Number.isSafeInteger(input.sourcePayload.generation))) {
|
|
109
|
+
return this.failed(feedback, [], 'recovery_event_invalid', 'task:error must identify the original task and generation');
|
|
110
|
+
}
|
|
111
|
+
const prompt = isTaskErrorRecovery ? TASK_RECOVERY_PROMPT : input.prompt;
|
|
112
|
+
const targetAgentAid = eventSession?.selfAID ?? input.trigger.agentAid;
|
|
60
113
|
feedback.target = target;
|
|
61
|
-
feedback.renderedTextHash = sha256(
|
|
62
|
-
feedback.renderedTextPreview = previewText(
|
|
114
|
+
feedback.renderedTextHash = sha256(prompt);
|
|
115
|
+
feedback.renderedTextPreview = previewText(prompt);
|
|
63
116
|
if (input.dryRun) {
|
|
64
117
|
return { status: 'completed', feedback, effects: [], error: null };
|
|
65
118
|
}
|
|
119
|
+
if (isTaskErrorRecovery && (!this.deps.recoverTask || !this.deps.eventBus)) {
|
|
120
|
+
return this.failed(feedback, [], 'recovery_unavailable', 'task recovery and outcome tracking must be configured');
|
|
121
|
+
}
|
|
66
122
|
const delivery = new AbortController();
|
|
123
|
+
const timeoutMs = executionTimeoutMs(input.trigger.execution);
|
|
67
124
|
let abortKind;
|
|
68
125
|
const abortDelivery = (kind, reason) => {
|
|
69
126
|
if (delivery.signal.aborted)
|
|
@@ -77,33 +134,36 @@ export class TriggerFeedbackDispatcher {
|
|
|
77
134
|
input.signal?.addEventListener('abort', onInputAbort, { once: true });
|
|
78
135
|
if (input.signal?.aborted)
|
|
79
136
|
onInputAbort();
|
|
80
|
-
const deadlineTimer = setTimeout(() => abortDelivery('timeout', new
|
|
81
|
-
deadlineTimer
|
|
137
|
+
const deadlineTimer = timeoutMs === undefined ? undefined : setTimeout(() => abortDelivery('timeout', new ExecutionTimeoutError('target_session_timeout', timeoutMs)), timeoutMs);
|
|
138
|
+
deadlineTimer?.unref?.();
|
|
82
139
|
let outcome;
|
|
140
|
+
let probeTimer;
|
|
141
|
+
let probing = false;
|
|
142
|
+
let disposed = false;
|
|
83
143
|
let releaseSessionLock;
|
|
84
144
|
try {
|
|
85
145
|
if (delivery.signal.aborted) {
|
|
86
146
|
const aborted = targetSessionCancellationError(abortKind, delivery.signal.reason, false);
|
|
87
147
|
return this.failed(feedback, [], aborted.code, aborted.message);
|
|
88
148
|
}
|
|
89
|
-
const binding = this.deps.getChannel(
|
|
90
|
-
if (!binding) {
|
|
91
|
-
return this.failed(feedback, [], 'channel_not_configured', `agent ${
|
|
149
|
+
const binding = this.deps.getChannel(targetAgentAid, target.channelKey);
|
|
150
|
+
if (!binding || binding.agentAid !== targetAgentAid) {
|
|
151
|
+
return this.failed(feedback, [], 'channel_not_configured', `agent ${targetAgentAid} has no channel ${target.channelKey}`);
|
|
92
152
|
}
|
|
93
153
|
const startedAt = Date.now();
|
|
94
154
|
const channelType = channelTypeFromKey(target.channelKey);
|
|
95
155
|
let session;
|
|
96
156
|
try {
|
|
97
|
-
const existingLookup = target.session === 'thread'
|
|
157
|
+
const existingLookup = eventSession ?? (target.session === 'thread'
|
|
98
158
|
? target.threadId && this.deps.sessionManager.getThreadSession
|
|
99
159
|
? this.deps.sessionManager.getThreadSession(target.channelKey, target.channelId, target.threadId)
|
|
100
160
|
: undefined
|
|
101
161
|
: this.deps.sessionManager.getActiveSession
|
|
102
162
|
? this.deps.sessionManager.getActiveSession(target.channelKey, target.channelId)
|
|
103
|
-
: undefined;
|
|
163
|
+
: undefined);
|
|
104
164
|
const existing = existingLookup === undefined
|
|
105
165
|
? undefined
|
|
106
|
-
: await raceWithAbort(Promise.resolve(existingLookup), delivery.signal);
|
|
166
|
+
: await raceWithAbort(targetSessionLookup(Promise.resolve(existingLookup)), delivery.signal);
|
|
107
167
|
if (existing) {
|
|
108
168
|
session = existing;
|
|
109
169
|
}
|
|
@@ -114,7 +174,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
114
174
|
const mainLookup = this.deps.sessionManager.getActiveSession?.(target.channelKey, target.channelId);
|
|
115
175
|
const main = mainLookup === undefined
|
|
116
176
|
? undefined
|
|
117
|
-
: await raceWithAbort(Promise.resolve(mainLookup), delivery.signal);
|
|
177
|
+
: await raceWithAbort(targetSessionLookup(Promise.resolve(mainLookup)), delivery.signal);
|
|
118
178
|
const mainMetadata = main?.metadata;
|
|
119
179
|
const targetDelivery = targetDeliveryFor(target);
|
|
120
180
|
const chatType = targetDelivery?.chatType
|
|
@@ -126,7 +186,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
126
186
|
: mainMetadata?.groupId;
|
|
127
187
|
const peerId = mainMetadata?.peerId ?? `trigger:${input.trigger.id}`;
|
|
128
188
|
const peerType = mainMetadata?.peerType ?? 'system';
|
|
129
|
-
session = await raceWithAbort(this.deps.sessionManager.getOrCreateSession(target.channelKey, target.channelId, main?.projectPath ?? binding.projectPath, target.threadId, {
|
|
189
|
+
session = await raceWithAbort(targetSessionLookup(this.deps.sessionManager.getOrCreateSession(target.channelKey, target.channelId, main?.projectPath ?? binding.projectPath, target.threadId, {
|
|
130
190
|
channelKey: mainMetadata?.channelKey ?? target.channelKey,
|
|
131
191
|
peerId,
|
|
132
192
|
peerName: mainMetadata?.peerName ?? input.trigger.name,
|
|
@@ -134,17 +194,17 @@ export class TriggerFeedbackDispatcher {
|
|
|
134
194
|
...(groupId ? { groupId } : {}),
|
|
135
195
|
...(mainMetadata?.groupName ? { groupName: mainMetadata.groupName } : {}),
|
|
136
196
|
replyContext: replyContextFromTarget(target),
|
|
137
|
-
}, input.trigger.name, peerId, chatType, main?.baseagent ?? binding.baseagent, main?.selfAID ??
|
|
197
|
+
}, input.trigger.name, peerId, chatType, main?.baseagent ?? binding.baseagent, main?.selfAID ?? targetAgentAid, main?.channelType ?? channelType, peerType)), delivery.signal);
|
|
138
198
|
}
|
|
139
199
|
else {
|
|
140
200
|
const targetDelivery = targetDeliveryFor(target);
|
|
141
|
-
session = await raceWithAbort(this.deps.sessionManager.getOrCreateSession(target.channelKey, target.channelId, binding.projectPath, undefined, {
|
|
201
|
+
session = await raceWithAbort(targetSessionLookup(this.deps.sessionManager.getOrCreateSession(target.channelKey, target.channelId, binding.projectPath, undefined, {
|
|
142
202
|
channelKey: target.channelKey,
|
|
143
203
|
peerId: `trigger:${input.trigger.id}`,
|
|
144
204
|
peerName: input.trigger.name,
|
|
145
205
|
...(targetDelivery?.chatType === 'group' ? { groupId: targetDelivery.groupId } : {}),
|
|
146
206
|
replyContext: replyContextFromTarget(target),
|
|
147
|
-
}, input.trigger.name, undefined, targetDelivery?.chatType === 'group' ? 'group' : 'private', binding.baseagent,
|
|
207
|
+
}, input.trigger.name, undefined, targetDelivery?.chatType === 'group' ? 'group' : 'private', binding.baseagent, targetAgentAid, channelType, 'system')), delivery.signal);
|
|
148
208
|
}
|
|
149
209
|
}
|
|
150
210
|
catch (err) {
|
|
@@ -178,17 +238,23 @@ export class TriggerFeedbackDispatcher {
|
|
|
178
238
|
channel: target.channelKey,
|
|
179
239
|
channelType,
|
|
180
240
|
channelId: target.channelId,
|
|
181
|
-
selfAID:
|
|
241
|
+
selfAID: targetAgentAid,
|
|
182
242
|
baseagent: session.baseagent || binding.baseagent,
|
|
183
243
|
threadId: session.threadId || '',
|
|
184
244
|
chatType: messageChatType,
|
|
185
245
|
peerId: `trigger:${input.trigger.id}`,
|
|
186
246
|
peerName: input.trigger.name,
|
|
187
247
|
peerType: 'system',
|
|
188
|
-
content:
|
|
248
|
+
content: prompt,
|
|
189
249
|
messageId: input.attemptId,
|
|
190
250
|
timestamp: Date.now(),
|
|
191
251
|
source: 'trigger',
|
|
252
|
+
...(eventSession ? {
|
|
253
|
+
// Bind the exact session; never fall back to a newly activated main
|
|
254
|
+
// session or create a replacement for a deleted source thread.
|
|
255
|
+
boundSessionId: eventSession.id,
|
|
256
|
+
encrypted: input.sourcePayload?.encrypted,
|
|
257
|
+
} : {}),
|
|
192
258
|
causation: input.causation,
|
|
193
259
|
groupId: targetChatType === 'group' ? targetDelivery.groupId : undefined,
|
|
194
260
|
replyContext: replyContextFromTarget(target),
|
|
@@ -202,30 +268,128 @@ export class TriggerFeedbackDispatcher {
|
|
|
202
268
|
modelOverride: input.trigger.execution.model,
|
|
203
269
|
effortOverride: input.trigger.execution.effort,
|
|
204
270
|
permissionModeOverride: input.trigger.execution.permissionMode,
|
|
205
|
-
originPeerId: input.trigger.origin?.peerId,
|
|
206
|
-
originChannelKey: input.trigger.origin?.channelKey,
|
|
207
|
-
originChannelType: input.trigger.origin?.channelType
|
|
271
|
+
originPeerId: eventSession ? input.sourcePayload.peerId : input.trigger.origin?.peerId,
|
|
272
|
+
originChannelKey: eventSession ? target.channelKey : input.trigger.origin?.channelKey,
|
|
273
|
+
originChannelType: eventSession ? channelType : input.trigger.origin?.channelType
|
|
208
274
|
?? (input.trigger.origin?.channelKey ? channelTypeFromKey(input.trigger.origin.channelKey) : undefined),
|
|
209
|
-
|
|
275
|
+
...(eventSession ? { originChatType: messageChatType, originConversationId: target.channelId } : {}),
|
|
276
|
+
originControl: !eventSession && input.trigger.origin?.channelKey === 'daemon',
|
|
210
277
|
authorizedBy: input.trigger.authorizedBy,
|
|
211
278
|
},
|
|
212
279
|
};
|
|
213
280
|
outcome = this.waitForTriggerOutcome(input.runId, input.attemptId, delivery.signal);
|
|
281
|
+
let missingSince;
|
|
282
|
+
let observedTaskId;
|
|
283
|
+
let orphanNotificationOwned = false;
|
|
284
|
+
const notifyOrphan = async () => {
|
|
285
|
+
if (orphanNotificationOwned || disposed || delivery.signal.aborted)
|
|
286
|
+
return;
|
|
287
|
+
orphanNotificationOwned = true;
|
|
288
|
+
const text = '⚠️ 任务执行状态丢失,已结束本次执行。';
|
|
289
|
+
const envelope = buildEnvelope({
|
|
290
|
+
taskId: observedTaskId ?? input.attemptId, sessionId: session.id,
|
|
291
|
+
channel: target.channelKey, channelId: target.channelId,
|
|
292
|
+
agentName: binding.agentName, chatmode: 'interactive', causation: input.causation,
|
|
293
|
+
replyContext: { ...replyContextFromTarget(target), sessionId: session.id,
|
|
294
|
+
metadata: { ...session.metadata?.replyContext?.metadata,
|
|
295
|
+
...(message.encrypted !== undefined ? { encrypted: message.encrypted } : {}) } },
|
|
296
|
+
});
|
|
297
|
+
await binding.adapter.send(envelope, { kind: 'status.error',
|
|
298
|
+
metadata: { errorType: 'orphaned_target_session', message: text } });
|
|
299
|
+
await binding.adapter.send(envelope, { kind: 'result.error', reason: 'orphaned_target_session', text });
|
|
300
|
+
};
|
|
301
|
+
const inspect = async () => {
|
|
302
|
+
if (!this.deps.inspectTargetExecution || disposed || delivery.signal.aborted)
|
|
303
|
+
return undefined;
|
|
304
|
+
const observed = await targetSessionLookup(this.deps.inspectTargetExecution(session.id, input.attemptId, targetAgentAid));
|
|
305
|
+
if (disposed || delivery.signal.aborted)
|
|
306
|
+
return undefined;
|
|
307
|
+
observedTaskId = observed.taskId ?? observedTaskId;
|
|
308
|
+
if (observed.state === 'terminal') {
|
|
309
|
+
const base = { triggerId: input.trigger.id, name: input.trigger.name, runId: input.runId,
|
|
310
|
+
attemptId: input.attemptId, originTriggerId: input.trigger.id, messageId: input.attemptId,
|
|
311
|
+
targetChannel: target.channelKey, targetChannelId: target.channelId, fireTime: input.firedAt };
|
|
312
|
+
const event = observed.outcome === 'completed'
|
|
313
|
+
? { ...base, type: 'trigger:completed', durationMs: Date.now() - startedAt }
|
|
314
|
+
: observed.outcome === 'failed'
|
|
315
|
+
? { ...base, type: 'trigger:failed', error: observed.reason ?? 'target_session_failed', phase: 'execute' }
|
|
316
|
+
: { ...base, type: 'trigger:skipped', reason: observed.reason ?? 'stale_generation',
|
|
317
|
+
decisionSource: 'infrastructure', executionState: 'interrupted' };
|
|
318
|
+
outcome?.settle(event);
|
|
319
|
+
return event;
|
|
320
|
+
}
|
|
321
|
+
if (observed.state !== 'missing') {
|
|
322
|
+
missingSince = undefined;
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
missingSince ??= Date.now();
|
|
326
|
+
if (Date.now() - missingSince >= TARGET_SESSION_ORPHAN_GRACE_MS) {
|
|
327
|
+
if (!observed.hasTerminalOwner
|
|
328
|
+
|| this.deps.messageQueue.getMessageState(session.id, input.attemptId, targetAgentAid).state !== 'active') {
|
|
329
|
+
await notifyOrphan();
|
|
330
|
+
}
|
|
331
|
+
abortDelivery('cancelled', new OrphanedTargetSessionError());
|
|
332
|
+
}
|
|
333
|
+
return undefined;
|
|
334
|
+
};
|
|
335
|
+
if (this.deps.inspectTargetExecution) {
|
|
336
|
+
probeTimer = setInterval(() => {
|
|
337
|
+
if (probing || disposed)
|
|
338
|
+
return;
|
|
339
|
+
probing = true;
|
|
340
|
+
void inspect().catch(() => { missingSince = undefined; }).finally(() => { probing = false; });
|
|
341
|
+
}, TARGET_SESSION_PROBE_MS);
|
|
342
|
+
probeTimer.unref?.();
|
|
343
|
+
}
|
|
214
344
|
let enqueuePromise;
|
|
215
345
|
let event;
|
|
216
346
|
try {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
347
|
+
if (isTaskErrorRecovery) {
|
|
348
|
+
const recovery = await this.deps.recoverTask({
|
|
349
|
+
sessionId: session.id, agentAid: targetAgentAid, automatic: true,
|
|
350
|
+
expectedTaskId: input.sourcePayload.taskId,
|
|
351
|
+
expectedGeneration: input.sourcePayload.generation,
|
|
352
|
+
peerId: input.sourcePayload.peerId,
|
|
353
|
+
encrypted: input.sourcePayload.encrypted,
|
|
354
|
+
message, signal: delivery.signal,
|
|
355
|
+
});
|
|
356
|
+
if (recovery.status !== 'queued_recovery') {
|
|
357
|
+
if (delivery.signal.aborted)
|
|
358
|
+
throw delivery.signal.reason;
|
|
359
|
+
return { status: 'skipped', reason: `recovery_${recovery.status}`, feedback, effects: [], error: null };
|
|
360
|
+
}
|
|
361
|
+
if (!recovery.completion)
|
|
362
|
+
throw new Error('task recovery completion tracking is unavailable');
|
|
363
|
+
enqueuePromise = recovery.completion;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
enqueuePromise = this.deps.messageQueue.enqueue(session.id, message, session.projectPath, {
|
|
367
|
+
interruptible: false,
|
|
368
|
+
agentName: binding.agentName,
|
|
369
|
+
sessionKeyField: session.sessionKey,
|
|
370
|
+
selfAID: targetAgentAid,
|
|
371
|
+
signal: delivery.signal,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
224
374
|
if (outcome) {
|
|
225
375
|
const enqueueFailure = new Promise((_, reject) => {
|
|
226
376
|
void enqueuePromise.catch(reject);
|
|
227
377
|
});
|
|
228
|
-
|
|
378
|
+
const queueCompletion = enqueuePromise.then(async () => {
|
|
379
|
+
const terminal = await settleTriggerOutcome(outcome.promise, TARGET_SESSION_OUTCOME_GRACE_MS);
|
|
380
|
+
if (terminal)
|
|
381
|
+
return terminal;
|
|
382
|
+
if (disposed || delivery.signal.aborted)
|
|
383
|
+
return undefined;
|
|
384
|
+
const reconciled = await inspect();
|
|
385
|
+
if (reconciled)
|
|
386
|
+
return reconciled;
|
|
387
|
+
if (this.deps.inspectTargetExecution)
|
|
388
|
+
return outcome.promise;
|
|
389
|
+
await notifyOrphan();
|
|
390
|
+
throw new OrphanedTargetSessionError();
|
|
391
|
+
});
|
|
392
|
+
event = await Promise.race([outcome.promise, queueCompletion, enqueueFailure]);
|
|
229
393
|
}
|
|
230
394
|
else {
|
|
231
395
|
await raceWithAbort(enqueuePromise, delivery.signal);
|
|
@@ -261,12 +425,12 @@ export class TriggerFeedbackDispatcher {
|
|
|
261
425
|
}
|
|
262
426
|
: undefined;
|
|
263
427
|
return {
|
|
264
|
-
status: interruption ? 'skipped' : 'failed',
|
|
428
|
+
status: interruption || event.reason === 'recovery_stale' ? 'skipped' : 'failed',
|
|
265
429
|
reason: event.reason,
|
|
266
430
|
...(interruption ? { interruption } : {}),
|
|
267
431
|
feedback,
|
|
268
432
|
effects: [this.inboundEffect('success', target, session.id, startedAt)],
|
|
269
|
-
error: interruption
|
|
433
|
+
error: interruption || event.reason === 'recovery_stale'
|
|
270
434
|
? null
|
|
271
435
|
: { code: event.reason || 'target_session_skipped', message: event.reason || 'target session skipped' },
|
|
272
436
|
};
|
|
@@ -294,14 +458,17 @@ export class TriggerFeedbackDispatcher {
|
|
|
294
458
|
}
|
|
295
459
|
return {
|
|
296
460
|
status: 'failed',
|
|
297
|
-
reason: 'enqueue_error',
|
|
461
|
+
reason: err instanceof OrphanedTargetSessionError ? err.reason : 'enqueue_error',
|
|
298
462
|
feedback,
|
|
299
463
|
effects: [this.inboundEffect('failed', target, session.id, startedAt, undefined, err?.message || String(err))],
|
|
300
|
-
error: { code: 'enqueue_error', message: err?.message || String(err) },
|
|
464
|
+
error: { code: err instanceof OrphanedTargetSessionError ? err.reason : 'enqueue_error', message: err?.message || String(err) },
|
|
301
465
|
};
|
|
302
466
|
}
|
|
303
467
|
}
|
|
304
468
|
finally {
|
|
469
|
+
disposed = true;
|
|
470
|
+
if (probeTimer)
|
|
471
|
+
clearInterval(probeTimer);
|
|
305
472
|
releaseSessionLock?.();
|
|
306
473
|
clearTimeout(deadlineTimer);
|
|
307
474
|
input.signal?.removeEventListener('abort', onInputAbort);
|
|
@@ -334,7 +501,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
334
501
|
};
|
|
335
502
|
}
|
|
336
503
|
resolveDeliveryTarget(trigger) {
|
|
337
|
-
if (trigger.feedback.strategy === 'silent')
|
|
504
|
+
if (trigger.feedback.strategy === 'silent' || trigger.feedback.strategy === 'event_session')
|
|
338
505
|
return undefined;
|
|
339
506
|
if (trigger.feedback.strategy === 'target')
|
|
340
507
|
return trigger.feedback.target;
|
|
@@ -526,6 +693,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
526
693
|
if (!this.deps.eventBus)
|
|
527
694
|
return undefined;
|
|
528
695
|
let cancel = () => { };
|
|
696
|
+
let settle = (_event) => { };
|
|
529
697
|
const promise = new Promise(resolve => {
|
|
530
698
|
let settled = false;
|
|
531
699
|
const finish = (event) => {
|
|
@@ -570,8 +738,9 @@ export class TriggerFeedbackDispatcher {
|
|
|
570
738
|
if (signal?.aborted)
|
|
571
739
|
onAbort();
|
|
572
740
|
cancel = () => finish();
|
|
741
|
+
settle = event => finish(event);
|
|
573
742
|
});
|
|
574
|
-
return { promise, cancel: () => cancel() };
|
|
743
|
+
return { promise, cancel: () => cancel(), settle: event => settle(event) };
|
|
575
744
|
}
|
|
576
745
|
failed(feedback, effects, code, message) {
|
|
577
746
|
return {
|
|
@@ -751,9 +920,10 @@ function feedbackCancellation(parent, timeoutMs) {
|
|
|
751
920
|
};
|
|
752
921
|
}
|
|
753
922
|
function targetSessionCancellationError(kind, reason, barrierTimedOut) {
|
|
754
|
-
const code =
|
|
923
|
+
const code = reason instanceof OrphanedTargetSessionError ? reason.reason
|
|
924
|
+
: kind === 'timeout' ? 'target_session_timeout' : 'cancelled';
|
|
755
925
|
const base = kind === 'timeout'
|
|
756
|
-
? `target session timed out after ${
|
|
926
|
+
? `target session timed out after ${reason instanceof ExecutionTimeoutError ? reason.timeoutMs : 'unknown'}ms`
|
|
757
927
|
: reason instanceof Error
|
|
758
928
|
? reason.message
|
|
759
929
|
: 'target session delivery cancelled';
|
|
@@ -796,6 +966,21 @@ function settleWithin(promise, timeoutMs) {
|
|
|
796
966
|
promise.then(() => finish(true), () => finish(true));
|
|
797
967
|
});
|
|
798
968
|
}
|
|
969
|
+
function settleTriggerOutcome(promise, timeoutMs) {
|
|
970
|
+
return new Promise(resolve => {
|
|
971
|
+
let settled = false;
|
|
972
|
+
const finish = (value) => {
|
|
973
|
+
if (settled)
|
|
974
|
+
return;
|
|
975
|
+
settled = true;
|
|
976
|
+
clearTimeout(timer);
|
|
977
|
+
resolve(value);
|
|
978
|
+
};
|
|
979
|
+
const timer = setTimeout(() => finish(undefined), timeoutMs);
|
|
980
|
+
timer.unref?.();
|
|
981
|
+
promise.then(finish, () => finish(undefined));
|
|
982
|
+
});
|
|
983
|
+
}
|
|
799
984
|
function sleep(ms, signal) {
|
|
800
985
|
if (signal?.aborted)
|
|
801
986
|
return Promise.resolve(false);
|
|
@@ -815,3 +1000,11 @@ function sleep(ms, signal) {
|
|
|
815
1000
|
signal?.addEventListener('abort', onAbort, { once: true });
|
|
816
1001
|
});
|
|
817
1002
|
}
|
|
1003
|
+
/** Bound local session lookup/setup without limiting an admitted task's execution. */
|
|
1004
|
+
function targetSessionLookup(promise) {
|
|
1005
|
+
return new Promise((resolve, reject) => {
|
|
1006
|
+
const timer = setTimeout(() => reject(new Error('target_session_setup_timeout')), 30_000);
|
|
1007
|
+
timer.unref?.();
|
|
1008
|
+
promise.then(resolve, reject).finally(() => clearTimeout(timer));
|
|
1009
|
+
});
|
|
1010
|
+
}
|
package/dist/trigger/parser.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CronExpressionParser } from 'cron-parser';
|
|
2
2
|
const TRIGGER_UPDATE_FLAGS = new Set([
|
|
3
|
-
'once', 'delay', 'at', 'cron', 'every', 'event', 'tz',
|
|
3
|
+
'once', 'delay', 'at', 'cron', 'every', 'event', 'event-filter', 'tz',
|
|
4
4
|
'prompt', 'name', 'description',
|
|
5
|
-
'script-file', 'script-runtime', 'script-args', 'script-timeout',
|
|
5
|
+
'script-file', 'script-runtime', 'script-args', 'script-timeout', 'execution-timeout',
|
|
6
6
|
'feedback', 'target-channel', 'target-channel-id', 'target-chat-type', 'target-session', 'target-thread-id',
|
|
7
7
|
'trigger-thread', 'baseagent',
|
|
8
8
|
'on-error', 'noop-sentinel', 'retry-attempts', 'retry-backoff',
|
|
@@ -10,9 +10,9 @@ const TRIGGER_UPDATE_FLAGS = new Set([
|
|
|
10
10
|
'max-runs', 'max-duration', 'concurrency', 'missed-policy',
|
|
11
11
|
]);
|
|
12
12
|
const TRIGGER_CREATE_FLAGS = new Set([
|
|
13
|
-
'once', 'delay', 'at', 'cron', 'every', 'event', 'tz',
|
|
13
|
+
'once', 'delay', 'at', 'cron', 'every', 'event', 'event-filter', 'tz',
|
|
14
14
|
'exec', 'prompt', 'name', 'agent',
|
|
15
|
-
'script-path', 'script-runtime', 'script-args', 'script-timeout',
|
|
15
|
+
'script-path', 'script-runtime', 'script-args', 'script-timeout', 'execution-timeout',
|
|
16
16
|
'feedback', 'target-channel', 'target-channel-id', 'target-chat-type', 'target-session', 'target-thread-id',
|
|
17
17
|
'trigger-thread', 'baseagent',
|
|
18
18
|
'model', 'effort', 'permission', 'max-runs', 'max-duration',
|
|
@@ -205,7 +205,9 @@ function parseFeedbackStrategy(flags) {
|
|
|
205
205
|
return { ok: false, error: '--feedback 不能为空' };
|
|
206
206
|
if (raw === 'origin' || raw === 'target' || raw === 'silent')
|
|
207
207
|
return { ok: true, value: raw };
|
|
208
|
-
|
|
208
|
+
if (raw === 'event-session' || raw === 'event_session')
|
|
209
|
+
return { ok: true, value: 'event_session' };
|
|
210
|
+
return { ok: false, error: '--feedback 只接受 origin、target、event-session 或 silent' };
|
|
209
211
|
}
|
|
210
212
|
function parseTriggerThread(flags) {
|
|
211
213
|
if (!flags.has('trigger-thread'))
|
|
@@ -298,6 +300,24 @@ function parseSourceFlags(flags, opts = {}) {
|
|
|
298
300
|
return { ok: false, error: '--event 不能为空' };
|
|
299
301
|
return { ok: true, scheduleType: 'event', scheduleValue: raw };
|
|
300
302
|
}
|
|
303
|
+
function parseEventFilterFlag(flags) {
|
|
304
|
+
if (!flags.has('event-filter'))
|
|
305
|
+
return { ok: true };
|
|
306
|
+
const raw = flags.get('event-filter');
|
|
307
|
+
if (!raw || raw === true)
|
|
308
|
+
return { ok: false, error: '--event-filter 不能为空' };
|
|
309
|
+
let value;
|
|
310
|
+
try {
|
|
311
|
+
value = JSON.parse(raw);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return { ok: false, error: '--event-filter 必须是合法的 JSON 对象' };
|
|
315
|
+
}
|
|
316
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
317
|
+
return { ok: false, error: '--event-filter 必须是合法的 JSON 对象' };
|
|
318
|
+
}
|
|
319
|
+
return { ok: true, value: value };
|
|
320
|
+
}
|
|
301
321
|
function commonParsed(flags, opts = {}) {
|
|
302
322
|
const deprecated = rejectDeprecatedFlags(flags);
|
|
303
323
|
if (deprecated)
|
|
@@ -311,6 +331,12 @@ function commonParsed(flags, opts = {}) {
|
|
|
311
331
|
const source = parseSourceFlags(flags, opts);
|
|
312
332
|
if (!source.ok)
|
|
313
333
|
return source;
|
|
334
|
+
const eventFilter = parseEventFilterFlag(flags);
|
|
335
|
+
if (!eventFilter.ok)
|
|
336
|
+
return eventFilter;
|
|
337
|
+
if (flags.has('event-filter') && source.scheduleType !== 'event' && (!opts.update || source.scheduleType !== undefined)) {
|
|
338
|
+
return { ok: false, error: '--event-filter 只能和 --event 一起使用' };
|
|
339
|
+
}
|
|
314
340
|
if (flags.has('tz') && source.scheduleType !== 'cron' && (!opts.update || source.scheduleType !== undefined)) {
|
|
315
341
|
return { ok: false, error: '--tz 只能和 --cron 一起使用' };
|
|
316
342
|
}
|
|
@@ -329,6 +355,11 @@ function commonParsed(flags, opts = {}) {
|
|
|
329
355
|
const scriptTimeout = parseDurationFlag(flags, 'script-timeout', '--script-timeout');
|
|
330
356
|
if (!scriptTimeout.ok)
|
|
331
357
|
return scriptTimeout;
|
|
358
|
+
const executionTimeout = opts.update && flags.get('execution-timeout') === 'default'
|
|
359
|
+
? { ok: true, value: undefined }
|
|
360
|
+
: parseDurationFlag(flags, 'execution-timeout', '--execution-timeout');
|
|
361
|
+
if (!executionTimeout.ok)
|
|
362
|
+
return executionTimeout;
|
|
332
363
|
const maxRuns = parsePositiveIntegerFlag(flags, 'max-runs', '--max-runs');
|
|
333
364
|
if (!maxRuns.ok)
|
|
334
365
|
return maxRuns;
|
|
@@ -418,10 +449,18 @@ function commonParsed(flags, opts = {}) {
|
|
|
418
449
|
}
|
|
419
450
|
const targetSessionValue = targetSession.value ?? (targetThreadId ? 'thread' : 'main');
|
|
420
451
|
const feedbackStrategy = feedback.value ?? (hasTargetField ? 'target' : 'origin');
|
|
452
|
+
if (feedbackStrategy === 'event_session') {
|
|
453
|
+
if (hasTargetField)
|
|
454
|
+
return { ok: false, error: '--feedback event-session 不能指定固定 target 字段' };
|
|
455
|
+
if (!opts.update && (source.scheduleType !== 'event' || inferredExecution !== 'target_session')) {
|
|
456
|
+
return { ok: false, error: '--feedback event-session 需要 --event 和 --exec target-session' };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
421
459
|
return {
|
|
422
460
|
ok: true,
|
|
423
461
|
value: {
|
|
424
462
|
...source,
|
|
463
|
+
eventFilter: eventFilter.value,
|
|
425
464
|
executionType: execution.value,
|
|
426
465
|
inferredExecution,
|
|
427
466
|
feedbackStrategy,
|
|
@@ -437,6 +476,7 @@ function commonParsed(flags, opts = {}) {
|
|
|
437
476
|
scriptRuntime: scriptRuntime,
|
|
438
477
|
scriptArgs,
|
|
439
478
|
scriptTimeoutMs: scriptTimeout.value,
|
|
479
|
+
executionTimeoutMs: executionTimeout.value,
|
|
440
480
|
triggerThread: triggerThread.value,
|
|
441
481
|
baseagent: baseagent.value,
|
|
442
482
|
maxRuns: maxRuns.value,
|
|
@@ -462,6 +502,7 @@ export function parseTriggerSet(args) {
|
|
|
462
502
|
scheduleType: value.scheduleType,
|
|
463
503
|
scheduleValue: value.scheduleValue ?? '',
|
|
464
504
|
timezone: value.timezone,
|
|
505
|
+
eventFilter: value.eventFilter,
|
|
465
506
|
executionType: value.inferredExecution,
|
|
466
507
|
feedbackStrategy: value.feedbackStrategy,
|
|
467
508
|
targetChannel: value.targetChannel,
|
|
@@ -476,6 +517,7 @@ export function parseTriggerSet(args) {
|
|
|
476
517
|
scriptRuntime: value.scriptRuntime,
|
|
477
518
|
scriptArgs: value.scriptArgs,
|
|
478
519
|
scriptTimeoutMs: value.scriptTimeoutMs,
|
|
520
|
+
executionTimeoutMs: value.executionTimeoutMs,
|
|
479
521
|
triggerThread: value.triggerThread,
|
|
480
522
|
baseagent: value.baseagent,
|
|
481
523
|
maxRuns: value.maxRuns,
|
|
@@ -502,6 +544,7 @@ export function parseTriggerSetArgv(args, opts = {}) {
|
|
|
502
544
|
scheduleType: value.scheduleType,
|
|
503
545
|
scheduleValue: value.scheduleValue ?? '',
|
|
504
546
|
timezone: value.timezone,
|
|
547
|
+
eventFilter: value.eventFilter,
|
|
505
548
|
executionType: value.inferredExecution,
|
|
506
549
|
feedbackStrategy: value.feedbackStrategy,
|
|
507
550
|
targetChannel: value.targetChannel,
|
|
@@ -516,6 +559,7 @@ export function parseTriggerSetArgv(args, opts = {}) {
|
|
|
516
559
|
scriptRuntime: value.scriptRuntime,
|
|
517
560
|
scriptArgs: value.scriptArgs,
|
|
518
561
|
scriptTimeoutMs: value.scriptTimeoutMs,
|
|
562
|
+
executionTimeoutMs: value.executionTimeoutMs,
|
|
519
563
|
triggerThread: value.triggerThread,
|
|
520
564
|
baseagent: value.baseagent,
|
|
521
565
|
maxRuns: value.maxRuns,
|
|
@@ -625,6 +669,10 @@ function parseTriggerUpdateFlags(nameOrId, flags, opts = {}) {
|
|
|
625
669
|
update.scriptFile = scriptFile.value;
|
|
626
670
|
if (value.model !== undefined)
|
|
627
671
|
update.model = value.model;
|
|
672
|
+
if (flags.get('execution-timeout') === 'default')
|
|
673
|
+
update.executionTimeoutMs = null;
|
|
674
|
+
else if (value.executionTimeoutMs !== undefined)
|
|
675
|
+
update.executionTimeoutMs = value.executionTimeoutMs;
|
|
628
676
|
if (value.effort !== undefined)
|
|
629
677
|
update.effort = value.effort;
|
|
630
678
|
if (value.permissionMode !== undefined)
|
|
@@ -659,6 +707,8 @@ function parseTriggerUpdateFlags(nameOrId, flags, opts = {}) {
|
|
|
659
707
|
update.description = description.value || null;
|
|
660
708
|
if (flags.has('feedback') && value.feedbackStrategy !== undefined)
|
|
661
709
|
update.feedback = value.feedbackStrategy;
|
|
710
|
+
if (flags.has('event-filter'))
|
|
711
|
+
update.eventFilter = value.eventFilter;
|
|
662
712
|
if (value.targetChannel !== undefined)
|
|
663
713
|
update.targetChannel = value.targetChannel;
|
|
664
714
|
if (value.targetChannelId !== undefined)
|
package/dist/trigger/patch.js
CHANGED
|
@@ -5,8 +5,10 @@ const PATCH_KEYS = new Set([
|
|
|
5
5
|
'scheduleType',
|
|
6
6
|
'scheduleValue',
|
|
7
7
|
'timezone',
|
|
8
|
+
'eventFilter',
|
|
8
9
|
'prompt',
|
|
9
10
|
'model',
|
|
11
|
+
'executionTimeoutMs',
|
|
10
12
|
'effort',
|
|
11
13
|
'permissionMode',
|
|
12
14
|
'maxRuns',
|
|
@@ -56,6 +58,8 @@ export function applyTriggerPatch(definition, input, opts = {}) {
|
|
|
56
58
|
}
|
|
57
59
|
if (patch.model !== undefined)
|
|
58
60
|
setOptional(updated.execution, 'model', patch.model);
|
|
61
|
+
if (patch.executionTimeoutMs !== undefined)
|
|
62
|
+
setOptional(updated.execution, 'timeoutMs', patch.executionTimeoutMs);
|
|
59
63
|
if (patch.effort !== undefined)
|
|
60
64
|
setOptional(updated.execution, 'effort', patch.effort);
|
|
61
65
|
if (patch.permissionMode !== undefined)
|
|
@@ -226,6 +230,11 @@ function applySourcePatch(updated, patch) {
|
|
|
226
230
|
else
|
|
227
231
|
updated.source.timezone = String(patch.timezone);
|
|
228
232
|
}
|
|
233
|
+
if (patch.eventFilter !== undefined) {
|
|
234
|
+
if (updated.source.type !== 'event')
|
|
235
|
+
throw new Error('eventFilter is only valid for an event trigger');
|
|
236
|
+
updated.source.filter = patch.eventFilter;
|
|
237
|
+
}
|
|
229
238
|
}
|
|
230
239
|
function sourceFromSchedule(type, value) {
|
|
231
240
|
switch (type) {
|