@aitne/daemon 0.1.9 → 0.1.11
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/dist/adapters/adapter-watchdog.d.ts +70 -0
- package/dist/adapters/adapter-watchdog.js +115 -0
- package/dist/adapters/discord.d.ts +17 -1
- package/dist/adapters/discord.js +33 -0
- package/dist/adapters/notification-manager.d.ts +27 -1
- package/dist/adapters/notification-manager.js +54 -39
- package/dist/adapters/slack-adapter.d.ts +26 -1
- package/dist/adapters/slack-adapter.js +41 -0
- package/dist/adapters/telegram-adapter.d.ts +18 -1
- package/dist/adapters/telegram-adapter.js +41 -2
- package/dist/adapters/types.d.ts +20 -0
- package/dist/adapters/whatsapp-adapter.d.ts +26 -7
- package/dist/adapters/whatsapp-adapter.js +74 -21
- package/dist/api/env-writer.d.ts +1 -0
- package/dist/api/env-writer.js +17 -7
- package/dist/api/helpers/agent-errors-registry.d.ts +5 -5
- package/dist/api/helpers/agent-errors-registry.js +5 -5
- package/dist/api/routes/agent-schedule.js +5 -1
- package/dist/api/routes/agent.js +33 -12
- package/dist/api/routes/agents/index.js +75 -16
- package/dist/api/routes/agents/views.d.ts +37 -2
- package/dist/api/routes/agents/views.js +64 -2
- package/dist/api/routes/apple-calendar.js +4 -1
- package/dist/api/routes/background-task.d.ts +22 -0
- package/dist/api/routes/background-task.js +338 -0
- package/dist/api/routes/browser-history.js +9 -1
- package/dist/api/routes/calendar.js +12 -2
- package/dist/api/routes/context/path-resolve.js +6 -1
- package/dist/api/routes/context/permissions.js +12 -2
- package/dist/api/routes/context/snapshots.js +0 -3
- package/dist/api/routes/context/write.js +3 -17
- package/dist/api/routes/dashboard/config.js +58 -12
- package/dist/api/routes/dashboard/cost-approvals.js +66 -0
- package/dist/api/routes/dashboard/notifications.js +9 -9
- package/dist/api/routes/dashboard/oauth-google.js +5 -3
- package/dist/api/routes/feedback.d.ts +3 -0
- package/dist/api/routes/feedback.js +349 -0
- package/dist/api/routes/git.js +10 -3
- package/dist/api/routes/github.js +5 -1
- package/dist/api/routes/integrations/crud-patch.js +5 -1
- package/dist/api/routes/integrations-reconcile.js +2 -2
- package/dist/api/routes/mcp.js +65 -13
- package/dist/api/routes/notion.d.ts +1 -1
- package/dist/api/routes/observations.js +7 -7
- package/dist/api/routes/obsidian.d.ts +1 -1
- package/dist/api/routes/receipts.js +5 -1
- package/dist/api/routes/setup-migrate.js +1 -1
- package/dist/api/routes/setup.js +1 -1
- package/dist/api/routes/task-flows.d.ts +1 -1
- package/dist/api/routes/task-flows.js +1 -1
- package/dist/api/routes/tuning.d.ts +29 -0
- package/dist/api/routes/tuning.js +304 -0
- package/dist/api/server.d.ts +44 -16
- package/dist/api/server.js +12 -0
- package/dist/bootstrap/adapters.d.ts +19 -0
- package/dist/bootstrap/adapters.js +61 -0
- package/dist/bootstrap/api.d.ts +5 -3
- package/dist/bootstrap/api.js +45 -13
- package/dist/bootstrap/catchup.d.ts +1 -1
- package/dist/bootstrap/catchup.js +11 -11
- package/dist/bootstrap/event-pipeline.d.ts +11 -0
- package/dist/bootstrap/event-pipeline.js +246 -8
- package/dist/bootstrap/observers.js +9 -6
- package/dist/bootstrap/schedule-helpers.d.ts +104 -6
- package/dist/bootstrap/schedule-helpers.js +172 -19
- package/dist/config.js +32 -12
- package/dist/core/agent-core.d.ts +33 -1
- package/dist/core/agent-core.js +36 -1
- package/dist/core/agents/activity-scan-cadence.d.ts +103 -0
- package/dist/core/agents/activity-scan-cadence.js +127 -0
- package/dist/core/agents/agent-route-override.d.ts +53 -0
- package/dist/core/agents/agent-route-override.js +69 -0
- package/dist/core/agents/builtin-registry.d.ts +51 -14
- package/dist/core/agents/builtin-registry.js +92 -15
- package/dist/core/agents/config-gate-reconcile.d.ts +38 -0
- package/dist/core/agents/config-gate-reconcile.js +51 -0
- package/dist/core/agents/cron-substitute.d.ts +1 -1
- package/dist/core/agents/cron-substitute.js +1 -1
- package/dist/core/agents/custom-routine-migration.d.ts +60 -0
- package/dist/core/agents/custom-routine-migration.js +149 -0
- package/dist/core/agents/firing-blocked.d.ts +1 -1
- package/dist/core/agents/hourly-cadence.d.ts +102 -0
- package/dist/core/agents/hourly-cadence.js +126 -0
- package/dist/core/agents/loader-boot.js +23 -0
- package/dist/core/agents/loader.d.ts +19 -0
- package/dist/core/agents/loader.js +34 -2
- package/dist/core/agents/override-merge.d.ts +1 -1
- package/dist/core/agents/override-merge.js +9 -1
- package/dist/core/agents/recurrence-convert.d.ts +1 -1
- package/dist/core/agents/recurrence-convert.js +1 -1
- package/dist/core/agents/recurring-schedule-adapter.js +8 -0
- package/dist/core/alerts.js +6 -6
- package/dist/core/backends/auth-health-monitor.d.ts +2 -2
- package/dist/core/backends/auth-health-monitor.js +1 -1
- package/dist/core/backends/backend-router.d.ts +27 -1
- package/dist/core/backends/backend-router.js +165 -1
- package/dist/core/backends/claude-code-core.d.ts +71 -31
- package/dist/core/backends/claude-code-core.js +282 -54
- package/dist/core/backends/cli-quota-guards.d.ts +29 -1
- package/dist/core/backends/cli-quota-guards.js +40 -5
- package/dist/core/backends/codex-core.d.ts +6 -0
- package/dist/core/backends/codex-core.js +22 -6
- package/dist/core/backends/failure-spend.d.ts +58 -0
- package/dist/core/backends/failure-spend.js +137 -0
- package/dist/core/backends/gemini-cli-core.d.ts +6 -0
- package/dist/core/backends/gemini-cli-core.js +38 -6
- package/dist/core/backends/model-registry.d.ts +1 -1
- package/dist/core/backends/model-registry.js +4 -4
- package/dist/core/backends/opencode-core.d.ts +1 -1
- package/dist/core/backends/opencode-core.js +5 -5
- package/dist/core/backends/plan-presets.js +47 -18
- package/dist/core/bang-commands/commands-cost.js +3 -1
- package/dist/core/bang-commands/commands-report.js +4 -3
- package/dist/core/bang-commands/commands-research.js +4 -1
- package/dist/core/bang-commands/commands-revert-tuning.d.ts +18 -0
- package/dist/core/bang-commands/commands-revert-tuning.js +63 -0
- package/dist/core/bang-commands/commands-stop-start.js +3 -3
- package/dist/core/bang-commands/commands-task-control.d.ts +19 -0
- package/dist/core/bang-commands/commands-task-control.js +147 -0
- package/dist/core/bang-commands/commands-wiki.js +5 -5
- package/dist/core/bang-commands/index.d.ts +2 -0
- package/dist/core/bang-commands/index.js +12 -0
- package/dist/core/bang-commands/registry.d.ts +12 -0
- package/dist/core/browser-history/research-cluster-fanout.d.ts +28 -14
- package/dist/core/browser-history/research-cluster-fanout.js +39 -16
- package/dist/core/channel-timeline.d.ts +5 -1
- package/dist/core/channel-timeline.js +13 -0
- package/dist/core/context/index-reconciler.js +5 -2
- package/dist/core/context/policy-index-reconciler.d.ts +6 -4
- package/dist/core/context/policy-index-runner.js +25 -6
- package/dist/core/context-builder-calendar.js +10 -2
- package/dist/core/context-builder-conversation.d.ts +8 -1
- package/dist/core/context-builder-conversation.js +41 -7
- package/dist/core/context-builder-yesterday.js +4 -3
- package/dist/core/context-builder.d.ts +7 -2
- package/dist/core/context-builder.js +193 -5
- package/dist/core/context-file-serializer.d.ts +1 -1
- package/dist/core/context-file-serializer.js +1 -1
- package/dist/core/context-health.js +2 -2
- package/dist/core/context-paths.d.ts +11 -1
- package/dist/core/context-paths.js +17 -1
- package/dist/core/context-validation/prepare-write.js +1 -1
- package/dist/core/context-validation/routine-rulebook.d.ts +1 -1
- package/dist/core/context-vault-aliases.d.ts +0 -13
- package/dist/core/context-vault-aliases.js +37 -0
- package/dist/core/custom-routines.d.ts +99 -0
- package/dist/core/custom-routines.js +187 -0
- package/dist/core/daemon-api-cli.js +50 -1
- package/dist/core/day-boundary.d.ts +46 -0
- package/dist/core/day-boundary.js +40 -0
- package/dist/core/dispatcher-activity-scan.d.ts +221 -0
- package/dist/core/dispatcher-activity-scan.js +775 -0
- package/dist/core/dispatcher-error-handling.d.ts +6 -11
- package/dist/core/dispatcher-error-handling.js +38 -62
- package/dist/core/dispatcher-hourly-check.js +6 -1
- package/dist/core/dispatcher-message-handler.d.ts +10 -0
- package/dist/core/dispatcher-message-handler.js +24 -0
- package/dist/core/dispatcher-morning-routine.d.ts +6 -6
- package/dist/core/dispatcher-morning-routine.js +13 -13
- package/dist/core/dispatcher-result-processor.d.ts +33 -0
- package/dist/core/dispatcher-result-processor.js +167 -11
- package/dist/core/dispatcher-scheduled-background-task.d.ts +42 -0
- package/dist/core/dispatcher-scheduled-background-task.js +89 -0
- package/dist/core/dispatcher-scheduled-tasks.d.ts +104 -1
- package/dist/core/dispatcher-scheduled-tasks.js +480 -8
- package/dist/core/dispatcher-task-delivery.d.ts +105 -0
- package/dist/core/dispatcher-task-delivery.js +555 -0
- package/dist/core/dispatcher-types.d.ts +48 -9
- package/dist/core/dispatcher-types.js +3 -3
- package/dist/core/dispatcher.d.ts +112 -31
- package/dist/core/dispatcher.js +297 -60
- package/dist/core/dm-freshness-metrics.d.ts +1 -1
- package/dist/core/drift-effects.js +2 -2
- package/dist/core/feedback/consolidation-prep.d.ts +94 -0
- package/dist/core/feedback/consolidation-prep.js +254 -0
- package/dist/core/feedback/eviction-scorer.d.ts +81 -0
- package/dist/core/feedback/eviction-scorer.js +136 -0
- package/dist/core/feedback/lesson-format.d.ts +79 -0
- package/dist/core/feedback/lesson-format.js +199 -0
- package/dist/core/feedback/lesson-injection.d.ts +98 -0
- package/dist/core/feedback/lesson-injection.js +174 -0
- package/dist/core/feedback/lesson-merge.d.ts +51 -0
- package/dist/core/feedback/lesson-merge.js +88 -0
- package/dist/core/feedback/lesson-store-overview.d.ts +46 -0
- package/dist/core/feedback/lesson-store-overview.js +42 -0
- package/dist/core/feedback/promotion-gate.d.ts +69 -0
- package/dist/core/feedback/promotion-gate.js +117 -0
- package/dist/core/feedback/regeneralization-prep.d.ts +87 -0
- package/dist/core/feedback/regeneralization-prep.js +152 -0
- package/dist/core/feedback/scope-parser.d.ts +86 -0
- package/dist/core/feedback/scope-parser.js +141 -0
- package/dist/core/feedback/self-performance-prep.d.ts +186 -0
- package/dist/core/feedback/self-performance-prep.js +541 -0
- package/dist/core/feedback/tuning-actuator.d.ts +198 -0
- package/dist/core/feedback/tuning-actuator.js +432 -0
- package/dist/core/feedback/tuning-recommender.d.ts +247 -0
- package/dist/core/feedback/tuning-recommender.js +580 -0
- package/dist/core/feedback/tuning-revert-monitor.d.ts +90 -0
- package/dist/core/feedback/tuning-revert-monitor.js +213 -0
- package/dist/core/health-monitor.d.ts +6 -0
- package/dist/core/health-monitor.js +1 -1
- package/dist/core/injection-policy.d.ts +83 -1
- package/dist/core/injection-policy.js +61 -3
- package/dist/core/integration-main-backend.js +4 -0
- package/dist/core/management-md.d.ts +2 -2
- package/dist/core/management-md.js +51 -13
- package/dist/core/morning/orchestrator.d.ts +2 -2
- package/dist/core/morning/orchestrator.js +2 -2
- package/dist/core/notification-gate.d.ts +64 -0
- package/dist/core/notification-gate.js +51 -0
- package/dist/core/notification-rate-limit.d.ts +40 -0
- package/dist/core/notification-rate-limit.js +50 -0
- package/dist/core/policy-files.d.ts +1 -1
- package/dist/core/policy-files.js +2 -2
- package/dist/core/pre-pass-freshness.d.ts +4 -4
- package/dist/core/retention.d.ts +5 -0
- package/dist/core/retention.js +20 -4
- package/dist/core/review-context.d.ts +1 -1
- package/dist/core/review-context.js +10 -5
- package/dist/core/roadmap-write-lock.d.ts +2 -1
- package/dist/core/roadmap-write-lock.js +15 -10
- package/dist/core/routine-acquisition-plan.d.ts +47 -1
- package/dist/core/routine-acquisition-plan.js +78 -20
- package/dist/core/routine-fetch-window-retry.js +7 -4
- package/dist/core/routine-fetch-window-runner.d.ts +39 -3
- package/dist/core/routine-fetch-window-runner.js +264 -13
- package/dist/core/routine-windows.d.ts +2 -2
- package/dist/core/routine-windows.js +8 -5
- package/dist/core/scheduler.d.ts +175 -16
- package/dist/core/scheduler.js +559 -102
- package/dist/core/signal-detector.d.ts +51 -1
- package/dist/core/signal-detector.js +321 -24
- package/dist/core/skills-compiler-denied-tools.js +2 -2
- package/dist/core/skills-compiler-skill-index.d.ts +2 -2
- package/dist/core/skills-compiler-skill-index.js +2 -2
- package/dist/core/skills-compiler-variants.d.ts +1 -1
- package/dist/core/skills-compiler-variants.js +8 -0
- package/dist/core/skills-compiler.d.ts +29 -26
- package/dist/core/skills-compiler.js +117 -81
- package/dist/core/skills-manifest.d.ts +37 -0
- package/dist/core/skills-manifest.js +73 -2
- package/dist/core/sleep-inhibitor.d.ts +79 -0
- package/dist/core/sleep-inhibitor.js +132 -0
- package/dist/core/slim-system-prompt-loader.d.ts +77 -0
- package/dist/core/slim-system-prompt-loader.js +141 -0
- package/dist/core/spawn-gates.d.ts +126 -0
- package/dist/core/spawn-gates.js +180 -0
- package/dist/core/today-direct-writer.d.ts +60 -14
- package/dist/core/today-direct-writer.js +90 -13
- package/dist/core/today-write-lock.d.ts +4 -2
- package/dist/core/today-write-lock.js +30 -20
- package/dist/core/wake-detector.d.ts +55 -0
- package/dist/core/wake-detector.js +80 -0
- package/dist/core/wiki/compile-lock.d.ts +1 -1
- package/dist/core/wiki/compile-lock.js +1 -1
- package/dist/core/wiki/wiki-fts.js +13 -6
- package/dist/core/workdir.js +15 -6
- package/dist/db/activity-scan-signals.d.ts +77 -0
- package/dist/db/activity-scan-signals.js +378 -0
- package/dist/db/agents-store.d.ts +28 -0
- package/dist/db/agents-store.js +62 -0
- package/dist/db/background-task-clarifications-store.d.ts +81 -0
- package/dist/db/background-task-clarifications-store.js +152 -0
- package/dist/db/background-task-store.d.ts +207 -0
- package/dist/db/background-task-store.js +380 -0
- package/dist/db/browser-history-store.d.ts +39 -6
- package/dist/db/browser-history-store.js +51 -7
- package/dist/db/browser-task-clarifications-store.d.ts +12 -0
- package/dist/db/browser-task-clarifications-store.js +35 -5
- package/dist/db/browser-task-store.d.ts +3 -0
- package/dist/db/browser-task-store.js +29 -4
- package/dist/db/deferred-dm.d.ts +86 -0
- package/dist/db/deferred-dm.js +199 -0
- package/dist/db/feedback-signals-store.d.ts +77 -0
- package/dist/db/feedback-signals-store.js +144 -0
- package/dist/db/migrations.js +380 -0
- package/dist/db/observations.d.ts +2 -2
- package/dist/db/observations.js +3 -3
- package/dist/db/schema.js +260 -22
- package/dist/db/voice-transcripts-store.d.ts +1 -1
- package/dist/index.js +86 -29
- package/dist/messaging/browser-task-mcp-notifier.d.ts +12 -70
- package/dist/messaging/browser-task-mcp-notifier.js +30 -151
- package/dist/messaging/browser-task-screenshot-attachment.d.ts +15 -0
- package/dist/messaging/browser-task-screenshot-attachment.js +63 -0
- package/dist/observers/delegated-sync-worker.d.ts +6 -6
- package/dist/observers/delegated-sync-worker.js +10 -10
- package/dist/observers/git-delegated-cron.d.ts +1 -1
- package/dist/observers/git-delegated-cron.js +2 -2
- package/dist/observers/github-poller-classifier.d.ts +3 -3
- package/dist/observers/github-poller-classifier.js +3 -3
- package/dist/observers/imminent-event-scheduler.d.ts +1 -1
- package/dist/observers/imminent-event-scheduler.js +1 -1
- package/dist/observers/mail-poller.d.ts +1 -0
- package/dist/observers/mail-poller.js +42 -3
- package/dist/observers/observation-summarizer/summarizer-client.d.ts +2 -2
- package/dist/observers/observation-summarizer/summarizer-client.js +2 -2
- package/dist/observers/observation-summarizer/worker.d.ts +2 -2
- package/dist/observers/observation-summarizer/worker.js +4 -4
- package/dist/observers/obsidian-watcher.d.ts +1 -1
- package/dist/observers/obsidian-watcher.js +1 -1
- package/dist/safety/agent-write-tracker.d.ts +4 -4
- package/dist/safety/agent-write-tracker.js +4 -4
- package/dist/safety/always-disallowed.d.ts +1 -1
- package/dist/safety/always-disallowed.js +39 -0
- package/dist/safety/audit.d.ts +43 -5
- package/dist/safety/audit.js +86 -18
- package/dist/safety/risk-classifier.d.ts +6 -0
- package/dist/safety/risk-classifier.js +97 -18
- package/dist/scheduler/activity-scan-gate.d.ts +86 -0
- package/dist/scheduler/activity-scan-gate.js +132 -0
- package/dist/services/background-task/background-task-budget.d.ts +80 -0
- package/dist/services/background-task/background-task-budget.js +91 -0
- package/dist/services/background-task/background-task-driver.d.ts +105 -0
- package/dist/services/background-task/background-task-driver.js +416 -0
- package/dist/services/background-task/background-task-runner.d.ts +96 -0
- package/dist/services/background-task/background-task-runner.js +673 -0
- package/dist/services/background-task/background-task-tools.d.ts +84 -0
- package/dist/services/background-task/background-task-tools.js +247 -0
- package/dist/services/background-task/background-task-transition-events.d.ts +43 -0
- package/dist/services/background-task/background-task-transition-events.js +54 -0
- package/dist/services/browser-history/automation/egress-denylist.d.ts +1 -1
- package/dist/services/browser-history/automation/egress-denylist.js +34 -8
- package/dist/services/browser-history/lifecycle/platform.js +44 -2
- package/dist/services/browser-history/managed-chromium/sandbox-launcher.js +0 -1
- package/dist/services/browser-task/browser-task-runner.js +53 -8
- package/dist/services/mcp/probe.js +30 -8
- package/dist/services/observations-batch.d.ts +1 -1
- package/dist/services/observations-batch.js +2 -2
- package/dist/settings/runtime-settings.d.ts +45 -12
- package/dist/settings/runtime-settings.js +215 -40
- package/dist/settings/settings-store.js +11 -3
- package/package.json +4 -4
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity-scan cadence resolution (AGENTS_HUB_REDESIGN_PLAN.md §2).
|
|
3
|
+
*
|
|
4
|
+
* The activity-scan Agent's firing window (interval + active hours) and its
|
|
5
|
+
* observation-threshold gate live on the **agent row** —
|
|
6
|
+
* `agents.metadata_json.runtime_window`, written by `PATCH /api/agents/
|
|
7
|
+
* activity-scan` (`schedule_window` body block) and preserved across loader
|
|
8
|
+
* re-runs / `npm i -g` by `loader.ts:nextMetadata`. The `activityScan*`
|
|
9
|
+
* config keys (`hourlyCheck*` before the v0.1.11 rename) are deprecated but
|
|
10
|
+
* still parsed; they act as the per-field fallback so a value an operator
|
|
11
|
+
* persisted pre-redesign keeps working until they touch the agent-level
|
|
12
|
+
* setting.
|
|
13
|
+
*
|
|
14
|
+
* Resolution order, per field: `runtime_window` override → legacy config key
|
|
15
|
+
* (which itself carries the shipped default). Pure module — callers fetch the
|
|
16
|
+
* stored override via `agents-store.ts:getRuntimeWindow` and supply the live
|
|
17
|
+
* config; this keeps the precedence logic in the 100%-coverage set.
|
|
18
|
+
*/
|
|
19
|
+
/** Field bounds, shared by the PATCH validator and the sanitizer. */
|
|
20
|
+
export const RUNTIME_WINDOW_BOUNDS = {
|
|
21
|
+
interval_minutes: { min: 5, max: 1440 },
|
|
22
|
+
active_start_hour: { min: 0, max: 23 },
|
|
23
|
+
active_end_hour: { min: 1, max: 24 },
|
|
24
|
+
min_observations: { min: 0, max: 1000 },
|
|
25
|
+
};
|
|
26
|
+
export const RUNTIME_WINDOW_FIELDS = Object.keys(RUNTIME_WINDOW_BOUNDS);
|
|
27
|
+
/** Shipped defaults — mirror `runtime-settings.ts` (`activityScan*` keys). */
|
|
28
|
+
export const ACTIVITY_SCAN_CADENCE_DEFAULTS = {
|
|
29
|
+
intervalMinutes: 120,
|
|
30
|
+
activeStartHour: 4,
|
|
31
|
+
activeEndHour: 24,
|
|
32
|
+
minObservations: 1,
|
|
33
|
+
};
|
|
34
|
+
/** True when `value` is an integer within the field's bounds. */
|
|
35
|
+
export function isValidRuntimeWindowValue(field, value) {
|
|
36
|
+
if (typeof value !== "number" || !Number.isInteger(value))
|
|
37
|
+
return false;
|
|
38
|
+
const { min, max } = RUNTIME_WINDOW_BOUNDS[field];
|
|
39
|
+
return value >= min && value <= max;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Sanitize a raw `metadata_json.runtime_window` blob (untrusted: hand-edited
|
|
43
|
+
* DBs, older daemons). Out-of-bounds / non-integer fields are dropped — the
|
|
44
|
+
* resolver then falls back to config for them rather than failing the boot.
|
|
45
|
+
*/
|
|
46
|
+
export function parseRuntimeWindowOverride(value) {
|
|
47
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
48
|
+
return {};
|
|
49
|
+
const raw = value;
|
|
50
|
+
const out = {};
|
|
51
|
+
for (const field of RUNTIME_WINDOW_FIELDS) {
|
|
52
|
+
const v = raw[field];
|
|
53
|
+
if (isValidRuntimeWindowValue(field, v))
|
|
54
|
+
out[field] = v;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the effective cadence: per-field `runtime_window` override, else the
|
|
60
|
+
* legacy config key. A start ≥ end pairing (possible when an override touches
|
|
61
|
+
* only one side of an old config window) is repaired by widening the end to
|
|
62
|
+
* `start + 1` so `buildActivityScanCronExpr` always receives a non-empty window.
|
|
63
|
+
*/
|
|
64
|
+
/** Pick `v` when it is a finite number, else `fallback`. */
|
|
65
|
+
function num(v, fallback) {
|
|
66
|
+
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
67
|
+
}
|
|
68
|
+
export function resolveActivityScanCadence(override, config) {
|
|
69
|
+
const o = override ?? {};
|
|
70
|
+
const activeStartHour = o.active_start_hour
|
|
71
|
+
?? num(config.activityScanActiveStartHour, ACTIVITY_SCAN_CADENCE_DEFAULTS.activeStartHour);
|
|
72
|
+
let activeEndHour = o.active_end_hour
|
|
73
|
+
?? num(config.activityScanActiveEndHour, ACTIVITY_SCAN_CADENCE_DEFAULTS.activeEndHour);
|
|
74
|
+
if (activeEndHour <= activeStartHour)
|
|
75
|
+
activeEndHour = Math.min(activeStartHour + 1, 24);
|
|
76
|
+
return {
|
|
77
|
+
intervalMinutes: o.interval_minutes
|
|
78
|
+
?? num(config.activityScanIntervalMinutes, ACTIVITY_SCAN_CADENCE_DEFAULTS.intervalMinutes),
|
|
79
|
+
activeStartHour,
|
|
80
|
+
activeEndHour,
|
|
81
|
+
minObservations: o.min_observations
|
|
82
|
+
?? num(config.activityScanMinObservations, ACTIVITY_SCAN_CADENCE_DEFAULTS.minObservations),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Merge a PATCH `schedule_window` block onto the stored override. Per-field
|
|
87
|
+
* type/bounds are validated; the cross-field window check (`end > start`) runs
|
|
88
|
+
* against the post-merge **resolved** values so a partial patch can't sneak an
|
|
89
|
+
* empty window past per-field validation. `null` resets a field back to the
|
|
90
|
+
* config fallback. `cadenceChanged` tells the route whether a cron rebuild
|
|
91
|
+
* (`reloadCrons`) is needed — `min_observations` is a fire-time gate and never
|
|
92
|
+
* requires one.
|
|
93
|
+
*/
|
|
94
|
+
export function mergeRuntimeWindow(current, patch, config) {
|
|
95
|
+
const next = { ...current };
|
|
96
|
+
let cadenceChanged = false;
|
|
97
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
98
|
+
if (!RUNTIME_WINDOW_FIELDS.includes(key)) {
|
|
99
|
+
return { ok: false, field: `schedule_window.${key}`, error: "invalid_field_value" };
|
|
100
|
+
}
|
|
101
|
+
const field = key;
|
|
102
|
+
if (value === null) {
|
|
103
|
+
if (next[field] !== undefined) {
|
|
104
|
+
delete next[field];
|
|
105
|
+
if (field !== "min_observations")
|
|
106
|
+
cadenceChanged = true;
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!isValidRuntimeWindowValue(field, value)) {
|
|
111
|
+
return { ok: false, field: `schedule_window.${field}`, error: "invalid_field_value" };
|
|
112
|
+
}
|
|
113
|
+
if (next[field] !== value) {
|
|
114
|
+
next[field] = value;
|
|
115
|
+
if (field !== "min_observations")
|
|
116
|
+
cadenceChanged = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const requestedEnd = next.active_end_hour
|
|
120
|
+
?? num(config.activityScanActiveEndHour, ACTIVITY_SCAN_CADENCE_DEFAULTS.activeEndHour);
|
|
121
|
+
const requestedStart = next.active_start_hour
|
|
122
|
+
?? num(config.activityScanActiveStartHour, ACTIVITY_SCAN_CADENCE_DEFAULTS.activeStartHour);
|
|
123
|
+
if (requestedEnd <= requestedStart) {
|
|
124
|
+
return { ok: false, field: "schedule_window.active_end_hour", error: "invalid_window" };
|
|
125
|
+
}
|
|
126
|
+
return { ok: true, value: next, cadenceChanged };
|
|
127
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BackendId, ProcessModelTier } from "@aitne/shared";
|
|
2
|
+
/**
|
|
3
|
+
* Built-in Agent runtime route override (AGENT_DEFINITIONS_DESIGN.md §6.4.1,
|
|
4
|
+
* runtime wiring).
|
|
5
|
+
*
|
|
6
|
+
* A built-in Agent's Definition-tab edits land in
|
|
7
|
+
* `agents.metadata_json.override_snapshot`. Until this module existed they
|
|
8
|
+
* were display-only — routing stayed governed entirely by
|
|
9
|
+
* `process_backend_config`. `BackendRouter.resolveBinding` now calls
|
|
10
|
+
* `extractAgentRouteOverride` on the snapshot of the firing's resolved Agent
|
|
11
|
+
* (`event.data.agentId`, stamped by `Dispatcher.beginAgentExecution`) and
|
|
12
|
+
* layers the result UNDER any caller-explicit options:
|
|
13
|
+
*
|
|
14
|
+
* caller-explicit (chat picker, run-now hint, schedule row)
|
|
15
|
+
* > agent override (this module)
|
|
16
|
+
* > process_backend_config / process-key defaults
|
|
17
|
+
*
|
|
18
|
+
* Pure + dependency-light so it stays in the 100%-coverage set; the router
|
|
19
|
+
* supplies the snapshot it read from the `agents` row.
|
|
20
|
+
*/
|
|
21
|
+
export interface AgentRouteOverride {
|
|
22
|
+
/** Tier override, applied as a `requestedTier` default. */
|
|
23
|
+
tier: ProcessModelTier | null;
|
|
24
|
+
/** Model pin; when set, `backendId` names the owning backend. */
|
|
25
|
+
modelId: string | null;
|
|
26
|
+
/** Owning backend for `modelId` (stored, or inferred from the registry). */
|
|
27
|
+
backendId: BackendId | null;
|
|
28
|
+
/** Per-execution turn cap, applied onto the resolved binding. */
|
|
29
|
+
maxTurns: number | null;
|
|
30
|
+
/** Per-execution budget cap, applied onto the resolved binding. */
|
|
31
|
+
maxBudgetUsd: number | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Find the backend that owns `modelId` in the static model registry. Needed
|
|
35
|
+
* for override snapshots written before `backend.backend_id` existed (the
|
|
36
|
+
* model field was a free-text input then). Returns `null` for an id no
|
|
37
|
+
* registered backend knows — the model pin is dropped in that case rather
|
|
38
|
+
* than guessed, because executing a model id on the wrong backend fails the
|
|
39
|
+
* whole firing.
|
|
40
|
+
*/
|
|
41
|
+
export declare function inferBackendForModel(modelId: string): BackendId | null;
|
|
42
|
+
/**
|
|
43
|
+
* Extract the routing-relevant overrides from a built-in's
|
|
44
|
+
* `override_snapshot`. Returns `null` when the snapshot carries nothing that
|
|
45
|
+
* affects routing (so the router can skip the merge entirely). Values are
|
|
46
|
+
* re-guarded with the same contracts `override-merge.ts` enforces —
|
|
47
|
+
* defence-in-depth against a hand-edited snapshot; an out-of-contract value
|
|
48
|
+
* is dropped, never thrown on.
|
|
49
|
+
*
|
|
50
|
+
* A model pin without a resolvable backend (no stored `backend.backend_id`,
|
|
51
|
+
* no registry match) drops the pin but keeps the tier/limit overrides.
|
|
52
|
+
*/
|
|
53
|
+
export declare function extractAgentRouteOverride(snapshot: unknown): AgentRouteOverride | null;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AGENT_TIERS, BACKEND_IDS } from "@aitne/shared";
|
|
2
|
+
import { findRegisteredModel } from "../backends/model-registry.js";
|
|
3
|
+
function isTier(value) {
|
|
4
|
+
return typeof value === "string" && AGENT_TIERS.includes(value);
|
|
5
|
+
}
|
|
6
|
+
function isBackendId(value) {
|
|
7
|
+
return typeof value === "string" && BACKEND_IDS.includes(value);
|
|
8
|
+
}
|
|
9
|
+
function isPositiveInt(value) {
|
|
10
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
11
|
+
}
|
|
12
|
+
function isNonNegativeFinite(value) {
|
|
13
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Find the backend that owns `modelId` in the static model registry. Needed
|
|
17
|
+
* for override snapshots written before `backend.backend_id` existed (the
|
|
18
|
+
* model field was a free-text input then). Returns `null` for an id no
|
|
19
|
+
* registered backend knows — the model pin is dropped in that case rather
|
|
20
|
+
* than guessed, because executing a model id on the wrong backend fails the
|
|
21
|
+
* whole firing.
|
|
22
|
+
*/
|
|
23
|
+
export function inferBackendForModel(modelId) {
|
|
24
|
+
for (const backendId of BACKEND_IDS) {
|
|
25
|
+
if (findRegisteredModel(backendId, modelId))
|
|
26
|
+
return backendId;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extract the routing-relevant overrides from a built-in's
|
|
32
|
+
* `override_snapshot`. Returns `null` when the snapshot carries nothing that
|
|
33
|
+
* affects routing (so the router can skip the merge entirely). Values are
|
|
34
|
+
* re-guarded with the same contracts `override-merge.ts` enforces —
|
|
35
|
+
* defence-in-depth against a hand-edited snapshot; an out-of-contract value
|
|
36
|
+
* is dropped, never thrown on.
|
|
37
|
+
*
|
|
38
|
+
* A model pin without a resolvable backend (no stored `backend.backend_id`,
|
|
39
|
+
* no registry match) drops the pin but keeps the tier/limit overrides.
|
|
40
|
+
*/
|
|
41
|
+
export function extractAgentRouteOverride(snapshot) {
|
|
42
|
+
if (typeof snapshot !== "object" || snapshot === null || Array.isArray(snapshot)) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const snap = snapshot;
|
|
46
|
+
const tier = isTier(snap["backend.tier"]) ? snap["backend.tier"] : null;
|
|
47
|
+
const rawModel = snap["backend.model"];
|
|
48
|
+
let modelId = typeof rawModel === "string" && rawModel.length > 0 ? rawModel : null;
|
|
49
|
+
let backendId = null;
|
|
50
|
+
if (modelId !== null) {
|
|
51
|
+
const rawBackend = snap["backend.backend_id"];
|
|
52
|
+
backendId = isBackendId(rawBackend) ? rawBackend : inferBackendForModel(modelId);
|
|
53
|
+
if (backendId === null)
|
|
54
|
+
modelId = null;
|
|
55
|
+
}
|
|
56
|
+
const maxTurns = isPositiveInt(snap["limits.max_turns"])
|
|
57
|
+
? snap["limits.max_turns"]
|
|
58
|
+
: null;
|
|
59
|
+
const maxBudgetUsd = isNonNegativeFinite(snap["limits.max_budget_usd"])
|
|
60
|
+
? snap["limits.max_budget_usd"]
|
|
61
|
+
: null;
|
|
62
|
+
if (tier === null
|
|
63
|
+
&& modelId === null
|
|
64
|
+
&& maxTurns === null
|
|
65
|
+
&& maxBudgetUsd === null) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return { tier, modelId, backendId, maxTurns, maxBudgetUsd };
|
|
69
|
+
}
|
|
@@ -29,8 +29,8 @@ import type { ProcessKey, StopWarning } from "@aitne/shared";
|
|
|
29
29
|
*/
|
|
30
30
|
/**
|
|
31
31
|
* Resolves a built-in's cron expression from the live `dayBoundaryHour`
|
|
32
|
-
* config. `null` for the interval-gated `
|
|
33
|
-
* runtime window (`
|
|
32
|
+
* config. `null` for the interval-gated `activity-scan`, whose cadence is a
|
|
33
|
+
* runtime window (`buildActivityScanCronExpr(intervalMinutes, activeStart,
|
|
34
34
|
* activeEnd)`), not a fixed expression — the loader's drift check is a no-op
|
|
35
35
|
* for a `null` resolver (§5.5.1).
|
|
36
36
|
*/
|
|
@@ -39,8 +39,8 @@ export type CronExpressionResolver = (config: {
|
|
|
39
39
|
}) => string;
|
|
40
40
|
/**
|
|
41
41
|
* How `setupRecurringJobs` fires a built-in. NB: a non-null `processKey` does
|
|
42
|
-
* NOT imply `emit_routine`/`queue_wake` — `
|
|
43
|
-
* `routine.
|
|
42
|
+
* NOT imply `emit_routine`/`queue_wake` — `activity-scan` carries
|
|
43
|
+
* `routine.activity_scan` yet fires via `in_process_callback`.
|
|
44
44
|
*
|
|
45
45
|
* - `emit_routine` — `emitRoutine(routine, data?)` puts a `routine.<name>`
|
|
46
46
|
* event on the bus. `data` is the fixed payload the scheduler passes; the
|
|
@@ -50,7 +50,7 @@ export type CronExpressionResolver = (config: {
|
|
|
50
50
|
* baked literal would be wrong).
|
|
51
51
|
* - `queue_wake` — `queueMorningRoutineWake(...)` enqueues a durable wake
|
|
52
52
|
* row instead of a transient event (morning-routine only).
|
|
53
|
-
* - `in_process_callback` — a typed daemon callback (`
|
|
53
|
+
* - `in_process_callback` — a typed daemon callback (`onActivityScan`,
|
|
54
54
|
* `onRoadmapMaintenance`, `onContextIndexReconcile`); the last two are
|
|
55
55
|
* no-LLM passes with `processKey: null`.
|
|
56
56
|
*/
|
|
@@ -65,6 +65,35 @@ export type BuiltinSchedulerFn = {
|
|
|
65
65
|
kind: "in_process_callback";
|
|
66
66
|
callbackName: string;
|
|
67
67
|
};
|
|
68
|
+
/**
|
|
69
|
+
* Hub grouping for the `/agents` dashboard (AGENTS_HUB_REDESIGN_PLAN.md §1).
|
|
70
|
+
* Built-ins declare one of the three operational categories; user Agents are
|
|
71
|
+
* implicitly `"user"` at the API layer (not a registry value).
|
|
72
|
+
*
|
|
73
|
+
* - `synthesis` — routines that write the user-facing synthesis surfaces
|
|
74
|
+
* (today.md, journals, reviews).
|
|
75
|
+
* - `monitoring` — interval watchers that triage observations and surface
|
|
76
|
+
* activity proactively.
|
|
77
|
+
* - `maintenance` — mechanical / background upkeep passes.
|
|
78
|
+
*/
|
|
79
|
+
export declare const AGENT_CATEGORIES: readonly ["synthesis", "monitoring", "maintenance"];
|
|
80
|
+
export type AgentCategory = (typeof AGENT_CATEGORIES)[number];
|
|
81
|
+
/**
|
|
82
|
+
* A context-vault policy file a built-in reads at prompt-assembly time —
|
|
83
|
+
* its editable "rulebook" surface (AGENTS_HUB_REDESIGN_PLAN.md §1 / §4.2).
|
|
84
|
+
* The dashboard's per-agent Rulebook tab renders one editor per entry,
|
|
85
|
+
* loading/saving through the context API chokepoint (`/api/context/<path>`);
|
|
86
|
+
* the vault stays the storage, this is declaration only. Paths are the
|
|
87
|
+
* canonical class-prefixed form (`context-paths.ts`).
|
|
88
|
+
*/
|
|
89
|
+
export interface AgentPolicyFile {
|
|
90
|
+
/** Canonical vault-relative path, e.g. `policies/routines/morning.md`. */
|
|
91
|
+
path: string;
|
|
92
|
+
/** Short editor-card title, e.g. "Morning rulebook". */
|
|
93
|
+
label: string;
|
|
94
|
+
/** One-liner explaining what the file controls. */
|
|
95
|
+
description: string;
|
|
96
|
+
}
|
|
68
97
|
export interface BuiltinAgentRegistryEntry {
|
|
69
98
|
/** Kebab-case slug; also the `agents.id` and the `agent.md` directory name. */
|
|
70
99
|
slug: string;
|
|
@@ -80,7 +109,7 @@ export interface BuiltinAgentRegistryEntry {
|
|
|
80
109
|
description: string;
|
|
81
110
|
/**
|
|
82
111
|
* Cron with `{dayBoundaryHour}` / `{dayBoundaryHour-1}` resolved from live
|
|
83
|
-
* config, or `null` for the runtime-window `
|
|
112
|
+
* config, or `null` for the runtime-window `activity-scan` (§5.5.1).
|
|
84
113
|
*/
|
|
85
114
|
cronExpression: CronExpressionResolver | null;
|
|
86
115
|
/**
|
|
@@ -103,6 +132,14 @@ export interface BuiltinAgentRegistryEntry {
|
|
|
103
132
|
stopWarning: StopWarning;
|
|
104
133
|
/** The mechanism `setupRecurringJobs` uses to fire this slug. */
|
|
105
134
|
schedulerFn: BuiltinSchedulerFn;
|
|
135
|
+
/** Hub grouping for the `/agents` dashboard (see `AGENT_CATEGORIES`). */
|
|
136
|
+
category: AgentCategory;
|
|
137
|
+
/**
|
|
138
|
+
* The vault policy files this built-in reads at prompt-assembly time —
|
|
139
|
+
* surfaced as its Rulebook tab. Empty for built-ins with no editable
|
|
140
|
+
* rulebook (no-LLM passes, sweeps).
|
|
141
|
+
*/
|
|
142
|
+
policyFiles: readonly AgentPolicyFile[];
|
|
106
143
|
}
|
|
107
144
|
export declare const BUILTIN_AGENT_REGISTRY: readonly BuiltinAgentRegistryEntry[];
|
|
108
145
|
/** Slug → entry, for O(1) lookup from the loader and the scheduler gate. */
|
|
@@ -115,15 +152,15 @@ export declare function getBuiltinRegistryEntry(slug: string): BuiltinAgentRegis
|
|
|
115
152
|
export declare function isBuiltinAgentSlug(slug: string): boolean;
|
|
116
153
|
/**
|
|
117
154
|
* The live config a runtime-window built-in's cadence is resolved from. Today
|
|
118
|
-
* the only runtime-window built-in is `
|
|
119
|
-
* `
|
|
120
|
-
* `
|
|
155
|
+
* the only runtime-window built-in is `activity-scan`, whose firing window is
|
|
156
|
+
* `buildActivityScanCronExpr(intervalMinutes, activeStart, activeEnd)` — so the three
|
|
157
|
+
* `activityScan*` fields are all that's needed. A narrow shape (not the whole
|
|
121
158
|
* `AgentConfig`) keeps this module pure / coverage-friendly.
|
|
122
159
|
*/
|
|
123
160
|
export interface RuntimeWindowCadenceConfig {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
161
|
+
activityScanIntervalMinutes: number;
|
|
162
|
+
activityScanActiveStartHour: number;
|
|
163
|
+
activityScanActiveEndHour: number;
|
|
127
164
|
}
|
|
128
165
|
/**
|
|
129
166
|
* The interval cadence of a runtime-window built-in: how often it fires
|
|
@@ -146,8 +183,8 @@ export interface IntervalCadence {
|
|
|
146
183
|
*
|
|
147
184
|
* A built-in is "runtime-window" iff its registry `cronExpression` resolver is
|
|
148
185
|
* `null` — the documented marker (§5.5.1) that its cadence is owned by
|
|
149
|
-
* `
|
|
150
|
-
* is the sole such entry, so the mapping reads the `
|
|
186
|
+
* `buildActivityScanCronExpr` from live config, not a baked cron. Today `activity-scan`
|
|
187
|
+
* is the sole such entry, so the mapping reads the `activityScan*` config. A
|
|
151
188
|
* second runtime-window built-in would need its own branch here — the
|
|
152
189
|
* `cronExpression === null` gate plus this comment keep that requirement
|
|
153
190
|
* visible. Pure: the caller supplies the live config (read at request time so a
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hub grouping for the `/agents` dashboard (AGENTS_HUB_REDESIGN_PLAN.md §1).
|
|
3
|
+
* Built-ins declare one of the three operational categories; user Agents are
|
|
4
|
+
* implicitly `"user"` at the API layer (not a registry value).
|
|
5
|
+
*
|
|
6
|
+
* - `synthesis` — routines that write the user-facing synthesis surfaces
|
|
7
|
+
* (today.md, journals, reviews).
|
|
8
|
+
* - `monitoring` — interval watchers that triage observations and surface
|
|
9
|
+
* activity proactively.
|
|
10
|
+
* - `maintenance` — mechanical / background upkeep passes.
|
|
11
|
+
*/
|
|
12
|
+
export const AGENT_CATEGORIES = ["synthesis", "monitoring", "maintenance"];
|
|
1
13
|
/**
|
|
2
14
|
* Backward-wrapping hour arithmetic shared by the `{dayBoundaryHour-1}`
|
|
3
15
|
* builtins. `(dayBoundaryHour + 23) % 24` in the scheduler is the same value;
|
|
@@ -25,6 +37,28 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
25
37
|
reactivation_hint: "Re-enable from /agents/morning-routine. The next firing catches up with a broader observation window.",
|
|
26
38
|
},
|
|
27
39
|
schedulerFn: { kind: "queue_wake", routine: "morning_routine" },
|
|
40
|
+
category: "synthesis",
|
|
41
|
+
// journal-format / journal-export hang off morning-routine because the
|
|
42
|
+
// morning pipeline is their only consumer (task-flows
|
|
43
|
+
// `routine.morning_routine_{today,journal}` + the morning composers —
|
|
44
|
+
// verified 2026-06-10, AGENTS_HUB_REDESIGN_PLAN.md §1).
|
|
45
|
+
policyFiles: [
|
|
46
|
+
{
|
|
47
|
+
path: "policies/routines/morning.md",
|
|
48
|
+
label: "Morning rulebook",
|
|
49
|
+
description: "Checks and rules injected into the morning routine prompt.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
path: "policies/journal-format.md",
|
|
53
|
+
label: "Journal format",
|
|
54
|
+
description: "Template and voice rules for the daily journal synthesis.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
path: "policies/journal-export.md",
|
|
58
|
+
label: "Journal export rules",
|
|
59
|
+
description: "Redaction and inclusion rules applied when journal content is exported.",
|
|
60
|
+
},
|
|
61
|
+
],
|
|
28
62
|
},
|
|
29
63
|
{
|
|
30
64
|
slug: "evening-review",
|
|
@@ -43,6 +77,14 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
43
77
|
reactivation_hint: "Re-enable from /agents/evening-review. Resumes on the next 18:00 firing.",
|
|
44
78
|
},
|
|
45
79
|
schedulerFn: { kind: "emit_routine", routine: "evening_review" },
|
|
80
|
+
category: "synthesis",
|
|
81
|
+
policyFiles: [
|
|
82
|
+
{
|
|
83
|
+
path: "policies/routines/evening.md",
|
|
84
|
+
label: "Evening rulebook",
|
|
85
|
+
description: "Checks and rules injected into the evening review prompt.",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
46
88
|
},
|
|
47
89
|
{
|
|
48
90
|
slug: "weekly-review",
|
|
@@ -61,6 +103,14 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
61
103
|
reactivation_hint: "Re-enable from /agents/weekly-review. Resumes on the next Friday 19:00 firing.",
|
|
62
104
|
},
|
|
63
105
|
schedulerFn: { kind: "emit_routine", routine: "weekly_review" },
|
|
106
|
+
category: "synthesis",
|
|
107
|
+
policyFiles: [
|
|
108
|
+
{
|
|
109
|
+
path: "policies/routines/weekly.md",
|
|
110
|
+
label: "Weekly rulebook",
|
|
111
|
+
description: "Checks and rules injected into the weekly review prompt.",
|
|
112
|
+
},
|
|
113
|
+
],
|
|
64
114
|
},
|
|
65
115
|
{
|
|
66
116
|
slug: "monthly-review",
|
|
@@ -78,33 +128,50 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
78
128
|
"Month-end retrospective",
|
|
79
129
|
],
|
|
80
130
|
dependent_agents: [],
|
|
81
|
-
reactivation_hint: "Monthly review is opt-in (
|
|
131
|
+
reactivation_hint: "Monthly review is opt-in (off by default). Enable from /agents/monthly-review.",
|
|
82
132
|
},
|
|
83
133
|
schedulerFn: { kind: "emit_routine", routine: "monthly_review" },
|
|
134
|
+
category: "synthesis",
|
|
135
|
+
policyFiles: [
|
|
136
|
+
{
|
|
137
|
+
path: "policies/routines/monthly.md",
|
|
138
|
+
label: "Monthly rulebook",
|
|
139
|
+
description: "Checks and rules injected into the monthly review prompt.",
|
|
140
|
+
},
|
|
141
|
+
],
|
|
84
142
|
},
|
|
85
143
|
{
|
|
86
|
-
slug: "
|
|
87
|
-
name: "
|
|
144
|
+
slug: "activity-scan",
|
|
145
|
+
name: "Activity Scan",
|
|
88
146
|
description: "Triages pending observations and proactively surfaces new mail / calendar / git / notion activity each interval within active hours.",
|
|
89
|
-
// Runtime-window cadence — `
|
|
147
|
+
// Runtime-window cadence — `buildActivityScanCronExpr(...)` owns the expression,
|
|
90
148
|
// so the registry resolver is `null` and the loader's drift check skips
|
|
91
149
|
// this slug (§5.5.1). The Phase 4 YAML still carries a self-documenting
|
|
92
150
|
// literal to satisfy the schema's `cron → expression` refinement.
|
|
93
151
|
cronExpression: null,
|
|
94
|
-
processKey: "routine.
|
|
95
|
-
//
|
|
96
|
-
// `
|
|
152
|
+
processKey: "routine.activity_scan",
|
|
153
|
+
// `agents.enabled` is the single on/off switch (AGENTS_HUB_REDESIGN_PLAN.md
|
|
154
|
+
// §2 — the legacy `activityScanEnabled` config gate was unified into it; a
|
|
155
|
+
// one-time boot reconcile carries an operator's old `false` forward).
|
|
97
156
|
defaultEnabled: true,
|
|
98
157
|
stopWarning: {
|
|
99
158
|
level: "high",
|
|
100
159
|
services_lost: [
|
|
101
|
-
"
|
|
160
|
+
"Periodic observation triage",
|
|
102
161
|
"Proactive surfacing of new mail / calendar / git / notion activity",
|
|
103
162
|
],
|
|
104
163
|
dependent_agents: [],
|
|
105
|
-
reactivation_hint: "Re-enable from /agents/
|
|
164
|
+
reactivation_hint: "Re-enable from /agents/activity-scan. Resumes on the next interval tick within active hours.",
|
|
106
165
|
},
|
|
107
|
-
schedulerFn: { kind: "in_process_callback", callbackName: "
|
|
166
|
+
schedulerFn: { kind: "in_process_callback", callbackName: "onActivityScan" },
|
|
167
|
+
category: "monitoring",
|
|
168
|
+
policyFiles: [
|
|
169
|
+
{
|
|
170
|
+
path: "policies/routines/activity-scan.md",
|
|
171
|
+
label: "Activity scan rulebook",
|
|
172
|
+
description: "Checks and rules injected into the activity scan prompt.",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
108
175
|
},
|
|
109
176
|
{
|
|
110
177
|
slug: "user-profile-sweep-morning",
|
|
@@ -128,6 +195,8 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
128
195
|
routine: "user_profile_sweep",
|
|
129
196
|
data: { phase: "morning" },
|
|
130
197
|
},
|
|
198
|
+
category: "maintenance",
|
|
199
|
+
policyFiles: [],
|
|
131
200
|
},
|
|
132
201
|
{
|
|
133
202
|
slug: "user-profile-sweep-evening",
|
|
@@ -151,6 +220,8 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
151
220
|
routine: "user_profile_sweep",
|
|
152
221
|
data: { phase: "evening" },
|
|
153
222
|
},
|
|
223
|
+
category: "maintenance",
|
|
224
|
+
policyFiles: [],
|
|
154
225
|
},
|
|
155
226
|
{
|
|
156
227
|
slug: "roadmap-maintenance",
|
|
@@ -174,6 +245,8 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
174
245
|
kind: "in_process_callback",
|
|
175
246
|
callbackName: "onRoadmapMaintenance",
|
|
176
247
|
},
|
|
248
|
+
category: "maintenance",
|
|
249
|
+
policyFiles: [],
|
|
177
250
|
},
|
|
178
251
|
{
|
|
179
252
|
slug: "context-index-reconcile",
|
|
@@ -197,6 +270,8 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
197
270
|
kind: "in_process_callback",
|
|
198
271
|
callbackName: "onContextIndexReconcile",
|
|
199
272
|
},
|
|
273
|
+
category: "maintenance",
|
|
274
|
+
policyFiles: [],
|
|
200
275
|
},
|
|
201
276
|
{
|
|
202
277
|
slug: "skill-curation",
|
|
@@ -218,6 +293,8 @@ export const BUILTIN_AGENT_REGISTRY = [
|
|
|
218
293
|
// `cadence` (daily/weekly/monthly) is read from the DB at fire time, so it
|
|
219
294
|
// is intentionally absent from `data` here — see BuiltinSchedulerFn.
|
|
220
295
|
schedulerFn: { kind: "emit_routine", routine: "skill_curation" },
|
|
296
|
+
category: "maintenance",
|
|
297
|
+
policyFiles: [],
|
|
221
298
|
},
|
|
222
299
|
];
|
|
223
300
|
/** Slug → entry, for O(1) lookup from the loader and the scheduler gate. */
|
|
@@ -238,8 +315,8 @@ export function isBuiltinAgentSlug(slug) {
|
|
|
238
315
|
*
|
|
239
316
|
* A built-in is "runtime-window" iff its registry `cronExpression` resolver is
|
|
240
317
|
* `null` — the documented marker (§5.5.1) that its cadence is owned by
|
|
241
|
-
* `
|
|
242
|
-
* is the sole such entry, so the mapping reads the `
|
|
318
|
+
* `buildActivityScanCronExpr` from live config, not a baked cron. Today `activity-scan`
|
|
319
|
+
* is the sole such entry, so the mapping reads the `activityScan*` config. A
|
|
243
320
|
* second runtime-window built-in would need its own branch here — the
|
|
244
321
|
* `cronExpression === null` gate plus this comment keep that requirement
|
|
245
322
|
* visible. Pure: the caller supplies the live config (read at request time so a
|
|
@@ -250,8 +327,8 @@ export function resolveRuntimeWindowCadence(slug, config) {
|
|
|
250
327
|
if (!entry || entry.cronExpression !== null)
|
|
251
328
|
return null;
|
|
252
329
|
return {
|
|
253
|
-
interval_minutes: config.
|
|
254
|
-
active_start_hour: config.
|
|
255
|
-
active_end_hour: config.
|
|
330
|
+
interval_minutes: config.activityScanIntervalMinutes,
|
|
331
|
+
active_start_hour: config.activityScanActiveStartHour,
|
|
332
|
+
active_end_hour: config.activityScanActiveEndHour,
|
|
256
333
|
};
|
|
257
334
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
/**
|
|
3
|
+
* One-time enable-switch unification (AGENTS_HUB_REDESIGN_PLAN.md §2).
|
|
4
|
+
*
|
|
5
|
+
* Pre-redesign, two built-ins carried a SECOND on/off switch in runtime
|
|
6
|
+
* config, ANDed on top of `agents.enabled` at fire time:
|
|
7
|
+
*
|
|
8
|
+
* - `activityScanEnabled` (persisted as `hourlyCheckEnabled` before the
|
|
9
|
+
* v0.1.11 rename; default true) → activity-scan
|
|
10
|
+
* - `monthlyReviewEnabled` (default false) → monthly-review
|
|
11
|
+
*
|
|
12
|
+
* The scheduler now consults only `agents.enabled`, so an operator's
|
|
13
|
+
* non-default config value must be carried onto the agent row exactly once —
|
|
14
|
+
* otherwise an old `hourlyCheckEnabled=false` would silently re-enable the
|
|
15
|
+
* activity scan on upgrade (and an opted-in monthly review would stop firing).
|
|
16
|
+
* The legacy settings row reaches `settings.activityScanEnabled` here via
|
|
17
|
+
* `LEGACY_RUNTIME_SETTING_KEY_ALIASES` (settings-store read aliasing), so a
|
|
18
|
+
* pre-agents-hub DB upgrading straight past the rename still carries its
|
|
19
|
+
* disable forward.
|
|
20
|
+
*
|
|
21
|
+
* Boot-time, not a DB `Migration`: it must run AFTER the agents loader has
|
|
22
|
+
* seeded the rows (migrations run before the loader), and it uses the same
|
|
23
|
+
* `setEnabled` dashboard-toggle semantics (stamps `enabled_overridden_at`).
|
|
24
|
+
* Idempotent via the `runtime_state` flag; defaults produce zero changes, so
|
|
25
|
+
* a fresh install is a flagged no-op.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CONFIG_GATES_RECONCILED_KEY = "agents.config_gates_reconciled";
|
|
28
|
+
export interface ConfigGateSettings {
|
|
29
|
+
activityScanEnabled: boolean;
|
|
30
|
+
monthlyReviewEnabled: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface ConfigGateReconcileResult {
|
|
33
|
+
/** False when the runtime_state flag showed the reconcile already ran. */
|
|
34
|
+
applied: boolean;
|
|
35
|
+
/** Slugs whose `agents.enabled` was changed (empty on default configs). */
|
|
36
|
+
changes: string[];
|
|
37
|
+
}
|
|
38
|
+
export declare function reconcileConfigGates(db: Database.Database, settings: ConfigGateSettings, now?: number): ConfigGateReconcileResult;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getAgent, setEnabled } from "../../db/agents-store.js";
|
|
2
|
+
import { readRuntimeState, writeRuntimeState } from "../../db/runtime-state.js";
|
|
3
|
+
import { createLogger } from "../../logging.js";
|
|
4
|
+
const logger = createLogger("agents-config-gate-reconcile");
|
|
5
|
+
/**
|
|
6
|
+
* One-time enable-switch unification (AGENTS_HUB_REDESIGN_PLAN.md §2).
|
|
7
|
+
*
|
|
8
|
+
* Pre-redesign, two built-ins carried a SECOND on/off switch in runtime
|
|
9
|
+
* config, ANDed on top of `agents.enabled` at fire time:
|
|
10
|
+
*
|
|
11
|
+
* - `activityScanEnabled` (persisted as `hourlyCheckEnabled` before the
|
|
12
|
+
* v0.1.11 rename; default true) → activity-scan
|
|
13
|
+
* - `monthlyReviewEnabled` (default false) → monthly-review
|
|
14
|
+
*
|
|
15
|
+
* The scheduler now consults only `agents.enabled`, so an operator's
|
|
16
|
+
* non-default config value must be carried onto the agent row exactly once —
|
|
17
|
+
* otherwise an old `hourlyCheckEnabled=false` would silently re-enable the
|
|
18
|
+
* activity scan on upgrade (and an opted-in monthly review would stop firing).
|
|
19
|
+
* The legacy settings row reaches `settings.activityScanEnabled` here via
|
|
20
|
+
* `LEGACY_RUNTIME_SETTING_KEY_ALIASES` (settings-store read aliasing), so a
|
|
21
|
+
* pre-agents-hub DB upgrading straight past the rename still carries its
|
|
22
|
+
* disable forward.
|
|
23
|
+
*
|
|
24
|
+
* Boot-time, not a DB `Migration`: it must run AFTER the agents loader has
|
|
25
|
+
* seeded the rows (migrations run before the loader), and it uses the same
|
|
26
|
+
* `setEnabled` dashboard-toggle semantics (stamps `enabled_overridden_at`).
|
|
27
|
+
* Idempotent via the `runtime_state` flag; defaults produce zero changes, so
|
|
28
|
+
* a fresh install is a flagged no-op.
|
|
29
|
+
*/
|
|
30
|
+
export const CONFIG_GATES_RECONCILED_KEY = "agents.config_gates_reconciled";
|
|
31
|
+
export function reconcileConfigGates(db, settings, now = Date.now()) {
|
|
32
|
+
if (readRuntimeState(db, CONFIG_GATES_RECONCILED_KEY) !== null) {
|
|
33
|
+
return { applied: false, changes: [] };
|
|
34
|
+
}
|
|
35
|
+
const changes = [];
|
|
36
|
+
// Non-default legacy value → carry onto the agent row. Default values are
|
|
37
|
+
// left alone so the YAML/registry-shipped enabled state stays authoritative.
|
|
38
|
+
if (!settings.activityScanEnabled && getAgent(db, "activity-scan")?.enabled === true) {
|
|
39
|
+
setEnabled(db, "activity-scan", false, now, now);
|
|
40
|
+
changes.push("activity-scan");
|
|
41
|
+
}
|
|
42
|
+
if (settings.monthlyReviewEnabled && getAgent(db, "monthly-review")?.enabled === false) {
|
|
43
|
+
setEnabled(db, "monthly-review", true, now, now);
|
|
44
|
+
changes.push("monthly-review");
|
|
45
|
+
}
|
|
46
|
+
writeRuntimeState(db, CONFIG_GATES_RECONCILED_KEY, new Date(now).toISOString());
|
|
47
|
+
if (changes.length > 0) {
|
|
48
|
+
logger.info({ changes }, "Carried legacy config enable gates onto agent rows");
|
|
49
|
+
}
|
|
50
|
+
return { applied: true, changes };
|
|
51
|
+
}
|