mixdog 0.9.1 → 0.9.2

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 (214) hide show
  1. package/package.json +8 -1
  2. package/scripts/_bench-cwc.json +20 -0
  3. package/scripts/agent-loop-policy-test.mjs +37 -0
  4. package/scripts/agent-parallel-smoke.mjs +54 -10
  5. package/scripts/background-task-meta-smoke.mjs +1 -1
  6. package/scripts/bench-run.mjs +262 -0
  7. package/scripts/compact-smoke.mjs +12 -0
  8. package/scripts/compact-trigger-migration-smoke.mjs +67 -1
  9. package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
  10. package/scripts/internal-comms-bench.mjs +727 -0
  11. package/scripts/internal-comms-smoke.mjs +75 -0
  12. package/scripts/lead-workflow-smoke.mjs +4 -4
  13. package/scripts/live-worker-smoke.mjs +9 -9
  14. package/scripts/output-style-bench.mjs +285 -0
  15. package/scripts/output-style-smoke.mjs +13 -10
  16. package/scripts/patch-replay.mjs +90 -0
  17. package/scripts/provider-stream-stall-test.mjs +276 -0
  18. package/scripts/provider-toolcall-test.mjs +599 -1
  19. package/scripts/routing-corpus.mjs +281 -0
  20. package/scripts/session-bench.mjs +1526 -0
  21. package/scripts/session-diag.mjs +595 -0
  22. package/scripts/task-bench.mjs +207 -0
  23. package/scripts/tool-failures.mjs +6 -6
  24. package/scripts/tool-smoke.mjs +306 -66
  25. package/scripts/toolcall-args-test.mjs +81 -0
  26. package/src/agents/debugger/AGENT.md +4 -4
  27. package/src/agents/heavy-worker/AGENT.md +4 -2
  28. package/src/agents/reviewer/AGENT.md +4 -4
  29. package/src/agents/worker/AGENT.md +4 -2
  30. package/src/app.mjs +10 -6
  31. package/src/defaults/{hidden-roles.json → agents.json} +7 -7
  32. package/src/examples/schedules/SCHEDULE.example.md +32 -0
  33. package/src/examples/webhooks/WEBHOOK.example.md +40 -0
  34. package/src/headless-role.mjs +14 -14
  35. package/src/help.mjs +1 -0
  36. package/src/lib/rules-builder.cjs +32 -54
  37. package/src/mixdog-session-runtime.mjs +710 -318
  38. package/src/output-styles/default.md +12 -7
  39. package/src/output-styles/minimal.md +25 -0
  40. package/src/output-styles/oneline.md +21 -0
  41. package/src/output-styles/simple.md +10 -9
  42. package/src/repl.mjs +12 -2
  43. package/src/rules/agent/00-common.md +7 -5
  44. package/src/rules/agent/30-explorer.md +7 -8
  45. package/src/rules/lead/01-general.md +3 -1
  46. package/src/rules/lead/lead-tool.md +7 -0
  47. package/src/rules/shared/01-tool.md +17 -12
  48. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
  49. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
  50. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
  51. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
  52. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
  53. package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
  54. package/src/runtime/agent/orchestrator/config.mjs +3 -0
  55. package/src/runtime/agent/orchestrator/context/collect.mjs +131 -67
  56. package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
  57. package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
  58. package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -16
  59. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
  61. package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
  62. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +332 -57
  63. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +59 -32
  64. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +27 -20
  65. package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
  66. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
  67. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
  68. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +210 -21
  69. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +78 -3
  70. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +202 -98
  71. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +183 -20
  72. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
  73. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +11 -5
  74. package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
  75. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +15 -9
  76. package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
  77. package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
  78. package/src/runtime/agent/orchestrator/session/loop.mjs +394 -132
  79. package/src/runtime/agent/orchestrator/session/manager.mjs +217 -170
  80. package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
  81. package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
  82. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
  83. package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
  84. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -24
  85. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
  86. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
  87. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +0 -0
  88. package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
  90. package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
  91. package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
  92. package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
  93. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +13 -4
  94. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
  95. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +18 -2
  96. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
  97. package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -1
  99. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
  100. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4076 -3985
  101. package/src/runtime/agent/orchestrator/tools/patch.mjs +116 -2
  102. package/src/runtime/channels/backends/discord.mjs +99 -9
  103. package/src/runtime/channels/backends/telegram.mjs +501 -0
  104. package/src/runtime/channels/index.mjs +441 -1224
  105. package/src/runtime/channels/lib/config.mjs +54 -2
  106. package/src/runtime/channels/lib/format.mjs +4 -2
  107. package/src/runtime/channels/lib/output-forwarder.mjs +80 -67
  108. package/src/runtime/channels/lib/runtime-paths.mjs +29 -0
  109. package/src/runtime/channels/lib/scheduler.mjs +1 -1
  110. package/src/runtime/channels/lib/telegram-format.mjs +283 -0
  111. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  112. package/src/runtime/channels/lib/transcript-discovery.mjs +19 -1
  113. package/src/runtime/channels/lib/webhook.mjs +59 -31
  114. package/src/runtime/channels/tool-defs.mjs +1 -1
  115. package/src/runtime/memory/index.mjs +184 -19
  116. package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
  117. package/src/runtime/memory/lib/core-memory-store.mjs +1 -1
  118. package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
  119. package/src/runtime/memory/lib/memory-cycle2.mjs +9 -6
  120. package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
  121. package/src/runtime/memory/lib/memory.mjs +101 -4
  122. package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
  123. package/src/runtime/memory/lib/session-ingest.mjs +107 -0
  124. package/src/runtime/memory/lib/trace-store.mjs +69 -22
  125. package/src/runtime/memory/tool-defs.mjs +6 -3
  126. package/src/runtime/shared/channel-notification-routing.mjs +12 -0
  127. package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
  128. package/src/runtime/shared/config.mjs +9 -0
  129. package/src/runtime/shared/llm/http-agent.mjs +12 -5
  130. package/src/runtime/shared/schedules-store.mjs +21 -19
  131. package/src/runtime/shared/tool-surface.mjs +98 -13
  132. package/src/runtime/shared/transcript-writer.mjs +129 -0
  133. package/src/runtime/shared/update-checker.mjs +214 -0
  134. package/src/standalone/agent-tool.mjs +255 -109
  135. package/src/standalone/channel-admin.mjs +133 -40
  136. package/src/standalone/channel-worker.mjs +8 -291
  137. package/src/standalone/explore-tool.mjs +2 -2
  138. package/src/standalone/memory-runtime-proxy.mjs +3 -1
  139. package/src/standalone/provider-admin.mjs +11 -0
  140. package/src/standalone/usage-dashboard.mjs +1 -1
  141. package/src/tui/App.jsx +2096 -732
  142. package/src/tui/components/ConfirmBar.jsx +47 -0
  143. package/src/tui/components/ContextPanel.jsx +5 -3
  144. package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
  145. package/src/tui/components/Markdown.jsx +22 -98
  146. package/src/tui/components/Message.jsx +14 -35
  147. package/src/tui/components/Picker.jsx +87 -12
  148. package/src/tui/components/PromptInput.jsx +83 -7
  149. package/src/tui/components/QueuedCommands.jsx +1 -1
  150. package/src/tui/components/SlashCommandPalette.jsx +8 -5
  151. package/src/tui/components/Spinner.jsx +7 -7
  152. package/src/tui/components/StatusLine.jsx +40 -21
  153. package/src/tui/components/TextEntryPanel.jsx +51 -7
  154. package/src/tui/components/ToolExecution.jsx +170 -98
  155. package/src/tui/components/TurnDone.jsx +4 -4
  156. package/src/tui/components/UsagePanel.jsx +1 -1
  157. package/src/tui/components/tool-output-format.mjs +159 -21
  158. package/src/tui/components/tool-output-format.test.mjs +87 -0
  159. package/src/tui/display-width.mjs +69 -0
  160. package/src/tui/display-width.test.mjs +35 -0
  161. package/src/tui/dist/index.mjs +6965 -2391
  162. package/src/tui/engine.mjs +287 -126
  163. package/src/tui/index.jsx +117 -7
  164. package/src/tui/keyboard-protocol.mjs +42 -0
  165. package/src/tui/lib/voice-recorder.mjs +453 -0
  166. package/src/tui/markdown/format-token.mjs +129 -76
  167. package/src/tui/markdown/format-token.test.mjs +61 -19
  168. package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
  169. package/src/tui/markdown/render-ansi.test.mjs +1 -1
  170. package/src/tui/markdown/streaming-markdown.mjs +167 -0
  171. package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
  172. package/src/tui/markdown/table-layout.mjs +9 -9
  173. package/src/tui/paste-attachments.mjs +0 -11
  174. package/src/tui/prompt-history-store.mjs +129 -0
  175. package/src/tui/prompt-history-store.test.mjs +52 -0
  176. package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
  177. package/src/tui/theme.mjs +41 -657
  178. package/src/tui/themes/base.mjs +86 -0
  179. package/src/tui/themes/basic.mjs +85 -0
  180. package/src/tui/themes/catppuccin.mjs +72 -0
  181. package/src/tui/themes/dracula.mjs +70 -0
  182. package/src/tui/themes/everforest.mjs +71 -0
  183. package/src/tui/themes/gruvbox.mjs +71 -0
  184. package/src/tui/themes/index.mjs +71 -0
  185. package/src/tui/themes/indigo.mjs +78 -0
  186. package/src/tui/themes/kanagawa.mjs +80 -0
  187. package/src/tui/themes/light.mjs +81 -0
  188. package/src/tui/themes/nord.mjs +72 -0
  189. package/src/tui/themes/onedark.mjs +16 -0
  190. package/src/tui/themes/rosepine.mjs +70 -0
  191. package/src/tui/themes/teal.mjs +81 -0
  192. package/src/tui/themes/tokyonight.mjs +79 -0
  193. package/src/tui/themes/utils.mjs +106 -0
  194. package/src/tui/themes/warm.mjs +79 -0
  195. package/src/tui/transcript-tool-failures.mjs +13 -2
  196. package/src/ui/markdown.mjs +1 -1
  197. package/src/ui/model-display.mjs +2 -2
  198. package/src/ui/statusline.mjs +26 -27
  199. package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
  200. package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
  201. package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
  202. package/src/workflows/default/WORKFLOW.md +39 -12
  203. package/src/workflows/sequential/WORKFLOW.md +46 -0
  204. package/src/workflows/solo/WORKFLOW.md +7 -0
  205. package/vendor/ink/build/display-width.js +62 -0
  206. package/vendor/ink/build/ink.js +100 -12
  207. package/vendor/ink/build/measure-text.js +4 -1
  208. package/vendor/ink/build/output.js +115 -9
  209. package/vendor/ink/build/render-node-to-output.js +4 -1
  210. package/vendor/ink/build/render.js +4 -0
  211. package/src/output-styles/extreme-simple.md +0 -20
  212. package/src/rules/lead/04-workflow.md +0 -51
  213. package/src/workflows/default/workflow.json +0 -13
  214. package/src/workflows/solo/workflow.json +0 -7
