mixdog 1.2.5 → 1.3.0

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 (493) hide show
  1. package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +19 -0
  3. package/package.json +4 -1
  4. package/scripts/check-model-recommendations.mjs +89 -0
  5. package/scripts/gate-local.mjs +7 -0
  6. package/scripts/lib/gate-scheduler.mjs +2 -2
  7. package/scripts/lib/isolated-test-env.mjs +16 -0
  8. package/scripts/lib/run-node-tests.mjs +5 -14
  9. package/scripts/provider-pingpong-live.mjs +9 -9
  10. package/src/agents/advisor/AGENT.md +4 -4
  11. package/src/agents/advisor/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +5 -4
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/defaults/shipped-history.json +17 -0
  15. package/src/defaults/skills/browser-use/SKILL.md +7 -1
  16. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  17. package/src/defaults/skills/memory-management/SKILL.md +4 -1
  18. package/src/defaults/skills/setup/references/actions.md +11 -4
  19. package/src/defaults/skills/setup-guide/SKILL.md +175 -0
  20. package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
  21. package/src/defaults/skills/visualize/SKILL.md +3 -2
  22. package/src/lib/rules-builder.cjs +56 -7
  23. package/src/output-styles/common.md +22 -6
  24. package/src/output-styles/detailed.md +7 -5
  25. package/src/output-styles/minimal.md +7 -3
  26. package/src/output-styles/simple.md +2 -3
  27. package/src/rules/agent/AGENT.md +7 -1
  28. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  29. package/src/rules/agent-mode/MIXY.md +21 -0
  30. package/src/rules/agent-mode/ROUTINE.md +6 -0
  31. package/src/rules/lead/LEAD.md +9 -4
  32. package/src/rules/shared/10-tool-workflow.md +2 -1
  33. package/src/rules/shared/60-verification.md +4 -5
  34. package/src/rules/shared/70-delivery.md +3 -0
  35. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  37. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  39. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
  40. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
  41. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  42. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
  43. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
  44. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  45. package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
  46. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  49. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  50. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  51. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  53. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  54. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  58. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  62. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  65. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  66. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  69. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  70. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  80. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  81. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  83. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  84. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  86. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  88. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  92. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  94. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  95. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  96. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  97. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  98. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  99. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  100. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
  101. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  102. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  103. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
  104. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
  109. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
  110. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  111. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  112. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  113. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  114. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  115. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  116. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  117. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
  118. package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
  119. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  120. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  121. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  122. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  123. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  124. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  125. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  126. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
  127. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  128. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  129. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  130. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  131. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  132. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  134. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  135. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  140. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  146. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  147. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  148. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  150. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  157. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  158. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  159. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  163. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
  166. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  167. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  168. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  169. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  171. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  174. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  175. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  176. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
  177. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
  178. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  179. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  180. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  181. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  182. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  183. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  184. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  185. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  186. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
  189. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  191. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  197. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  198. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  199. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  200. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  201. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  203. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  208. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  209. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  210. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  211. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  212. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  213. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  214. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  215. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  216. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  217. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  218. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  219. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  220. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  221. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
  222. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  224. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  225. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  226. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  227. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  228. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  229. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  230. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  231. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  232. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
  233. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
  234. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  235. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
  236. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
  237. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  238. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
  239. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  240. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  241. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  242. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  243. package/src/runtime/attachments/office-extract.mjs +11 -9
  244. package/src/runtime/browser-bridge/client.mjs +24 -0
  245. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  246. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  247. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  248. package/src/runtime/channels/lib/webhook.mjs +0 -1
  249. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  250. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  251. package/src/runtime/computer-bridge/client.mjs +28 -1
  252. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  253. package/src/runtime/connectors/google-mcp.mjs +446 -0
  254. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  255. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  256. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  257. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  258. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  259. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  260. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  261. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  262. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  263. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  264. package/src/runtime/memory/lib/memory.mjs +7 -1
  265. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  266. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  268. package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
  269. package/src/runtime/memory/tool-defs.mjs +5 -0
  270. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  271. package/src/runtime/office/core/tabular.mjs +1 -1
  272. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  273. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  274. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  275. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  276. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  277. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  278. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  279. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  280. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  281. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  282. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  283. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  284. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  285. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  286. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  287. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  288. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  289. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  290. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  291. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  292. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  293. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  294. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  295. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  296. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  297. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  298. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  299. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  300. package/src/runtime/shared/agent-avatar.mjs +320 -0
  301. package/src/runtime/shared/agent-route-config.d.mts +3 -0
  302. package/src/runtime/shared/agent-route-config.mjs +16 -0
  303. package/src/runtime/shared/atomic-file.mjs +36 -14
  304. package/src/runtime/shared/background-tasks.mjs +60 -20
  305. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  306. package/src/runtime/shared/config.mjs +8 -11
  307. package/src/runtime/shared/connector-accounts.mjs +15 -0
  308. package/src/runtime/shared/connector-catalog.d.mts +52 -0
  309. package/src/runtime/shared/connector-catalog.mjs +230 -0
  310. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  311. package/src/runtime/shared/connector-triggers.mjs +43 -0
  312. package/src/runtime/shared/file-lock.mjs +7 -1
  313. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  314. package/src/runtime/shared/file-permissions.d.mts +19 -4
  315. package/src/runtime/shared/file-permissions.mjs +310 -4
  316. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  317. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  318. package/src/runtime/shared/held-request-host.d.mts +12 -0
  319. package/src/runtime/shared/held-request-host.mjs +71 -0
  320. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  321. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  322. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  323. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  324. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  325. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  326. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  327. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  328. package/src/runtime/shared/notify-trace.mjs +8 -1
  329. package/src/runtime/shared/plain-preview.d.mts +1 -0
  330. package/src/runtime/shared/plain-preview.mjs +28 -0
  331. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  332. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  333. package/src/runtime/shared/process-runner.mjs +38 -0
  334. package/src/runtime/shared/provider-accounts.mjs +2 -1
  335. package/src/runtime/shared/provider-api-key.mjs +0 -1
  336. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  337. package/src/runtime/shared/resource-admission.mjs +60 -18
  338. package/src/runtime/shared/routine-limits.d.mts +11 -0
  339. package/src/runtime/shared/routine-limits.mjs +21 -0
  340. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  341. package/src/runtime/shared/routine-trigger.mjs +44 -0
  342. package/src/runtime/shared/run-child.mjs +84 -0
  343. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  344. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  345. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  346. package/src/runtime/shared/singleton-owner.mjs +126 -42
  347. package/src/runtime/shared/slow-span.mjs +4 -12
  348. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  349. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  350. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  351. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  352. package/src/runtime/shared/turn-changes.mjs +0 -8
  353. package/src/runtime/shared/usage-readout-totals.mjs +56 -0
  354. package/src/runtime/shared/user-data-guard.mjs +131 -34
  355. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  356. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  357. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  358. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  359. package/src/runtime/tidy/runners/biome.mjs +3 -1
  360. package/src/runtime/tidy/shadow.mjs +2 -1
  361. package/src/runtime/web-search/index.mjs +5 -7
  362. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  363. package/src/runtime/web-search/tool-defs.mjs +6 -1
  364. package/src/session-runtime/agent-home-delivery.mjs +459 -0
  365. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  366. package/src/session-runtime/agent-room-delivery.mjs +92 -0
  367. package/src/session-runtime/agent-task-sessions.mjs +200 -0
  368. package/src/session-runtime/boot/apis.mjs +50 -18
  369. package/src/session-runtime/boot/facade.mjs +5 -8
  370. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  371. package/src/session-runtime/boot/tools.mjs +3 -0
  372. package/src/session-runtime/channel-config-api.mjs +53 -5
  373. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  374. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  375. package/src/session-runtime/held-requests.mjs +228 -0
  376. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  377. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  378. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  379. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
  380. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  381. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  382. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  383. package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
  384. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  385. package/src/session-runtime/lifecycle/shared.mjs +25 -2
  386. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  387. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  388. package/src/session-runtime/lifecycle-api.mjs +3 -1
  389. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  390. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  391. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  392. package/src/session-runtime/model-route/set-route.mjs +14 -3
  393. package/src/session-runtime/owned-automation-run.mjs +229 -0
  394. package/src/session-runtime/provider-auth/login.mjs +10 -6
  395. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  396. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  397. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  398. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  399. package/src/session-runtime/provider-models.mjs +76 -10
  400. package/src/session-runtime/provider-readiness.mjs +4 -0
  401. package/src/session-runtime/resource-api.mjs +5 -0
  402. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  403. package/src/session-runtime/resource-skills-api.mjs +12 -0
  404. package/src/session-runtime/room-member-gate.mjs +48 -0
  405. package/src/session-runtime/routine-home-turn.mjs +156 -0
  406. package/src/session-runtime/routine-owner.mjs +48 -0
  407. package/src/session-runtime/schedule-session-run.mjs +30 -64
  408. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  409. package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
  410. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  411. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  412. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  413. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  414. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  415. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  416. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  417. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  418. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  419. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  420. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  422. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  423. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  424. package/src/session-runtime/services/agent-tool.mjs +20 -0
  425. package/src/session-runtime/services/channel-admin.mjs +93 -24
  426. package/src/session-runtime/services/memory-access.mjs +37 -0
  427. package/src/session-runtime/services/provider-admin.mjs +166 -59
  428. package/src/session-runtime/services/schedule-access.mjs +91 -0
  429. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  430. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  431. package/src/session-runtime/session-create/session-options.mjs +34 -7
  432. package/src/session-runtime/session-hooks.mjs +16 -8
  433. package/src/session-runtime/setup-tool/executor.mjs +68 -6
  434. package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
  435. package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
  436. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  437. package/src/session-runtime/skills-api.mjs +16 -1
  438. package/src/session-runtime/tool-policy-refresh.mjs +238 -29
  439. package/src/session-runtime/turn/session-ops.mjs +10 -3
  440. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
  441. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
  442. package/src/session-runtime/usage-stats-api.mjs +6 -1
  443. package/src/session-runtime/webhook-session-run.mjs +49 -67
  444. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  445. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
  446. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  447. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  448. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  449. package/src/standalone/daemon-agent-control.mjs +1 -8
  450. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  451. package/src/standalone/daemon-owner.mjs +117 -25
  452. package/src/standalone/daemon-session-control.mjs +11 -2
  453. package/src/standalone/daemon.mjs +61 -17
  454. package/src/standalone/session-call-cache.mjs +6 -0
  455. package/src/standalone/session-protocol.mjs +28 -1
  456. package/src/standalone/session-service/retention/busy.mjs +7 -2
  457. package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
  458. package/src/standalone/session-service.mjs +19 -0
  459. package/src/standalone/session-transport/routes.mjs +7 -6
  460. package/src/tui/app/model-options.mjs +39 -2
  461. package/src/tui/app/model-picker.mjs +16 -2
  462. package/src/tui/app/provider-setup-picker.mjs +1 -2
  463. package/src/tui/app/slash-commands.mjs +20 -0
  464. package/src/tui/dist/index.mjs +487 -128
  465. package/src/tui/session/context-state.mjs +6 -1
  466. package/src/tui/session/notice-surface.mjs +35 -4
  467. package/src/tui/session/notice-text.mjs +0 -1
  468. package/src/tui/session/queue-helpers.mjs +2 -1
  469. package/src/tui/session/session-api/extensions.mjs +4 -0
  470. package/src/tui/session/session-api/intake/submission.mjs +12 -13
  471. package/src/tui/session/session-api/integrations.mjs +9 -5
  472. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  473. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  474. package/src/tui/session/session-api/routes.mjs +48 -3
  475. package/src/tui/session/session-flow/drain.mjs +20 -3
  476. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  477. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  478. package/src/tui/session/session-flow/steering.mjs +104 -24
  479. package/src/tui/session/session-flow.mjs +2 -0
  480. package/src/tui/session/tool-approval.mjs +26 -5
  481. package/src/tui/session/transcript-intake.mjs +6 -2
  482. package/src/tui/session/transcript-spill.mjs +5 -1
  483. package/src/tui/session/tui-steering-persist.mjs +65 -42
  484. package/src/tui/session/turn-live-call.mjs +56 -0
  485. package/src/tui/session/turn-stream.mjs +33 -0
  486. package/src/tui/session/turn.mjs +50 -7
  487. package/src/ui/statusline.mjs +1 -6
  488. package/src/ui/streaming-markdown-heal.mjs +24 -7
  489. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  490. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  491. package/src/workflows/default/WORKFLOW.md +9 -13
  492. package/src/session-runtime/automation-agents.mjs +0 -94
  493. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -98,6 +98,8 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
