@aitne/daemon 0.1.10 → 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.js +8 -5
- 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.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/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/context/permissions.js +3 -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 +48 -12
- package/dist/api/routes/dashboard/cost-approvals.js +66 -0
- package/dist/api/routes/dashboard/notifications.js +9 -9
- package/dist/api/routes/integrations/crud-patch.js +5 -1
- package/dist/api/routes/integrations-reconcile.js +2 -2
- 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 +9 -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 +245 -7
- 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 +26 -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 +25 -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 +39 -15
- 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 +62 -20
- 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 +1 -1
- package/dist/core/context-paths.js +1 -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 +49 -0
- 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 +17 -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 +63 -1
- package/dist/core/dispatcher-scheduled-tasks.js +213 -6
- 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 +284 -59
- package/dist/core/dm-freshness-metrics.d.ts +1 -1
- package/dist/core/drift-effects.js +2 -2
- package/dist/core/feedback/consolidation-prep.js +17 -5
- package/dist/core/feedback/eviction-scorer.js +6 -2
- package/dist/core/feedback/lesson-format.js +9 -4
- package/dist/core/feedback/lesson-injection.d.ts +1 -1
- package/dist/core/feedback/lesson-injection.js +17 -2
- package/dist/core/feedback/lesson-store-overview.d.ts +8 -4
- package/dist/core/feedback/lesson-store-overview.js +8 -4
- package/dist/core/feedback/regeneralization-prep.js +29 -16
- 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 +4 -4
- package/dist/core/injection-policy.js +4 -4
- 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 +12 -0
- package/dist/core/signal-detector.js +53 -9
- 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 +2 -2
- package/dist/core/today-direct-writer.js +1 -1
- 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/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/migrations.js +330 -0
- package/dist/db/observations.d.ts +2 -2
- package/dist/db/observations.js +3 -3
- package/dist/db/schema.js +217 -16
- 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/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 +75 -11
- 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 +16 -6
- 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/observations-batch.d.ts +1 -1
- package/dist/services/observations-batch.js +2 -2
- package/dist/settings/runtime-settings.d.ts +38 -11
- package/dist/settings/runtime-settings.js +203 -40
- package/dist/settings/settings-store.js +11 -3
- package/package.json +4 -4
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background-task clarifications — BACKGROUND_TASK_RUNNER_DESIGN.md §6.
|
|
3
|
+
*
|
|
4
|
+
* One row per `ask_user` round-trip. The worker writes the row when it
|
|
5
|
+
* calls `ask_user`, the runner transitions the task to `awaiting_user`,
|
|
6
|
+
* and the delivery boundary surfaces the question to the owner (active
|
|
7
|
+
* delivery turn or idle draft send). The owner replies via DM; the DM
|
|
8
|
+
* agent forwards the answer through `POST /api/background-task/:id/clarify`
|
|
9
|
+
* which calls `resolveClarification` here.
|
|
10
|
+
*
|
|
11
|
+
* Deadline enforcement: a daemon housekeeping tick sweeps
|
|
12
|
+
* `WHERE resolved = 0 AND deadline_at < now()` via
|
|
13
|
+
* `listOverdueClarifications` and transitions the parent task to
|
|
14
|
+
* `timeout` (releasing the slot). The TTL is CONFIGURABLE
|
|
15
|
+
* (`backgroundTaskClarificationTtlMinutes`) and longer than
|
|
16
|
+
* browser-task's fixed 5 min — no browser resource is held while parked.
|
|
17
|
+
*
|
|
18
|
+
* I/O-bound. Excluded from the coverage gate.
|
|
19
|
+
*/
|
|
20
|
+
const SELECT_COLUMNS = `id, task_id, question, context_summary,
|
|
21
|
+
asked_at, deadline_at, delivered_at, answer, answered_at, resolved`;
|
|
22
|
+
function fromDbRow(row) {
|
|
23
|
+
return {
|
|
24
|
+
id: row.id,
|
|
25
|
+
taskId: row.task_id,
|
|
26
|
+
question: row.question,
|
|
27
|
+
contextSummary: row.context_summary,
|
|
28
|
+
askedAt: row.asked_at,
|
|
29
|
+
deadlineAt: row.deadline_at,
|
|
30
|
+
deliveredAt: row.delivered_at,
|
|
31
|
+
answer: row.answer,
|
|
32
|
+
answeredAt: row.answered_at,
|
|
33
|
+
resolved: row.resolved === 1,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function createClarification(db, input) {
|
|
37
|
+
const deadline = input.askedAt + input.ttlMs;
|
|
38
|
+
db.prepare(`INSERT INTO background_task_clarifications
|
|
39
|
+
(id, task_id, question, context_summary,
|
|
40
|
+
asked_at, deadline_at, delivered_at, answer, answered_at, resolved)
|
|
41
|
+
VALUES (?, ?, ?, ?, ?, ?, NULL, NULL, NULL, 0)`).run(input.id, input.taskId, input.question, input.contextSummary, input.askedAt, deadline);
|
|
42
|
+
const row = getClarification(db, input.id);
|
|
43
|
+
if (!row) {
|
|
44
|
+
throw new Error(`createClarification: post-insert row for ${input.id} missing`);
|
|
45
|
+
}
|
|
46
|
+
return row;
|
|
47
|
+
}
|
|
48
|
+
export function getClarification(db, id) {
|
|
49
|
+
const row = db
|
|
50
|
+
.prepare(`SELECT ${SELECT_COLUMNS} FROM background_task_clarifications WHERE id = ?`)
|
|
51
|
+
.get(id);
|
|
52
|
+
return row ? fromDbRow(row) : null;
|
|
53
|
+
}
|
|
54
|
+
export function listClarificationsForTask(db, taskId) {
|
|
55
|
+
const rows = db
|
|
56
|
+
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
57
|
+
FROM background_task_clarifications
|
|
58
|
+
WHERE task_id = ?
|
|
59
|
+
ORDER BY asked_at ASC`)
|
|
60
|
+
.all(taskId);
|
|
61
|
+
return rows.map(fromDbRow);
|
|
62
|
+
}
|
|
63
|
+
/** The most-recent unresolved clarification for a task — the one a
|
|
64
|
+
* /clarify reply without an explicit id resolves against. */
|
|
65
|
+
export function getOpenClarificationForTask(db, taskId) {
|
|
66
|
+
const row = db
|
|
67
|
+
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
68
|
+
FROM background_task_clarifications
|
|
69
|
+
WHERE task_id = ? AND resolved = 0
|
|
70
|
+
ORDER BY asked_at DESC
|
|
71
|
+
LIMIT 1`)
|
|
72
|
+
.get(taskId);
|
|
73
|
+
return row ? fromDbRow(row) : null;
|
|
74
|
+
}
|
|
75
|
+
/** CAS-resolve a clarification with the owner's answer. Refuses if
|
|
76
|
+
* already resolved (idempotent forwarding) or past deadline (the
|
|
77
|
+
* deadline scanner owns the timeout transition). */
|
|
78
|
+
export function resolveClarification(db, input) {
|
|
79
|
+
const existing = getClarification(db, input.id);
|
|
80
|
+
if (!existing)
|
|
81
|
+
return { ok: false, row: null, reason: "not_found" };
|
|
82
|
+
if (existing.resolved) {
|
|
83
|
+
return { ok: false, row: existing, reason: "already_resolved" };
|
|
84
|
+
}
|
|
85
|
+
if (input.answeredAt > existing.deadlineAt) {
|
|
86
|
+
return { ok: false, row: existing, reason: "expired" };
|
|
87
|
+
}
|
|
88
|
+
const result = db
|
|
89
|
+
.prepare(`UPDATE background_task_clarifications
|
|
90
|
+
SET answer = ?, answered_at = ?, resolved = 1
|
|
91
|
+
WHERE id = ? AND resolved = 0`)
|
|
92
|
+
.run(input.answer, input.answeredAt, input.id);
|
|
93
|
+
if (result.changes === 0) {
|
|
94
|
+
const after = getClarification(db, input.id);
|
|
95
|
+
return { ok: false, row: after, reason: "already_resolved" };
|
|
96
|
+
}
|
|
97
|
+
return { ok: true, row: getClarification(db, input.id) };
|
|
98
|
+
}
|
|
99
|
+
/** Sweep target — every unresolved clarification whose deadline has
|
|
100
|
+
* passed. The scanner transitions each parent task to `timeout`. */
|
|
101
|
+
export function listOverdueClarifications(db, nowMs) {
|
|
102
|
+
const rows = db
|
|
103
|
+
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
104
|
+
FROM background_task_clarifications
|
|
105
|
+
WHERE resolved = 0 AND deadline_at < ?
|
|
106
|
+
ORDER BY deadline_at ASC`)
|
|
107
|
+
.all(nowMs);
|
|
108
|
+
return rows.map(fromDbRow);
|
|
109
|
+
}
|
|
110
|
+
/** Mark a clarification resolved without an answer (deadline path). */
|
|
111
|
+
export function expireClarification(db, id, nowMs) {
|
|
112
|
+
const result = db
|
|
113
|
+
.prepare(`UPDATE background_task_clarifications
|
|
114
|
+
SET resolved = 1, answered_at = ?
|
|
115
|
+
WHERE id = ? AND resolved = 0`)
|
|
116
|
+
.run(nowMs, id);
|
|
117
|
+
if (result.changes === 0)
|
|
118
|
+
return null;
|
|
119
|
+
return getClarification(db, id);
|
|
120
|
+
}
|
|
121
|
+
export function markClarificationDelivered(db, id, deliveredAt) {
|
|
122
|
+
const result = db
|
|
123
|
+
.prepare(`UPDATE background_task_clarifications
|
|
124
|
+
SET delivered_at = COALESCE(delivered_at, ?)
|
|
125
|
+
WHERE id = ?`)
|
|
126
|
+
.run(deliveredAt, id);
|
|
127
|
+
return result.changes > 0 ? getClarification(db, id) : null;
|
|
128
|
+
}
|
|
129
|
+
/** Delivery recovery target — undelivered, still-open clarifications
|
|
130
|
+
* whose parent task is parked, joined with that task's delivery fields. */
|
|
131
|
+
export function listUndeliveredClarifications(db, nowMs, limit = 20) {
|
|
132
|
+
const rows = db
|
|
133
|
+
.prepare(`SELECT c.id, c.task_id, c.question, c.context_summary,
|
|
134
|
+
c.asked_at, c.deadline_at, c.delivered_at,
|
|
135
|
+
c.answer, c.answered_at, c.resolved,
|
|
136
|
+
t.originating_channel, t.title, t.brief
|
|
137
|
+
FROM background_task_clarifications c
|
|
138
|
+
JOIN background_task t ON t.id = c.task_id
|
|
139
|
+
WHERE c.resolved = 0
|
|
140
|
+
AND c.delivered_at IS NULL
|
|
141
|
+
AND c.deadline_at >= ?
|
|
142
|
+
AND t.state = 'awaiting_user'
|
|
143
|
+
ORDER BY c.asked_at ASC
|
|
144
|
+
LIMIT ?`)
|
|
145
|
+
.all(nowMs, limit);
|
|
146
|
+
return rows.map((row) => ({
|
|
147
|
+
...fromDbRow(row),
|
|
148
|
+
taskOriginatingChannel: row.originating_channel,
|
|
149
|
+
taskTitle: row.title,
|
|
150
|
+
taskBrief: row.brief,
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background-task row store — BACKGROUND_TASK_RUNNER_DESIGN.md §6.
|
|
3
|
+
*
|
|
4
|
+
* I/O-bound CRUD over `background_task`. The state machine is enforced
|
|
5
|
+
* at this layer via the CHECK constraint on the `state` column (closed
|
|
6
|
+
* set) plus the per-transition CAS helpers below — `markRunning`,
|
|
7
|
+
* `markAwaitingUser`, `markRunningFromParked`, `markTerminal` — each
|
|
8
|
+
* one's WHERE clause refuses an out-of-order write so a race between two
|
|
9
|
+
* writers cannot flip a row backwards.
|
|
10
|
+
*
|
|
11
|
+
* The genuinely new shape vs `browser_task` is the ARTIFACT: `report`
|
|
12
|
+
* (verbatim result — the fidelity anchor), `draft` (worker-authored
|
|
13
|
+
* summary), `notify` (the worker's disposition vs the spawn-time policy),
|
|
14
|
+
* `significance`, and `artifact_path`. `markTerminal` writes them in the
|
|
15
|
+
* same transition as the terminal state so a worker's `finish` (or the
|
|
16
|
+
* runner's fail-loud synthesis) is atomic.
|
|
17
|
+
*
|
|
18
|
+
* Pure decision logic (slot arithmetic) is reused from
|
|
19
|
+
* `services/browser-task/browser-task-slots.ts`; this module is the SQL
|
|
20
|
+
* wrapper and is excluded from the coverage gate (same posture as
|
|
21
|
+
* `browser-task-store.ts`).
|
|
22
|
+
*/
|
|
23
|
+
import type Database from "better-sqlite3";
|
|
24
|
+
export type BackgroundTaskState = "pending" | "running" | "awaiting_user" | "completed" | "failed" | "timeout" | "cancelled";
|
|
25
|
+
export type BackgroundTaskNotificationPolicy = "always" | "if_significant" | "silent";
|
|
26
|
+
export type BackgroundTaskTier = "lite" | "medium" | "high";
|
|
27
|
+
export declare const BACKGROUND_TASK_TERMINAL_STATES: ReadonlySet<BackgroundTaskState>;
|
|
28
|
+
export declare const BACKGROUND_TASK_NON_TERMINAL_STATES: ReadonlySet<BackgroundTaskState>;
|
|
29
|
+
export interface BackgroundTaskRow {
|
|
30
|
+
id: string;
|
|
31
|
+
brief: string;
|
|
32
|
+
title: string | null;
|
|
33
|
+
state: BackgroundTaskState;
|
|
34
|
+
notificationPolicy: BackgroundTaskNotificationPolicy;
|
|
35
|
+
/** Phase 4 if_significant criteria DSL (§4.3) — concrete atomic
|
|
36
|
+
* conditions the worker checks one-by-one. Empty/null ⇒ the worker
|
|
37
|
+
* falls back to the prose criteria in the brief. */
|
|
38
|
+
significanceCriteria: string[] | null;
|
|
39
|
+
report: string | null;
|
|
40
|
+
draft: string | null;
|
|
41
|
+
/** null until finished; true ⇒ surface, false ⇒ file only. */
|
|
42
|
+
notify: boolean | null;
|
|
43
|
+
significance: string | null;
|
|
44
|
+
artifactPath: string | null;
|
|
45
|
+
outcomeDetail: string | null;
|
|
46
|
+
originatingChannel: string | null;
|
|
47
|
+
correlationId: string | null;
|
|
48
|
+
scheduleRowId: number | null;
|
|
49
|
+
tier: BackgroundTaskTier | null;
|
|
50
|
+
maxBudgetUsd: number | null;
|
|
51
|
+
backendSessionId: string | null;
|
|
52
|
+
createdAt: number;
|
|
53
|
+
startedAt: number | null;
|
|
54
|
+
finishedAt: number | null;
|
|
55
|
+
deliveredAt: number | null;
|
|
56
|
+
}
|
|
57
|
+
export interface CreateBackgroundTaskInput {
|
|
58
|
+
id: string;
|
|
59
|
+
brief: string;
|
|
60
|
+
title: string | null;
|
|
61
|
+
notificationPolicy: BackgroundTaskNotificationPolicy;
|
|
62
|
+
/** Phase 4 if_significant criteria DSL (§4.3) — optional structured
|
|
63
|
+
* conditions. Persisted as a JSON array; null/empty stores SQL NULL. */
|
|
64
|
+
significanceCriteria?: readonly string[] | null;
|
|
65
|
+
originatingChannel: string | null;
|
|
66
|
+
correlationId: string | null;
|
|
67
|
+
scheduleRowId: number | null;
|
|
68
|
+
tier: BackgroundTaskTier | null;
|
|
69
|
+
maxBudgetUsd: number | null;
|
|
70
|
+
createdAt: number;
|
|
71
|
+
}
|
|
72
|
+
/** Insert a fresh row in state=pending. The slot manager promotes it to
|
|
73
|
+
* `running` once a slot frees. */
|
|
74
|
+
export declare function createBackgroundTask(db: Database.Database, input: CreateBackgroundTaskInput): BackgroundTaskRow;
|
|
75
|
+
/**
|
|
76
|
+
* §10.3 brief-dedup — find a still-relevant task with an IDENTICAL brief
|
|
77
|
+
* spawned inside the dedup window, so a runaway fan-out (the
|
|
78
|
+
* RESEARCH_CLUSTER_COST_FIX_PLAN class: a replayed trigger POSTing the
|
|
79
|
+
* same brief many times in minutes) collapses onto the first task instead
|
|
80
|
+
* of spawning N workers. Matches on `brief` + `tier` (the two inputs that
|
|
81
|
+
* define "the same work" — `notificationPolicy` only affects delivery, not
|
|
82
|
+
* the work done) within `sinceMs`, and excludes the FAIL terminals
|
|
83
|
+
* (`failed`/`timeout`/`cancelled`) so a prior failure is retryable rather
|
|
84
|
+
* than sticky. A `completed` duplicate inside the window IS returned — the
|
|
85
|
+
* answer already exists, re-running would just re-spend. Newest first.
|
|
86
|
+
*/
|
|
87
|
+
export declare function findRecentDuplicateBackgroundTask(db: Database.Database, input: {
|
|
88
|
+
brief: string;
|
|
89
|
+
tier: BackgroundTaskTier | null;
|
|
90
|
+
sinceMs: number;
|
|
91
|
+
}): BackgroundTaskRow | null;
|
|
92
|
+
export declare function getBackgroundTask(db: Database.Database, id: string): BackgroundTaskRow | null;
|
|
93
|
+
export interface ListBackgroundTasksOptions {
|
|
94
|
+
states?: readonly BackgroundTaskState[];
|
|
95
|
+
/** §10.5 — filter the worker disposition: `false` = the filed
|
|
96
|
+
* (notify=false) digest pull, `true` = already-surfaced. Rows whose
|
|
97
|
+
* `notify` is still NULL (unfinished) are excluded when this is set. */
|
|
98
|
+
notify?: boolean;
|
|
99
|
+
/** Keep only rows finished at/after this epoch-ms — the digest "since
|
|
100
|
+
* yesterday" window. */
|
|
101
|
+
finishedSinceMs?: number;
|
|
102
|
+
limit?: number;
|
|
103
|
+
offset?: number;
|
|
104
|
+
}
|
|
105
|
+
export declare function listBackgroundTasks(db: Database.Database, options?: ListBackgroundTasksOptions): readonly BackgroundTaskRow[];
|
|
106
|
+
export declare function countBackgroundTasks(db: Database.Database, options?: ListBackgroundTasksOptions): number;
|
|
107
|
+
/** Pending → running. CAS on prior state so a concurrent terminal
|
|
108
|
+
* transition (cancel-while-pending) does not get clobbered. */
|
|
109
|
+
export declare function markRunning(db: Database.Database, id: string, startedAt: number): BackgroundTaskRow | null;
|
|
110
|
+
/** Running → awaiting_user. Slot stays held; resume via /clarify. */
|
|
111
|
+
export declare function markAwaitingUser(db: Database.Database, id: string): BackgroundTaskRow | null;
|
|
112
|
+
/** awaiting_user → running. Used by /clarify resume. */
|
|
113
|
+
export declare function markRunningFromParked(db: Database.Database, id: string): BackgroundTaskRow | null;
|
|
114
|
+
export interface TerminalTransitionInput {
|
|
115
|
+
id: string;
|
|
116
|
+
state: "completed" | "failed" | "timeout" | "cancelled";
|
|
117
|
+
outcomeDetail: string | null;
|
|
118
|
+
finishedAt: number;
|
|
119
|
+
/** Artifact fields. Passing `undefined`/`null` leaves the existing
|
|
120
|
+
* column unchanged (COALESCE). `finish` writes all of them on the
|
|
121
|
+
* `completed` path; the runner's fail-loud synthesis writes
|
|
122
|
+
* `report`/`draft`/`notify` on the `failed`/`timeout` path. */
|
|
123
|
+
report?: string | null;
|
|
124
|
+
draft?: string | null;
|
|
125
|
+
/** `true`/`false` set explicitly; `undefined` leaves it NULL. */
|
|
126
|
+
notify?: boolean;
|
|
127
|
+
significance?: string | null;
|
|
128
|
+
artifactPath?: string | null;
|
|
129
|
+
}
|
|
130
|
+
/** Any non-terminal state → terminal, writing the artifact atomically.
|
|
131
|
+
* Idempotent — re-running on an already-terminal row CAS-misses and
|
|
132
|
+
* returns null. */
|
|
133
|
+
export declare function markTerminal(db: Database.Database, input: TerminalTransitionInput): BackgroundTaskRow | null;
|
|
134
|
+
/** Capture the SDK session id once the first turn streams it, so a
|
|
135
|
+
* /clarify resume can `query({resume})` the warm session. */
|
|
136
|
+
export declare function setBackendSessionId(db: Database.Database, id: string, sessionId: string): void;
|
|
137
|
+
export declare function markBackgroundTaskDelivered(db: Database.Database, id: string, deliveredAt: number): BackgroundTaskRow | null;
|
|
138
|
+
/** Delivery recovery target — completed rows whose worker stored a
|
|
139
|
+
* notify=true artifact but whose DM was never sent/recorded (§10.2). */
|
|
140
|
+
export declare function listUndeliveredBackgroundTaskReports(db: Database.Database, limit?: number): readonly BackgroundTaskRow[];
|
|
141
|
+
/** §10.5 — filed (notify=false) results, for the periodic digest +
|
|
142
|
+
* owner pull ("did that monitor ever run?"). */
|
|
143
|
+
export declare function listFiledBackgroundTaskResults(db: Database.Database, sinceMs: number, limit?: number): readonly BackgroundTaskRow[];
|
|
144
|
+
/**
|
|
145
|
+
* §10.2 boot re-dispatch-from-brief — reset every non-terminal row to
|
|
146
|
+
* `pending` (clearing the lost in-memory session) so the event-pipeline
|
|
147
|
+
* boot hook can re-run each one's brief through the runner. Returns the
|
|
148
|
+
* ids reset so the caller can fan out the re-dispatch.
|
|
149
|
+
*
|
|
150
|
+
* Unlike browser_task's `sweepNonTerminalRowsForBootRecovery` (which
|
|
151
|
+
* force-fails), background tasks are re-dispatchable because the brief is
|
|
152
|
+
* self-contained. `backend_session_id` is cleared since the prior SDK
|
|
153
|
+
* session is unreachable after a restart.
|
|
154
|
+
*
|
|
155
|
+
* Open clarifications belonging to the reset tasks are resolved in the
|
|
156
|
+
* SAME transaction. The pre-restart run that raised an `ask_user` is
|
|
157
|
+
* gone, so its clarification row is orphaned: a surviving `resolved = 0`
|
|
158
|
+
* row would later trip the deadline scanner (`listOverdueClarifications`
|
|
159
|
+
* → `expireForDeadline`) into transitioning the FRESH re-dispatched run
|
|
160
|
+
* to `timeout` — and because re-dispatch makes the task ACTIVE again
|
|
161
|
+
* (pending→running), that `expireForDeadline` is NOT a no-op the way it
|
|
162
|
+
* is for a terminal row. Clearing them here closes that window.
|
|
163
|
+
*/
|
|
164
|
+
export declare function resetNonTerminalForBootRedispatch(db: Database.Database, nowMs?: number): readonly {
|
|
165
|
+
id: string;
|
|
166
|
+
}[];
|
|
167
|
+
/**
|
|
168
|
+
* Phase 4 resume-across-restart (§10.2) — the non-terminal rows the boot
|
|
169
|
+
* recovery path partitions into "resume the SDK session" vs "re-dispatch
|
|
170
|
+
* from brief". Returns just the discriminators (id, state, session id) so
|
|
171
|
+
* the caller can decide without loading the full artifact.
|
|
172
|
+
*/
|
|
173
|
+
export declare function listNonTerminalBackgroundTasks(db: Database.Database): readonly {
|
|
174
|
+
id: string;
|
|
175
|
+
state: BackgroundTaskState;
|
|
176
|
+
backendSessionId: string | null;
|
|
177
|
+
}[];
|
|
178
|
+
/**
|
|
179
|
+
* Phase 4 resume-across-restart (§10.2) — reset ONE non-terminal row back
|
|
180
|
+
* to `pending` for re-dispatch-from-brief, clearing its (now unreachable)
|
|
181
|
+
* SDK session id and resolving its orphaned open clarifications in the same
|
|
182
|
+
* transaction (same rationale as the bulk
|
|
183
|
+
* `resetNonTerminalForBootRedispatch`: a surviving `resolved = 0` row would
|
|
184
|
+
* trip the deadline scanner into timing out the FRESH re-dispatched run).
|
|
185
|
+
* Used by the boot path for the rows it re-dispatches and by the runner's
|
|
186
|
+
* resume-failure fallback. Returns the row id when it was non-terminal,
|
|
187
|
+
* else null (idempotent on an already-terminal / missing row).
|
|
188
|
+
*/
|
|
189
|
+
export declare function resetSingleForBootRedispatch(db: Database.Database, id: string, nowMs?: number): string | null;
|
|
190
|
+
/**
|
|
191
|
+
* Fold a just-answered clarification into the task's brief so a COLD
|
|
192
|
+
* re-dispatch (when the warm SDK session can't be resumed across a restart,
|
|
193
|
+
* §10.2) still carries the owner's answer and doesn't re-ask the same
|
|
194
|
+
* question. The worker only ever sees the brief, so appending the resolved
|
|
195
|
+
* Q&A is the only way to thread the answer into a fresh run. Idempotency is
|
|
196
|
+
* not required — this runs at most once per clarification per re-dispatch,
|
|
197
|
+
* and the clarify route has already CAS-resolved the row.
|
|
198
|
+
*/
|
|
199
|
+
export declare function appendResolvedClarificationToBrief(db: Database.Database, id: string, question: string | null, answer: string): void;
|
|
200
|
+
/**
|
|
201
|
+
* Retention prune for terminal rows older than `cutoffMs`. Children in
|
|
202
|
+
* `background_task_clarifications` go with the parent via ON DELETE
|
|
203
|
+
* CASCADE. Non-terminal rows are never deleted (the boot re-dispatch
|
|
204
|
+
* sweep owns them). `finished_at` is the lifetime anchor with a
|
|
205
|
+
* `created_at` fallback for the rare unset-finished_at terminal.
|
|
206
|
+
*/
|
|
207
|
+
export declare function deleteTerminalBackgroundTasksOlderThan(db: Database.Database, cutoffMs: number): number;
|