@@ -10,7 +10,7 @@
10
10
  * BP_1 system#1 (1h) — shared tool policy + compact skill manifest
11
11
  * BP_2 system#2 (1h) — role/system rules (Lead / agent / hidden role)
12
12
  * BP_3 system#3 (1h) — stable memory/meta marker (sessionMarker system block; tier3)
13
- * BP_4 messages (1h/5m) — sliding tool_result / prior user-text tail
13
+ * BP_4 messages (5m) — sliding tool_result / prior user-text tail
14
14
  *
15
15
  * Tool schemas still sit before system in the provider prompt prefix. We do
16
16
  * not spend a separate cache_control slot on tools; the first system BP covers
@@ -35,7 +35,7 @@
35
35
  */
36
36
 
37
37
  import { createHash } from 'crypto';
38
- import { getHiddenRole } from '../internal-roles.mjs';
38
+ import { getHiddenAgent } from '../internal-agents.mjs';
39
39
 
40
40
  /**
41
41
  * One-shot, LLM-only maintenance hidden roles (cycle1/cycle2/cycle3-agent):
@@ -49,8 +49,8 @@ import { getHiddenRole } from '../internal-roles.mjs';
49
49
  * 'unified' and therefore excluded — they run a tool loop whose tail caches
50
50
  * legitimately reuse across iterations.
51
51
  */
