2 Commits
Author SHA1 Message Date
Algis DumbrisandClaude Opus 4.6 7848911a5f fix: ignore system DMs in reactor — prevent stalemate notification cascade
Release / Build darwin/amd64 (push) Canceled after 0s
Release / Build linux/amd64 (push) Canceled after 0s
Release / Build darwin/arm64 (push) Canceled after 0s
Release / Build linux/arm64 (push) Canceled after 0s
Release / Generate Homebrew Formula (push) Canceled after 0s
Release / GitHub Release (push) Canceled after 0s
Release / Docker Image (push) Canceled after 0s
Release / Publish to MCP Registry (push) Canceled after 0s
The StaleWorker sends DMs from 'system' to all channel members when
workflow messages are stuck in 'proposed' state. These DMs were
triggering reactive agent runs, which couldn't action the stale
messages, burning daily budget on wasted K8s Jobs.

Now: reactor silently ignores all messages from 'system' sender.
System notifications are for human review, not agent action.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 08:56:37 +02:00
Algis DumbrisandClaude Opus 4.6 4b8c574096 fix: Agent Runs page stuck on Loading — use $effect instead of onMount
Release / Build darwin/amd64 (push) Canceled after 0s
Release / Build linux/amd64 (push) Canceled after 0s
Release / Build darwin/arm64 (push) Canceled after 0s
Release / Build linux/arm64 (push) Canceled after 0s
Release / Generate Homebrew Formula (push) Canceled after 0s
Release / GitHub Release (push) Canceled after 0s
Release / Docker Image (push) Canceled after 0s
Release / Publish to MCP Registry (push) Canceled after 0s
The onMount + async pattern wasn't triggering Svelte 5 reactivity
properly. Switched to $effect with $user dependency (same pattern
used by Sidebar and other components). Also waits for auth before
loading data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 08:30:36 +02:00
3 changed files with 32 additions and 15 deletions
+7
View File
@@ -75,6 +75,13 @@ func (r *Reactor) Dispatch(ctx context.Context, event dispatcher.MessageEvent) e
// evaluateTrigger runs the decision chain for a single agent.
func (r *Reactor) evaluateTrigger(ctx context.Context, agentName string, event dispatcher.MessageEvent) error {
// 0. Ignore system messages — stalemate worker notifications, retention warnings,
// and other automated DMs should NOT trigger reactive runs. They're notifications
// meant for the human owner, not actionable work for agents.
if event.FromAgent == "system" {
return nil
}
// 1. Get agent config
agent, err := r.agentStore.GetAgentByName(ctx, agentName)
if err != nil {
+6 -6
View File
@@ -11,30 +11,30 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Instrument+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link href="/_app/immutable/entry/start.DZCPQR8C.js" rel="modulepreload">
<link href="/_app/immutable/chunks/C-zifBrA.js" rel="modulepreload">
<link href="/_app/immutable/entry/start.C53XvHet.js" rel="modulepreload">
<link href="/_app/immutable/chunks/BYAQw6Ic.js" rel="modulepreload">
<link href="/_app/immutable/chunks/BjgrqnN-.js" rel="modulepreload">
<link href="/_app/immutable/chunks/BK7DUW2U.js" rel="modulepreload">
<link href="/_app/immutable/chunks/CslSvznw.js" rel="modulepreload">
<link href="/_app/immutable/chunks/C_dJMdcr.js" rel="modulepreload">
<link href="/_app/immutable/chunks/Du3f5uIc.js" rel="modulepreload">
<link href="/_app/immutable/chunks/B3RSY5nb.js" rel="modulepreload">
<link href="/_app/immutable/entry/app.BsYzd6w8.js" rel="modulepreload">
<link href="/_app/immutable/entry/app.1r_Gkim3.js" rel="modulepreload">
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">
<script>
{
__sveltekit_3d3whq = {
__sveltekit_1vc73p1 = {
base: ""
};
const element = document.currentScript.parentElement;
Promise.all([
import("/_app/immutable/entry/start.DZCPQR8C.js"),
import("/_app/immutable/entry/app.BsYzd6w8.js")
import("/_app/immutable/entry/start.C53XvHet.js"),
import("/_app/immutable/entry/app.1r_Gkim3.js")
]).then(([kit, app]) => {
kit.start(app, element);
});
+19 -9
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { runs } from '$lib/api/client';
import { onMount } from 'svelte';
import { user } from '$lib/stores/auth';
let runsList = $state<any[]>([]);
let total = $state(0);
@@ -9,11 +9,21 @@
let filterStatus = $state('');
let loading = $state(true);
let expandedRun = $state<number | null>(null);
let _intervalId: ReturnType<typeof setInterval> | null = null;
let _initialized = $state(false);
onMount(() => {
loadData();
const interval = setInterval(loadData, 10000);
return () => clearInterval(interval);
$effect(() => {
if (!_initialized && $user) {
_initialized = true;
loadData();
_intervalId = setInterval(loadData, 10000);
}
return () => {
if (_intervalId) {
clearInterval(_intervalId);
_intervalId = null;
}
};
});
async function loadData() {
@@ -25,8 +35,8 @@
runsList = runsRes.runs ?? [];
total = runsRes.total;
reactiveAgents = agentsRes.agents ?? [];
} catch {
// handled
} catch (e) {
console.error('Failed to load runs data:', e);
}
loading = false;
}
@@ -121,13 +131,13 @@
<!-- Filters -->
<div class="filters">
<select bind:value={filterAgent} onchange={loadData}>
<select bind:value={filterAgent} onchange={() => loadData()}>
<option value="">All agents</option>
{#each reactiveAgents as agent}
<option value={agent.name}>{agent.name}</option>
{/each}
</select>
<select bind:value={filterStatus} onchange={loadData}>
<select bind:value={filterStatus} onchange={() => loadData()}>
<option value="">All statuses</option>
<option value="running">Running</option>
<option value="succeeded">Succeeded</option>