98
98
  registry.upsertWorkerSessionDeferred(session, tag, {
99
99
  status: 'running',
100
100
  stage: 'running',
101
+ // The send's own task: a restart that ends this turn reports it by id.
102
+ task_id: job?.taskId,
101
103
  turnStartedAt: new Date().toISOString(),
102
104
  });
103
105
  let handoffMsgStart = 0;
@@ -224,5 +226,26 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
224
226
  return renderResult({ ...extras, ...views.renderJob(job, false) });
225
227
  }
226
228
 
227
- return { prepareSend, dispatchToExistingSession };
229
+ // A background-task completion was queued for this worker. A busy worker
230
+ // takes it at its next tool boundary; an idle one runs a follow-up turn on
231
+ // an empty prompt, which drains the queued completion (never an empty user
232
+ // turn). Its answer reaches the owner like any send result.
233
+ function wakeIdleWorker(sessionId) {
234
+ const id = clean(sessionId);
235
+ if (!id || views.isSessionBusy(id)) return false;
236
+ const session = mgr.getSession(id);
237
+ if (!session || session.closed) return false;
238
+ const owner = clean(session.ownerSessionId || session.parentSessionId);
239
+ const notifyContext = owner
240
+ ? { callerSessionId: owner, ownerSessionId: owner, clientHostPid: session.clientHostPid || null }
241
+ : null;
242
+ void dispatchToExistingSession({ args: {}, session, sessionId: id, prompt: '' }, notifyContext).catch((error) => {
243
+ try {
244
+ process.stderr.write(`[agent] completion wake failed session=${id}: ${error?.message || error}\n`);
245
+ } catch {}
246
+ });
247
+ return true;
248
+ }
249
+
250
+ return { prepareSend, dispatchToExistingSession, wakeIdleWorker };
228
251
  }