52
- function isOneShotMaintenanceRole(role) {
53
- const hidden = getHiddenRole(role);
52
+ function isOneShotMaintenanceAgent(agent) {
53
+ const hidden = getHiddenAgent(agent);
54
54
  return Boolean(
55
55
  hidden
56
56
  && hidden.kind === 'maintenance'
@@ -66,12 +66,15 @@ function isOneShotMaintenanceRole(role) {
66
66
  * '5m' → ephemeral 5m TTL (1.25x write premium, 0.1x read)
67
67
  * 'none' → no breakpoint written on this layer
68
68
  *
69
- * Public agents stay resumable for up to 1h (the terminal-reap window)
70
- * for same-task reuse, so their message tail uses 1h too. Hidden multi-turn
71
- * roles (explorer / scheduler / webhook) run a single fan-out or entry-driven
72
- * session that is not resumed for same-task reuse, so their volatile tail stays
73
- * at the cheaper 5m TTL. (Tail TTL only affects explicit-breakpoint providers
74
- * Anthropic; no-op elsewhere.)
69
+ * BP1~3 stay at 1h: the system/role/tier3 prefix is shared across sessions
70
+ * (pool-stable), so the 2x write premium is amortized cross-session and the
71
+ * warm window survives per-session gaps. The volatile message tail (BP4) is
72
+ * per-session and trace data (2026-06) shows request gaps are p99 4.5min
73
+ * 5m+ gaps mean a cold tail anyway, and the smart-compact path rebuilds the
74
+ * history at that boundary. So every session's tail uses the cheaper 5m TTL
75
+ * (1.25x write vs 2x), aligned with the 5m terminal-reap window for agents.
76
+ * (Tail TTL only affects explicit-breakpoint providers — Anthropic; no-op
77
+ * elsewhere.)
75
78
  *
76
79
  * Exception: one-shot LLM-only maintenance roles are asked once on a fresh
77
80
  * session and closed, so their volatile per-call message tail is never read
@@ -81,15 +84,15 @@ function isOneShotMaintenanceRole(role) {
81
84
  * the 1h TTL expiry (writes every run, 0 reads). All layers go 'none' for
82
85
  * these roles — single-iteration calls pay the write premium with no reuse.
83
86
  */
84
- export function resolveCacheStrategy(role) {
85
- if (isOneShotMaintenanceRole(role)) {
87
+ export function resolveCacheStrategy(agent) {
88
+ if (isOneShotMaintenanceAgent(agent)) {
86
89
  return { tools: 'none', system: 'none', tier3: 'none', messages: 'none' };
87
90
  }
88
- if (getHiddenRole(role)) {
91
+ if (getHiddenAgent(agent)) {
89
92
  return { tools: 'none', system: '1h', tier3: '1h', messages: '5m' };
90
93
  }
91
- // Public agents: resumable up to 1h for same-task reuse -> 1h tail.
92
- return { tools: 'none', system: '1h', tier3: '1h', messages: '1h' };
94
+ // Lead + public agents: per-session volatile tail -> 5m (see doc above).
95
+ return { tools: 'none', system: '1h', tier3: '1h', messages: '5m' };
93
96
  }
94
97
 
95
98
  /**
@@ -97,7 +100,7 @@ export function resolveCacheStrategy(role) {
97
100
  *
98
101
  * @param {string} provider
99
102
  * @param {string} [sessionId]
100
- * @param {string} [role]
103
+ * @param {string} [agent]
101
104
  * @returns {object} partial sendOpts — spread into provider.send call
102
105
  */
103
106
 
@@ -356,8 +359,8 @@ export function resolveProviderPromptCacheLane(provider, opts = {}, config = {})
356
359
  };
357
360
  }
358
361
 
359
- export function buildProviderCacheOpts(provider, sessionId, role) {
360
- const ttls = resolveCacheStrategy(role);
362
+ export function buildProviderCacheOpts(provider, sessionId, agent) {
363
+ const ttls = resolveCacheStrategy(agent);
361
364
  const capability = cacheCapabilityForProvider(provider);
362
365
  if (capability === 'explicit-breakpoint') {
363
366
  // 2026-03-06 Anthropic dropped default TTL 1h→5m. We send
@@ -400,8 +403,8 @@ export function computePrefixContent(systemPrompt, tools) {
400
403
  /**
401
404
  * Longest-lived layer TTL (seconds) for registry expiry tracking.
402
405
  */
403
- export function ttlSecondsForCache(role) {
404
- const ttls = resolveCacheStrategy(role);
406
+ export function ttlSecondsForCache(agent) {
407
+ const ttls = resolveCacheStrategy(agent);
405
408
  if (
406
409
  ttls.tools === 'none'
407
410
  && ttls.system === 'none'
@@ -19,12 +19,44 @@
19
19
 
20
20
  import { createSession } from '../session/manager.mjs';
21
21
  import { traceAgentPreset } from '../agent-trace.mjs';
22
- import { resolveAgentSessionPermission } from '../internal-roles.mjs';
22
+ import { resolveAgentSessionPermission } from '../internal-agents.mjs';
23
23
  import { loadConfig } from '../config.mjs';
24
+ import { AGENT_OWNER } from '../agent-owner.mjs';
25
+
26
+ import {
27
+ COMPACT_TYPE_RECALL_FASTTRACK,
28
+ COMPACT_TYPE_SEMANTIC,
29
+ normalizeCompactType,
30
+ } from '../session/compact.mjs';
31
+
32
+ function memoryModuleEnabled(config) {
33
+ const entry = config?.modules?.memory;
34
+ if (entry && typeof entry === 'object' && entry.enabled === false) return false;
35
+ return true;
36
+ }
37
+
38
+ function normalizeAgentCompactionConfig(value = {}, { memoryEnabled = true } = {}) {
39
+ const raw = value && typeof value === 'object' ? value : {};
40
+ let compactType = normalizeCompactType(
41
+ raw.compactType ?? raw.compact_type ?? raw.type,
42
+ COMPACT_TYPE_SEMANTIC,
43
+ );
44
+ // recall-fasttrack depends on memory ingest/recall; fall back to semantic when
45
+ // the memory module is disabled (same rule as Lead session runtime).
46
+ if (compactType === COMPACT_TYPE_RECALL_FASTTRACK && memoryEnabled === false) {
47
+ compactType = COMPACT_TYPE_SEMANTIC;
48
+ }
49
+ return {
50
+ ...raw,
51
+ auto: raw.auto !== false && raw.enabled !== false,
52
+ type: compactType,
53
+ compactType,
54
+ };
55
+ }
24
56
 
25
57
  /**
26
58
  * @param {object} opts
27
- * @param {string} opts.role — canonical role name ('worker', 'explorer', ...)
59
+ * @param {string} opts.agent — canonical agent name ('worker', 'explorer', ...)
28
60
  * @param {string} opts.presetName — resolved preset identifier
29
61
  * @param {object} opts.preset — resolved preset object from agent-config
30
62
  * @param {object} opts.runtimeSpec — resolveRuntimeSpec output; must carry .scopeKey / .lane
@@ -32,7 +64,7 @@ import { loadConfig } from '../config.mjs';
32
64
  * @param {string|null} [opts.cwd] — absolute working dir; null is the fixed agent sentinel meaning "no caller workspace context"
33
65
  * @param {string} [opts.owner='agent']
34
66
  * @param {string} [opts.permissionMode] — permissionMode forwarded from the MCP payload ('bypassPermissions', 'acceptEdits', 'plan', 'dontAsk', 'default')
35
- * @param {string[]} [opts.schemaAllowedTools] — schema-level allowlist from a hidden-role toolSchemaProfile
67
+ * @param {string[]} [opts.schemaAllowedTools] — schema-level allowlist from a hidden-agent toolSchemaProfile
36
68
  * @param {string} [opts.sourceType]
37
69
  * @param {string} [opts.sourceName]
38
70
  * @param {string} [opts.taskType]
@@ -42,7 +74,7 @@ import { loadConfig } from '../config.mjs';
42
74
  * @returns {{ session: object, effectiveCwd: string|null }}
43
75
  */
44
76
  export function prepareAgentSession({
45
- role,
77
+ agent,
46
78
  presetName,
47
79
  preset,
48
80
  runtimeSpec,
@@ -61,7 +93,10 @@ export function prepareAgentSession({
61
93
  cacheKeyOverride,
62
94
  schemaAllowedTools,
63
95
  }) {
64
- const effectivePermission = resolveAgentSessionPermission(role, permission);
96
+ const effectivePermission = resolveAgentSessionPermission(agent, permission);
97
+ // No per-agent loop caps: sessions either pin maxLoopIterations explicitly
98
+ // or fall through to the shared runaway guard (LEAD_MAX_LOOP_ITERATIONS).
99
+ const effectiveMaxLoopIterations = maxLoopIterations;
65
100
  // Pass cwd through verbatim — null is the fixed agent sentinel meaning
66
101
  // "no caller workspace context" (cycle1-agent shards, etc). Upgrading
67
102
  // null → process.cwd() here would defeat cache-shard fork suppression.
@@ -73,12 +108,11 @@ export function prepareAgentSession({
73
108
  let compaction = null;
74
109
  try {
75
110
  const cfg = loadConfig({ secrets: false });
76
- // Agent worker sessions should keep the higher-quality semantic compact
77
- // path even when the Lead session uses recall-fasttrack for cheap
78
- // auto-clear/auto-compact. Cycle maintenance prompts are small enough
79
- // that this normally only matters for long-lived worker conversations.
80
- const base = cfg?.compaction && typeof cfg.compaction === 'object' ? cfg.compaction : {};
81
- compaction = { ...base, type: '1', compactType: '1' };
111
+ if (cfg?.compaction && typeof cfg.compaction === 'object') {
112
+ compaction = normalizeAgentCompactionConfig(cfg.compaction, {
113
+ memoryEnabled: memoryModuleEnabled(cfg),
114
+ });
115
+ }
82
116
  } catch { /* config is best-effort for agent compaction policy */ }
83
117
  const sessionOpts = {
84
118
  preset,
@@ -86,9 +120,9 @@ export function prepareAgentSession({
86
120
  scopeKey: runtimeSpec.scopeKey,
87
121
  lane: runtimeSpec.lane,
88
122
  cwd: effectiveCwd,
89
- role: role || undefined,
123
+ agent: agent || undefined,
90
124
  taskType: taskType || undefined,
91
- maxLoopIterations: Number.isFinite(maxLoopIterations) ? maxLoopIterations : undefined,
125
+ maxLoopIterations: Number.isFinite(effectiveMaxLoopIterations) ? effectiveMaxLoopIterations : undefined,
92
126
  sourceType: sourceType || undefined,
93
127
  sourceName: sourceName || undefined,
94
128
  ownerSessionId: effectiveOwnerSessionId || null,
@@ -106,7 +140,7 @@ export function prepareAgentSession({
106
140
  try {
107
141
  traceAgentPreset({
108
142
  sessionId: session.id,
109
- role: role || null,
143
+ agent: agent || null,
110
144
  presetName: presetName || null,
111
145
  // runtimeSpec carries scopeKey/lane but resolveRuntimeSpec does not
112
146
  // populate model/provider — fall back to preset fields.
@@ -29,7 +29,16 @@ let _toolFailureTimer = null;
29
29
  let _toolFailureFlushInFlight = false;
30
30
  const _LOCAL_TRACE_FLUSH_LINES = 100;
31
31
  const _LOCAL_TRACE_FLUSH_MS = 1000;
32
- const _LOCAL_TRACE_MAX_BYTES = 10 * 1024 * 1024; // 10 MB — rotate to .1 above this.
32
+ const _LOCAL_TRACE_MAX_BYTES = 10 * 1024 * 1024; // 10 MB — rotate to .1/.2/.3 above this.
33
+ // Rotation generations kept on disk (.1 newest … .N oldest). A single .1
34
+ // generation proved too short a window — bench rounds (session-bench /
35
+ // task-bench re-scoring) were losing their raw turn rows to a second rotation
36
+ // within hours. 3 generations ≈ 40 MB worst case per log. Env-overridable via
37
+ // MIXDOG_AGENT_TRACE_ROTATE_KEEP (positive integer).
38
+ const _LOCAL_TRACE_ROTATE_KEEP = (() => {
39
+ const v = parseInt(process.env.MIXDOG_AGENT_TRACE_ROTATE_KEEP, 10);
40
+ return Number.isFinite(v) && v > 0 ? v : 3;
41
+ })();
33
42
  const _TOOL_FAILURE_FLUSH_LINES = 50;
34
43
  const _TOOL_FAILURE_FLUSH_MS = 1000;
35
44
  const MIXDOG_SLOW_TOOL_TRACE_MS = (() => {
@@ -59,7 +68,15 @@ function _rotateLocalTraceIfNeeded(path) {
59
68
  try {
60
69
  const stat = statSync(path);
61
70
  if (stat && stat.size > _LOCAL_TRACE_MAX_BYTES) {
62
- try { renameSync(path, `${path}.1`); }
71
+ try {
72
+ // Shift generations oldest-first: .2 → .3, .1 → .2, live → .1.
73
+ // The oldest (.KEEP) is overwritten by the rename below it.
74
+ for (let gen = _LOCAL_TRACE_ROTATE_KEEP - 1; gen >= 1; gen -= 1) {
75
+ const src = `${path}.${gen}`;
76
+ if (existsSync(src)) renameSync(src, `${path}.${gen + 1}`);
77
+ }
78
+ renameSync(path, `${path}.1`);
79
+ }
63
80
  catch (err) {
64
81
  warnAgentOnce('agent-trace:local-rotate', `[agent-trace] local rotate failed (${err?.message})`);
65
82
  }
@@ -364,6 +381,7 @@ function traceAgentCompact({
364
381
  iteration,
365
382
  stage,
366
383
  trigger,
384
+ compact_type,
367
385
  prune_count,
368
386
  compact_changed,
369
387
  input_prefix_hash,
@@ -373,20 +391,26 @@ function traceAgentCompact({
373
391
  after_bytes,
374
392
  context_window,
375
393
  budget_tokens,
394
+ boundary_tokens,
395
+ target_budget_tokens,
376
396
  reserve_tokens,
397
+ pressure_tokens,
398
+ trigger_tokens,
377
399
  message_tokens_est,
400
+ duration_ms,
378
401
  provider,
379
402
  model,
380
403
  error,
381
404
  error_code,
405
+ details,
382
406
  }) {
383
- if (process.env.MIXDOG_AGENT_TRACE_VERBOSE !== '1') return;
384
407
  appendAgentTrace({
385
408
  sessionId,
386
409
  iteration,
387
410
  kind: 'compact_meta',
388
411
  stage: stage || null,
389
412
  trigger: trigger || null,
413
+ compact_type: compact_type || null,
390
414
  prune_count: prune_count ?? 0,
391
415
  compact_changed: !!compact_changed,
392
416
  input_prefix_hash: input_prefix_hash || null,
@@ -396,12 +420,18 @@ function traceAgentCompact({
396
420
  after_bytes: after_bytes ?? null,
397
421
  context_window: context_window ?? null,
398
422
  budget_tokens: budget_tokens ?? null,
423
+ boundary_tokens: boundary_tokens ?? null,
424
+ target_budget_tokens: target_budget_tokens ?? null,
399
425
  reserve_tokens: reserve_tokens ?? null,
426
+ pressure_tokens: pressure_tokens ?? null,
427
+ trigger_tokens: trigger_tokens ?? null,
400
428
  message_tokens_est: message_tokens_est ?? null,
429
+ duration_ms: duration_ms ?? null,
401
430
  provider: provider || null,
402
431
  model: model || null,
403
432
  error: error || null,
404
433
  error_code: error_code || null,
434
+ details: details && typeof details === 'object' ? details : null,
405
435
  });
406
436
  }
407
437
 
@@ -488,6 +518,22 @@ function summarizeToolArgs(toolName, args) {
488
518
  return Object.keys(out).length ? out : null;
489
519
  }
490
520
 
521
+ function stableTraceStringify(value) {
522
+ if (value === null || value === undefined) return JSON.stringify(value);
523
+ if (typeof value !== 'object') return JSON.stringify(value);
524
+ if (Array.isArray(value)) return '[' + value.map(stableTraceStringify).join(',') + ']';
525
+ const keys = Object.keys(value).sort();
526
+ return '{' + keys.map((k) => `${JSON.stringify(k)}:${stableTraceStringify(value[k])}`).join(',') + '}';
527
+ }
528
+
529
+ function hashTraceValue(value) {
530
+ try {
531
+ return createHash('sha256').update(stableTraceStringify(value)).digest('hex').slice(0, 16);
532
+ } catch {
533
+ return null;
534
+ }
535
+ }
536
+
491
537
  function _resolveToolFailurePath() {
492
538
  if (process.env.MIXDOG_TOOL_FAILURE_LOG_DISABLE === '1') return null;
493
539
  if (_toolFailurePath) return _toolFailurePath;
@@ -601,7 +647,7 @@ function classifyToolFailure(resultText, toolName) {
601
647
  return 'runtime/failure';
602
648
  }
603
649
 
604
- function traceAgentToolFailure({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, role, model, cwd, resultText, resultKind = 'error' }) {
650
+ function traceAgentToolFailure({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, agent, model, cwd, resultText, resultKind = 'error' }) {
605
651
  if (process.env.MIXDOG_AGENT_TRACE_DISABLE === '1') return;
606
652
  if (!_resolveToolFailurePath()) return;
607
653
  try {
@@ -614,7 +660,7 @@ function traceAgentToolFailure({ sessionId, iteration, toolName, toolKind, toolM
614
660
  tool_kind: toolKind || null,
615
661
  result_kind: resultKind || 'error',
616
662
  category: classifyToolFailure(cleanText, toolName),
617
- role: role || null,
663
+ agent: agent || null,
618
664
  model: model || null,
619
665
  cwd: cwd || null,
620
666
  tool_ms: Number.isFinite(Number(toolMs)) ? Number(toolMs) : null,
@@ -630,12 +676,13 @@ function traceAgentToolFailure({ sessionId, iteration, toolName, toolKind, toolM
630
676
  }
631
677
  }
632
678
 
633
- function traceAgentTool({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, role, resultKind, model, resultText, cwd }) {
679
+ function traceAgentTool({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, agent, resultKind, model, resultText, cwd }) {
634
680
  const nextCallCount = countJsonNextCalls(resultText);
635
681
  const resultBytesEst = typeof resultText === 'string' ? Buffer.byteLength(resultText, 'utf8') : 0;
636
682
  const resultLinesEst = typeof resultText === 'string' && resultText.length > 0 ? resultText.split('\n').length : 0;
637
683
  const numericToolMs = Number(toolMs);
638
684
  const summarizedArgs = summarizeToolArgs(toolName, toolArgs);
685
+ const toolArgsHash = summarizedArgs ? hashTraceValue(summarizedArgs) : null;
639
686
  // Flat shape — fields named exactly as the agent_calls PG columns so
640
687
  // insertAgentCalls can pick them up by direct property access without
641
688
  // a payload-unwrap step. result_kind has no column and rides as plain
@@ -644,12 +691,14 @@ function traceAgentTool({ sessionId, iteration, toolName, toolKind, toolMs, tool
644
691
  sessionId,
645
692
  iteration,
646
693
  kind: 'tool',
647
- role: role || null,
694
+ agent: agent || null,
648
695
  model: model || null,
649
696
  tool_name: toolName,
650
697
  tool_kind: toolKind,
651
698
  tool_ms: toolMs,
652
699
  tool_args: summarizedArgs,
700
+ tool_args_hash: toolArgsHash,
701
+ tool_args_summary: summarizedArgs,
653
702
  result_kind: resultKind || null,
654
703
  result_has_next_call: nextCallCount > 0,
655
704
  result_next_call_count: nextCallCount,
@@ -665,7 +714,7 @@ function traceAgentTool({ sessionId, iteration, toolName, toolKind, toolMs, tool
665
714
  sessionId,
666
715
  iteration,
667
716
  kind: 'tool_slow',
668
- role: role || null,
717
+ agent: agent || null,
669
718
  model: model || null,
670
719
  tool_name: toolName,
671
720
  tool_kind: toolKind,
@@ -674,6 +723,8 @@ function traceAgentTool({ sessionId, iteration, toolName, toolKind, toolMs, tool
674
723
  threshold_ms: MIXDOG_SLOW_TOOL_TRACE_MS,
675
724
  result_kind: resultKind || null,
676
725
  tool_args: summarizedArgs,
726
+ tool_args_hash: toolArgsHash,
727
+ tool_args_summary: summarizedArgs,
677
728
  result_has_next_call: nextCallCount > 0,
678
729
  result_next_call_count: nextCallCount,
679
730
  result_bytes_est: resultBytesEst,
@@ -683,7 +734,7 @@ function traceAgentTool({ sessionId, iteration, toolName, toolKind, toolMs, tool
683
734
  });
684
735
  }
685
736
  if (resultKind === 'error') {
686
- traceAgentToolFailure({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, role, model, cwd, resultText, resultKind });
737
+ traceAgentToolFailure({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, agent, model, cwd, resultText, resultKind });
687
738
  }
688
739
  }
689
740
 
@@ -741,25 +792,27 @@ function traceStreamAborted({ sessionId, info }) {
741
792
  });
742
793
  }
743
794
 
744
- function traceAgentPreset({ sessionId, role, presetName, model, provider, parentSessionId }) {
795
+ function traceAgentPreset({ sessionId, agent, presetName, model, provider, parentSessionId }) {
745
796
  // Fires once per dispatch right after the preset has been resolved and
746
797
  // its runtime spec (provider/model) assembled. Useful for after-the-fact
747
- // routing analysis: "which role landed on which preset / provider / model
798
+ // routing analysis: "which agent landed on which preset / provider / model
748
799
  // on this request?"
749
800
  appendAgentTrace({
750
801
  sessionId,
751
802
  kind: 'preset_assign',
752
- role: role || null,
803
+ agent: agent || null,
753
804
  preset_name: presetName || null,
754
805
  model: model || null,
755
806
  provider: provider || null,
756
807
  parent_session_id: parentSessionId || null,
808
+ parentSessionId: parentSessionId || null,
757
809
  });
758
810
  }
759
811
 
760
812
  function traceAgentFetch({ sessionId, headersMs, httpStatus, handshakeRetries, handshakeRetryClassifiers, provider, model, transport }) {
761
813
  const payload = {
762
814
  headers_ms: headersMs,
815
+ phase: 'http_response_headers',
763
816
  http_status: httpStatus,
764
817
  provider: provider || null,
765
818
  model: model || null,
@@ -786,17 +839,23 @@ function traceAgentFetch({ sessionId, headersMs, httpStatus, handshakeRetries, h
786
839
  }
787
840
 
788
841
  function traceAgentSse({ sessionId, sseParseMs, ttftMs, provider, model, transport }) {
842
+ const streamTotalMs = sseParseMs;
843
+ const firstTokenMs = ttftMs;
789
844
  appendAgentTrace({
790
845
  sessionId,
791
846
  kind: 'sse',
792
847
  sse_parse_ms: sseParseMs,
848
+ stream_total_ms: streamTotalMs,
793
849
  ttft_ms: ttftMs,
850
+ first_token_ms: firstTokenMs,
794
851
  provider: provider || null,
795
852
  model: model || null,
796
853
  transport: transport || null,
797
854
  payload: {
798
855
  sse_parse_ms: sseParseMs,
856
+ stream_total_ms: streamTotalMs,
799
857
  ttft_ms: ttftMs,
858
+ first_token_ms: firstTokenMs,
800
859
  provider: provider || null,
801
860
  model: model || null,
802
861
  transport: transport || null,
@@ -804,6 +863,19 @@ function traceAgentSse({ sessionId, sseParseMs, ttftMs, provider, model, transpo
804
863
  });
805
864
  }
806
865
 
866
+ function extractThinkingTokens(rawUsage) {
867
+ if (!rawUsage || typeof rawUsage !== 'object') return null;
868
+ const direct = Number(rawUsage.thinking_tokens ?? rawUsage.thinkingTokens);
869
+ if (Number.isFinite(direct) && direct >= 0) return direct;
870
+ const details = rawUsage.output_tokens_details
871
+ || rawUsage.completion_tokens_details;
872
+ if (details && typeof details === 'object') {
873
+ const nested = Number(details.reasoning_tokens ?? details.thinking_tokens);
874
+ if (Number.isFinite(nested) && nested >= 0) return nested;
875
+ }
876
+ return null;
877
+ }
878
+
807
879
  function traceAgentUsage({ sessionId, iteration, inputTokens, outputTokens, cachedTokens, cacheWriteTokens, promptTokens, model, modelDisplay, responseId, rawUsage, provider, serviceTier, requestKind }) {
808
880
  const inclusive = isInclusiveProvider(provider);
809
881
  const inTok = inputTokens || 0;
@@ -816,12 +888,14 @@ function traceAgentUsage({ sessionId, iteration, inputTokens, outputTokens, cach
816
888
  ? Math.max(inTok, cacheRead + cacheWrite)
817
889
  : inTok + cacheRead + cacheWrite);
818
890
  const resolvedServiceTier = serviceTier || rawUsage?.service_tier || rawUsage?.serviceTier || null;
891
+ const thinkingTokens = extractThinkingTokens(rawUsage);
819
892
  appendAgentTrace({
820
893
  sessionId,
821
894
  iteration,
822
895
  kind: 'usage_raw',
823
896
  input_tokens: inputTokens,
824
897
  output_tokens: outputTokens,
898
+ thinking_tokens: thinkingTokens,
825
899
  cached_tokens: cachedTokens,
826
900
  cache_write_tokens: cacheWrite,
827
901
  uncached_input_tokens: uncachedInputTokens,
@@ -837,6 +911,7 @@ function traceAgentUsage({ sessionId, iteration, inputTokens, outputTokens, cach
837
911
  provider: provider || null,
838
912
  prompt_tokens: promptTotal,
839
913
  uncached_input_tokens: uncachedInputTokens,
914
+ thinking_tokens: thinkingTokens,
840
915
  model_display: modelDisplay || null,
841
916
  response_id: responseId || null,
842
917
  service_tier: resolvedServiceTier,
@@ -383,6 +383,7 @@ export function loadConfig(options = {}) {
383
383
  trajectory: { enabled: true, ...raw.trajectory },
384
384
  runtime: raw.runtime && typeof raw.runtime === 'object' ? raw.runtime : {},
385
385
  shell: raw.shell && typeof raw.shell === 'object' ? raw.shell : {},
386
+ update: raw.update && typeof raw.update === 'object' ? { ...raw.update } : {},
386
387
  };
387
388
  }
388
389
  catch { /* fall through */ }
@@ -408,6 +409,7 @@ export function loadConfig(options = {}) {
408
409
  trajectory: { enabled: true },
409
410
  runtime: {},
410
411
  shell: {},
412
+ update: {},
411
413
  };
412
414
  }
413
415
  /**
@@ -482,6 +484,7 @@ export function saveConfig(config) {
482
484
  trajectory: config.trajectory || {},
483
485
  runtime: config.runtime || {},
484
486
  shell: config.shell || {},
487
+ update: config.update || {},
485
488
  }));
486
489
  }
487
490
  // --- Preset helpers ---