mixdog 1.3.3 → 1.3.5

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 (210) hide show
  1. package/LICENSES/oh-my-pi-MIT.txt +23 -0
  2. package/NOTICE.md +15 -0
  3. package/README.md +11 -0
  4. package/package.json +3 -2
  5. package/scripts/embed-google-oauth-client.mjs +49 -0
  6. package/scripts/lib/test-spawn-ledger.mjs +46 -1
  7. package/scripts/test.mjs +5 -0
  8. package/src/defaults/shipped-history.json +8 -0
  9. package/src/defaults/skills/browser-use/SKILL.md +21 -9
  10. package/src/defaults/skills/setup/SKILL.md +7 -2
  11. package/src/defaults/skills/setup/references/actions.md +82 -27
  12. package/src/defaults/skills/setup/references/surfaces.md +67 -34
  13. package/src/defaults/skills/setup-guide/SKILL.md +3 -3
  14. package/src/lib/keychain-cjs.cjs +359 -29
  15. package/src/rules/agent-mode/AGENT_MODE.md +10 -2
  16. package/src/rules/agent-mode/MIXY.md +12 -0
  17. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
  18. package/src/runtime/agent/orchestrator/config.mjs +18 -0
  19. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +2 -2
  20. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  21. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
  22. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
  23. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
  24. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
  25. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
  26. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
  27. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +68 -23
  28. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +22 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  31. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -3
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
  35. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +19 -2
  38. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
  41. package/src/runtime/agent/orchestrator/providers/cursor.mjs +7 -0
  42. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
  43. package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
  44. package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
  45. package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
  46. package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
  47. package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
  48. package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
  49. package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
  50. package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
  51. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
  52. package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
  53. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
  54. package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
  55. package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
  58. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
  60. package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
  61. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  62. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
  63. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
  64. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +17 -0
  65. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  68. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
  69. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
  71. package/src/runtime/agent/orchestrator/providers/registry.mjs +17 -3
  72. package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
  73. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  74. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
  75. package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
  76. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  77. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
  78. package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
  79. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
  80. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
  81. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
  83. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
  84. package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
  85. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +15 -3
  86. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +5 -0
  87. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +36 -4
  88. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -0
  89. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +15 -3
  90. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
  91. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  92. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
  93. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +50 -2
  94. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
  95. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +11 -2
  96. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +11 -2
  97. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
  98. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
  99. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
  100. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
  101. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
  102. package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
  103. package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
  104. package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
  105. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
  106. package/src/runtime/agent/orchestrator/session/routine-result.mjs +11 -2
  107. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
  108. package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
  109. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +125 -12
  110. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
  111. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
  112. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
  113. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +7 -1
  114. package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
  115. package/src/runtime/channels/lib/scheduler.mjs +109 -14
  116. package/src/runtime/channels/lib/schedules-db.mjs +49 -0
  117. package/src/runtime/channels/lib/tool-dispatch.mjs +13 -0
  118. package/src/runtime/channels/lib/worker-main.mjs +9 -0
  119. package/src/runtime/office/com/com-adapter.mjs +17 -1
  120. package/src/runtime/office/com/office-com-host.ps1 +51 -1
  121. package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
  122. package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
  123. package/src/runtime/office/pdf/document-preview.mjs +326 -8
  124. package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
  125. package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
  126. package/src/runtime/office/portable/portable-soffice.mjs +45 -5
  127. package/src/runtime/shared/agent-room-host.mjs +1 -1
  128. package/src/runtime/shared/bot-hops.mjs +62 -2
  129. package/src/runtime/shared/config.mjs +49 -22
  130. package/src/runtime/shared/connector-catalog.d.mts +4 -2
  131. package/src/runtime/shared/connector-catalog.mjs +16 -8
  132. package/src/runtime/shared/developer-options.mjs +32 -1
  133. package/src/runtime/shared/google-oauth-client.generated.json +4 -0
  134. package/src/runtime/shared/google-oauth-client.mjs +34 -9
  135. package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
  136. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
  137. package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
  138. package/src/runtime/shared/llm/usage-rollup.mjs +4 -383
  139. package/src/runtime/shared/llm/well-formed.mjs +66 -0
  140. package/src/runtime/shared/provider-accounts.mjs +224 -58
  141. package/src/runtime/shared/provider-api-key.mjs +19 -8
  142. package/src/runtime/shared/routine-trigger.mjs +42 -0
  143. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  144. package/src/runtime/shared/transcript-metadata.mjs +38 -0
  145. package/src/runtime/shared/user-data-guard.mjs +30 -2
  146. package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
  147. package/src/session-runtime/agent-home-delivery.mjs +57 -13
  148. package/src/session-runtime/agent-room-delivery.mjs +28 -1
  149. package/src/session-runtime/agent-task-sessions.mjs +292 -79
  150. package/src/session-runtime/agent-tool-routing.mjs +49 -4
  151. package/src/session-runtime/boot/begin.mjs +3 -2
  152. package/src/session-runtime/boot/tools.mjs +4 -0
  153. package/src/session-runtime/bot-chain.mjs +32 -0
  154. package/src/session-runtime/bot-status.mjs +7 -4
  155. package/src/session-runtime/channel-config-api.mjs +63 -17
  156. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
  157. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
  158. package/src/session-runtime/internal-tool-executor.mjs +4 -0
  159. package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -1
  160. package/src/session-runtime/mixy-heartbeat.mjs +807 -0
  161. package/src/session-runtime/model-route/route-tuning.mjs +10 -6
  162. package/src/session-runtime/owned-automation-run.mjs +33 -12
  163. package/src/session-runtime/provider-auth/login.mjs +7 -0
  164. package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
  165. package/src/session-runtime/routine-home-turn.mjs +33 -6
  166. package/src/session-runtime/schedule-session-run.mjs +7 -3
  167. package/src/session-runtime/services/agent-tool/close-flow.mjs +14 -2
  168. package/src/session-runtime/services/agent-tool/execute.mjs +6 -1
  169. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +11 -2
  170. package/src/session-runtime/services/agent-tool/render.mjs +3 -1
  171. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
  172. package/src/session-runtime/services/agent-tool/tool-def.mjs +1 -1
  173. package/src/session-runtime/services/channel-admin.mjs +66 -18
  174. package/src/session-runtime/services/channel-worker.mjs +1 -1
  175. package/src/session-runtime/services/provider-admin.mjs +128 -25
  176. package/src/session-runtime/services/schedule-access.mjs +14 -0
  177. package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
  178. package/src/session-runtime/session-create/session-options.mjs +7 -4
  179. package/src/session-runtime/settings-system-api.mjs +16 -1
  180. package/src/session-runtime/setup-tool/executor.mjs +49 -14
  181. package/src/session-runtime/setup-tool/extended-actions.mjs +29 -3
  182. package/src/session-runtime/setup-tool/settings-contract.mjs +65 -4
  183. package/src/session-runtime/setup-tool/tool-defs.mjs +30 -3
  184. package/src/session-runtime/task-session-route.mjs +99 -0
  185. package/src/session-runtime/tool-policy/policy-stage.mjs +5 -2
  186. package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
  187. package/src/session-runtime/tool-surface.mjs +4 -0
  188. package/src/session-runtime/usage-stats-api.mjs +1 -1
  189. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
  190. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
  191. package/src/session-runtime/workspace/transitions.mjs +10 -2
  192. package/src/standalone/daemon-session-control.mjs +88 -20
  193. package/src/standalone/daemon.mjs +8 -0
  194. package/src/standalone/session-protocol.mjs +5 -0
  195. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
  196. package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
  197. package/src/standalone/session-service.mjs +13 -0
  198. package/src/standalone/session-tool-output.mjs +8 -5
  199. package/src/tui/app/model-options.mjs +2 -0
  200. package/src/tui/dist/index.mjs +335 -172
  201. package/src/tui/session/notice-surface.mjs +17 -1
  202. package/src/tui/session/session-api/integrations.mjs +1 -0
  203. package/src/tui/session/session-api/lifecycle.mjs +8 -0
  204. package/src/tui/session/session-api/settings.mjs +14 -2
  205. package/src/tui/session/turn-stream.mjs +17 -1
  206. package/src/tui/session/turn.mjs +22 -2
  207. package/src/vendor/statusline/src/gateway/claude-current.mjs +0 -58
  208. package/src/vendor/statusline/src/gateway/route-meta.mjs +1 -361
  209. package/src/vendor/statusline/src/gateway/session-routes.mjs +0 -55
  210. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +0 -285
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Rows posted into an agent's home thread (`sess_home_<owner>`) from outside
3
3
  * its turns: held requests of unattended runs, reports of task sessions the
