@mono-agent/agent-app 0.20.14 → 0.21.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 (262) hide show
  1. package/README.md +227 -80
  2. package/dist/adapter-send-tools.d.ts +3 -2
  3. package/dist/adapter-send-tools.d.ts.map +1 -1
  4. package/dist/adapter-send-tools.js +15 -5
  5. package/dist/adapter-send-tools.js.map +1 -1
  6. package/dist/app-controller-channels.d.ts +2 -0
  7. package/dist/app-controller-channels.d.ts.map +1 -1
  8. package/dist/app-controller-channels.js +10 -1
  9. package/dist/app-controller-channels.js.map +1 -1
  10. package/dist/app-controller-maintenance.d.ts +3 -1
  11. package/dist/app-controller-maintenance.d.ts.map +1 -1
  12. package/dist/app-controller-maintenance.js +3 -0
  13. package/dist/app-controller-maintenance.js.map +1 -1
  14. package/dist/app-controller-responder.d.ts +2 -0
  15. package/dist/app-controller-responder.d.ts.map +1 -1
  16. package/dist/app-controller-responder.js +21 -17
  17. package/dist/app-controller-responder.js.map +1 -1
  18. package/dist/app-controller-traceability.d.ts.map +1 -1
  19. package/dist/app-controller-traceability.js +3 -0
  20. package/dist/app-controller-traceability.js.map +1 -1
  21. package/dist/app-controller-types.d.ts +1 -0
  22. package/dist/app-controller-types.d.ts.map +1 -1
  23. package/dist/app-controller.d.ts +2 -0
  24. package/dist/app-controller.d.ts.map +1 -1
  25. package/dist/app-controller.js +3 -0
  26. package/dist/app-controller.js.map +1 -1
  27. package/dist/artifact-retention.js +11 -0
  28. package/dist/artifact-retention.js.map +1 -1
  29. package/dist/background.d.ts +0 -6
  30. package/dist/background.d.ts.map +1 -1
  31. package/dist/background.js +5 -58
  32. package/dist/background.js.map +1 -1
  33. package/dist/channel-drivers/tui.d.ts +2 -2
  34. package/dist/channel-drivers/tui.d.ts.map +1 -1
  35. package/dist/channel-drivers/tui.js +27 -8
  36. package/dist/channel-drivers/tui.js.map +1 -1
  37. package/dist/cli-args.d.ts +4 -5
  38. package/dist/cli-args.d.ts.map +1 -1
  39. package/dist/cli-args.js +20 -19
  40. package/dist/cli-args.js.map +1 -1
  41. package/dist/cli-background-command.d.ts.map +1 -1
  42. package/dist/cli-background-command.js +4 -0
  43. package/dist/cli-background-command.js.map +1 -1
  44. package/dist/cli-commands.d.ts.map +1 -1
  45. package/dist/cli-commands.js +13 -2
  46. package/dist/cli-commands.js.map +1 -1
  47. package/dist/cli-help.d.ts.map +1 -1
  48. package/dist/cli-help.js +33 -19
  49. package/dist/cli-help.js.map +1 -1
  50. package/dist/cli-init-command.d.ts.map +1 -1
  51. package/dist/cli-init-command.js +26 -22
  52. package/dist/cli-init-command.js.map +1 -1
  53. package/dist/cli-install-skill-command.d.ts.map +1 -1
  54. package/dist/cli-install-skill-command.js +12 -3
  55. package/dist/cli-install-skill-command.js.map +1 -1
  56. package/dist/config-reference.d.ts +1 -0
  57. package/dist/config-reference.d.ts.map +1 -1
  58. package/dist/config-reference.js +66 -10
  59. package/dist/config-reference.js.map +1 -1
  60. package/dist/configured-agent.d.ts +9 -1
  61. package/dist/configured-agent.d.ts.map +1 -1
  62. package/dist/configured-agent.js +95 -29
  63. package/dist/configured-agent.js.map +1 -1
  64. package/dist/cron-control-store.d.ts.map +1 -1
  65. package/dist/cron-control-store.js +4 -2
  66. package/dist/cron-control-store.js.map +1 -1
  67. package/dist/doctor.d.ts.map +1 -1
  68. package/dist/doctor.js +215 -45
  69. package/dist/doctor.js.map +1 -1
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +1 -0
  73. package/dist/index.js.map +1 -1
  74. package/dist/interaction-bridge.d.ts +3 -3
  75. package/dist/interaction-bridge.d.ts.map +1 -1
  76. package/dist/interaction-bridge.js +27 -10
  77. package/dist/interaction-bridge.js.map +1 -1
  78. package/dist/launchd.d.ts +2 -0
  79. package/dist/launchd.d.ts.map +1 -1
  80. package/dist/launchd.js +3 -0
  81. package/dist/launchd.js.map +1 -1
  82. package/dist/local-tui-session.d.ts +14 -0
  83. package/dist/local-tui-session.d.ts.map +1 -0
  84. package/dist/local-tui-session.js +100 -0
  85. package/dist/local-tui-session.js.map +1 -0
  86. package/dist/mcp-apps.d.ts.map +1 -1
  87. package/dist/mcp-apps.js +3 -0
  88. package/dist/mcp-apps.js.map +1 -1
  89. package/dist/memory-journal.d.ts +53 -0
  90. package/dist/memory-journal.d.ts.map +1 -0
  91. package/dist/memory-journal.js +586 -0
  92. package/dist/memory-journal.js.map +1 -0
  93. package/dist/memory-recall.d.ts.map +1 -1
  94. package/dist/memory-recall.js +16 -2
  95. package/dist/memory-recall.js.map +1 -1
  96. package/dist/memory-retrieval.d.ts +9 -0
  97. package/dist/memory-retrieval.d.ts.map +1 -1
  98. package/dist/memory-retrieval.js +20 -0
  99. package/dist/memory-retrieval.js.map +1 -1
  100. package/dist/modules/base.js +1 -1
  101. package/dist/modules/base.js.map +1 -1
  102. package/dist/modules/known-tools.d.ts +1 -1
  103. package/dist/modules/known-tools.d.ts.map +1 -1
  104. package/dist/modules/known-tools.js +1 -0
  105. package/dist/modules/known-tools.js.map +1 -1
  106. package/dist/monitors-command.js +12 -2
  107. package/dist/monitors-command.js.map +1 -1
  108. package/dist/monitors-config.d.ts +4 -1
  109. package/dist/monitors-config.d.ts.map +1 -1
  110. package/dist/monitors-config.js +5 -1
  111. package/dist/monitors-config.js.map +1 -1
  112. package/dist/monitors-context.d.ts.map +1 -1
  113. package/dist/monitors-context.js +14 -2
  114. package/dist/monitors-context.js.map +1 -1
  115. package/dist/monitors-service.d.ts +2 -2
  116. package/dist/monitors-service.d.ts.map +1 -1
  117. package/dist/monitors-service.js +227 -96
  118. package/dist/monitors-service.js.map +1 -1
  119. package/dist/monitors-store.d.ts +11 -1
  120. package/dist/monitors-store.d.ts.map +1 -1
  121. package/dist/monitors-store.js +36 -6
  122. package/dist/monitors-store.js.map +1 -1
  123. package/dist/notify-destinations.d.ts +3 -2
  124. package/dist/notify-destinations.d.ts.map +1 -1
  125. package/dist/notify-destinations.js +6 -7
  126. package/dist/notify-destinations.js.map +1 -1
  127. package/dist/posted-reply-history.d.ts.map +1 -1
  128. package/dist/posted-reply-history.js +40 -3
  129. package/dist/posted-reply-history.js.map +1 -1
  130. package/dist/proactive-notify.d.ts +20 -1
  131. package/dist/proactive-notify.d.ts.map +1 -1
  132. package/dist/proactive-notify.js +56 -3
  133. package/dist/proactive-notify.js.map +1 -1
  134. package/dist/process-job-channel-routing.js +2 -1
  135. package/dist/process-job-channel-routing.js.map +1 -1
  136. package/dist/process-job-output-tail.d.ts +53 -0
  137. package/dist/process-job-output-tail.d.ts.map +1 -0
  138. package/dist/process-job-output-tail.js +257 -0
  139. package/dist/process-job-output-tail.js.map +1 -0
  140. package/dist/process-jobs-config.d.ts +1 -1
  141. package/dist/process-jobs-config.js +1 -1
  142. package/dist/process-jobs-config.js.map +1 -1
  143. package/dist/process-jobs-context.d.ts +3 -1
  144. package/dist/process-jobs-context.d.ts.map +1 -1
  145. package/dist/process-jobs-context.js +44 -11
  146. package/dist/process-jobs-context.js.map +1 -1
  147. package/dist/process-jobs-runtime.d.ts.map +1 -1
  148. package/dist/process-jobs-runtime.js +14 -0
  149. package/dist/process-jobs-runtime.js.map +1 -1
  150. package/dist/process-jobs-service.d.ts.map +1 -1
  151. package/dist/process-jobs-service.js +115 -23
  152. package/dist/process-jobs-service.js.map +1 -1
  153. package/dist/process-jobs-store.d.ts +3 -1
  154. package/dist/process-jobs-store.d.ts.map +1 -1
  155. package/dist/process-jobs-store.js +4 -1
  156. package/dist/process-jobs-store.js.map +1 -1
  157. package/dist/process-output-redaction.d.ts +26 -1
  158. package/dist/process-output-redaction.d.ts.map +1 -1
  159. package/dist/process-output-redaction.js +164 -2
  160. package/dist/process-output-redaction.js.map +1 -1
  161. package/dist/project-skills.d.ts +11 -5
  162. package/dist/project-skills.d.ts.map +1 -1
  163. package/dist/project-skills.js +88 -39
  164. package/dist/project-skills.js.map +1 -1
  165. package/dist/provider-auth-checks.d.ts +27 -0
  166. package/dist/provider-auth-checks.d.ts.map +1 -0
  167. package/dist/provider-auth-checks.js +349 -0
  168. package/dist/provider-auth-checks.js.map +1 -0
  169. package/dist/provider-auth-observations.d.ts +22 -0
  170. package/dist/provider-auth-observations.d.ts.map +1 -0
  171. package/dist/provider-auth-observations.js +139 -0
  172. package/dist/provider-auth-observations.js.map +1 -0
  173. package/dist/provider-auth-operator.d.ts +19 -0
  174. package/dist/provider-auth-operator.d.ts.map +1 -0
  175. package/dist/provider-auth-operator.js +560 -0
  176. package/dist/provider-auth-operator.js.map +1 -0
  177. package/dist/provider-auth-status.d.ts +20 -0
  178. package/dist/provider-auth-status.d.ts.map +1 -0
  179. package/dist/provider-auth-status.js +235 -0
  180. package/dist/provider-auth-status.js.map +1 -0
  181. package/dist/provider-model-catalog.d.ts +17 -0
  182. package/dist/provider-model-catalog.d.ts.map +1 -1
  183. package/dist/provider-model-catalog.js +113 -2
  184. package/dist/provider-model-catalog.js.map +1 -1
  185. package/dist/provider-setup.d.ts +22 -0
  186. package/dist/provider-setup.d.ts.map +1 -1
  187. package/dist/provider-setup.js +101 -15
  188. package/dist/provider-setup.js.map +1 -1
  189. package/dist/reply-artifacts.d.ts +3 -1
  190. package/dist/reply-artifacts.d.ts.map +1 -1
  191. package/dist/reply-artifacts.js +45 -10
  192. package/dist/reply-artifacts.js.map +1 -1
  193. package/dist/request-model-override.d.ts +11 -2
  194. package/dist/request-model-override.d.ts.map +1 -1
  195. package/dist/request-model-override.js +51 -1
  196. package/dist/request-model-override.js.map +1 -1
  197. package/dist/request-scoped-mcp.d.ts +3 -0
  198. package/dist/request-scoped-mcp.d.ts.map +1 -1
  199. package/dist/request-scoped-mcp.js +1 -1
  200. package/dist/request-scoped-mcp.js.map +1 -1
  201. package/dist/run-history.d.ts.map +1 -1
  202. package/dist/run-history.js +56 -13
  203. package/dist/run-history.js.map +1 -1
  204. package/dist/seen-conversations.d.ts +4 -3
  205. package/dist/seen-conversations.d.ts.map +1 -1
  206. package/dist/seen-conversations.js +6 -5
  207. package/dist/seen-conversations.js.map +1 -1
  208. package/dist/session-history.d.ts +14 -0
  209. package/dist/session-history.d.ts.map +1 -1
  210. package/dist/session-history.js +120 -5
  211. package/dist/session-history.js.map +1 -1
  212. package/dist/systemd-command.d.ts +8 -0
  213. package/dist/systemd-command.d.ts.map +1 -0
  214. package/dist/systemd-command.js +206 -0
  215. package/dist/systemd-command.js.map +1 -0
  216. package/dist/systemd.d.ts +51 -0
  217. package/dist/systemd.d.ts.map +1 -0
  218. package/dist/systemd.js +299 -0
  219. package/dist/systemd.js.map +1 -0
  220. package/dist/tool-output-artifacts.d.ts +4 -0
  221. package/dist/tool-output-artifacts.d.ts.map +1 -0
  222. package/dist/tool-output-artifacts.js +17 -0
  223. package/dist/tool-output-artifacts.js.map +1 -0
  224. package/dist/tui-command.d.ts +0 -45
  225. package/dist/tui-command.d.ts.map +1 -1
  226. package/dist/tui-command.js +27 -264
  227. package/dist/tui-command.js.map +1 -1
  228. package/dist/untrusted-text.js +2 -2
  229. package/dist/web-command.d.ts +3 -0
  230. package/dist/web-command.d.ts.map +1 -1
  231. package/dist/web-command.js +112 -7
  232. package/dist/web-command.js.map +1 -1
  233. package/dist/web-request-coordinator.d.ts +19 -0
  234. package/dist/web-request-coordinator.d.ts.map +1 -0
  235. package/dist/web-request-coordinator.js +242 -0
  236. package/dist/web-request-coordinator.js.map +1 -0
  237. package/dist/wizard/prompts.d.ts.map +1 -1
  238. package/dist/wizard/prompts.js +1 -0
  239. package/dist/wizard/prompts.js.map +1 -1
  240. package/dist/wizard/run.js +1 -1
  241. package/dist/wizard/run.js.map +1 -1
  242. package/package.json +18 -18
  243. package/schema/mono-agent.config.schema.json +120 -8
  244. package/skills/mono-agent-composer/SKILL.md +4 -4
  245. package/skills/mono-agent-composer/references/config-blueprint.md +18 -7
  246. package/skills/mono-agent-composer/references/discovery-questions.md +10 -5
  247. package/skills/mono-agent-composer/references/feature-coverage.md +30 -14
  248. package/skills/mono-agent-composer/references/package-map.md +6 -3
  249. package/skills/mono-agent-composer/references/playbooks.md +20 -5
  250. package/skills/mono-agent-composer/references/validation.md +4 -3
  251. package/dist/configuration-proposal-main.d.ts +0 -3
  252. package/dist/configuration-proposal-main.d.ts.map +0 -1
  253. package/dist/configuration-proposal-main.js +0 -13
  254. package/dist/configuration-proposal-main.js.map +0 -1
  255. package/dist/configuration-proposal-tool.d.ts +0 -33
  256. package/dist/configuration-proposal-tool.d.ts.map +0 -1
  257. package/dist/configuration-proposal-tool.js +0 -180
  258. package/dist/configuration-proposal-tool.js.map +0 -1
  259. package/dist/local-configuration.d.ts +0 -99
  260. package/dist/local-configuration.d.ts.map +0 -1
  261. package/dist/local-configuration.js +0 -1302
  262. package/dist/local-configuration.js.map +0 -1
