@aitne/daemon 0.1.2 → 0.1.4

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.
Files changed (253) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/whatsapp-adapter.d.ts.map +1 -1
  3. package/dist/adapters/whatsapp-adapter.js +0 -1
  4. package/dist/adapters/whatsapp-adapter.js.map +1 -1
  5. package/dist/api/integration-route-gate.d.ts +15 -11
  6. package/dist/api/integration-route-gate.d.ts.map +1 -1
  7. package/dist/api/integration-route-gate.js +60 -23
  8. package/dist/api/integration-route-gate.js.map +1 -1
  9. package/dist/api/json-body.d.ts +22 -7
  10. package/dist/api/json-body.d.ts.map +1 -1
  11. package/dist/api/json-body.js +27 -8
  12. package/dist/api/json-body.js.map +1 -1
  13. package/dist/api/routes/agent.d.ts.map +1 -1
  14. package/dist/api/routes/agent.js +18 -0
  15. package/dist/api/routes/agent.js.map +1 -1
  16. package/dist/api/routes/backends.d.ts.map +1 -1
  17. package/dist/api/routes/backends.js +96 -1
  18. package/dist/api/routes/backends.js.map +1 -1
  19. package/dist/api/routes/books.js +1 -1
  20. package/dist/api/routes/books.js.map +1 -1
  21. package/dist/api/routes/context.d.ts.map +1 -1
  22. package/dist/api/routes/context.js +13 -1
  23. package/dist/api/routes/context.js.map +1 -1
  24. package/dist/api/routes/dashboard.d.ts.map +1 -1
  25. package/dist/api/routes/dashboard.js +75 -5
  26. package/dist/api/routes/dashboard.js.map +1 -1
  27. package/dist/api/routes/github.d.ts.map +1 -1
  28. package/dist/api/routes/github.js +38 -5
  29. package/dist/api/routes/github.js.map +1 -1
  30. package/dist/api/routes/integrations.d.ts +35 -6
  31. package/dist/api/routes/integrations.d.ts.map +1 -1
  32. package/dist/api/routes/integrations.js +191 -16
  33. package/dist/api/routes/integrations.js.map +1 -1
  34. package/dist/api/routes/mail.d.ts.map +1 -1
  35. package/dist/api/routes/mail.js +112 -46
  36. package/dist/api/routes/mail.js.map +1 -1
  37. package/dist/api/routes/observations.d.ts.map +1 -1
  38. package/dist/api/routes/observations.js +161 -8
  39. package/dist/api/routes/observations.js.map +1 -1
  40. package/dist/api/routes/setup-migrate.d.ts +9 -1
  41. package/dist/api/routes/setup-migrate.d.ts.map +1 -1
  42. package/dist/api/routes/setup-migrate.js +4 -2
  43. package/dist/api/routes/setup-migrate.js.map +1 -1
  44. package/dist/api/routes/skills.d.ts.map +1 -1
  45. package/dist/api/routes/skills.js +39 -1
  46. package/dist/api/routes/skills.js.map +1 -1
  47. package/dist/api/routes/voice.d.ts.map +1 -1
  48. package/dist/api/routes/voice.js +154 -14
  49. package/dist/api/routes/voice.js.map +1 -1
  50. package/dist/bootstrap/adapters.d.ts +109 -0
  51. package/dist/bootstrap/adapters.d.ts.map +1 -0
  52. package/dist/bootstrap/adapters.js +237 -0
  53. package/dist/bootstrap/adapters.js.map +1 -0
  54. package/dist/bootstrap/catchup.d.ts +23 -0
  55. package/dist/bootstrap/catchup.d.ts.map +1 -0
  56. package/dist/bootstrap/catchup.js +124 -0
  57. package/dist/bootstrap/catchup.js.map +1 -0
  58. package/dist/bootstrap/schedule-helpers.d.ts +18 -0
  59. package/dist/bootstrap/schedule-helpers.d.ts.map +1 -0
  60. package/dist/bootstrap/schedule-helpers.js +96 -0
  61. package/dist/bootstrap/schedule-helpers.js.map +1 -0
  62. package/dist/bootstrap/services.d.ts +60 -0
  63. package/dist/bootstrap/services.d.ts.map +1 -0
  64. package/dist/bootstrap/services.js +209 -0
  65. package/dist/bootstrap/services.js.map +1 -0
  66. package/dist/core/backends/backend-router.d.ts +23 -0
  67. package/dist/core/backends/backend-router.d.ts.map +1 -1
  68. package/dist/core/backends/backend-router.js +48 -3
  69. package/dist/core/backends/backend-router.js.map +1 -1
  70. package/dist/core/backends/claude-auth.d.ts +70 -0
  71. package/dist/core/backends/claude-auth.d.ts.map +1 -0
  72. package/dist/core/backends/claude-auth.js +198 -0
  73. package/dist/core/backends/claude-auth.js.map +1 -0
  74. package/dist/core/backends/claude-code-core.d.ts +47 -119
  75. package/dist/core/backends/claude-code-core.d.ts.map +1 -1
  76. package/dist/core/backends/claude-code-core.js +112 -1565
  77. package/dist/core/backends/claude-code-core.js.map +1 -1
  78. package/dist/core/backends/claude-delegated.d.ts +86 -0
  79. package/dist/core/backends/claude-delegated.d.ts.map +1 -0
  80. package/dist/core/backends/claude-delegated.js +801 -0
  81. package/dist/core/backends/claude-delegated.js.map +1 -0
  82. package/dist/core/backends/claude-errors.d.ts +39 -0
  83. package/dist/core/backends/claude-errors.d.ts.map +1 -0
  84. package/dist/core/backends/claude-errors.js +71 -0
  85. package/dist/core/backends/claude-errors.js.map +1 -0
  86. package/dist/core/backends/claude-probe.d.ts +103 -0
  87. package/dist/core/backends/claude-probe.d.ts.map +1 -0
  88. package/dist/core/backends/claude-probe.js +336 -0
  89. package/dist/core/backends/claude-probe.js.map +1 -0
  90. package/dist/core/backends/claude-tool-collection.d.ts +135 -0
  91. package/dist/core/backends/claude-tool-collection.d.ts.map +1 -0
  92. package/dist/core/backends/claude-tool-collection.js +831 -0
  93. package/dist/core/backends/claude-tool-collection.js.map +1 -0
  94. package/dist/core/backends/gemini-cli-core.d.ts +21 -0
  95. package/dist/core/backends/gemini-cli-core.d.ts.map +1 -1
  96. package/dist/core/backends/gemini-cli-core.js +84 -6
  97. package/dist/core/backends/gemini-cli-core.js.map +1 -1
  98. package/dist/core/backends/prompt-utils.d.ts +1 -0
  99. package/dist/core/backends/prompt-utils.d.ts.map +1 -1
  100. package/dist/core/backends/prompt-utils.js +60 -3
  101. package/dist/core/backends/prompt-utils.js.map +1 -1
  102. package/dist/core/context-builder.d.ts +36 -12
  103. package/dist/core/context-builder.d.ts.map +1 -1
  104. package/dist/core/context-builder.js +179 -89
  105. package/dist/core/context-builder.js.map +1 -1
  106. package/dist/core/dispatcher-date-utils.d.ts +49 -0
  107. package/dist/core/dispatcher-date-utils.d.ts.map +1 -0
  108. package/dist/core/dispatcher-date-utils.js +132 -0
  109. package/dist/core/dispatcher-date-utils.js.map +1 -0
  110. package/dist/core/dispatcher-error-handling.d.ts +159 -0
  111. package/dist/core/dispatcher-error-handling.d.ts.map +1 -0
  112. package/dist/core/dispatcher-error-handling.js +393 -0
  113. package/dist/core/dispatcher-error-handling.js.map +1 -0
  114. package/dist/core/dispatcher-hourly-check.d.ts +150 -0
  115. package/dist/core/dispatcher-hourly-check.d.ts.map +1 -0
  116. package/dist/core/dispatcher-hourly-check.js +665 -0
  117. package/dist/core/dispatcher-hourly-check.js.map +1 -0
  118. package/dist/core/dispatcher-message-handler.d.ts +170 -0
  119. package/dist/core/dispatcher-message-handler.d.ts.map +1 -0
  120. package/dist/core/dispatcher-message-handler.js +1054 -0
  121. package/dist/core/dispatcher-message-handler.js.map +1 -0
  122. package/dist/core/dispatcher-morning-routine.d.ts +169 -0
  123. package/dist/core/dispatcher-morning-routine.d.ts.map +1 -0
  124. package/dist/core/dispatcher-morning-routine.js +434 -0
  125. package/dist/core/dispatcher-morning-routine.js.map +1 -0
  126. package/dist/core/dispatcher-prompt.d.ts +107 -0
  127. package/dist/core/dispatcher-prompt.d.ts.map +1 -0
  128. package/dist/core/dispatcher-prompt.js +227 -0
  129. package/dist/core/dispatcher-prompt.js.map +1 -0
  130. package/dist/core/dispatcher-repository-helpers.d.ts +39 -0
  131. package/dist/core/dispatcher-repository-helpers.d.ts.map +1 -0
  132. package/dist/core/dispatcher-repository-helpers.js +86 -0
  133. package/dist/core/dispatcher-repository-helpers.js.map +1 -0
  134. package/dist/core/dispatcher-result-processor.d.ts +145 -0
  135. package/dist/core/dispatcher-result-processor.d.ts.map +1 -0
  136. package/dist/core/dispatcher-result-processor.js +414 -0
  137. package/dist/core/dispatcher-result-processor.js.map +1 -0
  138. package/dist/core/dispatcher-scheduled-tasks.d.ts +406 -0
  139. package/dist/core/dispatcher-scheduled-tasks.d.ts.map +1 -0
  140. package/dist/core/dispatcher-scheduled-tasks.js +998 -0
  141. package/dist/core/dispatcher-scheduled-tasks.js.map +1 -0
  142. package/dist/core/dispatcher-types.d.ts +296 -0
  143. package/dist/core/dispatcher-types.d.ts.map +1 -0
  144. package/dist/core/dispatcher-types.js +106 -0
  145. package/dist/core/dispatcher-types.js.map +1 -0
  146. package/dist/core/dispatcher.d.ts +86 -610
  147. package/dist/core/dispatcher.d.ts.map +1 -1
  148. package/dist/core/dispatcher.js +293 -3542
  149. package/dist/core/dispatcher.js.map +1 -1
  150. package/dist/core/integration-health.d.ts +18 -10
  151. package/dist/core/integration-health.d.ts.map +1 -1
  152. package/dist/core/integration-health.js +31 -1
  153. package/dist/core/integration-health.js.map +1 -1
  154. package/dist/core/integration-lifecycle.d.ts +65 -0
  155. package/dist/core/integration-lifecycle.d.ts.map +1 -1
  156. package/dist/core/integration-lifecycle.js +167 -16
  157. package/dist/core/integration-lifecycle.js.map +1 -1
  158. package/dist/core/integration-main-backend.d.ts +40 -0
  159. package/dist/core/integration-main-backend.d.ts.map +1 -1
  160. package/dist/core/integration-main-backend.js +89 -2
  161. package/dist/core/integration-main-backend.js.map +1 -1
  162. package/dist/core/management-md.d.ts +51 -17
  163. package/dist/core/management-md.d.ts.map +1 -1
  164. package/dist/core/management-md.js +233 -56
  165. package/dist/core/management-md.js.map +1 -1
  166. package/dist/core/output-language-policy.d.ts +74 -0
  167. package/dist/core/output-language-policy.d.ts.map +1 -0
  168. package/dist/core/output-language-policy.js +194 -0
  169. package/dist/core/output-language-policy.js.map +1 -0
  170. package/dist/core/prompts.d.ts +1 -0
  171. package/dist/core/prompts.d.ts.map +1 -1
  172. package/dist/core/prompts.js +121 -3
  173. package/dist/core/prompts.js.map +1 -1
  174. package/dist/core/repository-management-docs.d.ts +24 -0
  175. package/dist/core/repository-management-docs.d.ts.map +1 -1
  176. package/dist/core/repository-management-docs.js +210 -26
  177. package/dist/core/repository-management-docs.js.map +1 -1
  178. package/dist/core/routine-acquisition-plan.d.ts +131 -0
  179. package/dist/core/routine-acquisition-plan.d.ts.map +1 -0
  180. package/dist/core/routine-acquisition-plan.js +268 -0
  181. package/dist/core/routine-acquisition-plan.js.map +1 -0
  182. package/dist/core/routine-fetch-window-runner.d.ts +201 -0
  183. package/dist/core/routine-fetch-window-runner.d.ts.map +1 -0
  184. package/dist/core/routine-fetch-window-runner.js +661 -0
  185. package/dist/core/routine-fetch-window-runner.js.map +1 -0
  186. package/dist/core/routine-windows.d.ts +156 -0
  187. package/dist/core/routine-windows.d.ts.map +1 -0
  188. package/dist/core/routine-windows.js +330 -0
  189. package/dist/core/routine-windows.js.map +1 -0
  190. package/dist/core/skills-compiler.d.ts +11 -0
  191. package/dist/core/skills-compiler.d.ts.map +1 -1
  192. package/dist/core/skills-compiler.js +102 -13
  193. package/dist/core/skills-compiler.js.map +1 -1
  194. package/dist/core/skills-manifest.d.ts.map +1 -1
  195. package/dist/core/skills-manifest.js +26 -0
  196. package/dist/core/skills-manifest.js.map +1 -1
  197. package/dist/core/system-reset.d.ts.map +1 -1
  198. package/dist/core/system-reset.js +25 -2
  199. package/dist/core/system-reset.js.map +1 -1
  200. package/dist/db/observations.d.ts +45 -2
  201. package/dist/db/observations.d.ts.map +1 -1
  202. package/dist/db/observations.js +112 -14
  203. package/dist/db/observations.js.map +1 -1
  204. package/dist/db/schema.d.ts.map +1 -1
  205. package/dist/db/schema.js +13 -25
  206. package/dist/db/schema.js.map +1 -1
  207. package/dist/index.js +83 -610
  208. package/dist/index.js.map +1 -1
  209. package/dist/observers/delegated-sync-worker.d.ts +45 -2
  210. package/dist/observers/delegated-sync-worker.d.ts.map +1 -1
  211. package/dist/observers/delegated-sync-worker.js +71 -21
  212. package/dist/observers/delegated-sync-worker.js.map +1 -1
  213. package/dist/observers/mail-poller.d.ts +12 -5
  214. package/dist/observers/mail-poller.d.ts.map +1 -1
  215. package/dist/observers/mail-poller.js +36 -14
  216. package/dist/observers/mail-poller.js.map +1 -1
  217. package/dist/observers/manager.d.ts +37 -5
  218. package/dist/observers/manager.d.ts.map +1 -1
  219. package/dist/observers/manager.js +28 -10
  220. package/dist/observers/manager.js.map +1 -1
  221. package/dist/safety/risk-classifier.d.ts.map +1 -1
  222. package/dist/safety/risk-classifier.js +5 -0
  223. package/dist/safety/risk-classifier.js.map +1 -1
  224. package/dist/services/delegated-backend-invoker.d.ts +1 -51
  225. package/dist/services/delegated-backend-invoker.d.ts.map +1 -1
  226. package/dist/services/delegated-backend-invoker.js +41 -480
  227. package/dist/services/delegated-backend-invoker.js.map +1 -1
  228. package/dist/services/delegated-invoker-audit.d.ts +94 -0
  229. package/dist/services/delegated-invoker-audit.d.ts.map +1 -0
  230. package/dist/services/delegated-invoker-audit.js +238 -0
  231. package/dist/services/delegated-invoker-audit.js.map +1 -0
  232. package/dist/services/delegated-invoker-cache-hits.d.ts +34 -0
  233. package/dist/services/delegated-invoker-cache-hits.d.ts.map +1 -0
  234. package/dist/services/delegated-invoker-cache-hits.js +104 -0
  235. package/dist/services/delegated-invoker-cache-hits.js.map +1 -0
  236. package/dist/services/delegated-invoker-janitors.d.ts +28 -0
  237. package/dist/services/delegated-invoker-janitors.d.ts.map +1 -0
  238. package/dist/services/delegated-invoker-janitors.js +104 -0
  239. package/dist/services/delegated-invoker-janitors.js.map +1 -0
  240. package/dist/services/delegated-invoker-utils.d.ts +42 -0
  241. package/dist/services/delegated-invoker-utils.d.ts.map +1 -0
  242. package/dist/services/delegated-invoker-utils.js +100 -0
  243. package/dist/services/delegated-invoker-utils.js.map +1 -0
  244. package/dist/services/delegated-task-runtime.d.ts +1 -1
  245. package/dist/services/delegated-task-runtime.js +1 -1
  246. package/dist/services/integrations/snapshot-partitions.d.ts +5 -0
  247. package/dist/services/integrations/snapshot-partitions.d.ts.map +1 -1
  248. package/dist/services/integrations/snapshot-partitions.js +12 -0
  249. package/dist/services/integrations/snapshot-partitions.js.map +1 -1
  250. package/dist/services/voice/transcriber-impl.d.ts.map +1 -1
  251. package/dist/services/voice/transcriber-impl.js +46 -0
  252. package/dist/services/voice/transcriber-impl.js.map +1 -1
  253. package/package.json +12 -12
