gateway-persistent-agents
Gatewayレイヤーを使用して、ハートビート、cronスケジューリング、webhookトリガー、永続的なポリシーエンジンを備えた常時稼働するAgentを構築できます。
description の原文を見る
Build always-on agents with heartbeats, cron scheduling, webhook triggers, and a persistent policy engine using the Gateway layer.
SKILL.md 本文
Gateway — 永続的なエージェント
エージェントの目的
必要な永続化パターン用に .withGateway() が正しく設定されたビルダーを生成し、エージェントを起動して正常にシャットダウンします。
このスキルを読み込む場合
- エージェントが継続的に実行される、またはスケジュール通りに人間のトリガーなしで実行される必要がある
- クーロンベースの自動化エージェントを構築している
- エージェントが外部システムからのウェブフックイベントに応答する
- エージェントが日次トークン/アクションバジェットとポリシー実行が必要である
実装ベースライン
import { ReactiveAgents } from "@reactive-agents/runtime";
const agent = await ReactiveAgents.create()
.withName("monitor")
.withProvider("anthropic")
.withReasoning({ defaultStrategy: "reactive", maxIterations: 8 })
.withTools({ allowedTools: ["web-search", "http-get"] })
.withGateway({
heartbeat: {
intervalMs: 1_800_000, // 30 minutes
policy: "adaptive", // skip if no new work
instruction: "Check for new alerts and summarize",
},
crons: [
{
schedule: "0 9 * * MON-FRI", // 9am weekdays
instruction: "Generate daily status report",
priority: "normal",
},
],
policies: {
dailyTokenBudget: 50_000,
maxActionsPerHour: 20,
},
})
.withCostTracking({ daily: 5.0 })
.withObservability({ verbosity: "normal" })
.withHealthCheck()
.build();
// Start the persistent loop
const handle = await agent.start();
// Graceful shutdown
process.on("SIGINT", async () => {
const summary = await handle.stop();
console.log(`Ran ${summary.totalRuns} times, ${summary.heartbeatsFired} heartbeats`);
process.exit(0);
});
主要なパターン
ハートビートポリシー
heartbeat: {
intervalMs: 3_600_000, // 1 hour
policy: "always", // always run regardless of activity
// policy: "adaptive" // skip if agent has nothing useful to do (default)
// policy: "conservative" // only run on explicit triggers
instruction: "Review incoming messages and respond to urgent ones",
maxConsecutiveSkips: 5, // stop skipping after 5 consecutive no-ops
}
クーロンスケジューリング
crons: [
{
schedule: "0 9 * * 1", // Every Monday at 9am (standard cron syntax)
instruction: "Review PRs and post weekly summary to Slack",
priority: "high", // "low" | "normal" | "high" | "critical"
timezone: "America/New_York",
enabled: true,
},
{
schedule: "*/15 * * * *", // Every 15 minutes
instruction: "Check for new support tickets and categorize them",
priority: "normal",
},
]
ウェブフックトリガー
webhooks: [
{
path: "/github/webhook",
adapter: "github",
secret: process.env.GITHUB_WEBHOOK_SECRET,
events: ["push", "pull_request"],
},
]
// Gateway starts an HTTP server on gateway.port (default: varies — check builder docs)
// Incoming webhooks are normalized and passed as tasks to the agent
ポリシーエンジン
policies: {
dailyTokenBudget: 100_000, // hard stop after N tokens/day
maxActionsPerHour: 50, // rate-limit proactive actions
heartbeatPolicy: "adaptive", // global override for all heartbeats
requireApprovalFor: ["file-write", "send-email"], // tools that need human approval
}
実行間での永続的なメモリ(ハートビート/クーロン間のエピソード的コンテキスト)
.withGateway({
persistMemoryAcrossRuns: true, // default: false
heartbeat: { intervalMs: 60_000, instruction: "Check for new work" },
crons: [{ schedule: "0 9 * * *", instruction: "Daily summary" }],
})
.withMemory({ tier: "enhanced", dbPath: "./memory.sqlite" })
persistMemoryAcrossRuns: true の場合、エージェントはすべてのゲートウェイ実行(ハートビート、クーロン、ウェブフック)で同じ安定した agentId を再利用します。これにより、メモリレイヤーは実行間でエピソード的コンテキストを維持できます — エージェントは前のハートビートで見たものを「記憶」し、次のクーロンを処理するときに重複した作業を避け、物語的な連続性を構築します。
永続化なし(デフォルト): 各ゲートウェイ実行は agent-name-heartbeat-1234567890 のような一意の agentId を取得するため、メモリは実行ごとに分離されます。ステートレスなチェックに適しています。
永続化あり: すべての実行が agent-name を共有するため、メモリは実行間で拡張されます。履歴を理解し、重複を避け、または物語的コンテキストを提供する必要があるエージェント(例:ダイジェストモニター、ステータストラッカー)に適しています。
GatewayOptions リファレンス
| フィールド | 型 | 備考 |
|---|---|---|
timezone | string | クーロンのデフォルトタイムゾーン(例:"America/New_York") |
persistMemoryAcrossRuns | boolean | すべてのゲートウェイ実行で同じエージェント ID を再利用し、メモリがハートビート/クーロンに拡張されるようにします。デフォルト:false |
heartbeat.intervalMs | number | デフォルト:60,000ms(1分) |
heartbeat.policy | "always"|"adaptive"|"conservative" | |
heartbeat.instruction | string | 各ハートビート用のタスクプロンプト |
heartbeat.maxConsecutiveSkips | number | N 回のノーオプ後にスキップを停止 |
crons[].schedule | string | 標準的なクーロン式 |
crons[].instruction | string | このクーロン用のタスクプロンプト |
crons[].priority | "low"|"normal"|"high"|"critical" | |
policies.dailyTokenBudget | number | 1日あたりのハードトークンキャップ |
policies.maxActionsPerHour | number | プロアクティブなアクションのレート制限 |
policies.requireApprovalFor | string[] | 人間の承認が必要なツール |
port | number | ウェブフックサーバーの HTTP ポート |
GatewaySummary(handle.stop() から)
| フィールド | 型 |
|---|---|
totalRuns | number |
heartbeatsFired | number |
cronChecks | number |
状態追跡(応用)
ゲートウェイは、すべてのポリシー決定を強化するゼロ LLM コスト状態を維持します。
type GatewayState = {
lastExecutionAt: Date | null // Enables adaptive skip
consecutiveHeartbeatSkips: number // Forces execute after N skips (safety net)
tokensUsedToday: number // For daily budget enforcement
actionsThisHour: number // For rate limit enforcement
pendingEvents: GatewayEvent[] // Queued work from webhooks
}
実行時に状態を確認します:const status = await agent.gatewayStatus()
状態追跡、ポリシー評価、および状態が決定を駆動する方法に関する完全なガイドについては、ゲートウェイ状態追跡リファレンスを参照してください。
落とし穴
.withGateway()だけでは何もしません — ループを開始するには、構築されたエージェントで.start()を呼び出す必要があります- ゲートウェイはノードプロセスを開いたままにします — シャットダウンハンドラー(
SIGINT、SIGTERM)を常に登録して、handle.stop()を呼び出します - ハートビート
intervalMsのデフォルトは 60,000ms(1分)です — 頻繁なチェックが必要ないエージェントの場合、より長い間隔を設定します - クーロン式は標準的な 5 フィールド形式(
min hour dom month dow)に従います — デプロイ前にクーロンパーサーで検証してください policies.dailyTokenBudgetは指定されたtimezoneの真夜中にリセットされます — タイムゾーンが正しく設定されていることを確認してください- ウェブフックシークレットは外部サービスが送信するものと一致する必要があります — 不一致の場合、すべてのウェブフックイベントが暗黙的に拒否されます
persistMemoryAcrossRuns: trueは.withMemory()が永続的なデータベース(例:SQLite)で有用であることが必要です — そうでない場合、メモリティアはメモリ内にデフォルト設定され、実行間でも消去されますconsecutiveHeartbeatSkipsはアダプティブモードのみです — 「always」および「conservative」モードはそれを使用しません(スキップをリセットしません)
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- tylerjrbuell
- ライセンス
- MIT
- 最終更新
- 2026/5/12
Source: https://github.com/tylerjrbuell/reactive-agents-ts / ライセンス: MIT