4
- * agent created, and routine results left by runs from before routines ran as
5
- * turns in the thread itself (routine-home-turn.mjs).
4
+ * agent created, the agent's own reply of a turn it ran in a hidden session
5
+ * (Mixy's heartbeat), and routine results left by runs from before routines
6
+ * ran as turns in the thread itself (routine-home-turn.mjs).
6
7
  *
7
8
  * Delivery is durable. The finished run is first ENQUEUED in a persisted
8
9
  * per-home queue (`routine-results.json`), keyed by the run id, so a retried
@@ -67,6 +68,12 @@ import {
67
68
  /** A queued item's stored message and live notice: a routine result, or a
68
69
  * held request of an unattended run (session-runtime/held-requests.mjs). */
69
70
  function deliveredRow(item, messageId) {
71
+ // The agent's own words from a turn it ran elsewhere (mixy-heartbeat.mjs):
72
+ // one ordinary reply of the agent in its thread.
73
+ if (item.kind === 'agent-message') {
74
+ const message = { role: 'assistant', content: item.text, meta: { transcript: { at: item.at, messageId } } };
75
+ return { message, notice: { text: item.text, tone: 'info', assistant: true } };
76
+ }
70
77
  if (item.kind === 'held-request') {
71
78
  const message = heldRequestMessage({ ...item.held, at: item.at, messageId });
72
79
  return { message, notice: heldRequestNotice(message) };
@@ -124,9 +131,11 @@ export function scheduleOwnerAgentId(schedule) {
124
131
  }
125
132
 
126
133
  let liveSurface = null;
127
- /** `{ busy(sessionId), notice(sessionId, notice), wake(sessionId, prompt, { id }),
128
- * submit(sessionId, prompt, options), abort(sessionId) }` from the session
129
- * service; `wake` starts one hidden turn with submission `id` (resolves
134
+ /** `{ busy(sessionId), notice(sessionId, notice), react(sessionId, messageId,
135
+ * reactions), wake(sessionId, prompt, { id }), submit(sessionId, prompt,
136
+ * options), abort(sessionId) }` from the session service; `react` shows a
137
+ * message's new reactions in the runtime hosting it (message-reactions.mjs),
138
+ * `wake` starts one hidden turn with submission `id` (resolves
130
139
  * false when it was refused, else `{ settled }`: a promise of the turn's end
131
140
  * status, 'done' when it finished), `submit` queues a routine turn
132
141
  * (resolves whether it was accepted), `abort` stops the running turn. */
@@ -413,9 +422,9 @@ export function createRoutineResultQueue(
413
422
  async omitted(homeId) {
414
423
  return (await read()).omitted[homeId] || null;
415
424
  },
416
- /** Queue `item` for `homeId`; `unwatch` drops that watch in the same write,
417
- * also when the item was queued or posted before. */
418
- async add(homeId, item, { unwatch = '' } = {}) {
425
+ /** Queue `item` for `homeId`; `unwatch` (run ids) drops those watches in the
426
+ * same write, also when the item was queued or posted before. */
427
+ async add(homeId, item, { unwatch = [] } = {}) {
419
428
  await update((doc) => {
420
429
  let next = null;
421
430
  if (item.roundTrip !== true) next = appended(doc, homeId, [item]);
@@ -434,9 +443,10 @@ export function createRoutineResultQueue(
434
443
  next = { ...next, rounds: { ...doc.rounds, [homeId]: counted } };
435
444
  }
436
445
  }
437
- if (!unwatch || !doc.watches[unwatch]) return next ?? undefined;
446
+ const dropped = unwatch.filter((runId) => doc.watches[runId]);
447
+ if (!dropped.length) return next ?? undefined;
438
448
  const watches = { ...doc.watches };
439
- delete watches[unwatch];
449
+ for (const runId of dropped) delete watches[runId];
440
450
  return { ...(next || doc), watches };
441
451
  });
442
452
  },
@@ -585,7 +595,19 @@ function homeProvenDeleted(homeId, agentPresence, roomPresence) {
585
595
  }
586
596
 
587
597
  /** The queued item of one task report (enqueueTask). */
588
- function taskReportItem({ runId, taskSessionId, title, status, text = '', target, files = [], omitted = 0, hop = 0 }) {
598
+ function taskReportItem({
599
+ runId,
600
+ taskSessionId,
601
+ title,
602
+ status,
603
+ text = '',
604
+ target,
605
+ files = [],
606
+ omitted = 0,
607
+ hop = 0,
608
+ watchId = '',
609
+ watchIds = [],
610
+ }) {
589
611
  // The model-facing reply keeps its lines up to REPLY_LIMIT; the row's
590
612
  // one-line summary is derived from it (agentTaskMessage).
591
613
  const reply = boundedReply(text);
@@ -601,6 +623,11 @@ function taskReportItem({ runId, taskSessionId, title, status, text = '', target
601
623
  ...(reply.chars > reply.text.length ? { textChars: reply.chars } : {}),
602
624
  // Any session other than a task session the agent created.
603
625
  ...(target === 'session' ? { target } : {}),
626
+ // The send this report ends (the `sendId` the send's result named).
627
+ ...(watchId ? { sendId: String(watchId) } : {}),
628
+ // Every send this one turn answered (sends folded into a running turn
629
+ // report once); `sendId` is the first of them.
630
+ ...(watchIds.length > 1 ? { sendIds: watchIds.map(String) } : {}),
604
631
  // The files the turn produced (handoff-attachments.mjs collectTurnArtifacts).
605
632
  ...(Array.isArray(files) && files.length ? { files, ...(omitted > 0 ? { omitted } : {}) } : {}),
606
633
  roundTrip: status !== 'started' && status !== 'blocked',
@@ -997,11 +1024,11 @@ export function createAgentHomeDelivery({
997
1024
  * create) for its home thread, then start draining it. `status` 'started'
998
1025
  * and 'blocked' only post a line; a turn's end also wakes the agent. */
999
1026
  async function enqueueTask(agentId, report) {
1000
- const { runId, taskSessionId, watchId = '', from = '' } = report;
1027
+ const { runId, taskSessionId, watchId = '', watchIds = [], from = '' } = report;
1001
1028
  const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
1002
1029
  if (!runId || !taskSessionId) throw new Error('task report: runId and taskSessionId required');
1003
1030
  const item = taskReportItem(report);
1004
- const unwatch = watchId ? String(watchId) : '';
1031
+ const unwatch = [...new Set([watchId, ...watchIds].filter(Boolean).map(String))];
1005
1032
  // A room member's own work reports to its member session, never its home.
1006
1033
  const target = roomMemberOfSession(from)?.agentId === agentId ? from : homeId;
1007
1034
  await queue.add(target, item, { unwatch });
@@ -1009,6 +1036,17 @@ export function createAgentHomeDelivery({
1009
1036
  return target;
1010
1037
  }
1011
1038
 
1039
+ /** Persist `text`, the agent's own reply from turn `runId` it ran outside
1040
+ * its thread, for `agentId`'s home thread, then start draining it. It posts
1041
+ * once, as the agent's message; no turn follows. */
1042
+ async function enqueueMessage(agentId, { runId, text }) {
1043
+ const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
1044
+ if (!runId || !String(text || '').trim()) throw new Error('agent message: runId and text required');
1045
+ await queue.add(homeId, { runId: String(runId), kind: 'agent-message', text: String(text).trim(), at: Date.now() });
1046
+ void drain(homeId);
1047
+ return homeId;
1048
+ }
1049
+
1012
1050
  /** Show `run`'s live-only row (routineRunNotice: `running`, or a result whose
1013
1051
  * delivery failed) in `row`'s owner home when it is open and idle. Nothing
1014
1052
  * is stored and no turn or unread mark follows; the posted result (same
@@ -1054,6 +1092,7 @@ export function createAgentHomeDelivery({
1054
1092
  enqueue,
1055
1093
  enqueueHeld,
1056
1094
  enqueueTask,
1095
+ enqueueMessage,
1057
1096
  announce,
1058
1097
  drain,
1059
1098
  recover,
@@ -1128,6 +1167,11 @@ export async function deliverHeldRequest(agentId, held) {
1128
1167
  return (await processDelivery()).enqueueHeld(agentId, held);
1129
1168
  }
1130
1169
 
1170
+ /** Queue the agent's own reply of a turn it ran outside its home thread. */
1171
+ export async function deliverAgentMessage(agentId, message) {
1172
+ return (await processDelivery()).enqueueMessage(agentId, message);
1173
+ }
1174
+
1131
1175
  /** Queue one report of a task session for `agentId`'s home thread. */
1132
1176
  export async function deliverAgentTask(agentId, report) {
1133
1177
  return (await processDelivery()).enqueueTask(agentId, report);
@@ -15,6 +15,7 @@ import {
15
15
  roomRowItem,
16
16
  roomRowMessage,
17
17
  } from '../runtime/agent/orchestrator/session/agent-room.mjs';
18
+ import { reactInSession } from '../runtime/agent/orchestrator/session/message-reactions.mjs';
18
19
  import { artifactRecords } from '../runtime/shared/handoff-artifacts.mjs';
19
20
  import { collectTurnArtifacts, sessionRoots, turnSlice } from './handoff-attachments.mjs';
20
21
  import {
@@ -150,7 +151,28 @@ export function createAgentRoomDelivery({ loadSession, saveSession, live = agent
150
151
  return commit(sessionId, () => prepared);
151
152
  });
152
153
  }
153
- return { append };
154
+
155
+ /** A member's reaction (`change`: message-reactions.mjs reactToMessage's,
156
+ * members never repeating one another's emoji) on a user row of the log
157
+ * `sessionId`, in line with the posts; a room open in a window shows it at
158
+ * once. Resolves reactToMessage's result. */
159
+ async function react(sessionId, change) {
160
+ if (!roomIdOfSession(sessionId)) throw new TypeError('not a group-room session');
161
+ return serialized(sessionId, async () => {
162
+ const session = loadSession(sessionId);
163
+ if (!session || session.closed === true) throw new Error(`session ${sessionId} is not available`);
164
+ const result = reactInSession(session, { ...change, othersKeep: true });
165
+ if (!result.changed) return result;
166
+ await saveSession(session);
167
+ try {
168
+ live()?.react?.(sessionId, result.messageId, result.reactions);
169
+ } catch (error) {
170
+ log(`live reaction in ${sessionId} failed: ${error?.message || error}`);
171
+ }
172
+ return result;
173
+ });
174
+ }
175
+ return { append, react };
154
176
  }
155
177
 
156
178
  let processDelivery = null;
@@ -177,3 +199,8 @@ function roomDelivery() {
177
199
  export async function appendRoomRows(sessionId, rows) {
178
200
  return (await roomDelivery()).append(sessionId, rows);
179
201
  }
202
+
203
+ /** Daemon entry: a member's reaction on a user row of the room log `sessionId`. */
204
+ export async function reactInRoom(sessionId, change) {
205
+ return (await roomDelivery()).react(sessionId, change);
206
+ }