@@ -1,5 +1,5 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { filterDeniedToolsForBackend, getAgentDayDateStr, } from "@aitne/shared";
5
5
  import { createLogger } from "../logging.js";
@@ -11,6 +11,9 @@ import { buildRetryFollowup, buildTaskPrompt, classifyStructuredOutput, compileS
11
11
  import { DelegatedTaskResultCache, execScope, integrationVersionFor, runScope, } from "./delegated-task-result-cache.js";
12
12
  import { DelegatedTaskSessionPool, SESSION_POOL_TEMPDIR_PREFIX, } from "./delegated-task-session-pool.js";
13
13
  import { readRuntimeState, writeRuntimeState, } from "../db/runtime-state.js";
14
+ import { LegacyOneShotLease, mergeCost, readFileSyncIfExists, stripCodeFences, zeroCost, } from "./delegated-invoker-utils.js";
15
+ import { completeTaskHeader, recordAction, recordTaskHeaderInProgress, recordTaskToolStep, } from "./delegated-invoker-audit.js";
16
+ import { buildCacheHitRunResult, buildCacheHitTaskResult, } from "./delegated-invoker-cache-hits.js";
14
17
  const logger = createLogger("delegated-proxy-invoker");
15
18
  export class DelegatedBackendInvoker {
16
19
  deps;
@@ -174,7 +177,7 @@ export class DelegatedBackendInvoker {
174
177
  // Queue saturation — surfaces as 503 in the route handler. Don't
175
178
  // create a tempdir, don't materialize anything. Cost row is still
176
179
  // written (zero-cost) so the dashboard sees a saturation event.
177
- this.recordAction({
180
+ recordAction(this.deps.db, {
178
181
  backendId: fastCheck.backendId,
179
182
  modelId: fastCheck.modelId,
180
183
  params,
@@ -205,7 +208,7 @@ export class DelegatedBackendInvoker {
205
208
  this.releasePermit();
206
209
  const nowIso = new Date(this.now()).toISOString();
207
210
  const message = `integration state changed during queue wait: ${liveCheck.message}`;
208
- this.recordAction({
211
+ recordAction(this.deps.db, {
209
212
  backendId: liveCheck.backendId ?? fastCheck.backendId,
210
213
  modelId: fastCheck.modelId,
211
214
  params,
@@ -294,7 +297,7 @@ export class DelegatedBackendInvoker {
294
297
  }
295
298
  const completedAtIso = new Date(this.now()).toISOString();
296
299
  if (unimplemented) {
297
- this.recordAction({
300
+ recordAction(this.deps.db, {
298
301
  backendId,
299
302
  modelId,
300
303
  params,
@@ -314,7 +317,7 @@ export class DelegatedBackendInvoker {
314
317
  };
315
318
  }
316
319
  if (unhandledMessage !== null) {
317
- this.recordAction({
320
+ recordAction(this.deps.db, {
318
321
  backendId,
319
322
  modelId,
320
323
  params,
@@ -336,7 +339,7 @@ export class DelegatedBackendInvoker {
336
339
  if (!toolResult) {
337
340
  // Defensive: should not happen unless runDelegatedTool resolved with
338
341
  // null/undefined, which violates the contract.
339
- this.recordAction({
342
+ recordAction(this.deps.db, {
340
343
  backendId,
341
344
  modelId,
342
345
  params,
@@ -356,7 +359,7 @@ export class DelegatedBackendInvoker {
356
359
  };
357
360
  }
358
361
  if (toolResult.ok) {
359
- this.recordAction({
362
+ recordAction(this.deps.db, {
360
363
  backendId,
361
364
  modelId,
362
365
  params,
@@ -373,7 +376,7 @@ export class DelegatedBackendInvoker {
373
376
  modelId,
374
377
  };
375
378
  }
376
- this.recordAction({
379
+ recordAction(this.deps.db, {
377
380
  backendId,
378
381
  modelId,
379
382
  params,
@@ -403,10 +406,17 @@ export class DelegatedBackendInvoker {
403
406
  */
404
407
  resolvePreconditions(integrationKey, modelOverride) {
405
408
  const state = readIntegrations(this.deps.db)[integrationKey];
409
+ // INTEGRATION_NATIVE_MODE_DESIGN.md §17 (Phase B1 file list) — the
410
+ // invoker must defensively reject every non-delegated mode, including
411
+ // the new `native` mode. A flip from delegated to native during a
412
+ // queued task would otherwise resolve through this path with stale
413
+ // state; failing here forces the caller to re-route through the
414
+ // native MCP surface (§3.3 invariant: native MUST NOT call the
415
+ // daemon proxy).
406
416
  if (!state || state.mode !== "delegated" || !state.delegatedBackend) {
407
417
  return {
408
418
  ok: false,
409
- message: `integration '${integrationKey}' is not in delegated mode (mode=${state?.mode ?? "missing"}, delegatedBackend=${state?.delegatedBackend ?? "null"})`,
419
+ message: `integration '${integrationKey}' is not in delegated mode (mode=${state?.mode ?? "missing"}, delegatedBackend=${state?.delegatedBackend ?? "null"}, nativeBackend=${state?.nativeBackend ?? "null"})`,
410
420
  };
411
421
  }
412
422
  const backendId = state.delegatedBackend;
@@ -518,57 +528,13 @@ export class DelegatedBackendInvoker {
518
528
  mkdirSync(dirname(target), { recursive: true });
519
529
  writeFileSync(target, body, "utf-8");
520
530
  }
521
- // ── Cost / agent_actions persistence ────────────────────────────────────
522
- recordAction(args) {
523
- const detail = {
524
- integrationKey: args.params.integrationKey,
525
- toolName: args.params.toolName,
526
- toolArgsHash: hashArgs(args.params.toolArgs),
527
- ...(args.errorClass ? { errorClass: args.errorClass } : {}),
528
- };
529
- try {
530
- this.deps.db
531
- .prepare(
532
- // datetime(@started_at) coerces ISO-8601 input into SQLite's
533
- // canonical 'YYYY-MM-DD HH:MM:SS' so this row sorts correctly
534
- // alongside rows written via datetime('now') elsewhere — without
535
- // it, mixed formats break ORDER BY started_at.
536
- `INSERT INTO agent_actions (
537
- event_id, action_type, trigger, model_used,
538
- cost_usd, tokens_input, tokens_output,
539
- cache_creation_tokens, cache_read_tokens,
540
- duration_ms, num_turns, result, detail,
541
- started_at, completed_at, error, backend, cost_source
542
- ) VALUES (
543
- @event_id, 'delegated_proxy.invoke', @trigger, @model_used,
544
- @cost_usd, @tokens_input, @tokens_output,
545
- @cache_creation_tokens, @cache_read_tokens,
546
- @duration_ms, @num_turns, @result, @detail,
547
- datetime(@started_at), datetime(@completed_at), @error, @backend, 'sdk'
548
- )`)
549
- .run({
550
- event_id: args.params.parentEventId ?? null,
551
- trigger: args.params.parentProcessKey ?? null,
552
- model_used: args.modelId,
553
- cost_usd: args.cost.costUsd,
554
- tokens_input: args.cost.tokensInput,
555
- tokens_output: args.cost.tokensOutput,
556
- cache_creation_tokens: args.cost.cacheCreationTokens,
557
- cache_read_tokens: args.cost.cacheReadTokens,
558
- duration_ms: args.cost.durationMs,
559
- num_turns: args.cost.numTurns,
560
- result: args.result,
561
- detail: JSON.stringify(detail),
562
- started_at: args.startedAt,
563
- completed_at: args.completedAt,
564
- error: args.errorMessage ?? null,
565
- backend: args.backendId,
566
- });
567
- }
568
- catch (err) {
569
- logger.error({ err, integrationKey: args.params.integrationKey }, "failed to record delegated_proxy.invoke action");
570
- }
571
- }
531
+ // The five `agent_actions` row-writers (recordAction,
532
+ // recordCacheHitAuditRow, recordTaskHeaderInProgress, completeTaskHeader,
533
+ // recordTaskToolStep) live in `delegated-invoker-audit.ts`; the two
534
+ // cache-hit result builders (buildCacheHitTaskResult /
535
+ // buildCacheHitRunResult) live in `delegated-invoker-cache-hits.ts`.
536
+ // Call sites pass `this.deps.db` and `this.now` explicitly — see
537
+ // file-split-plan.md §9.
572
538
  // ── Model resolution ────────────────────────────────────────────────────
573
539
  resolveModel(state, integrationKey, backendId, modelOverride) {
574
540
  // Caller-side override (cadence path passes medium tier — see
@@ -701,11 +667,12 @@ export class DelegatedBackendInvoker {
701
667
  };
702
668
  const hit = cache.get(cacheKey);
703
669
  if (hit) {
704
- return this.buildCacheHitTaskResult({
670
+ return buildCacheHitTaskResult(this.deps.db, {
705
671
  params,
706
672
  hit,
707
673
  backendId: fastCheck.backendId,
708
674
  modelId: fastCheck.modelId,
675
+ now: this.now,
709
676
  });
710
677
  }
711
678
  }
@@ -823,7 +790,7 @@ export class DelegatedBackendInvoker {
823
790
  const taskHash = hashTaskArgs(params.task);
824
791
  const schemaHash = hashTaskArgs(params.outputSchema);
825
792
  // §11.1 — write header row BEFORE spawn so step rows can FK to its id.
826
- const headerId = this.recordTaskHeaderInProgress({
793
+ const headerId = recordTaskHeaderInProgress(this.deps.db, {
827
794
  actionType: "delegated_task.exec",
828
795
  backendId,
829
796
  modelId,
@@ -913,7 +880,7 @@ export class DelegatedBackendInvoker {
913
880
  structuredOutputEnabled,
914
881
  ...(wrappedSchema ? { wrappedSchema } : {}),
915
882
  onToolStep: (step) => {
916
- this.recordTaskToolStep({
883
+ recordTaskToolStep(this.deps.db, {
917
884
  parentTaskActionId: headerId,
918
885
  backendId,
919
886
  modelId,
@@ -1224,7 +1191,7 @@ export class DelegatedBackendInvoker {
1224
1191
  }
1225
1192
  }
1226
1193
  // §11.1 — finalise the header row.
1227
- this.completeTaskHeader({
1194
+ completeTaskHeader(this.deps.db, {
1228
1195
  headerId,
1229
1196
  result: outcome?.ok ? "success" : "failed",
1230
1197
  cost: aggregatedCost,
@@ -1282,56 +1249,6 @@ export class DelegatedBackendInvoker {
1282
1249
  }
1283
1250
  return outcome;
1284
1251
  }
1285
- /**
1286
- * §13 Phase 3.3 — synthesize a `TaskInvokeResult` from a cache hit and
1287
- * write the corresponding `delegated_task.exec` audit row with cost 0
1288
- * and `detail.cacheHit=true`. Cache hits do not consume the per-day
1289
- * quota (the quota counts subprocess invocations) and do not acquire a
1290
- * concurrency permit (looked up before `acquirePermit`).
1291
- */
1292
- buildCacheHitTaskResult(args) {
1293
- const nowIso = new Date(this.now()).toISOString();
1294
- const taskHash = hashTaskArgs(args.params.task);
1295
- const schemaHash = hashTaskArgs(args.params.outputSchema);
1296
- this.recordCacheHitAuditRow({
1297
- actionType: "delegated_task.exec",
1298
- backendId: args.backendId,
1299
- modelId: args.modelId,
1300
- ...(args.params.parentEventId !== undefined
1301
- ? { parentEventId: args.params.parentEventId }
1302
- : {}),
1303
- ...(args.params.parentProcessKey !== undefined
1304
- ? { parentProcessKey: args.params.parentProcessKey }
1305
- : {}),
1306
- timestamp: nowIso,
1307
- toolCallCount: args.hit.trace.length,
1308
- detail: {
1309
- integrationKey: args.params.integrationKey,
1310
- delegatedBackend: args.backendId,
1311
- taskHash,
1312
- schemaHash,
1313
- cacheHit: true,
1314
- toolCallCount: args.hit.trace.length,
1315
- retried: false,
1316
- // §11.2 — cache hits are gated on the original outcome being
1317
- // non-confirmation (see Phase 3.3 cache guard); record this
1318
- // explicitly so the metric aggregator's schema stays uniform
1319
- // across live + cache-hit rows.
1320
- needsConfirmation: false,
1321
- },
1322
- });
1323
- return {
1324
- ok: true,
1325
- result: args.hit.result,
1326
- needsConfirmation: false,
1327
- confirmationPlan: null,
1328
- cost: zeroCost(),
1329
- trace: args.hit.trace,
1330
- backendId: args.backendId,
1331
- modelId: args.modelId,
1332
- retried: false,
1333
- };
1334
- }
1335
1252
  /**
1336
1253
  * DELEGATED-TASK-MODE-DESIGN.md §4.2 — Phase 2 generic task mode.
1337
1254
  * Mirror of `task()` but with no `integrationKey`: the caller pins
@@ -1422,11 +1339,12 @@ export class DelegatedBackendInvoker {
1422
1339
  };
1423
1340
  const hit = cache.get(cacheKey);
1424
1341
  if (hit) {
1425
- return this.buildCacheHitRunResult({
1342
+ return buildCacheHitRunResult(this.deps.db, {
1426
1343
  params,
1427
1344
  hit,
1428
1345
  backendId,
1429
1346
  modelId: runModelId,
1347
+ now: this.now,
1430
1348
  });
1431
1349
  }
1432
1350
  }
@@ -1517,7 +1435,7 @@ export class DelegatedBackendInvoker {
1517
1435
  const schemaHash = hashTaskArgs(params.outputSchema);
1518
1436
  const allowedToolsHash = hashTaskArgs(allowedTools);
1519
1437
  // §11.1 — header row BEFORE spawn so step rows can FK to it.
1520
- const headerId = this.recordTaskHeaderInProgress({
1438
+ const headerId = recordTaskHeaderInProgress(this.deps.db, {
1521
1439
  actionType: "delegated_task.run",
1522
1440
  backendId,
1523
1441
  modelId,
@@ -1594,7 +1512,7 @@ export class DelegatedBackendInvoker {
1594
1512
  structuredOutputEnabled,
1595
1513
  ...(wrappedSchema ? { wrappedSchema } : {}),
1596
1514
  onToolStep: (step) => {
1597
- this.recordTaskToolStep({
1515
+ recordTaskToolStep(this.deps.db, {
1598
1516
  parentTaskActionId: headerId,
1599
1517
  backendId,
1600
1518
  modelId,
@@ -1873,7 +1791,7 @@ export class DelegatedBackendInvoker {
1873
1791
  }
1874
1792
  }
1875
1793
  // §11.1 — finalise the header row.
1876
- this.completeTaskHeader({
1794
+ completeTaskHeader(this.deps.db, {
1877
1795
  headerId,
1878
1796
  result: outcome?.ok ? "success" : "failed",
1879
1797
  cost: aggregatedCost,
@@ -1925,52 +1843,6 @@ export class DelegatedBackendInvoker {
1925
1843
  }
1926
1844
  return outcome;
1927
1845
  }
1928
- /**
1929
- * §13 Phase 3.3 — cache-hit synthesizer for `/run`. Same shape as
1930
- * `buildCacheHitTaskResult` but writes a `delegated_task.run` audit row.
1931
- */
1932
- buildCacheHitRunResult(args) {
1933
- const nowIso = new Date(this.now()).toISOString();
1934
- const taskHash = hashTaskArgs(args.params.task);
1935
- const schemaHash = hashTaskArgs(args.params.outputSchema);
1936
- const allowedToolsHash = hashTaskArgs(args.params.allowedTools);
1937
- this.recordCacheHitAuditRow({
1938
- actionType: "delegated_task.run",
1939
- backendId: args.backendId,
1940
- modelId: args.modelId,
1941
- ...(args.params.parentEventId !== undefined
1942
- ? { parentEventId: args.params.parentEventId }
1943
- : {}),
1944
- ...(args.params.parentProcessKey !== undefined
1945
- ? { parentProcessKey: args.params.parentProcessKey }
1946
- : {}),
1947
- timestamp: nowIso,
1948
- toolCallCount: args.hit.trace.length,
1949
- detail: {
1950
- delegatedBackend: args.backendId,
1951
- taskHash,
1952
- schemaHash,
1953
- allowedToolsHash,
1954
- allowedToolsCount: args.params.allowedTools.length,
1955
- cacheHit: true,
1956
- toolCallCount: args.hit.trace.length,
1957
- retried: false,
1958
- // §11.2 — see /exec equivalent.
1959
- needsConfirmation: false,
1960
- },
1961
- });
1962
- return {
1963
- ok: true,
1964
- result: args.hit.result,
1965
- needsConfirmation: false,
1966
- confirmationPlan: null,
1967
- cost: zeroCost(),
1968
- trace: args.hit.trace,
1969
- backendId: args.backendId,
1970
- modelId: args.modelId,
1971
- retried: false,
1972
- };
1973
- }
1974
1846
  /**
1975
1847
  * Resolve the model for a task-mode call.
1976
1848
  *
@@ -2039,181 +1911,6 @@ export class DelegatedBackendInvoker {
2039
1911
  logger.warn({ err }, "failed to increment delegated task quota counter");
2040
1912
  }
2041
1913
  }
2042
- // ── agent_actions header / step persistence ───────────────────────────────
2043
- /**
2044
- * §13 Phase 3.3 — single-shot INSERT for cache-hit audit rows. Cache
2045
- * hits don't go through the in-progress → complete two-step lifecycle
2046
- * (the outcome is known synchronously), so this writes one row with
2047
- * `result='success'`, `cost_usd=0`, `cost_source='cache'` for clean
2048
- * dashboard cost-source filtering.
2049
- */
2050
- recordCacheHitAuditRow(args) {
2051
- try {
2052
- const result = this.deps.db
2053
- .prepare(`INSERT INTO agent_actions (
2054
- event_id, action_type, trigger, model_used,
2055
- cost_usd, tokens_input, tokens_output,
2056
- cache_creation_tokens, cache_read_tokens,
2057
- duration_ms, num_turns, result, detail,
2058
- started_at, completed_at, error, backend, cost_source
2059
- ) VALUES (
2060
- @event_id, @action_type, @trigger, @model_used,
2061
- 0, 0, 0, 0, 0,
2062
- 0, @num_turns, 'success', @detail,
2063
- datetime(@ts), datetime(@ts), NULL, @backend, 'cache'
2064
- )`)
2065
- .run({
2066
- event_id: args.parentEventId ?? null,
2067
- action_type: args.actionType,
2068
- trigger: args.parentProcessKey ?? null,
2069
- model_used: args.modelId,
2070
- num_turns: args.toolCallCount,
2071
- detail: JSON.stringify(args.detail),
2072
- ts: args.timestamp,
2073
- backend: args.backendId,
2074
- });
2075
- return Number(result.lastInsertRowid);
2076
- }
2077
- catch (err) {
2078
- logger.error({ err, actionType: args.actionType, detail: args.detail }, "failed to write delegated_task cache-hit audit row");
2079
- return -1;
2080
- }
2081
- }
2082
- recordTaskHeaderInProgress(args) {
2083
- try {
2084
- const result = this.deps.db
2085
- .prepare(`INSERT INTO agent_actions (
2086
- event_id, action_type, trigger, model_used,
2087
- cost_usd, tokens_input, tokens_output,
2088
- cache_creation_tokens, cache_read_tokens,
2089
- duration_ms, num_turns, result, detail,
2090
- started_at, completed_at, error, backend, cost_source
2091
- ) VALUES (
2092
- @event_id, @action_type, @trigger, @model_used,
2093
- 0, 0, 0, 0, 0,
2094
- 0, 0, 'in_progress', @detail,
2095
- datetime(@started_at), NULL, NULL, @backend, 'sdk'
2096
- )`)
2097
- .run({
2098
- event_id: args.parentEventId ?? null,
2099
- action_type: args.actionType,
2100
- trigger: args.parentProcessKey ?? null,
2101
- model_used: args.modelId,
2102
- detail: JSON.stringify(args.detail),
2103
- started_at: args.startedAt,
2104
- backend: args.backendId,
2105
- });
2106
- return Number(result.lastInsertRowid);
2107
- }
2108
- catch (err) {
2109
- logger.error({ err, actionType: args.actionType, detail: args.detail }, "failed to write delegated_task header row");
2110
- return -1;
2111
- }
2112
- }
2113
- completeTaskHeader(args) {
2114
- if (args.headerId < 0)
2115
- return;
2116
- try {
2117
- this.deps.db
2118
- .prepare(`UPDATE agent_actions SET
2119
- result = @result,
2120
- cost_usd = @cost_usd,
2121
- tokens_input = @tokens_input,
2122
- tokens_output = @tokens_output,
2123
- cache_creation_tokens = @cache_creation_tokens,
2124
- cache_read_tokens = @cache_read_tokens,
2125
- duration_ms = @duration_ms,
2126
- num_turns = @num_turns,
2127
- completed_at = datetime(@completed_at),
2128
- error = @error,
2129
- detail = @detail
2130
- WHERE id = @id`)
2131
- .run({
2132
- id: args.headerId,
2133
- result: args.result,
2134
- cost_usd: args.cost.costUsd,
2135
- tokens_input: args.cost.tokensInput,
2136
- tokens_output: args.cost.tokensOutput,
2137
- cache_creation_tokens: args.cost.cacheCreationTokens,
2138
- cache_read_tokens: args.cost.cacheReadTokens,
2139
- duration_ms: args.cost.durationMs,
2140
- num_turns: args.cost.numTurns,
2141
- completed_at: args.completedAt,
2142
- error: args.errorMessage,
2143
- detail: JSON.stringify(args.detail),
2144
- });
2145
- }
2146
- catch (err) {
2147
- logger.error({ err, headerId: args.headerId }, "failed to update delegated_task.exec header row");
2148
- }
2149
- }
2150
- recordTaskToolStep(args) {
2151
- try {
2152
- this.deps.db
2153
- .prepare(`INSERT INTO agent_actions (
2154
- action_type, trigger, model_used,
2155
- cost_usd, tokens_input, tokens_output,
2156
- cache_creation_tokens, cache_read_tokens,
2157
- duration_ms, num_turns, result, detail,
2158
- started_at, completed_at, error, backend, cost_source
2159
- ) VALUES (
2160
- 'delegated_task.tool_step', NULL, @model_used,
2161
- @cost_usd, @tokens_input, @tokens_output,
2162
- 0, 0,
2163
- @duration_ms, 1, @result, @detail,
2164
- datetime('now'), datetime('now'), @error, @backend, 'sdk'
2165
- )`)
2166
- .run({
2167
- model_used: args.modelId,
2168
- cost_usd: args.step.costUsd,
2169
- tokens_input: args.step.tokensInput,
2170
- tokens_output: args.step.tokensOutput,
2171
- duration_ms: args.step.durationMs,
2172
- result: args.step.status === "ok" ? "success" : "failed",
2173
- detail: JSON.stringify({
2174
- ...(args.integrationKey ? { integrationKey: args.integrationKey } : {}),
2175
- toolName: args.step.toolName,
2176
- toolArgsHash: hashTaskArgs(args.step.toolArgs),
2177
- toolStatus: args.step.status,
2178
- parentTaskActionId: args.parentTaskActionId,
2179
- }),
2180
- error: args.step.status === "error" ? "tool_step_error" : null,
2181
- backend: args.backendId,
2182
- });
2183
- }
2184
- catch (err) {
2185
- logger.warn({ err, parentTaskActionId: args.parentTaskActionId }, "failed to write delegated_task.tool_step row");
2186
- }
2187
- }
2188
- }
2189
- /**
2190
- * §13 Phase 3.2 — synthetic lease used when pooling is disabled. Implements
2191
- * the same `release()` / `discard()` shape as `SessionPoolLease` so the
2192
- * task() / run() loop doesn't have to branch on whether pooling is active.
2193
- * Both methods clean up the tempdir (no TTL semantics — there's no pool
2194
- * to return to).
2195
- */
2196
- class LegacyOneShotLease {
2197
- sessionDir;
2198
- cleanup;
2199
- fromPool = false;
2200
- released = false;
2201
- constructor(sessionDir, cleanup) {
2202
- this.sessionDir = sessionDir;
2203
- this.cleanup = cleanup;
2204
- }
2205
- release() {
2206
- if (this.released)
2207
- return;
2208
- this.released = true;
2209
- this.cleanup();
2210
- }
2211
- discard() {
2212
- if (this.released)
2213
- return;
2214
- this.released = true;
2215
- this.cleanup();
2216
- }
2217
1914
  }
2218
1915
  const FALLBACK_PROXY_PROFILE = `# Delegated Proxy
2219
1916
 
@@ -2223,150 +1920,14 @@ exception: if the named tool's schema is not yet loaded, call ToolSearch
2223
1920
  to load it, then immediately call the named tool. Do not browse other
2224
1921
  tools. If the tool errors, return the error verbatim.
2225
1922
  `;
2226
- function readFileSyncIfExists(path) {
2227
- if (!existsSync(path))
2228
- return null;
2229
- return readFileSync(path, "utf-8");
2230
- }
2231
- function hashArgs(args) {
2232
- try {
2233
- const serialized = JSON.stringify(args ?? null);
2234
- return createHash("sha256")
2235
- .update(serialized)
2236
- .digest("hex")
2237
- .slice(0, 16);
2238
- }
2239
- catch {
2240
- return "unhashable";
2241
- }
2242
- }
2243
- function zeroCost() {
2244
- return {
2245
- tokensInput: 0,
2246
- tokensOutput: 0,
2247
- cacheCreationTokens: 0,
2248
- cacheReadTokens: 0,
2249
- costUsd: 0,
2250
- durationMs: 0,
2251
- numTurns: 0,
2252
- };
2253
- }
2254
- function mergeCost(a, b) {
2255
- return {
2256
- tokensInput: a.tokensInput + b.tokensInput,
2257
- tokensOutput: a.tokensOutput + b.tokensOutput,
2258
- cacheCreationTokens: a.cacheCreationTokens + b.cacheCreationTokens,
2259
- cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,
2260
- costUsd: a.costUsd + b.costUsd,
2261
- durationMs: a.durationMs + b.durationMs,
2262
- numTurns: a.numTurns + b.numTurns,
2263
- };
2264
- }
2265
- /**
2266
- * Local copy of the runtime helper's fence stripper to avoid cycle —
2267
- * `delegated-task-runtime.ts` already exports the canonical version, but
2268
- * importing it here would cycle (the runtime imports types from this
2269
- * file's `agent-core.ts` chain). Tiny duplication is the cleanest fix.
2270
- */
2271
- function stripCodeFences(input) {
2272
- let s = input.trim();
2273
- const fenceRe = /^```(?:json|JSON|jsonc|JSONC)?\s*\r?\n([\s\S]*?)\r?\n```$/;
2274
- const m = s.match(fenceRe);
2275
- if (m)
2276
- return m[1];
2277
- s = s.replace(/^```(?:json|JSON|jsonc|JSONC)?\s*\r?\n/, "");
2278
- s = s.replace(/\r?\n```\s*$/, "");
2279
- return s;
2280
- }
2281
1923
  /**
2282
1924
  * DELEGATED-TASK-MODE-DESIGN.md §8.3 — runtime_state key for the per-day
2283
1925
  * task-mode quota counter. Resets at the agent-day boundary; mirrors the
2284
1926
  * Gemini per-day request counter shape.
2285
1927
  */
2286
1928
  const DELEGATED_TASK_COUNT_STATE_KEY = "delegated_task_count_today";
2287
- /**
2288
- * DELEGATED-TASK-MODE-DESIGN.md §11.1 crash safety boot-time janitor
2289
- * that flips orphaned `delegated_task.exec` rows older than `maxAgeMs`
2290
- * (default 5 min) from `result='in_progress'` to `result='failed'` with
2291
- * `error='subprocess_orphaned'`. Without this, a daemon crash mid-task
2292
- * leaves the row in flight forever and poisons the dashboard's "in-flight
2293
- * task" counter.
2294
- *
2295
- * Returns the number of rows updated.
2296
- */
2297
- export function runDelegatedTaskOrphanJanitor(db, options = {}) {
2298
- const maxAgeMs = options.maxAgeMs ?? DELEGATED_PROXY_DEFAULTS.janitorMaxAgeMs;
2299
- const cutoffMs = (options.now?.() ?? Date.now()) - maxAgeMs;
2300
- const cutoffIso = new Date(cutoffMs).toISOString();
2301
- try {
2302
- const result = db
2303
- .prepare(`UPDATE agent_actions SET
2304
- result = 'failed',
2305
- error = 'subprocess_orphaned',
2306
- completed_at = datetime('now')
2307
- WHERE action_type IN ('delegated_task.exec', 'delegated_task.run', 'delegated_task.tool_step')
2308
- AND result = 'in_progress'
2309
- AND started_at < datetime(?)`)
2310
- .run(cutoffIso);
2311
- if (result.changes > 0) {
2312
- logger.info({ changes: result.changes }, "delegated task janitor: closed orphaned in-progress rows");
2313
- }
2314
- return result.changes;
2315
- }
2316
- catch (err) {
2317
- logger.warn({ err }, "delegated task janitor: SQL update failed");
2318
- return 0;
2319
- }
2320
- }
2321
- /**
2322
- * Boot-time janitor — scans the sessions root for orphan `proxy-*` dirs
2323
- * older than the configured threshold and removes them. Covers the SIGKILL
2324
- * mid-call case the per-call `finally` cannot. Safe to call before any
2325
- * invocations have happened.
2326
- *
2327
- * Returns the number of directories removed (for logging at startup).
2328
- */
2329
- export function runProxyTempdirJanitor(dataDir, options = {}) {
2330
- const now = options.now ?? Date.now;
2331
- const maxAgeMs = options.maxAgeMs ?? DELEGATED_PROXY_DEFAULTS.janitorMaxAgeMs;
2332
- const root = join(dataDir, "agent-sessions");
2333
- if (!existsSync(root))
2334
- return 0;
2335
- let removed = 0;
2336
- let entries;
2337
- try {
2338
- entries = readdirSync(root);
2339
- }
2340
- catch (err) {
2341
- logger.warn({ err, root }, "proxy janitor: readdir failed");
2342
- return 0;
2343
- }
2344
- for (const entry of entries) {
2345
- if (!entry.startsWith(DELEGATED_PROXY_DEFAULTS.tempdirPrefix))
2346
- continue;
2347
- const path = join(root, entry);
2348
- let stat;
2349
- try {
2350
- stat = statSync(path);
2351
- }
2352
- catch {
2353
- continue;
2354
- }
2355
- if (!stat.isDirectory())
2356
- continue;
2357
- if (now() - stat.mtimeMs < maxAgeMs)
2358
- continue;
2359
- try {
2360
- rmSync(path, { recursive: true, force: true });
2361
- removed++;
2362
- }
2363
- catch (err) {
2364
- logger.warn({ err, path }, "proxy janitor: rm failed");
2365
- }
2366
- }
2367
- if (removed > 0) {
2368
- logger.info({ removed }, "proxy janitor: removed orphan tempdirs");
2369
- }
2370
- return removed;
2371
- }
1929
+ // Boot-time janitors live in `delegated-invoker-janitors.ts`. Re-export
1930
+ // here so `index.ts` and tests that import from this module keep working
1931
+ // without an import-path churn see file-split-plan.md §6.
1932
+ export { runDelegatedTaskOrphanJanitor, runProxyTempdirJanitor, } from "./delegated-invoker-janitors.js";
2372
1933
  //# sourceMappingURL=delegated-backend-invoker.js.map