mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(cron): suppressAgentReply flag for silent cron jobs
This commit is contained in:
parent
55f4ba1195
commit
25e93c4a89
@ -8,6 +8,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import vip.mate.audit.service.AuditEventService;
|
||||
import vip.mate.cron.model.DeliveryConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -40,6 +41,18 @@ public class CronDeliveryListener {
|
||||
@Async("cronDeliveryExecutor")
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
|
||||
public void onCompleted(CronJobCompletedEvent ev) {
|
||||
// RFC-03 Lane C1: explicit silent mode short-circuits delivery
|
||||
// resolution. Tools already executed, the run row is already
|
||||
// persisted — only the agent's narrative reply is withheld from
|
||||
// the channel. Status row stays NONE (same as "no strategy
|
||||
// matched") so dashboards keep one canonical "not delivered"
|
||||
// bucket.
|
||||
DeliveryConfig dc = ev.job() != null ? ev.job().getDeliveryConfig() : null;
|
||||
if (dc != null && dc.isAgentReplySuppressed()) {
|
||||
log.debug("[CronDelivery] Job {} suppressAgentReply=true; skipping delivery",
|
||||
ev.job().getId());
|
||||
return;
|
||||
}
|
||||
Optional<CronResultDelivery> strategy = deliveries.stream()
|
||||
.filter(d -> d.supports(ev.job()))
|
||||
.findFirst();
|
||||
|
||||
@ -33,30 +33,66 @@ public record DeliveryConfig(
|
||||
* <p>Nullable for backwards compat with rows written before this
|
||||
* field was added (V62 baseline).
|
||||
*/
|
||||
@Nullable String userId
|
||||
@Nullable String userId,
|
||||
/**
|
||||
* RFC-03 Lane C1 — when {@code TRUE}, {@code CronDeliveryListener}
|
||||
* skips strategy resolution entirely and the run completes with
|
||||
* {@code delivery_status='NONE'}. Tools still execute, the run row
|
||||
* is still persisted, audit + token-usage all work — only the
|
||||
* agent's narrative reply is suppressed from the channel.
|
||||
*
|
||||
* <p>Use cases (QwenPaw #2452): noon health-check cron that just
|
||||
* pokes a database and writes structured output, project-weekly
|
||||
* report jobs that drop a file into a knowledge base, internal
|
||||
* pipelines that don't need an IM-visible "I did the thing"
|
||||
* trailing message.
|
||||
*
|
||||
* <p>{@code Boolean} (not {@code boolean}) so JSON deserialization
|
||||
* of pre-V75 rows leaves the field {@code null} — the listener
|
||||
* treats {@code null} and {@code FALSE} identically (deliver as
|
||||
* usual), preserving every existing job's behavior.
|
||||
*/
|
||||
@Nullable Boolean suppressAgentReply
|
||||
) {
|
||||
|
||||
/** 3-arg legacy constructor preserved so older deserialized rows still work. */
|
||||
public DeliveryConfig(@Nullable String targetId,
|
||||
@Nullable String threadId,
|
||||
@Nullable String accountId) {
|
||||
this(targetId, threadId, accountId, null);
|
||||
this(targetId, threadId, accountId, null, null);
|
||||
}
|
||||
|
||||
/** 4-arg legacy constructor — pre-RFC-03 callers that already carry userId. */
|
||||
public DeliveryConfig(@Nullable String targetId,
|
||||
@Nullable String threadId,
|
||||
@Nullable String accountId,
|
||||
@Nullable String userId) {
|
||||
this(targetId, threadId, accountId, userId, null);
|
||||
}
|
||||
|
||||
/** Convert from the {@link ChannelTarget} carried on a {@code ChatOrigin}. */
|
||||
public static DeliveryConfig from(@Nullable ChannelTarget t) {
|
||||
if (t == null) return null;
|
||||
return new DeliveryConfig(t.targetId(), t.threadId(), t.accountId(), null);
|
||||
return new DeliveryConfig(t.targetId(), t.threadId(), t.accountId(), null, null);
|
||||
}
|
||||
|
||||
/** Convert from {@link ChannelTarget} + the requester's senderId. */
|
||||
public static DeliveryConfig from(@Nullable ChannelTarget t, @Nullable String userId) {
|
||||
if (t == null) return null;
|
||||
return new DeliveryConfig(t.targetId(), t.threadId(), t.accountId(), userId);
|
||||
return new DeliveryConfig(t.targetId(), t.threadId(), t.accountId(), userId, null);
|
||||
}
|
||||
|
||||
/** Convert back to a {@link ChannelTarget} for ChatOrigin reconstruction. */
|
||||
public ChannelTarget toChannelTarget() {
|
||||
return new ChannelTarget(targetId, threadId, accountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC-03 Lane C1 — convenience predicate so listeners can short-circuit
|
||||
* delivery resolution without unwrapping the {@code Boolean}. Treats
|
||||
* {@code null} as {@code false} (the historical default).
|
||||
*/
|
||||
public boolean isAgentReplySuppressed() {
|
||||
return Boolean.TRUE.equals(suppressAgentReply);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user