package/dist/doctor.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { inspectWebControl } from "./web-request-coordinator.js";
1
2
  import { execFile as execFileCallback } from "node:child_process";
2
3
  import { constants } from "node:fs";
3
4
  import { access, lstat, mkdir, readdir, readFile, realpath, stat } from "node:fs/promises";
@@ -16,6 +17,7 @@ import { buildMonoAgentConfigView, EFFORT_LEVELS, findJsonSecretConfigWarnings,
16
17
  import { describeSandboxEffectiveState, MODEL_REFERENCE_ECHO_MAX_BYTES, MODEL_REFERENCE_REASON_MAX_BYTES, resolveSandboxEffectiveState, RuntimeAdapterError, sandboxEffectiveStateWarning, sanitizeModelReferenceText, } from "@mono-agent/runtime-adapter";
17
18
  import { isAppCoreConfigError, loadAppCoreConfig, } from "./app-config.js";
18
19
  import { isRememberToolAllowed, isRememberToolPolicyName } from "./memory-remember.js";
20
+ import { isMemoryJournalToolAllowed, isMemoryJournalToolPolicyName } from "./memory-journal.js";
19
21
  import { adapterSendToolNames, isAdapterSendToolAllowed, resolveAdapterSendToolsSettings } from "./adapter-send-tools.js";
20
22
  import { canonicalToolName, isAllowAllTools, isKnownToolName, isMcpToolName, suggestToolName } from "./modules/known-tools.js";
21
23
  import { collectChannelConfigViews } from "./channel-config-view.js";
@@ -37,8 +39,9 @@ import { formatInteractionBridgeUrl, loadInteractionSettings } from "./interacti
37
39
  import { FIRST_RUN_MEMORY_INITIALIZING_MARKER } from "./first-run-managed-memory.js";
38
40
  import { DEFAULT_MEMORY_EMBEDDING_ENDPOINTS, probeMemoryEmbeddingSelection, } from "./memory-embedding-service.js";
39
41
  import { piAuthRecoveryCommand } from "./provider-setup.js";
42
+ import { collectUsedProviderReferences } from "./provider-auth-status.js";
40
43
  import { inspectPiAuthStore } from "./pi-auth-store-inspection.js";
41
- import { checkManagedProjectSkills, managedProjectSkillsExist } from "./project-skills.js";
44
+ import { activeProjectSkillSelections, checkManagedProjectSkills, isRetiredProjectSkillName, managedProjectSkillsExist, } from "./project-skills.js";
42
45
  import { runtimeProvenanceDetail } from "./runtime-provenance.js";
43
46
  import { resolveAdvertisedModelEffort } from "./model-effort-capabilities.js";
44
47
  import { loadSupermemoryPlugin } from "./supermemory-plugin.js";
@@ -51,6 +54,7 @@ const CONTINUATION_V2_ROLLBACK_GUARD = "UPGRADED-TO-RECORDS-V3";
51
54
  const CONTINUATION_V2_ROLLBACK_GUARD_CONTENT = "This state directory uses continuation records v3. Older runtimes must not open records-v2.\n";
52
55
  const DOCTOR_STATUS_TIMEOUT_MS = 5_000;
53
56
  const DOCTOR_STATUS_MAX_BUFFER_BYTES = 64 * 1024;
57
+ const OLLAMA_WEB_SEARCH_PROBE_MAX_BYTES = 2 * 1024 * 1024;
54
58
  const defaultDoctorStatusExecFile = async (file, args, options) => {
55
59
  const { stdout } = await execFile(file, [...args], options);
56
60
  return { stdout };
@@ -78,7 +82,7 @@ export async function validateMonoAgentFolder(options) {
78
82
  }
79
83
  sections.push(await runtimeProvenanceSection(options.verifiedRuntimeProvenanceDetail));
80
84
  if (coreConfig !== undefined) {
81
- const staticTriggerCredentialRefs = await collectStaticTriggerCredentialRefs(drivers, options);
85
+ const staticTriggerCredentialRefs = await collectStaticTriggerCredentialRefs(coreConfig, drivers, options);
82
86
  const jsonResult = await readMonoAgentConfigJson(options.configPath);
83
87
  // Channel secrets (bot tokens, API keys) live outside the core view, so the
84
88
  // placement check spans both: core sections + every channel's config view.
@@ -238,37 +242,10 @@ function staticTriggerConfigEntries(driverId, loaded) {
238
242
  * Collect static trigger model overrides for credential readiness. Dynamic
239
243
  * webhook request-body overrides are intentionally unavailable at validate time.
240
244
  */
241
- async function collectStaticTriggerCredentialRefs(drivers, input) {
242
- const refs = [];
243
- const seen = new Set();
244
- for (const driver of drivers) {
245
- if (driver.id !== "webhook" && driver.id !== "cron")
246
- continue;
247
- let loaded;
248
- try {
249
- loaded = await driver.loadConfig(input);
250
- }
251
- catch {
252
- // The channel section owns malformed/unreadable config diagnostics.
253
- continue;
254
- }
255
- for (const { entryPath, entry } of staticTriggerConfigEntries(driver.id, loaded)) {
256
- if (typeof entry.model !== "string")
257
- continue;
258
- try {
259
- const ref = parseMonoRuntimeModelReference(entry.model);
260
- const key = `${entryPath}\u0000${modelReferenceKey(ref)}`;
261
- if (seen.has(key))
262
- continue;
263
- seen.add(key);
264
- refs.push({ label: entryPath, ref });
265
- }
266
- catch {
267
- // The channel section owns invalid model-reference syntax.
268
- }
269
- }
270
- }
271
- return refs;
245
+ async function collectStaticTriggerCredentialRefs(config, drivers, input) {
246
+ return (await collectUsedProviderReferences(config, drivers, input))
247
+ .filter(({ usage }) => usage.kind === "cron" || usage.kind === "webhook")
248
+ .map(({ usage, ref }) => ({ label: usage.label, ref }));
272
249
  }
273
250
  async function applyRequestModelOverrideCompatibilityChecks(sections, config, drivers, input) {
274
251
  const piModelResolutionFailures = [];
@@ -697,6 +674,8 @@ function hasNonEmptyCredentialValue(value) {
697
674
  async function contextSection(config, cwd) {
698
675
  const details = [];
699
676
  let status = "ok";
677
+ const activeSelectedSkills = activeProjectSkillSelections(config.context.selectedSkills);
678
+ const retiredSelectedSkills = config.context.selectedSkills.filter(isRetiredProjectSkillName);
700
679
  if (await pathExists(config.context.identityPath)) {
701
680
  details.push(`Identity: ${config.context.identityPath}`);
702
681
  }
@@ -708,10 +687,19 @@ async function contextSection(config, cwd) {
708
687
  status = "error";
709
688
  details.push(`Soul file is missing: ${config.context.soulPath}`);
710
689
  }
711
- if (config.context.skillsRoot !== undefined) {
690
+ for (const skill of retiredSelectedSkills) {
691
+ if (status === "ok")
692
+ status = "waiting";
693
+ details.push(`Skill \`${skill}\` is retired and ignored. Remove it from context.selectedSkills or ` +
694
+ "MONO_AGENT_SELECTED_SKILLS, then run `mono-agent install-skill --project --check`." +
695
+ (config.context.skillDisclosure === "index"
696
+ ? " Skill disclosure runs as `full` until the retired selector is removed."
697
+ : ""));
698
+ }
699
+ if (activeSelectedSkills.length > 0 && config.context.skillsRoot !== undefined) {
712
700
  if (await pathExists(config.context.skillsRoot)) {
713
701
  details.push(`Skills root: ${config.context.skillsRoot}`);
714
- for (const skill of config.context.selectedSkills) {
702
+ for (const skill of activeSelectedSkills) {
715
703
  const skillPath = join(config.context.skillsRoot, skill, "SKILL.md");
716
704
  if (await pathExists(skillPath)) {
717
705
  details.push(`Skill \`${skill}\`: ${skillPath}`);
@@ -727,7 +715,7 @@ async function contextSection(config, cwd) {
727
715
  details.push(`Skills root is missing: ${config.context.skillsRoot}`);
728
716
  }
729
717
  }
730
- else if (config.context.selectedSkills.length > 0) {
718
+ else if (activeSelectedSkills.length > 0) {
731
719
  status = "error";
732
720
  details.push("Skills are selected but context.skillsRoot is not set.");
733
721
  }
@@ -762,7 +750,15 @@ function memoryConsolidationCronIssue(expression) {
762
750
  }
763
751
  async function memorySection(config, cwd, env, liveness, allowFilesystemWrites, preferAppPluginInstall) {
764
752
  if (config.memory === undefined) {
765
- return { id: "memory", label: "Memory", status: "disabled", details: ["No memory configured."] };
753
+ return {
754
+ id: "memory",
755
+ label: "Memory",
756
+ status: "disabled",
757
+ details: [
758
+ "No memory configured.",
759
+ "Chronological journal: disabled because no local memory backend is configured.",
760
+ ],
761
+ };
766
762
  }
767
763
  // External backend (e.g. supermemory): mode/embeddings/llm are bujo-only and
768
764
  // ignored, so validate the plugin-owned shape before any soft liveness probe.
@@ -808,6 +804,9 @@ async function memorySection(config, cwd, env, liveness, allowFilesystemWrites,
808
804
  sm.apiKey === undefined
809
805
  ? "Auth: no API key configured (keyless — works only if the instance allows it)."
810
806
  : "Auth: API key configured.",
807
+ config.memory.recallTool?.enabled === false
808
+ ? "Explicit memory read tools are disabled by memory.recallTool.enabled. Chronological journal browsing is also unsupported by Supermemory."
809
+ : "Chronological journal: unsupported by Supermemory; MemoryJournal is not offered.",
811
810
  ];
812
811
  if (!liveness) {
813
812
  details.push("Supermemory liveness probe skipped; ingestion is async.");
@@ -825,6 +824,9 @@ async function memorySection(config, cwd, env, liveness, allowFilesystemWrites,
825
824
  }
826
825
  const details = [
827
826
  `Mode: ${config.memory.mode}, path: ${config.memory.path}, writeMode: ${config.memory.writeMode}.`,
827
+ config.memory.recallTool?.enabled === false
828
+ ? `Explicit memory read tools are disabled by memory.recallTool.enabled; the local ${config.memory.mode} tier supports chronology but MemoryJournal is not offered.`
829
+ : `Chronological journal: supported by the local ${config.memory.mode} tier when tool policy allows MemoryJournal.`,
828
830
  ];
829
831
  let status = "ok";
830
832
  if (config.memory.llm !== undefined) {
@@ -1237,6 +1239,27 @@ async function toolsSection(config, input) {
1237
1239
  details.push(`Allowed tools: ${allowedTools.join(", ")}.`);
1238
1240
  let mcpNoteAdded = false;
1239
1241
  for (const name of allowedTools) {
1242
+ if (isMemoryJournalToolPolicyName(name)) {
1243
+ // This app-owned MCP surface must be checked before the generic MCP
1244
+ // branch, using the same deny-wins spellings as runtime composition.
1245
+ if (!isMemoryJournalToolAllowed(config.tools)) {
1246
+ status = "waiting";
1247
+ details.push(`${name} is listed but tool policy still resolves to denied (deny wins, including the mcp__mono-agent-memory-journal__* spelling) - the tool will not be offered.`);
1248
+ }
1249
+ else if (config.memory === undefined) {
1250
+ status = "waiting";
1251
+ details.push(`${name} is in allowedTools but no memory block is configured - chronological journal browsing will not work.`);
1252
+ }
1253
+ else if (config.memory.recallTool?.enabled === false) {
1254
+ status = "waiting";
1255
+ details.push(`${name} is in allowedTools but memory.recallTool.enabled is off - explicit memory read tools will not work.`);
1256
+ }
1257
+ else if ((config.memory.backend ?? "bujo") === "supermemory") {
1258
+ status = "waiting";
1259
+ details.push(`${name} is in allowedTools but the Supermemory backend exposes no chronological journal surface - the tool will not be offered.`);
1260
+ }
1261
+ continue;
1262
+ }
1240
1263
  if (isRememberToolPolicyName(name)) {
1241
1264
  // Reconcile with the runtime's own resolution, which honours the
1242
1265
  // `mcp__mono-agent-memory-write__*` spellings and deny-wins. This check
@@ -1440,31 +1463,61 @@ async function toolsSection(config, input) {
1440
1463
  return { id: "tools", label: "Tools & MCP", status, details };
1441
1464
  }
1442
1465
  const MIN_AGENT_BROWSER_VERSION = [0, 33, 1];
1466
+ function formatSearchBackendChain(backends) {
1467
+ if (backends.length <= 1)
1468
+ return backends[0] ?? "none";
1469
+ return `${backends.slice(0, -1).join(", ")}, then ${backends.at(-1)}`;
1470
+ }
1443
1471
  async function webToolsSection(config, input, liveness) {
1444
1472
  const web = config.tools.web;
1445
1473
  const search = web?.search ?? {
1446
1474
  backend: "auto",
1475
+ maxRequestsPerRun: 4,
1447
1476
  codex: { model: "gpt-5.6-luna" },
1448
1477
  };
1449
1478
  const fetchConfig = web?.fetch ?? { render: "never", browserCommand: "agent-browser" };
1450
- const details = [`WebSearch backend: ${search.backend}.`];
1479
+ const details = [
1480
+ `WebSearch backend: ${search.backend}.`,
1481
+ `WebSearch request budget: ${search.maxRequestsPerRun ?? 4} per logical run.`,
1482
+ `Web coordination: ${web?.coordination ?? "process"}.`,
1483
+ ];
1451
1484
  let status = "ok";
1452
- if (search.endpoint === undefined) {
1485
+ if (web?.coordination === "host") {
1486
+ try {
1487
+ const shared = await inspectWebControl();
1488
+ details.push(shared.exists ? "Host web control state is valid." : "Host web control state will be initialized on first request.");
1489
+ }
1490
+ catch {
1491
+ status = "waiting";
1492
+ details.push("Host web control state is unavailable; web requests will fail closed. Inspect with mono-agent web-control status.");
1493
+ }
1494
+ }
1495
+ const searxngEndpoint = search.searxng?.endpoint ?? search.endpoint;
1496
+ const autoEligibleBackends = [
1497
+ ...(search.ollama === undefined ? [] : ["configured Ollama"]),
1498
+ ...(searxngEndpoint === undefined ? [] : ["configured SearXNG"]),
1499
+ "Codex",
1500
+ "keyless",
1501
+ ];
1502
+ const autoAfterOllama = formatSearchBackendChain(autoEligibleBackends.slice(1));
1503
+ if (searxngEndpoint === undefined) {
1453
1504
  details.push(search.backend === "keyless"
1454
1505
  ? "SearXNG is not configured; keyless search is enabled."
1455
1506
  : search.backend === "codex"
1456
1507
  ? "SearXNG is not configured; strict Codex subscription search is enabled."
1457
1508
  : search.backend === "searxng"
1458
1509
  ? "SearXNG is not configured."
1459
- : "SearXNG is not configured; auto mode starts with Codex subscription search, then keyless search.");
1510
+ : search.ollama === undefined
1511
+ ? "SearXNG is not configured; auto mode starts with Codex subscription search, then keyless search."
1512
+ : "SearXNG is not configured; auto mode uses configured Ollama, then Codex subscription search, then keyless search.");
1460
1513
  }
1461
1514
  else {
1462
- details.push(`SearXNG endpoint: ${search.endpoint}.`);
1515
+ details.push(`SearXNG endpoint: ${searxngEndpoint}.`);
1463
1516
  if (!liveness) {
1464
1517
  details.push("SearXNG liveness was not probed.");
1465
1518
  }
1466
1519
  else {
1467
- const probe = await probeSearxngEndpoint(search.endpoint);
1520
+ const probe = await probeSearxngEndpoint(searxngEndpoint);
1468
1521
  if (probe.ok) {
1469
1522
  details.push("SearXNG JSON search probe succeeded.");
1470
1523
  }
@@ -1472,14 +1525,42 @@ async function webToolsSection(config, input, liveness) {
1472
1525
  status = "waiting";
1473
1526
  details.push(`[WARN] SearXNG JSON search probe failed (${probe.reason}). ` +
1474
1527
  (search.backend === "auto"
1475
- ? "Start the local companion or fix tools.web.search.endpoint; auto mode can still fall back to Codex subscription search, then keyless search."
1476
- : "Start the local companion or fix tools.web.search.endpoint; strict SearXNG mode has no fallback."));
1528
+ ? "Start the local companion or fix tools.web.search.searxng.endpoint; auto mode can still fall back to Codex subscription search, then keyless search."
1529
+ : "Start the local companion or fix tools.web.search.searxng.endpoint; strict SearXNG mode has no fallback."));
1530
+ }
1531
+ }
1532
+ }
1533
+ if (search.backend === "ollama" || (search.backend === "auto" && search.ollama !== undefined)) {
1534
+ const ollama = search.ollama;
1535
+ if (ollama === undefined) {
1536
+ status = "waiting";
1537
+ details.push("[WARN] Ollama Web Search is selected but its resolved configuration is missing.");
1538
+ }
1539
+ else if (!liveness) {
1540
+ details.push(`Ollama Web Search origin: ${ollama.baseUrl}. ${search.backend === "ollama" ? "Strict Ollama mode has no fallback." : `Auto mode advances to ${autoAfterOllama} when Ollama is unavailable.`}`);
1541
+ details.push("Ollama Web Search liveness was not probed.");
1542
+ }
1543
+ else {
1544
+ details.push(`Ollama Web Search origin: ${ollama.baseUrl}. ${search.backend === "ollama" ? "Strict Ollama mode has no fallback." : `Auto mode advances to ${autoAfterOllama} when Ollama is unavailable.`}`);
1545
+ const probe = await probeOllamaWebSearch(ollama);
1546
+ if (probe.ok)
1547
+ details.push("Ollama Web Search JSON probe succeeded.");
1548
+ else {
1549
+ status = "waiting";
1550
+ details.push(`[WARN] Ollama Web Search probe failed (${probe.reason}). ${search.backend === "ollama" ? "Strict Ollama mode has no fallback." : `Auto mode can still advance to ${autoAfterOllama}.`}`);
1477
1551
  }
1478
1552
  }
1479
1553
  }
1554
+ else if (search.ollama !== undefined) {
1555
+ details.push(`Ollama Web Search is configured but inactive because backend ${search.backend} is strict.`);
1556
+ }
1480
1557
  if (search.backend === "auto") {
1481
1558
  const codexModel = search.codex?.model ?? "gpt-5.6-luna";
1482
- details.push(`Codex subscription fallback model: ${codexModel}; readiness is checked lazily when auto mode reaches that fallback.`);
1559
+ const beforeCodex = autoEligibleBackends.slice(0, autoEligibleBackends.indexOf("Codex"));
1560
+ const codexPosition = beforeCodex.length === 0
1561
+ ? "as the first eligible backend"
1562
+ : `after ${formatSearchBackendChain(beforeCodex)}`;
1563
+ details.push(`Codex subscription fallback model: ${codexModel}; readiness is checked lazily when auto mode reaches it ${codexPosition}.`);
1483
1564
  }
1484
1565
  else if (search.backend === "codex") {
1485
1566
  const codexModel = search.codex?.model ?? "gpt-5.6-luna";
@@ -1519,6 +1600,95 @@ async function webToolsSection(config, input, liveness) {
1519
1600
  }
1520
1601
  return { id: "web-tools", label: "Web search & fetch", status, details };
1521
1602
  }
1603
+ async function probeOllamaWebSearch(config) {
1604
+ const ctrl = new AbortController();
1605
+ const timer = setTimeout(() => { ctrl.abort(); }, LIVENESS_PROBE_TIMEOUT_MS);
1606
+ const official = config.baseUrl === "https://ollama.com";
1607
+ const paths = official ? ["/api/web_search"] : ["/api/experimental/web_search", "/api/web_search"];
1608
+ try {
1609
+ for (let index = 0; index < paths.length; index += 1) {
1610
+ const response = await fetch(`${config.baseUrl}${paths[index]}`, {
1611
+ method: "POST",
1612
+ headers: {
1613
+ Accept: "application/json",
1614
+ "Content-Type": "application/json",
1615
+ ...(official ? { Authorization: `Bearer ${config.apiKey}` } : {}),
1616
+ },
1617
+ body: JSON.stringify({ query: "mono-agent doctor", max_results: 1 }),
1618
+ redirect: "error",
1619
+ signal: ctrl.signal,
1620
+ });
1621
+ if (!official && index === 0 && [404, 405].includes(response.status)) {
1622
+ await response.body?.cancel();
1623
+ continue;
1624
+ }
1625
+ if ([401, 403].includes(response.status)) {
1626
+ await response.body?.cancel();
1627
+ return { ok: false, reason: official
1628
+ ? `hosted authentication failed; check ${config.apiKeyEnv}`
1629
+ : "the local proxy requires sign-in; run ollama signin or repair its proxy authentication" };
1630
+ }
1631
+ if (!response.ok) {
1632
+ await response.body?.cancel();
1633
+ return { ok: false, reason: `HTTP ${response.status}` };
1634
+ }
1635
+ const declared = Number(response.headers.get("content-length"));
1636
+ if (Number.isFinite(declared) && declared > OLLAMA_WEB_SEARCH_PROBE_MAX_BYTES) {
1637
+ await response.body?.cancel();
1638
+ return { ok: false, reason: `response exceeded ${OLLAMA_WEB_SEARCH_PROBE_MAX_BYTES} bytes` };
1639
+ }
1640
+ const bytes = await readBoundedProbeResponse(response, OLLAMA_WEB_SEARCH_PROBE_MAX_BYTES);
1641
+ let body;
1642
+ try {
1643
+ body = JSON.parse(new TextDecoder().decode(bytes));
1644
+ }
1645
+ catch {
1646
+ return { ok: false, reason: "response was not valid JSON" };
1647
+ }
1648
+ if (!body || typeof body !== "object" || !Array.isArray(body.results)) {
1649
+ return { ok: false, reason: "response did not contain a results array" };
1650
+ }
1651
+ return { ok: true, reason: "" };
1652
+ }
1653
+ return { ok: false, reason: "this Ollama version supports neither local Web Search endpoint" };
1654
+ }
1655
+ catch (error) {
1656
+ return { ok: false, reason: error instanceof Error ? error.message : String(error) };
1657
+ }
1658
+ finally {
1659
+ clearTimeout(timer);
1660
+ }
1661
+ }
1662
+ async function readBoundedProbeResponse(response, maxBytes) {
1663
+ const reader = response.body?.getReader();
1664
+ if (reader === undefined)
1665
+ throw new Error("response body could not be read safely");
1666
+ const chunks = [];
1667
+ let total = 0;
1668
+ try {
1669
+ while (true) {
1670
+ const next = await reader.read();
1671
+ if (next.done)
1672
+ break;
1673
+ total += next.value.byteLength;
1674
+ if (total > maxBytes) {
1675
+ await reader.cancel();
1676
+ throw new Error(`response exceeded ${maxBytes} bytes`);
1677
+ }
1678
+ chunks.push(next.value);
1679
+ }
1680
+ }
1681
+ finally {
1682
+ reader.releaseLock();
1683
+ }
1684
+ const joined = new Uint8Array(total);
1685
+ let offset = 0;
1686
+ for (const chunk of chunks) {
1687
+ joined.set(chunk, offset);
1688
+ offset += chunk.byteLength;
1689
+ }
1690
+ return joined;
1691
+ }
1522
1692
  async function probeSearxngEndpoint(endpoint) {
1523
1693
  const ctrl = new AbortController();
1524
1694
  const timer = setTimeout(() => { ctrl.abort(); }, LIVENESS_PROBE_TIMEOUT_MS);