@@ -5,6 +5,7 @@
5
5
  * flip to running, and the cancellation checks around the turn.
6
6
  */
7
7
  import { nonNegativeInt, clearAgentStatuslineRoute } from '../helpers.mjs';
8
+ import { closeManagedSession } from '../../../lifecycle/shared.mjs';
8
9
 
9
10
  export function createDeferredSpawn({
10
11
  mgr,
@@ -22,7 +23,7 @@ export function createDeferredSpawn({
22
23
  function closePreparedSpawn(prepared, reason = 'agent-task-cancel') {
23
24
  if (!prepared?.session?.id) return;
24
25
  try {
25
- Promise.resolve(mgr.closeSession(prepared.session.id, reason)).catch(() => {});
26
+ Promise.resolve(closeManagedSession(mgr, prepared.session.id, reason)).catch(() => {});
26
27
  } catch {}
27
28
  try {
28
29
  clearAgentStatuslineRoute(prepared.session.id);
@@ -7,6 +7,7 @@ import { sanitizeTaskMeta, startBackgroundTask } from '../../../../runtime/share
7
7
  import { resourceAdmission } from '../../../../runtime/shared/resource-admission.mjs';
8
8
  import { clean, terminalPidForContext } from '../helpers.mjs';
9
9
  import { renderResult } from '../render.mjs';
10
+ import { closeManagedSession } from '../../../lifecycle/shared.mjs';
10
11
 
11
12
  /** The completion callback that hands a worker's result back to its caller session; null without a handoff. */
12
13
  function handoffNotifier(handoffSessionId, notifySessionCompletion) {
@@ -53,9 +54,9 @@ export function createJobStarter({ mgr, notifyStatusChange, notifySessionComplet
53
54
  const currentMeta = task?.meta || jobMeta;
54
55
  if (currentMeta?.sessionId) {
55
56
  try {
56
- Promise.resolve(mgr.closeSession(currentMeta.sessionId, 'agent-task-cancel', { tombstone: false })).catch(
57
- () => {}
58
- );
57
+ Promise.resolve(
58
+ closeManagedSession(mgr, currentMeta.sessionId, 'agent-task-cancel', { tombstone: false })
59
+ ).catch(() => {});
59
60
  } catch {}
60
61
  }
61
62
  setImmediate(notifyStatusChange);
@@ -9,6 +9,7 @@ import {
9
9
  agentDefinitionExists,
10
10
  clean,
11
11
  normalizeAgentName,
12
+ readAgentFrontmatterKind,
12
13
  readAgentFrontmatterPermission,
13
14
  resolvePrompt,
14
15
  terminalPidForContext,
@@ -18,8 +19,13 @@ import { normalizeAgentPermission } from '../../../../runtime/shared/markdown-fr
18
19
  import { resolveAgentSpawnPreset } from '../spawn-preset.mjs';
19
20
  import { AGENT_OWNER } from '../../../../runtime/agent/orchestrator/agent-owner.mjs';
20
21
  import { workspaceCwdLock } from '../../../workspace/admission-gate.mjs';
22
+ import { isContactAgentId } from '../../../../runtime/agent/orchestrator/runtime-core/workflow-ids.mjs';
23
+ import { AGENT_MODE, resolveSessionMode } from '../../../../runtime/agent/orchestrator/session/agent-mode.mjs';
24
+ import { MIXY_AGENT_ID } from '../../../../runtime/agent/orchestrator/session/agent-home.mjs';
25
+ import { mixyDisplayName } from '../../../../runtime/agent/orchestrator/session/mixy-name.mjs';
21
26
 
22
27
  export function createSpawnPlanner({
28
+ mgr = null,
23
29
  cfgMod,
24
30
  dataDir,
25
31
  STANDALONE_SOURCE_ROOT,
@@ -44,6 +50,18 @@ export function createSpawnPlanner({
44
50
  if (isAgentDisabled(config, agent)) {
45
51
  throw new Error(`agent spawn: agent "${agent}" is turned off`);
46
52
  }
53
+ // Only Mixy hands work to a contact agent; any other agent-mode Lead
54
+ // delegates to sub-agents alone (its catalog lists no contact either).
55
+ if (isContactAgentId(agent, readAgentFrontmatterKind(agent, dataDir, STANDALONE_SOURCE_ROOT))) {
56
+ const callerId = clean(context?.callerSessionId || context?.sessionId);
57
+ const caller = (callerId && mgr?.getSession?.(callerId)) || null;
58
+ const { mode, agentId } = resolveSessionMode({ session: caller, sessionId: callerId });
59
+ if (mode === AGENT_MODE && agentId !== MIXY_AGENT_ID) {
60
+ throw new Error(
61
+ `agent spawn: only ${mixyDisplayName()} (the representative agent) can hand work to the contact agent "${agent}"; delegate to a sub-agent instead`
62
+ );
63
+ }
64
+ }
47
65
  const agentPermission = readAgentFrontmatterPermission(agent, dataDir, STANDALONE_SOURCE_ROOT);
48
66
  const agentPerm = normalizeAgentPermission(agentPermission) || null;
49
67
  const { presetName, preset } = resolveAgentSpawnPreset(config, args);
@@ -56,10 +74,7 @@ export function createSpawnPlanner({
56
74
  // Workers share their Lead's execution root. While the Lead runs in its
57
75
  // worktree, that root is locked: neither args.cwd nor an inherited
58
76
  // (pre-transition) cwd can send a worker elsewhere.
59
- const lockedCwd = workspaceCwdLock([
60
- context?.ownerSessionId,
61
- context?.callerSessionId || context?.sessionId,
62
- ]);
77
+ const lockedCwd = workspaceCwdLock([context?.ownerSessionId, context?.callerSessionId || context?.sessionId]);
63
78
  const baseCwd = resolve(lockedCwd || callerCwd || defaultCwd || process.cwd());
64
79
  const workerCwd = !lockedCwd && clean(args.cwd) ? resolve(baseCwd, args.cwd) : baseCwd;
65
80
  const prompt = await resolvePrompt(args, workerCwd);
@@ -58,8 +58,10 @@ export function createSpawnPreparer({
58
58
  ensureProvider,
59
59
  sessionSurface = null,
60
60
  refreshTagsFromSessions,
61
+ mgr = null,
61
62
  }) {
62
63
  const { resolveSpawnPlan, spawnSessionSpec } = createSpawnPlanner({
64
+ mgr,
63
65
  cfgMod,
64
66
  dataDir,
65
67
  STANDALONE_SOURCE_ROOT,
@@ -39,9 +39,13 @@ export function createSpawnRunner({
39
39
  emitSubagentEvent,
40
40
  sessionSurface = null,
41
41
  createTurnReviewCollector,
42
+ onWorkerCompletionQueued = null,
42
43
  }) {
43
44
  // Owner/worker completion notification lives in ../notify.mjs.
44
- const { workerNotifyFn, notifyOwnerAgentCompletionEarly } = createNotify(mgr, { notifySessionCompletion });
45
+ const { workerNotifyFn, notifyOwnerAgentCompletionEarly } = createNotify(mgr, {
46
+ notifySessionCompletion,
47
+ onWorkerCompletionQueued,
48
+ });
45
49
 
46
50
  // Idle-progress watchdogs (shared sweep timer) live in
47
51
  // agent-watchdog-registry.mjs.
@@ -32,14 +32,16 @@ export function createTagLookup({ tags, mgr, readWorkerRows, reaper, getLiveSess
32
32
  const rows = [];
33
33
  const seen = new Set();
34
34
  const tombstones = reaper.tagTombstoneIndex();
35
- const add = (session, fallbackTag = '') => {
35
+ // `loaded`: `session` is getLiveSession's own answer (not a catalog
36
+ // summary), so consumers may reuse it instead of loading it again.
37
+ const add = (session, fallbackTag = '', loaded = false) => {
36
38
  const tag = agentTagOf(session) || clean(fallbackTag);
37
39
  if (!tag || !session?.id || session.closed === true) return;
38
40
  if (isLeadPoolAgent(session.agent)) return;
39
41
  if (!sessionMatchesContext(session, context)) return;
40
42
  if (seen.has(session.id)) return;
41
43
  seen.add(session.id);
42
- rows.push({ tag, session });
44
+ rows.push(loaded ? { tag, session, loaded: true } : { tag, session });
43
45
  };
44
46
  const addIndexRow = (row) => {
45
47
  const tag = clean(row?.tag);
@@ -70,9 +72,12 @@ export function createTagLookup({ tags, mgr, readWorkerRows, reaper, getLiveSess
70
72
  }
71
73
  }
72
74
  for (const [tag, sessionId] of tags.entries()) {
75
+ // add() drops an id already listed; loading it first (a whole-session
76
+ // read for an idle worker) was pure cost on every status pulse.
77
+ if (seen.has(sessionId)) continue;
73
78
  const session = getLiveSession(sessionId);
74
79
  if (session && reaper.tombstoneBlocksScan(session, tag, tombstones)) continue;
75
- add(session, tag);
80
+ add(session, tag, true);
76
81
  }
77
82
  return rows;
78
83
  }
@@ -112,6 +112,9 @@ export function createTagRegistry({ dataDir, cfgMod, mgr }) {
112
112
  readWorkerRows,
113
113
  writeWorkerRows: index.writeWorkerRows,
114
114
  flushWorkerIndexMutations: index.flushWorkerIndexMutations,
115
+ recoverStaleWorkerRows: index.recoverStaleWorkerRows,
116
+ pendingRestartFailures: index.pendingRestartFailures,
117
+ markRestartNotified: index.markRestartNotified,
115
118
  upsertWorkerSession: index.upsertWorkerSession,
116
119
  upsertWorkerSessionDeferred,
117
120
  upsertLeadSession,
@@ -55,6 +55,9 @@ export function normalizeWorkerRows(value) {
55
55
  // Why a `failed` row failed (row-liveness, a watchdog stop). Always
56
56
  // present, so a later whole-row write clears a stale reason.
57
57
  failureReason: clean(row.failureReason) || null,
58
+ // When the owner was told this row's turn died with a process restart;
59
+ // always present, so new work on the row starts unnotified.
60
+ restartNotified: clean(row.restartNotified) || null,
58
61
  permission: clean(row.permission) || null,
59
62
  toolPermission: clean(row.toolPermission) || null,
60
63
  messages: positiveInt(row.messages) || 0,
@@ -112,6 +115,7 @@ export function workerRowFromSession(session, fallbackTag = '', extra = {}, getS
112
115
  task_id: clean(extra.task_id || extra.taskId) || null,
113
116
  error: clean(extra.error) || null,
114
117
  failureReason: clean(extra.failureReason) || null,
118
+ restartNotified: clean(extra.restartNotified) || null,
115
119
  permission: clean(session?.permission) || null,
116
120
  toolPermission: clean(session?.toolPermission) || null,
117
121
  messages: Array.isArray(session?.messages) ? session.messages.length : 0,
@@ -161,14 +161,19 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
161
161
  });
162
162
  }
163
163
 
164
- // Startup recovery: stale active rows settle — as failed when the process
165
- // that ran their turn is gone (the turn never finished), otherwise to idle —
166
- // and an approval wait left behind by a runtime that is gone (daemon
167
- // restart) is cleared.
168
- function recoverStaleWorkerRows() {
164
+ // Startup recovery: stale active rows settle — as failed when another
165
+ // process ran their turn (it is gone, or is the predecessor still shutting
166
+ // down: either way the turn never finished), otherwise to idle — and an
167
+ // approval wait left behind by a runtime that is gone (daemon restart) is
168
+ // cleared. `deadOnly` (later sweeps) settles only rows whose runtime is
169
+ // provably dead, never a live process's quiet turn.
170
+ function recoverStaleWorkerRows({ deadOnly = false } = {}) {
169
171
  const now = Date.now();
170
172
  const rows = store.readAll();
171
- const staleActive = rows.filter((row) => liveness.isStaleActive(row, now));
173
+ const isStale = deadOnly
174
+ ? (row) => isActiveWorkerRow(row) && runtimeDied(row)
175
+ : (row) => liveness.isStaleActive(row, now);
176
+ const staleActive = rows.filter(isStale);
172
177
  const staleWaits = rows.some(isStaleApprovalWait);
173
178
  if (!staleActive.length && !staleWaits) return false;
174
179
  if (staleActive.length) {
@@ -176,12 +181,11 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
176
181
  for (const row of staleActive) {
177
182
  const key = workerRowKey(row);
178
183
  const current = byKey.get(key);
179
- if (!current || !liveness.isStaleActive(current, now)) continue;
184
+ if (!current || !isStale(current)) continue;
185
+ const ranElsewhere = positiveInt(current.runtimePid) && positiveInt(current.runtimePid) !== process.pid;
180
186
  byKey.set(
181
187
  key,
182
- runtimeDied(current)
183
- ? liveness.failedRow(current, now, PROCESS_RESTART_FAILURE)
184
- : liveness.idleRow(current, now)
188
+ ranElsewhere ? liveness.failedRow(current, now, PROCESS_RESTART_FAILURE) : liveness.idleRow(current, now)
185
189
  );
186
190
  }
187
191
  });
@@ -190,6 +194,34 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
190
194
  return true;
191
195
  }
192
196
 
197
+ const isUnnotifiedRestartFailure = (row) =>
198
+ row.status === 'failed' &&
199
+ row.failureReason === PROCESS_RESTART_FAILURE &&
200
+ Boolean(clean(row.ownerSessionId)) &&
201
+ !row.restartNotified;
202
+
203
+ /** Rows whose turn a process restart ended and whose owner has not been told
204
+ * yet — whoever settled the row (this process at startup, or the
205
+ * predecessor's exit flush). Read-only: the caller enqueues the owner's
206
+ * notification durably, THEN calls `markRestartNotified`, so a crash in
207
+ * between retries (the notification's stable id makes the retry exactly-once). */
208
+ function pendingRestartFailures() {
209
+ return store.readAll().filter(isUnnotifiedRestartFailure);
210
+ }
211
+
212
+ /** Stamp these rows as told, once their notification is durably queued. */
213
+ function markRestartNotified(rows) {
214
+ const stamp = new Date().toISOString();
215
+ store.write((byKey) => {
216
+ for (const row of rows) {
217
+ const key = workerRowKey(row);
218
+ const current = byKey.get(key);
219
+ if (!current || !isUnnotifiedRestartFailure(current)) continue;
220
+ byKey.set(key, { ...current, restartNotified: stamp });
221
+ }
222
+ });
223
+ }
224
+
193
225
  function flushWorkerIndexOnExit() {
194
226
  batch.flush();
195
227
  flushActiveWorkerRows();
@@ -285,5 +317,7 @@ export function createWorkerIndex({ dataDir, cfgMod, mgr, tags, tagAgents, tagCw
285
317
  flushActiveWorkerRows,
286
318
  flushWorkerIndexOnExit,
287
319
  recoverStaleWorkerRows,
320
+ pendingRestartFailures,
321
+ markRestartNotified,
288
322
  };
289
323
  }
@@ -9,6 +9,7 @@ import { liveAgentStatusRow } from './agent-tool/job-views/session-progress.mjs'
9
9
  import { createSpawnFlow } from './agent-tool/spawn-flow.mjs';
10
10
  import { createSendFlow } from './agent-tool/send-flow.mjs';
11
11
  import { createCloseFlow } from './agent-tool/close-flow.mjs';
12
+ import { createRestartFailureNotifier } from './agent-tool/restart-notify.mjs';
12
13
  import { createTerminalTrace } from './agent-tool/terminal-trace.mjs';
13
14
  import { createAgentExecute } from './agent-tool/execute.mjs';
14
15
  import { createTurnReviewCollector } from './agent-tool/turn-review.mjs';
@@ -70,8 +71,24 @@ export function createStandaloneAgent({
70
71
  }
71
72
 
72
73
  const registry = createTagRegistry({ dataDir, cfgMod, mgr });
74
+ // Tasks the previous process was running died with it: tell their owners.
75
+ // Later sweeps also catch rows the predecessor settled as it shut down.
76
+ const notifyRestartFailures = createRestartFailureNotifier({
77
+ pendingRestartFailures: registry.pendingRestartFailures,
78
+ markRestartNotified: registry.markRestartNotified,
79
+ mgr,
80
+ notifySessionCompletion,
81
+ });
82
+ const sweepRestartFailures = () => {
83
+ registry.recoverStaleWorkerRows({ deadOnly: true });
84
+ notifyRestartFailures();
85
+ };
86
+ notifyRestartFailures();
73
87
  const views = createJobViews({ ...registry, mgr, reg, cfgMod, DEFAULT_SPAWN_PREP_TIMEOUT_MS });
88
+ // Late-bound: the send flow that wakes an idle worker is built after spawn.
89
+ let wakeIdleWorker = null;
74
90
  const spawnFlow = createSpawnFlow({
91
+ onWorkerCompletionQueued: (sessionId) => wakeIdleWorker?.(sessionId),
75
92
  ...registry,
76
93
  ...views,
77
94
  mgr,
@@ -96,6 +113,7 @@ export function createStandaloneAgent({
96
113
  views,
97
114
  spawnFlow,
98
115
  });
116
+ wakeIdleWorker = sendFlow.wakeIdleWorker;
99
117
  const closeFlow = createCloseFlow({ mgr, registry, views });
100
118
  const terminalTrace = createTerminalTrace({ registry });
101
119
  const execute = createAgentExecute({
@@ -116,6 +134,7 @@ export function createStandaloneAgent({
116
134
  void awaitKeychainPrewarm();
117
135
  return { workers: [], jobs: [], scope: null };
118
136
  }
137
+ sweepRestartFailures();
119
138
  const scopedContext = agentScope({}, context);
120
139
  const ownerSession = callerSessionForContext(scopedContext);
121
140
  const pid = terminalPidForContext(scopedContext);
@@ -134,6 +153,7 @@ export function createStandaloneAgent({
134
153
  void awaitKeychainPrewarm();
135
154
  return [];
136
155
  }
156
+ sweepRestartFailures();
137
157
  const scopedContext = agentScope({ recover: true }, context);
138
158
  registry.refreshTagsFromSessions({ scanSessions: true, context: scopedContext });
139
159
  return views.list({ scanSessions: false, context: scopedContext });
@@ -23,13 +23,14 @@ import {
23
23
  setEndpointEnabled as dbSetEndpointEnabled,
24
24
  } from '../../runtime/channels/lib/webhooks-db.mjs';
25
25
  import { normalizeAutomationAttachments } from '../../runtime/shared/automation-attachments.mjs';
26
- import { migrateCodexModelRef } from '../../runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs';
26
+ import { assertRoutineOwner, routineOwnerProblem } from '../routine-owner.mjs';
27
27
  import { hasEnabledAutomation } from '../../runtime/shared/automation-presence.mjs';
28
28
  import { resolveScheduleTimezone, validateScheduleCron } from '../../runtime/shared/schedule-time.mjs';
29
29
  import { pgClusterExists } from '../../runtime/memory/lib/pg/adapter.mjs';
30
30
  import { resolvePluginData } from '../../runtime/shared/plugin-paths.mjs';
31
31
  import { readHookPublicBase } from '../../runtime/channels/lib/webhook/relay-tunnel.mjs';
32
32
  import { WEBHOOK_TEST_FIELD, WEBHOOK_TEST_HEADER } from '../../runtime/channels/lib/webhook/request-handler.mjs';
33
+ import { MIXY_AGENT_ID, agentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
33
34
 
34
35
  const NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
35
36
 
@@ -187,7 +188,7 @@ function parseAtDatetime(at) {
187
188
  // Map the store's def shape onto the flat display shape every schedule reader
188
189
  // (channelSetup, renderChannelStatus, TUI pickers) consumes: `.time` renders
189
190
  // the cron or the one-shot datetime, `.route` the channel/session target.
190
- function scheduleToDisplay(s) {
191
+ function scheduleToDisplay(s, ownerProblem = '') {
191
192
  return {
192
193
  name: s.name,
193
194
  description: s.description || '',
@@ -195,26 +196,85 @@ function scheduleToDisplay(s) {
195
196
  whenAt: s.whenAt || undefined,
196
197
  whenCron: s.whenCron || undefined,
197
198
  timezone: s.timezone || undefined,
198
- // Shown (and re-saved by the editor) on the catalog successor of a superseded model.
199
- model: s.model ? migrateCodexModelRef(s.model) : undefined,
200
199
  cwd: s.cwd || undefined,
201
- workflow: s.workflow || undefined,
202
200
  attachments: s.attachments || undefined,
203
201
  enabled: s.enabled !== false,
204
202
  instructions: s.prompt,
205
203
  route: 'session',
204
+ // The bot it belongs to: each run is a turn in that bot's chat.
205
+ owner: s.ownerAgentId || MIXY_AGENT_ID,
206
+ // Why it is paused for its owner (routine-owner.mjs); absent when it runs.
207
+ ...(ownerProblem ? { ownerProblem } : {}),
208
+ nextFireAt: isoOrUndefined(s.nextFireAt),
209
+ lastSuccessAt: isoOrUndefined(s.lastSuccessAt),
210
+ lastFailedAt: isoOrUndefined(s.lastFailedAt),
211
+ lastSkippedAt: isoOrUndefined(s.lastSkippedAt),
212
+ ...routineHealth(s),
213
+ };
214
+ }
215
+
216
+ // Failures in a row (the routine pauses itself at the limit) and the results
217
+ // of finished runs still not queued for the owner: `{ count, failed, error }`,
218
+ // `failed` when the queue refused one (the app offers a retry).
219
+ function routineHealth(row) {
220
+ const entries = Object.values(row.resultDelivery || {}).filter(Boolean);
221
+ const refused = entries.filter((entry) => entry.state === 'failed').at(-1);
222
+ return {
223
+ consecutiveFailures: Number(row.consecutiveFailures) || 0,
224
+ ...(entries.length
225
+ ? {
226
+ undelivered: {
227
+ count: entries.length,
228
+ failed: Boolean(refused),
229
+ ...(refused?.error ? { error: String(refused.error) } : {}),
230
+ },
231
+ }
232
+ : {}),
233
+ };
234
+ }
235
+
236
+ function isoOrUndefined(value) {
237
+ if (!value) return undefined;
238
+ const at = new Date(value);
239
+ return Number.isNaN(at.getTime()) ? undefined : at.toISOString();
240
+ }
241
+
242
+ // A schedule's or webhook's owner: an explicit agent id, else the saved owner
243
+ // on an overwrite, else Mixy.
244
+ function scheduleOwner(owner, existing) {
245
+ const value = String(owner ?? '').trim();
246
+ if (value) {
247
+ if (!agentHomeSessionId(value)) throw new Error(`schedule owner "${value}" is not a valid agent id`);
248
+ return value;
249
+ }
250
+ return existing?.ownerAgentId || MIXY_AGENT_ID;
251
+ }
252
+
253
+ /** Each owner's problem (routine-owner.mjs), probed once per owner. */
254
+ function ownerProblems() {
255
+ const seen = new Map();
256
+ return (ownerAgentId) => {
257
+ const owner = ownerAgentId || MIXY_AGENT_ID;
258
+ if (!seen.has(owner))
259
+ seen.set(
260
+ owner,
261
+ routineOwnerProblem(owner).catch(() => '')
262
+ );
263
+ return seen.get(owner);
206
264
  };
207
265
  }
208
266
 
209
267
  export async function listSchedules() {
210
268
  const rows = await dbListSchedules();
211
- return rows.map(scheduleToDisplay);
269
+ const problemOf = ownerProblems();
270
+ return Promise.all(rows.map(async (row) => scheduleToDisplay(row, await problemOf(row.ownerAgentId))));
212
271
  }
213
272
 
214
273
  // Register or update a schedule in the PG store. Recurring input maps `time`
215
274
  // (+ optional `days`) to a cron; one-shot input maps an `at` datetime; the two
216
275
  // are mutually exclusive (also enforced by the store's when_at/when_cron XOR).
217
- // Every schedule runs as a visible app session and requires a model.
276
+ // Every schedule runs as a turn in its owner bot's chat; a bot that does not
277
+ // exist (no representative bot yet, an archived bot) cannot own one.
218
278
  export async function saveSchedule({
219
279
  name,
220
280
  description = '',
@@ -222,26 +282,26 @@ export async function saveSchedule({
222
282
  at,
223
283
  timezone,
224
284
  days,
225
- model,
226
285
  cwd,
227
- workflow,
228
286
  attachments,
229
287
  enabled,
230
288
  instructions,
289
+ owner,
231
290
  overwrite = false,
232
291
  } = {}) {
233
292
  const id = assertScheduleName(name);
234
293
  const body = String(instructions || '').trim();
235
294
  if (!body) throw new Error('schedule instructions are required');
236
- const scheduleModel = String(model || '').trim();
237
- if (!scheduleModel) throw new Error('schedule model is required — choose a model before saving');
238
295
  const hasTime = time != null && String(time).trim() !== '';
239
296
  const hasAt = at != null && String(at).trim() !== '';
240
297
  if (hasTime && hasAt) throw new Error('provide either `time` (recurring) or `at` (one-shot), not both');
241
298
  if (!hasTime && !hasAt) throw new Error('either `time` (recurring cron) or `at` (one-shot datetime) is required');
242
- if (overwrite !== true && (await dbGetSchedule(id))) {
299
+ const existing = await dbGetSchedule(id);
300
+ if (overwrite !== true && existing) {
243
301
  throw new Error(`schedule "${id}" already exists`);
244
302
  }
303
+ const ownerAgentId = scheduleOwner(owner, existing);
304
+ await assertRoutineOwner(ownerAgentId);
245
305
  const whenCron = hasTime ? validateScheduleCron(foldDaysIntoCron(normalizeCron(time), days)) : null;
246
306
  const whenAt = hasAt ? parseAtDatetime(at) : null;
247
307
  const scheduleTimezone = hasTime ? resolveScheduleTimezone(timezone) : null;
@@ -253,14 +313,13 @@ export async function saveSchedule({
253
313
  timezone: scheduleTimezone,
254
314
  target: 'session',
255
315
  channelId: null,
256
- model: scheduleModel,
257
316
  cwd: cwd ? String(cwd).trim() : null,
258
- workflow: workflow ? String(workflow).trim() : null,
259
317
  attachments: normalizeAutomationAttachments(attachments),
260
318
  delivery: 'app',
261
319
  prompt: body,
262
320
  enabled: enabled !== false,
263
321
  nextFireAt: whenAt,
322
+ ownerAgentId,
264
323
  });
265
324
  automationProbe.invalidate();
266
325
  return scheduleToDisplay(saved);
@@ -287,13 +346,13 @@ export async function setScheduleEnabled(name, enabled) {
287
346
  // store's migration hook.
288
347
  async function listWebhooks() {
289
348
  const endpoints = await dbListEndpoints();
290
- return endpoints.map((ep) => ({
349
+ const problemOf = ownerProblems();
350
+ const problems = await Promise.all(endpoints.map((ep) => problemOf(ep.ownerAgentId)));
351
+ return endpoints.map((ep, index) => ({
291
352
  name: ep.name,
292
353
  description: ep.description || '',
293
354
  parser: ep.parser || 'github',
294
- ...(ep.model ? { model: migrateCodexModelRef(ep.model) } : {}),
295
355
  ...(ep.cwd ? { cwd: ep.cwd } : {}),
296
- ...(ep.workflow ? { workflow: ep.workflow } : {}),
297
356
  ...(ep.attachments ? { attachments: ep.attachments } : {}),
298
357
  enabled: ep.enabled,
299
358
  // The store never projects the plaintext secret through list paths; it
@@ -302,6 +361,16 @@ async function listWebhooks() {
302
361
  secret: undefined,
303
362
  instructions: ep.instructions,
304
363
  route: 'session',
364
+ // The bot it belongs to: each run is a turn in that bot's chat.
365
+ owner: ep.ownerAgentId || MIXY_AGENT_ID,
366
+ ...(problems[index] ? { ownerProblem: problems[index] } : {}),
367
+ lastEventAt: isoOrUndefined(ep.lastEventAt),
368
+ lastSuccessAt: isoOrUndefined(ep.lastSuccessAt),
369
+ lastFailedAt: isoOrUndefined(ep.lastFailedAt),
370
+ lastSkippedAt: isoOrUndefined(ep.lastSkippedAt),
371
+ // Whether "Run now" has a received payload to re-run (never the payload).
372
+ hasLastPayload: ep.hasLastPayload === true,
373
+ ...routineHealth(ep),
305
374
  }));
306
375
  }
307
376
 
@@ -310,12 +379,11 @@ export async function saveWebhook({
310
379
  description = '',
311
380
  parser = 'github',
312
381
  secret,
313
- model,
314
382
  cwd,
315
- workflow,
316
383
  attachments,
317
384
  enabled,
318
385
  instructions,
386
+ owner,
319
387
  overwrite = false,
320
388
  } = {}) {
321
389
  const id = assertName(name, 'webhook name');
@@ -327,9 +395,12 @@ export async function saveWebhook({
327
395
  }
328
396
  const body = String(instructions || '').trim();
329
397
  if (!body) throw new Error('webhook instructions are required');
330
- if (overwrite !== true && (await dbLoadEndpoint(id))) {
398
+ const existing = await dbLoadEndpoint(id);
399
+ if (overwrite !== true && existing) {
331
400
  throw new Error(`webhook "${id}" already exists`);
332
401
  }
402
+ const ownerAgentId = scheduleOwner(owner, existing);
403
+ await assertRoutineOwner(ownerAgentId);
333
404
  // Secret semantics: an explicit value always wins; an EMPTY value on an
334
405
  // overwrite PRESERVES the stored secret (editing instructions must not
335
406
  // silently rotate the key the external service was configured with); only
@@ -343,23 +414,21 @@ export async function saveWebhook({
343
414
  description: String(description || '').trim(),
344
415
  parser: nextParser,
345
416
  channelId: null,
346
- model: model ? String(model).trim() : null,
347
417
  cwd: cwd ? String(cwd).trim() : null,
348
- workflow: workflow ? String(workflow).trim() : null,
349
418
  attachments: normalizeAutomationAttachments(attachments),
350
419
  delivery: 'app',
351
420
  secret: secretValue,
352
421
  instructions: body,
353
422
  enabled: enabled !== false,
423
+ ownerAgentId,
354
424
  });
355
425
  automationProbe.invalidate();
356
426
  return {
357
427
  name: id,
428
+ owner: saved.ownerAgentId || ownerAgentId,
358
429
  description: saved.description,
359
430
  parser: saved.parser,
360
- ...(saved.model ? { model: saved.model } : {}),
361
431
  ...(saved.cwd ? { cwd: saved.cwd } : {}),
362
- ...(saved.workflow ? { workflow: saved.workflow } : {}),
363
432
  ...(saved.attachments ? { attachments: saved.attachments } : {}),
364
433
  ...(enabled === false ? { enabled: false } : {}),
365
434
  secret: secretValue,
@@ -0,0 +1,37 @@
1
+ // Whose memory a session reads and writes (runtime/memory/lib/
2
+ // core-memory-access.mjs enforces it). Mixy is the Lead configuration, so the
3
+ // user's own sessions (an ordinary Lead session, Mixy's home) act as Mixy; an
4
+ // agent's home thread and its room member sessions act as that agent; a
5
+ // schedule or webhook run acts for its owning agent (`ownerAgentId`, stamped
6
+ // at creation); a delegated agent as its own agent id.
7
+ import { MIXY_AGENT_ID, agentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
8
+ import { resolveSessionMode } from '../../runtime/agent/orchestrator/session/agent-mode.mjs';
9
+ import { isAgentOwner } from '../../runtime/agent/orchestrator/agent-owner.mjs';
10
+ import { scheduleCallerScope } from './schedule-access.mjs';
11
+
12
+ const validAgentId = (value) => {
13
+ const id = typeof value === 'string' ? value.trim() : '';
14
+ return id && agentHomeSessionId(id) ? id : '';
15
+ };
16
+
17
+ /** The `memory_caller` `{ kind, agentId }` of a calling session record:
18
+ * 'human' and 'agent' are conversations with the user, 'room-member' and
19
+ * 'headless' unattended runs. */
20
+ export function memoryCallerScope(session) {
21
+ const scope = scheduleCallerScope(session);
22
+ if (scope.kind === 'human') return { kind: 'human', agentId: MIXY_AGENT_ID };
23
+ if (scope.kind !== 'headless') return scope;
24
+ const delegated = isAgentOwner(session) || Boolean(session?.parentSessionId);
25
+ return {
26
+ kind: 'headless',
27
+ agentId: validAgentId(session?.ownerAgentId) || (delegated ? validAgentId(session?.agent) : ''),
28
+ };
29
+ }
30
+
31
+ /** The agent whose own memory a session's prompt carries: its home thread's,
32
+ * room member's or run owner's agent, Mixy for the user's Lead sessions, and
33
+ * none for a delegated agent. `session` is the live record when there is
34
+ * one, else the reserved id and creation profile. */
35
+ export function injectedMemoryAgentId({ session = null, sessionId = '', profile = null } = {}) {
36
+ return resolveSessionMode({ session, sessionId, profile }).agentId;
37
+ }