@leuduan/lagent 0.0.0-stage → 44.0.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 (328) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +157 -2
  3. package/dist/chunks/2GCIWSOA.js +5 -0
  4. package/dist/chunks/2P47AHNK.js +7 -0
  5. package/dist/chunks/34KW6VNQ.js +1 -0
  6. package/dist/chunks/3UMZMPWW.js +1 -0
  7. package/dist/chunks/5IRF47YB.js +1 -0
  8. package/dist/chunks/6DRCKZ2C.js +1 -0
  9. package/dist/chunks/6FRNHMCV.js +1 -0
  10. package/dist/chunks/7LI64H5X.js +17 -0
  11. package/dist/chunks/7VAPNE3L.js +1 -0
  12. package/dist/chunks/ASSQZH3F.js +1 -0
  13. package/dist/chunks/B4FXK5ER.js +77 -0
  14. package/dist/chunks/BBCW2FZK.js +1 -0
  15. package/dist/chunks/BPRCULZH.js +1 -0
  16. package/dist/chunks/CANPZYTH.js +24 -0
  17. package/dist/chunks/CQEVREBT.js +1 -0
  18. package/dist/chunks/CUK7CGC7.js +1 -0
  19. package/dist/chunks/D4PQP5MA.js +3 -0
  20. package/dist/chunks/DDANMY45.js +3 -0
  21. package/dist/chunks/DDZ7YF26.js +1 -0
  22. package/dist/chunks/EMRB4KCN.js +6 -0
  23. package/dist/chunks/EPYQ5M3B.js +3 -0
  24. package/dist/chunks/FJLU4UH3.js +1 -0
  25. package/dist/chunks/G44LG6VL.js +1 -0
  26. package/dist/chunks/GGSVIIWJ.js +2 -0
  27. package/dist/chunks/HK6ZSONF.js +1 -0
  28. package/dist/chunks/IAAEP6VL.js +30 -0
  29. package/dist/chunks/JCTBX33H.js +36 -0
  30. package/dist/chunks/JFX2MXBA.js +4 -0
  31. package/dist/chunks/JFZZXVWD.js +15 -0
  32. package/dist/chunks/KUZCL2SH.js +1 -0
  33. package/dist/chunks/MHC6VPB4.js +7 -0
  34. package/dist/chunks/MMNNZCBO.js +5 -0
  35. package/dist/chunks/MNJ4SRF7.js +1 -0
  36. package/dist/chunks/N6IXG2VL.js +1 -0
  37. package/dist/chunks/OCBPT7KE.js +1 -0
  38. package/dist/chunks/OL5A6ITQ.js +1 -0
  39. package/dist/chunks/PUSUPTAT.js +1 -0
  40. package/dist/chunks/Q75FUN7D.js +2 -0
  41. package/dist/chunks/Q7S5LFGN.js +1 -0
  42. package/dist/chunks/RCIHV3KG.js +1 -0
  43. package/dist/chunks/S34ZA2R6.js +1 -0
  44. package/dist/chunks/SS3B5W34.js +12 -0
  45. package/dist/chunks/VYMT4TXD.js +1 -0
  46. package/dist/chunks/W57RW55W.js +1 -0
  47. package/dist/compositions/base.d.ts +11 -0
  48. package/dist/compositions/codex.d.ts +66 -0
  49. package/dist/compositions/codexPrompts.d.ts +56 -0
  50. package/dist/context.d.ts +109 -0
  51. package/dist/index.d.ts +55 -0
  52. package/dist/index.js +1 -0
  53. package/dist/journal/catalog.d.ts +112 -0
  54. package/dist/journal/forkChain.d.ts +16 -0
  55. package/dist/journal/index.d.ts +15 -0
  56. package/dist/journal/journal.d.ts +475 -0
  57. package/dist/journal/projection.d.ts +87 -0
  58. package/dist/journal/store.d.ts +181 -0
  59. package/dist/llm/client.d.ts +135 -0
  60. package/dist/llm/content.d.ts +52 -0
  61. package/dist/llm/failure.d.ts +82 -0
  62. package/dist/llm/index.d.ts +22 -0
  63. package/dist/llm/index.js +1 -0
  64. package/dist/llm/primitives.d.ts +286 -0
  65. package/dist/llm/prompt.d.ts +21 -0
  66. package/dist/llm/provider.d.ts +74 -0
  67. package/dist/llm/readLedger.d.ts +24 -0
  68. package/dist/llm/request.d.ts +58 -0
  69. package/dist/loop/agent.d.ts +18 -0
  70. package/dist/loop/authorization.d.ts +41 -0
  71. package/dist/loop/auxiliary.d.ts +58 -0
  72. package/dist/loop/chunks.d.ts +27 -0
  73. package/dist/loop/completion.d.ts +17 -0
  74. package/dist/loop/errors.d.ts +139 -0
  75. package/dist/loop/hooks.d.ts +274 -0
  76. package/dist/loop/index.d.ts +16 -0
  77. package/dist/loop/runner.d.ts +134 -0
  78. package/dist/loop/runtime.d.ts +76 -0
  79. package/dist/loop/strategy.d.ts +80 -0
  80. package/dist/loop/surfacePrepare.d.ts +30 -0
  81. package/dist/loop/tool.d.ts +106 -0
  82. package/dist/loop/toolCalls.d.ts +35 -0
  83. package/dist/plugin.d.ts +50 -0
  84. package/dist/plugin.js +1 -0
  85. package/dist/plugins/agentsMd.d.ts +80 -0
  86. package/dist/plugins/agentsMd.js +1 -0
  87. package/dist/plugins/ask/index.d.ts +26 -0
  88. package/dist/plugins/ask/index.js +1 -0
  89. package/dist/plugins/ask/service.d.ts +125 -0
  90. package/dist/plugins/ask/tools.d.ts +9 -0
  91. package/dist/plugins/commands/index.d.ts +43 -0
  92. package/dist/plugins/commands/index.js +1 -0
  93. package/dist/plugins/commands/output.d.ts +115 -0
  94. package/dist/plugins/commands/record.d.ts +558 -0
  95. package/dist/plugins/commands/service.d.ts +321 -0
  96. package/dist/plugins/commands/shell.d.ts +25 -0
  97. package/dist/plugins/commands/tools.d.ts +10 -0
  98. package/dist/plugins/compaction/checkpoint.d.ts +94 -0
  99. package/dist/plugins/compaction/config.d.ts +133 -0
  100. package/dist/plugins/compaction/estimate.d.ts +37 -0
  101. package/dist/plugins/compaction/index.d.ts +87 -0
  102. package/dist/plugins/compaction/index.js +7 -0
  103. package/dist/plugins/compaction/planner.d.ts +207 -0
  104. package/dist/plugins/compaction/prune.d.ts +9 -0
  105. package/dist/plugins/compaction/record.d.ts +227 -0
  106. package/dist/plugins/compaction/segments.d.ts +23 -0
  107. package/dist/plugins/compaction/state.d.ts +68 -0
  108. package/dist/plugins/compaction/summarize.d.ts +13 -0
  109. package/dist/plugins/dateAndBranch.d.ts +47 -0
  110. package/dist/plugins/dateAndBranch.js +1 -0
  111. package/dist/plugins/delegations/answers.d.ts +39 -0
  112. package/dist/plugins/delegations/assignmentKey.d.ts +22 -0
  113. package/dist/plugins/delegations/cleanup.d.ts +161 -0
  114. package/dist/plugins/delegations/constraint.d.ts +76 -0
  115. package/dist/plugins/delegations/index.d.ts +39 -0
  116. package/dist/plugins/delegations/index.js +1 -0
  117. package/dist/plugins/delegations/notices.d.ts +261 -0
  118. package/dist/plugins/delegations/obligations.d.ts +210 -0
  119. package/dist/plugins/delegations/record.d.ts +633 -0
  120. package/dist/plugins/delegations/request.d.ts +384 -0
  121. package/dist/plugins/delegations/role.d.ts +30 -0
  122. package/dist/plugins/delegations/service.d.ts +563 -0
  123. package/dist/plugins/delegations/standing.d.ts +19 -0
  124. package/dist/plugins/delegations/stopCheck.d.ts +21 -0
  125. package/dist/plugins/delegations/tools.d.ts +71 -0
  126. package/dist/plugins/delegations/waitContracts.d.ts +118 -0
  127. package/dist/plugins/delegations/waitResolver.d.ts +116 -0
  128. package/dist/plugins/diagnostics/digest.d.ts +14 -0
  129. package/dist/plugins/diagnostics/index.d.ts +68 -0
  130. package/dist/plugins/diagnostics/index.js +1 -0
  131. package/dist/plugins/fileTools/config.d.ts +10 -0
  132. package/dist/plugins/fileTools/editFiles.d.ts +117 -0
  133. package/dist/plugins/fileTools/fsRead.d.ts +17 -0
  134. package/dist/plugins/fileTools/gitDiscovery.d.ts +9 -0
  135. package/dist/plugins/fileTools/index.d.ts +18 -0
  136. package/dist/plugins/fileTools/index.js +1 -0
  137. package/dist/plugins/fileTools/ripgrep.d.ts +20 -0
  138. package/dist/plugins/fileTools/textEdit.d.ts +67 -0
  139. package/dist/plugins/fileTools/tools.d.ts +6 -0
  140. package/dist/plugins/historyRecall/history.d.ts +9 -0
  141. package/dist/plugins/historyRecall/index.d.ts +31 -0
  142. package/dist/plugins/historyRecall/index.js +1 -0
  143. package/dist/plugins/historyRecall/render.d.ts +34 -0
  144. package/dist/plugins/historyRecall/tools.d.ts +4 -0
  145. package/dist/plugins/mcp/catalog.d.ts +36 -0
  146. package/dist/plugins/mcp/config.d.ts +63 -0
  147. package/dist/plugins/mcp/connection.d.ts +53 -0
  148. package/dist/plugins/mcp/errors.d.ts +32 -0
  149. package/dist/plugins/mcp/index.d.ts +33 -0
  150. package/dist/plugins/mcp/index.js +5 -0
  151. package/dist/plugins/mcp/mount.d.ts +98 -0
  152. package/dist/plugins/mcp/names.d.ts +25 -0
  153. package/dist/plugins/mcp/render.d.ts +29 -0
  154. package/dist/plugins/mcp/slots.d.ts +15 -0
  155. package/dist/plugins/mcp/stdio.d.ts +49 -0
  156. package/dist/plugins/mcp/tools.d.ts +41 -0
  157. package/dist/plugins/mcp/version.d.ts +2 -0
  158. package/dist/plugins/routeNotice.d.ts +22 -0
  159. package/dist/plugins/routeNotice.js +1 -0
  160. package/dist/plugins/sandbox/absent.d.ts +33 -0
  161. package/dist/plugins/sandbox/client.d.ts +39 -0
  162. package/dist/plugins/sandbox/files.d.ts +28 -0
  163. package/dist/plugins/sandbox/index.d.ts +52 -0
  164. package/dist/plugins/sandbox/index.js +4 -0
  165. package/dist/plugins/sandbox/mode.d.ts +57 -0
  166. package/dist/plugins/sandbox/policy.d.ts +163 -0
  167. package/dist/plugins/sandbox/protocol.d.ts +107 -0
  168. package/dist/plugins/sandbox/service.d.ts +153 -0
  169. package/dist/plugins/sandbox/worker.d.ts +12 -0
  170. package/dist/plugins/sandbox/worker.js +1 -0
  171. package/dist/plugins/schedules/index.d.ts +21 -0
  172. package/dist/plugins/schedules/index.js +5 -0
  173. package/dist/plugins/schedules/record.d.ts +396 -0
  174. package/dist/plugins/schedules/service.d.ts +120 -0
  175. package/dist/plugins/schedules/time.d.ts +26 -0
  176. package/dist/plugins/schedules/tools.d.ts +6 -0
  177. package/dist/plugins/skills/discovery.d.ts +83 -0
  178. package/dist/plugins/skills/index.d.ts +31 -0
  179. package/dist/plugins/skills/index.js +1 -0
  180. package/dist/plugins/skills/tools.d.ts +11 -0
  181. package/dist/plugins/subAgents/availableRoutes.d.ts +53 -0
  182. package/dist/plugins/subAgents/index.d.ts +67 -0
  183. package/dist/plugins/subAgents/index.js +1 -0
  184. package/dist/plugins/subAgents/tools.d.ts +67 -0
  185. package/dist/plugins/threadDirs.d.ts +36 -0
  186. package/dist/plugins/threadDirs.js +1 -0
  187. package/dist/plugins/toolPolicy/index.d.ts +61 -0
  188. package/dist/plugins/toolPolicy/index.js +1 -0
  189. package/dist/plugins/truncateToolOutput.d.ts +30 -0
  190. package/dist/plugins/truncateToolOutput.js +6 -0
  191. package/dist/plugins/usage/index.d.ts +26 -0
  192. package/dist/plugins/usage/index.js +1 -0
  193. package/dist/plugins/usage/tracker.d.ts +34 -0
  194. package/dist/plugins/verify/index.d.ts +27 -0
  195. package/dist/plugins/verify/index.js +6 -0
  196. package/dist/plugins/verify/judgement.d.ts +16 -0
  197. package/dist/plugins/verify/record.d.ts +382 -0
  198. package/dist/plugins/verify/service.d.ts +93 -0
  199. package/dist/plugins/verify/state.d.ts +58 -0
  200. package/dist/plugins/webTools/html.d.ts +23 -0
  201. package/dist/plugins/webTools/index.d.ts +34 -0
  202. package/dist/plugins/webTools/index.js +1 -0
  203. package/dist/plugins/webTools/network.d.ts +23 -0
  204. package/dist/plugins/webTools/web.d.ts +32 -0
  205. package/dist/plugins/workflows/assignment.d.ts +20 -0
  206. package/dist/plugins/workflows/cleanup.d.ts +38 -0
  207. package/dist/plugins/workflows/definition.d.ts +184 -0
  208. package/dist/plugins/workflows/entryPlan.d.ts +95 -0
  209. package/dist/plugins/workflows/hostBindings.d.ts +146 -0
  210. package/dist/plugins/workflows/index.d.ts +28 -0
  211. package/dist/plugins/workflows/index.js +11 -0
  212. package/dist/plugins/workflows/observations.d.ts +81 -0
  213. package/dist/plugins/workflows/participantModels.d.ts +28 -0
  214. package/dist/plugins/workflows/participants.d.ts +143 -0
  215. package/dist/plugins/workflows/policy.d.ts +112 -0
  216. package/dist/plugins/workflows/record.d.ts +2849 -0
  217. package/dist/plugins/workflows/routing.d.ts +116 -0
  218. package/dist/plugins/workflows/schema.d.ts +26 -0
  219. package/dist/plugins/workflows/service.d.ts +477 -0
  220. package/dist/plugins/workflows/state.d.ts +373 -0
  221. package/dist/plugins/workflows/stopCheck.d.ts +13 -0
  222. package/dist/plugins/workflows/tools.d.ts +13 -0
  223. package/dist/plugins/workflows/view.d.ts +103 -0
  224. package/dist/plugins/workflows/workStatus.d.ts +21 -0
  225. package/dist/plugins/workspaceNotice.d.ts +36 -0
  226. package/dist/plugins/workspaceNotice.js +1 -0
  227. package/dist/providers/anthropic.d.ts +178 -0
  228. package/dist/providers/anthropicMessages.d.ts +66 -0
  229. package/dist/providers/codex.d.ts +71 -0
  230. package/dist/providers/codexAuth.d.ts +116 -0
  231. package/dist/providers/deepseek.d.ts +59 -0
  232. package/dist/providers/failure.d.ts +23 -0
  233. package/dist/providers/gateway.d.ts +24 -0
  234. package/dist/providers/index.d.ts +18 -0
  235. package/dist/providers/index.js +6 -0
  236. package/dist/providers/openaiChat.d.ts +73 -0
  237. package/dist/providers/openaiResponses.d.ts +109 -0
  238. package/dist/providers/opencodeCopilot.d.ts +23 -0
  239. package/dist/providers/opencodeGo.d.ts +109 -0
  240. package/dist/providers/shared.d.ts +112 -0
  241. package/dist/providers/stream.d.ts +156 -0
  242. package/dist/records/index.d.ts +13 -0
  243. package/dist/records/index.js +1 -0
  244. package/dist/records/journal.d.ts +2968 -0
  245. package/dist/records/toolResult.d.ts +65 -0
  246. package/dist/services/agents.d.ts +62 -0
  247. package/dist/services/catalogContributions.d.ts +73 -0
  248. package/dist/services/confinement/files.d.ts +118 -0
  249. package/dist/services/confinement/service.d.ts +219 -0
  250. package/dist/services/core.d.ts +28 -0
  251. package/dist/services/extensionEvents.d.ts +181 -0
  252. package/dist/services/journal.d.ts +26 -0
  253. package/dist/services/llm.d.ts +82 -0
  254. package/dist/services/modes.d.ts +65 -0
  255. package/dist/services/plugins.d.ts +34 -0
  256. package/dist/services/presets/definition.d.ts +154 -0
  257. package/dist/services/presets/installations.d.ts +139 -0
  258. package/dist/services/prompts.d.ts +85 -0
  259. package/dist/services/threads/activation.d.ts +100 -0
  260. package/dist/services/threads/admission.d.ts +174 -0
  261. package/dist/services/threads/birth.d.ts +219 -0
  262. package/dist/services/threads/index.d.ts +14 -0
  263. package/dist/services/threads/runEvents.d.ts +79 -0
  264. package/dist/services/threads/runOwner.d.ts +368 -0
  265. package/dist/services/threads/service.d.ts +450 -0
  266. package/dist/services/threads/thread.d.ts +268 -0
  267. package/dist/services/threads/view.d.ts +93 -0
  268. package/dist/services/tools.d.ts +118 -0
  269. package/dist/state/birth.d.ts +62 -0
  270. package/dist/state/chain.d.ts +46 -0
  271. package/dist/state/confirmations.d.ts +64 -0
  272. package/dist/state/continuation.d.ts +167 -0
  273. package/dist/state/decide.d.ts +72 -0
  274. package/dist/state/dispatches.d.ts +54 -0
  275. package/dist/state/errors.d.ts +26 -0
  276. package/dist/state/forks.d.ts +61 -0
  277. package/dist/state/holds.d.ts +104 -0
  278. package/dist/state/inbox.d.ts +188 -0
  279. package/dist/state/index.d.ts +31 -0
  280. package/dist/state/inputs.d.ts +58 -0
  281. package/dist/state/installations.d.ts +28 -0
  282. package/dist/state/limits.d.ts +14 -0
  283. package/dist/state/prompt.d.ts +13 -0
  284. package/dist/state/recovery.d.ts +7 -0
  285. package/dist/state/replace.d.ts +33 -0
  286. package/dist/state/requests.d.ts +129 -0
  287. package/dist/state/route.d.ts +61 -0
  288. package/dist/state/summary.d.ts +16 -0
  289. package/dist/state/surface.d.ts +153 -0
  290. package/dist/state/surfaceRead.d.ts +20 -0
  291. package/dist/state/thread.d.ts +73 -0
  292. package/dist/state/turns.d.ts +87 -0
  293. package/dist/state/waits.d.ts +38 -0
  294. package/dist/state/wake.d.ts +32 -0
  295. package/dist/stores/durableObject.d.ts +23 -0
  296. package/dist/stores/durableObject.js +1 -0
  297. package/dist/stores/durableObjectConnection.d.ts +27 -0
  298. package/dist/stores/memory.d.ts +29 -0
  299. package/dist/stores/sql.d.ts +59 -0
  300. package/dist/stores/sqlite.d.ts +31 -0
  301. package/dist/stores/sqlite.js +1 -0
  302. package/dist/sys/environment.d.ts +42 -0
  303. package/dist/sys/git.d.ts +47 -0
  304. package/dist/sys/paths.d.ts +9 -0
  305. package/dist/sys/spawn.d.ts +186 -0
  306. package/dist/testing/clock.d.ts +17 -0
  307. package/dist/testing/fakeLlm.d.ts +76 -0
  308. package/dist/testing/fedLlm.d.ts +34 -0
  309. package/dist/testing/helpers.d.ts +362 -0
  310. package/dist/testing/index.d.ts +13 -0
  311. package/dist/testing/index.js +1 -0
  312. package/dist/testing/processes.d.ts +13 -0
  313. package/dist/testing/settlement.d.ts +6 -0
  314. package/dist/testing/tmpDirs.d.ts +17 -0
  315. package/dist/util/async.d.ts +8 -0
  316. package/dist/util/diff.d.ts +25 -0
  317. package/dist/util/dispatch.d.ts +8 -0
  318. package/dist/util/errors.d.ts +28 -0
  319. package/dist/util/foldState.d.ts +17 -0
  320. package/dist/util/freeze.d.ts +2 -0
  321. package/dist/util/ids.d.ts +2 -0
  322. package/dist/util/json.d.ts +37 -0
  323. package/dist/util/jsonSchema.d.ts +7 -0
  324. package/dist/util/log.d.ts +6 -0
  325. package/dist/util/retries.d.ts +25 -0
  326. package/dist/util/text.d.ts +21 -0
  327. package/dist/util/timers.d.ts +43 -0
  328. package/package.json +183 -3
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The text side of `edit_files`: decoding a file as text and encoding it back exactly as it was
3
+ * kept, and locating a hunk's old text in it.
4
+ *
5
+ * A hunk is matched exactly first, then in the three looser passes Codex's `apply_patch` uses
6
+ * (`codex-rs/apply-patch/src/seek_sequence.rs`): line by line ignoring trailing whitespace, then
7
+ * surrounding whitespace, then also typographic punctuation. Unlike Codex, which takes the first
8
+ * place a pass finds, a pass here decides only when it finds exactly one: a second place fails the
9
+ * hunk as ambiguous, and so does a second exact match.
10
+ *
11
+ * A pass that ignores surrounding whitespace can match lines indented differently from the old text.
12
+ * The new text is then shifted by the same difference, so what replaces the lines sits where they
13
+ * did; see {@link reindent}.
14
+ */
15
+ /** A text file as `edit_files` keeps it: its text, and what it writes back around the text unchanged. */
16
+ export type TextFile = {
17
+ /** Whether the file starts with a UTF-8 byte-order mark, which `text` leaves out. */
18
+ readonly bom: boolean;
19
+ readonly text: string;
20
+ /** The file's line ending, from its first line; `\n` for a file with none. */
21
+ readonly eol: '\n' | '\r\n';
22
+ /** Whether the file ends with a line ending. */
23
+ readonly finalNewline: boolean;
24
+ };
25
+ /** Why a file is not text `edit_files` will edit, or `null` and the file. */
26
+ export declare function decodeText(bytes: Buffer): {
27
+ file: TextFile;
28
+ refusal: null;
29
+ } | {
30
+ file: null;
31
+ refusal: string;
32
+ };
33
+ /** `text` as the file's bytes, with the BOM the file had. */
34
+ export declare function encodeText(file: Pick<TextFile, 'bom'>, text: string): Buffer;
35
+ /** `text` with its line endings made the file's. */
36
+ export declare function withLineEndings(text: string, eol: TextFile['eol']): string;
37
+ /**
38
+ * New text for a file whose old text was `file`, ending in a newline exactly when the old text
39
+ * did: one is added when it had one, and every trailing line ending removed when it had none. An
40
+ * empty file has no ending to keep, so its new text is taken as given.
41
+ */
42
+ export declare function keepFinalNewline(file: TextFile, text: string): string;
43
+ export type Hunk = {
44
+ readonly old_text: string;
45
+ readonly new_text: string;
46
+ };
47
+ /** How a hunk's old text was found, or why it was not. */
48
+ export type HunkMatch = {
49
+ readonly found: true;
50
+ readonly text: string;
51
+ readonly pass: MatchPass;
52
+ /** Whether the new text was shifted to the file's indentation. */
53
+ readonly reindented: boolean;
54
+ } | {
55
+ readonly found: false;
56
+ readonly reason: string;
57
+ };
58
+ export type MatchPass = 'exact' | 'trailing-whitespace' | 'whitespace' | 'punctuation';
59
+ export declare const PASS_WORDING: Record<Exclude<MatchPass, 'exact'>, string>;
60
+ /**
61
+ * `text` with `hunk` applied, in the file's line endings. The old text must be found in exactly
62
+ * one place; when it is found nowhere, the reason shows what was looked for and the lines of the
63
+ * file nearest to it.
64
+ */
65
+ export declare function applyHunk(text: string, hunk: Hunk, eol: TextFile['eol']): HunkMatch;
66
+ /** Codex's normalization: trimmed, with dashes, quotes and odd spaces made ASCII. */
67
+ export declare function normalized(line: string): string;
@@ -0,0 +1,6 @@
1
+ import type { Tool } from '../../loop/index.js';
2
+ import type { FileToolsConfig } from './config.js';
3
+ /** What the model is told about the tools that need more than their description. */
4
+ export declare const guidance: Map<string, string>;
5
+ /** The file tools `config` provides: without `rg`, neither search tool; nothing searches by another means. */
6
+ export declare const fileToolsFor: (config: FileToolsConfig) => readonly Tool[];
@@ -0,0 +1,9 @@
1
+ import type { Journal } from '../../journal/index.js';
2
+ import type { Seq } from '../../records/journal.js';
3
+ /**
4
+ * Every message that has ever been on a thread's surface, numbered from 1 in lineage order, by the
5
+ * row behind it. Stand-ins are not numbered, so a number never moves: not across compactions,
6
+ * reopening or forks, which share their source's numbers up to the cut. The one numbering a
7
+ * checkpoint's footer names messages by and recall reads them back by, so the two always agree.
8
+ */
9
+ export declare function historyNumbers(journal: Pick<Journal, 'lineage'>, threadId: string): Map<Seq, number>;
@@ -0,0 +1,31 @@
1
+ import type { Plugin } from '@leuduan/cordis';
2
+ import { z } from 'zod';
3
+ import { HISTORY_RECALL_TOOLS } from './tools.js';
4
+ export { HISTORY_RECALL_TOOLS };
5
+ /** Message numbering, which compaction's checkpoints and stand-ins cite as recall reads it back. */
6
+ export { historyNumbers } from './history.js';
7
+ /**
8
+ * The line a stand-in ends on when its agent has both tools: where to read the `count` replaced
9
+ * messages back, `first` being the number of the first of them. Written here, beside the tools it
10
+ * names, so the pointer and what it points at change together. The form for several is the longer.
11
+ */
12
+ export declare const renderRecall: (first: number, count: number) => string;
13
+ export declare const HistoryRecallConfigSchema: z.ZodObject<{
14
+ agents: z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodLiteral<"global">, z.ZodLiteral<"all">]>;
15
+ }, z.core.$strict>;
16
+ export type HistoryRecallConfig = z.input<typeof HistoryRecallConfigSchema>;
17
+ /**
18
+ * Registers `history_read` and `history_search`: read-only tools over the journal that bring back
19
+ * what a replacement condensed, by the message numbers a checkpoint names. Each reads the calling
20
+ * thread's own lineage, a fork's inherited rows included, and nothing of any other thread. They are
21
+ * advertised to the selected agents from a thread's first request, and answer that nothing has been
22
+ * condensed until something has. Independent of any strategy: it reads the journal, not how the
23
+ * surface was replaced. A strategy that sees `history_read` granted points its checkpoints at it.
24
+ *
25
+ * Mounted on the untagged application context only: the tools are one grant for every thread.
26
+ *
27
+ * ```ts
28
+ * await root.plugin(historyRecall, { agents: ['main_agent'] })
29
+ * ```
30
+ */
31
+ export declare const historyRecall: Plugin.Object<HistoryRecallConfig>;
@@ -0,0 +1 @@
1
+ import{a,b,c,d,e}from"../../chunks/2GCIWSOA.js";import"../../chunks/JFX2MXBA.js";import"../../chunks/S34ZA2R6.js";import"../../chunks/CUK7CGC7.js";import"../../chunks/BPRCULZH.js";import"../../chunks/FJLU4UH3.js";import"../../chunks/DDANMY45.js";import"../../chunks/BBCW2FZK.js";import"../../chunks/MMNNZCBO.js";import"../../chunks/G44LG6VL.js";import"../../chunks/D4PQP5MA.js";export{b as HISTORY_RECALL_TOOLS,d as HistoryRecallConfigSchema,a as historyNumbers,e as historyRecall,c as renderRecall};
@@ -0,0 +1,34 @@
1
+ import type { PluginJournal } from '../../journal/index.js';
2
+ import { type MessageRole } from '../../llm/primitives.js';
3
+ /** One message that has been on a thread's surface, as recall shows it. */
4
+ export type HistoryMessage = {
5
+ /** Its history number: 1 for the first message the thread's conversation ever held. */
6
+ readonly number: number;
7
+ readonly role: MessageRole;
8
+ /** The tool a result answers; `null` for any other message. */
9
+ readonly name: string | null;
10
+ /** The message as rendered, without its header. */
11
+ readonly body: string;
12
+ /**
13
+ * Whether the surface no longer holds this message as itself: a replacement stands for it, as a
14
+ * span's checkpoint or a rewrite's shorter text.
15
+ */
16
+ readonly condensed: boolean;
17
+ };
18
+ /**
19
+ * Every message that has ever been on a thread's surface, in lineage order, numbered as
20
+ * `historyNumbers` numbers them and rendered as the model saw it: the same row-to-message logic the
21
+ * surface fold uses, with replacements ignored. A pure read over the journal: nothing here depends
22
+ * on how, or whether, the surface was ever replaced, except which messages `condensed` marks.
23
+ *
24
+ * A fork reads its source's rows up to its cut as its own, so it shares their numbers and text.
25
+ */
26
+ export declare function history(journal: Pick<PluginJournal, 'lineage' | 'state'>, threadId: string): HistoryMessage[];
27
+ /**
28
+ * A message in a transcript: its body in an envelope the code writes, which names its number, role
29
+ * and, for a result, its tool. A body cannot end the envelope or fake another, since every closing
30
+ * `</message` in it is turned into `<\/message`: nothing a message said speaks as the harness.
31
+ */
32
+ export declare const renderMessage: (message: HistoryMessage) => string;
33
+ /** A message named in a listing: `Message 5 (user)`, `Message 6 (tool read_file)`. */
34
+ export declare const describeMessage: (message: HistoryMessage) => string;
@@ -0,0 +1,4 @@
1
+ /** The tools the plugin grants, for a host's allowlist or an agent's tool list. */
2
+ export declare const HISTORY_RECALL_TOOLS: readonly ["history_read", "history_search"];
3
+ export declare const historyReadTool: import("../../loop/tool.js").Tool;
4
+ export declare const historySearchTool: import("../../loop/tool.js").Tool;
@@ -0,0 +1,36 @@
1
+ import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import { type Tool as RemoteTool } from '@modelcontextprotocol/sdk/types.js';
3
+ import { type ToolSpec } from '../../llm/primitives.js';
4
+ import type { McpConfig } from './config.js';
5
+ import type { UnexposableTool } from './errors.js';
6
+ /** One exposable tool: its lagent name, the definition the server listed, and the spec built from it. */
7
+ export type CatalogEntry = {
8
+ readonly name: string;
9
+ readonly remoteName: string;
10
+ readonly definition: RemoteTool;
11
+ readonly spec: ToolSpec;
12
+ /** Equal for equal definitions; a changed definition is a different tool. */
13
+ readonly fingerprint: string;
14
+ };
15
+ /** A complete, immutable snapshot of what a server offers, as lagent can expose it. */
16
+ export type Catalog = {
17
+ readonly entries: ReadonlyMap<string, CatalogEntry>;
18
+ readonly unexposable: readonly UnexposableTool[];
19
+ };
20
+ export declare const EMPTY_CATALOG: Catalog;
21
+ /**
22
+ * Every page of `tools/list`, requested directly. The SDK's `listTools()` replaces the client's
23
+ * validator and task caches on every page, and its list-changed refresh fetches only the first one.
24
+ */
25
+ export declare function listAllTools(client: Client, signal: AbortSignal): Promise<RemoteTool[]>;
26
+ /**
27
+ * What lagent can expose of a complete listing. With an allowlist only the listed tools are
28
+ * considered, under their aliases, and a listed tool the server does not offer is unexposable.
29
+ * Collisions are found over the whole listing, so the outcome never depends on how the server
30
+ * paged: every tool of a colliding group is unexposable.
31
+ */
32
+ export declare function buildCatalog(config: Pick<McpConfig, 'name' | 'tools'>, listed: readonly RemoteTool[]): Catalog;
33
+ /** Unexposable tools in one order, by tool and then reason, whatever order they were found in. */
34
+ export declare const sortUnexposable: (tools: readonly UnexposableTool[]) => UnexposableTool[];
35
+ /** Whether two reports of unexposable tools say the same thing. */
36
+ export declare const sameUnexposable: (left: readonly UnexposableTool[], right: readonly UnexposableTool[]) => boolean;
@@ -0,0 +1,63 @@
1
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
2
+ import { z } from 'zod';
3
+ /**
4
+ * The longest server name: `mcp__` and `__` around it still leave 33 of the 64 characters a tool
5
+ * name may have for the tool segment.
6
+ */
7
+ export declare const MAX_SERVER_NAME_LENGTH = 24;
8
+ /**
9
+ * A factory for any SDK transport. A transport is single-use, so every connection asks for a new one.
10
+ * `signal` aborts when the opening is abandoned (its deadline, the owner's signal, disposal): stop
11
+ * working then. A transport that arrives after that is closed by the mount.
12
+ */
13
+ export type McpTransportFactory = (signal: AbortSignal) => Transport | Promise<Transport>;
14
+ export declare const McpTransportSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
15
+ kind: z.ZodLiteral<"stdio">;
16
+ command: z.ZodTuple<[z.ZodString], z.ZodString>;
17
+ cwd: z.ZodString;
18
+ env: z.ZodRecord<z.ZodString, z.ZodString>;
19
+ }, z.core.$strict>, z.ZodObject<{
20
+ kind: z.ZodLiteral<"streamable-http">;
21
+ url: z.ZodURL;
22
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
23
+ }, z.core.$strict>, z.ZodObject<{
24
+ kind: z.ZodLiteral<"custom">;
25
+ create: z.ZodCustom<McpTransportFactory, McpTransportFactory>;
26
+ }, z.core.$strict>], "kind">;
27
+ export type McpTransportConfig = z.output<typeof McpTransportSchema>;
28
+ export declare const McpConfigSchema: z.ZodObject<{
29
+ name: z.ZodString;
30
+ transport: z.ZodDiscriminatedUnion<[z.ZodObject<{
31
+ kind: z.ZodLiteral<"stdio">;
32
+ command: z.ZodTuple<[z.ZodString], z.ZodString>;
33
+ cwd: z.ZodString;
34
+ env: z.ZodRecord<z.ZodString, z.ZodString>;
35
+ }, z.core.$strict>, z.ZodObject<{
36
+ kind: z.ZodLiteral<"streamable-http">;
37
+ url: z.ZodURL;
38
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
39
+ }, z.core.$strict>, z.ZodObject<{
40
+ kind: z.ZodLiteral<"custom">;
41
+ create: z.ZodCustom<McpTransportFactory, McpTransportFactory>;
42
+ }, z.core.$strict>], "kind">;
43
+ agents: z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodLiteral<"global">, z.ZodLiteral<"all">]>;
44
+ confirm: z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodLiteral<"none">, z.ZodObject<{
45
+ except: z.ZodArray<z.ZodString>;
46
+ }, z.core.$strict>]>;
47
+ onInterrupted: z.ZodUnion<readonly [z.ZodLiteral<"report">, z.ZodLiteral<"annotations">, z.ZodObject<{
48
+ rerun: z.ZodArray<z.ZodString>;
49
+ }, z.core.$strict>]>;
50
+ maxConcurrentCalls: z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<"unbounded">]>;
51
+ tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
52
+ name: z.ZodString;
53
+ as: z.ZodString;
54
+ }, z.core.$strict>]>>>;
55
+ instructions: z.ZodDefault<z.ZodBoolean>;
56
+ connectTimeoutSeconds: z.ZodDefault<z.ZodNumber>;
57
+ callTimeoutSeconds: z.ZodDefault<z.ZodNumber>;
58
+ maxCallSeconds: z.ZodDefault<z.ZodNumber>;
59
+ maxContentBytes: z.ZodDefault<z.ZodNumber>;
60
+ signal: z.ZodOptional<z.ZodCustom<AbortSignal, AbortSignal>>;
61
+ }, z.core.$strict>;
62
+ export type McpConfig = z.output<typeof McpConfigSchema>;
63
+ export type McpConfigInput = z.input<typeof McpConfigSchema>;
@@ -0,0 +1,53 @@
1
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
+ import type { McpTransportConfig } from './config.js';
4
+ /** One successful initialization: a client, its transport, and the server's instructions. */
5
+ export type Generation = {
6
+ readonly number: number;
7
+ readonly client: Client;
8
+ readonly transport: Transport;
9
+ readonly instructions: string | null;
10
+ /** False once the transport closed or the session ended; a dead generation is never reused. */
11
+ alive: boolean;
12
+ };
13
+ export type ConnectionOptions = {
14
+ readonly server: string;
15
+ readonly transport: McpTransportConfig;
16
+ /** The mount's lifetime: aborting it stops a stdio server's group. */
17
+ readonly lifetime: AbortSignal;
18
+ /** The live generation's server says its tools changed. */
19
+ readonly onToolsChanged: (generation: Generation) => void;
20
+ /** The live generation went away on its own. */
21
+ readonly onLost: (generation: Generation, reason: string) => void;
22
+ };
23
+ /**
24
+ * The transport, initialization and lifetime of one server's connection. Each successful
25
+ * initialization is a new generation; whoever holds one can tell whether it is still the live one.
26
+ * The client declares no capabilities, so the server can ask it for nothing: no sampling,
27
+ * elicitation or roots.
28
+ */
29
+ export declare class McpConnection {
30
+ private live;
31
+ private count;
32
+ private disposed;
33
+ private readonly options;
34
+ constructor(options: ConnectionOptions);
35
+ /** The live generation, if there is one. */
36
+ get current(): Generation | null;
37
+ /**
38
+ * Connects and initializes a new generation, which becomes the live one. `signal` bounds the whole
39
+ * opening: creating the transport (a custom factory gets the signal), starting it, `initialize` and
40
+ * the `initialized` notification. The SDK bounds only `initialize`; the rest could wait for ever.
41
+ * On expiry the client is closed, which closes the transport and deletes an HTTP session the server
42
+ * already granted (`closeOnce`); a factory that answers after that has its result closed.
43
+ */
44
+ open(signal: AbortSignal, timeoutMs: number): Promise<Generation>;
45
+ /** Ends a generation the server no longer recognizes, such as a session it answered 404 for. */
46
+ invalidate(generation: Generation): Promise<void>;
47
+ /** Ends the live generation: closing shuts a stdio server down and deletes an HTTP session (`closeOnce`). */
48
+ dispose(): Promise<void>;
49
+ private createTransport;
50
+ private describeClose;
51
+ }
52
+ /** Whether an error is the HTTP 404 a server answers for a session it ended. */
53
+ export declare const isSessionGone: (error: unknown) => boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * What an `mcp` mount reports. A rejected mount throws one, and every `ctx.reportError` raises one,
3
+ * so a host filters them from Cordis `internal/error` by class and `kind`. Named apart from the
4
+ * SDK's own `McpError`, which is a protocol error.
5
+ */
6
+ export type McpServerErrorKind =
7
+ /** A mount or reconnection that could not connect or initialize. */
8
+ 'connect'
9
+ /** A listing that failed; the last complete catalog stays published. */
10
+ | 'refresh'
11
+ /** Tools left out, each with its reason. */
12
+ | 'unexposable'
13
+ /** A connection that went away. */
14
+ | 'disconnect';
15
+ /** A remote tool that cannot be exposed, and why. */
16
+ export type UnexposableTool = {
17
+ readonly tool: string;
18
+ readonly reason: string;
19
+ };
20
+ export declare class McpServerError extends Error {
21
+ readonly name = "McpServerError";
22
+ readonly server: string;
23
+ readonly kind: McpServerErrorKind;
24
+ /** Set for `unexposable`. */
25
+ readonly tools: readonly UnexposableTool[];
26
+ constructor(server: string, kind: McpServerErrorKind, message: string, options?: {
27
+ cause?: unknown;
28
+ tools?: readonly UnexposableTool[];
29
+ });
30
+ }
31
+ /** A reason in one line, for messages and results. */
32
+ export declare const describeError: (error: unknown) => string;
@@ -0,0 +1,33 @@
1
+ import { type Plugin } from '@leuduan/cordis';
2
+ import { type McpConfigInput } from './config.js';
3
+ export { MAX_SERVER_NAME_LENGTH, McpConfigSchema, McpTransportSchema } from './config.js';
4
+ export type { McpConfig, McpConfigInput, McpTransportConfig, McpTransportFactory } from './config.js';
5
+ export { McpServerError } from './errors.js';
6
+ export type { McpServerErrorKind, UnexposableTool } from './errors.js';
7
+ export { MAX_TOOL_NAME_LENGTH, mcpToolName } from './names.js';
8
+ export { CALL_META_KEY, SESSION_RESET_NOTE } from './tools.js';
9
+ /**
10
+ * Connects to one MCP server and exposes its tools as ordinary lagent tools named
11
+ * `mcp__<server>__<tool>`, granted to `agents`. One mount is one server: a server that cannot be
12
+ * reached, or a tool listed in `tools` that cannot be exposed, rejects the mount with an
13
+ * `McpServerError` and leaves nothing registered. Tools found by discovery that cannot be exposed,
14
+ * a refresh that fails and a connection that goes away are reported through `ctx.reportError`.
15
+ *
16
+ * The plugin mounts no service, so the same mount works on the root, where one connection serves
17
+ * every thread, through `thread.ctx`, or inside a host preset. A failed mount stays in its owner's
18
+ * tree: an optional server is disposed when it fails, or a thread activation never becomes ready.
19
+ *
20
+ * ```ts
21
+ * await root.plugin(mcp, {
22
+ * name: 'docs',
23
+ * transport: { kind: 'stdio', command: ['node', 'server.js'], cwd: '/srv/docs', env: { PATH: '/usr/bin' } },
24
+ * agents: ['main'],
25
+ * confirm: 'all',
26
+ * onInterrupted: 'report',
27
+ * maxConcurrentCalls: 1,
28
+ * })
29
+ * ```
30
+ *
31
+ * The design and its reasons are in `docs/records/mcp.md`.
32
+ */
33
+ export declare const mcp: Plugin.Object<McpConfigInput>;
@@ -0,0 +1,5 @@
1
+ import{a as Y}from"../../chunks/ASSQZH3F.js";import{a as N,c as H}from"../../chunks/7LI64H5X.js";import{a as w}from"../../chunks/PUSUPTAT.js";import{a as v}from"../../chunks/34KW6VNQ.js";import"../../chunks/DDZ7YF26.js";import{b as z}from"../../chunks/EPYQ5M3B.js";import{b as B,c as W}from"../../chunks/JFX2MXBA.js";import"../../chunks/6FRNHMCV.js";import{c as U}from"../../chunks/CUK7CGC7.js";import"../../chunks/BPRCULZH.js";import"../../chunks/FJLU4UH3.js";import"../../chunks/DDANMY45.js";import{c as g}from"../../chunks/BBCW2FZK.js";import"../../chunks/MMNNZCBO.js";import"../../chunks/G44LG6VL.js";import{h as A}from"../../chunks/D4PQP5MA.js";import{scopeOf as Fe}from"@leuduan/cordis";import{z as c}from"zod";var S=64,Z=/^(?!.*__)[A-Za-z0-9](?:[A-Za-z0-9_-]*[A-Za-z0-9-])?$/,V=/^[A-Za-z0-9_-]+$/,me=n=>n.replace(/[^A-Za-z0-9_-]/g,"_"),O=(n,e,t)=>`mcp__${n}__${t??me(e)}`;var D=24,pe=c.strictObject({kind:c.literal("stdio"),command:c.tuple([c.string().min(1)],c.string()),cwd:c.string().min(1),env:c.record(c.string(),c.string())}),fe=c.strictObject({kind:c.literal("streamable-http"),url:c.url({protocol:/^https?$/,error:"url must be an http or https URL"}),headers:c.record(c.string(),c.string()).default({})}),ge=c.strictObject({kind:c.literal("custom"),create:c.custom(n=>typeof n=="function","create must be a function")}),X=c.discriminatedUnion("kind",[pe,fe,ge]),we=c.union([c.string().min(1),c.strictObject({name:c.string().min(1),as:c.string().regex(V,"as must use A-Z a-z 0-9 _ -")})]),P=n=>c.number().positive().finite().default(n),k=c.strictObject({name:c.string().max(D).regex(Z,"name must use A-Z a-z 0-9 _ -, start with a letter or digit, never end with _, and never contain __"),transport:X,agents:U,confirm:c.union([c.literal("all"),c.literal("none"),c.strictObject({except:c.array(c.string())})]),onInterrupted:c.union([c.literal("report"),c.literal("annotations"),c.strictObject({rerun:c.array(c.string())})]),maxConcurrentCalls:c.union([c.number().int().positive(),c.literal("unbounded")]),tools:c.array(we).optional(),instructions:c.boolean().default(!1),connectTimeoutSeconds:P(30),callTimeoutSeconds:P(120),maxCallSeconds:P(600),maxContentBytes:c.number().int().nonnegative().default(1024*1024),signal:c.custom(n=>n instanceof AbortSignal,"signal must be an AbortSignal").optional()}).superRefine((n,e)=>{if(n.maxCallSeconds<n.callTimeoutSeconds&&e.addIssue({code:"custom",path:["maxCallSeconds"],message:"must be at least callTimeoutSeconds"}),n.tools===void 0)return;let t=n.tools.map(s=>typeof s=="string"?s:s.name),r=t.find((s,a)=>t.indexOf(s)!==a);if(r!==void 0&&e.addIssue({code:"custom",path:["tools"],message:`lists ${r} more than once`}),typeof n.confirm=="object")for(let s of n.confirm.except)t.includes(s)||e.addIssue({code:"custom",path:["confirm","except"],message:`${s} is not in tools`});if(typeof n.onInterrupted=="object")for(let s of n.onInterrupted.rerun)t.includes(s)||e.addIssue({code:"custom",path:["onInterrupted","rerun"],message:`${s} is not in tools`})});import{ListToolsResultSchema as be}from"@modelcontextprotocol/sdk/types.js";var K={entries:new Map,unexposable:[]};async function Q(n,e){let t=[],r=new Set,s;do{let a=await n.request({method:"tools/list",params:s===void 0?{}:{cursor:s}},be,{signal:e});if(t.push(...a.tools),s=a.nextCursor,s!==void 0){if(r.has(s))throw new Error(`the server repeated the pagination cursor ${s}`);r.add(s)}}while(s!==void 0);return t}function ee(n,e){let t=n.tools===void 0?void 0:new Map(n.tools.map(o=>typeof o=="string"?[o,void 0]:[o.name,o.as])),r=[],s=[];for(let o of e){if(t!==void 0&&!t.has(o.name))continue;let u=O(n.name,o.name,t?.get(o.name));s.push({remote:o,name:u,problem:ve(o,u)})}if(t!==void 0){let o=new Set(e.map(u=>u.name));for(let u of t.keys())o.has(u)||r.push({tool:u,reason:"the server does not offer it"})}let a=new Map;for(let o of s)a.set(o.name,[...a.get(o.name)??[],o]);let i=new Map;for(let o of s){let u=a.get(o.name);if(u.length>1){let p=u.filter(l=>l!==o).map(l=>l.remote.name);r.push({tool:o.remote.name,reason:`${o.name} collides with ${p.join(", ")}`});continue}if(o.problem!==null){r.push({tool:o.remote.name,reason:o.problem});continue}i.set(o.name,{name:o.name,remoteName:o.remote.name,definition:o.remote,spec:A.parse(te(o.remote,o.name)),fingerprint:g(o.remote)})}return{entries:i,unexposable:L(r)}}var J=(n,e)=>n<e?-1:n>e?1:0,te=(n,e)=>({name:e,description:n.description??n.title??"",input_schema:n.inputSchema});function ve(n,e){return e.length>64?`${e} is ${e.length} characters, over the ${64} a tool name may have`:n.execution?.taskSupport==="required"?"it requires task-augmented execution":A.safeParse(te(n,e)).success?null:"its input schema is not an object schema"}var L=n=>[...n].sort((e,t)=>J(e.tool,t.tool)||J(e.reason,t.reason)),ne=(n,e)=>g(n)===g(e);import{Client as Ee}from"@modelcontextprotocol/sdk/client/index.js";import{StreamableHTTPClientTransport as oe,StreamableHTTPError as _e}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{ToolListChangedNotificationSchema as Me}from"@modelcontextprotocol/sdk/types.js";import Te from"@leuduan/lagent/package.json"with{type:"json"};function re(){return Te.version}import{ReadBuffer as xe,serializeMessage as Se}from"@modelcontextprotocol/sdk/shared/stdio.js";var ye=8*1024,b=class{onclose;onerror;onmessage;spawned=null;buffer=new xe;stderr="";exit=null;closed=!1;closedEarly=!1;options;constructor(e){this.options=e}get pid(){return this.spawned?.pid}get stderrTail(){return this.stderr}get exited(){return this.exit}async start(){if(this.spawned!==null)throw new Error("ContainedStdioTransport already started");let e=await H({command:this.options.command,cwd:this.options.cwd,env:this.options.env,signal:this.options.signal,killGraceMs:this.options.killGraceMs??N,stdio:"pipes"});if(this.spawned=e,this.closedEarly)throw await e.stop(),new Error("ContainedStdioTransport closed while starting");e.stdout.on("data",t=>this.receive(t)),e.stderr.setEncoding("utf8"),e.stderr.on("data",t=>{this.stderr=(this.stderr+t).slice(-ye),w.debug("MCP server '%s' stderr: %s",this.options.server,t.trimEnd())}),e.stdin.on("error",t=>this.onerror?.(t)),e.result.then(t=>{this.exit=t,this.closed=!0,this.onclose?.()})}receive(e){try{this.buffer.append(e)}catch(t){this.onerror?.(t instanceof Error?t:new Error(String(t)));return}for(;;){let t;try{t=this.buffer.readMessage()}catch(r){this.onerror?.(r instanceof Error?r:new Error(String(r)));continue}if(t===null)return;this.onmessage?.(t)}}async send(e){let t=this.spawned?.stdin;if(t===void 0||this.closed||t.destroyed)throw new Error("The MCP server is not running");t.write(Se(e))||await new Promise((r,s)=>{let a=()=>{t.off("close",i),r()},i=()=>{t.off("drain",a),s(new Error("The MCP server closed its input"))};t.once("drain",a),t.once("close",i)})}async close(){let e=this.spawned;if(e===null){this.closedEarly=!0;return}e.stdin.end();let t=this.options.killGraceMs??N,r,s=await Promise.race([e.result.then(()=>!0),new Promise(a=>r=setTimeout(()=>a(!1),t))]);clearTimeout(r),s?await e.result:await e.stop()}};var $e=5e3,y=class{live=null;count=0;disposed=!1;options;constructor(e){this.options=e}get current(){return this.live?.alive?this.live:null}async open(e,t){if(this.disposed)throw new Error("the mount is disposed");e.throwIfAborted();let r=new Ee({name:"lagent",version:re()},{capabilities:{}}),s={alive:!0},a={transport:null},i=null;r.onerror=l=>w.debug("MCP server '%s': %s",this.options.server,l),r.onclose=()=>{s.alive&&(s.alive=!1,i!==null&&(i.alive=!1),i!==null&&a.transport!==null&&!this.disposed&&this.options.onLost(i,this.describeClose(a.transport)))};let o=!1;r.setNotificationHandler(Me,async()=>{i===null?o=!0:i===this.current&&this.options.onToolsChanged(i)});let u=(async()=>{let l=Ce(await this.createTransport(e));if(a.transport=l,e.aborted)throw await T(l.close()),e.reason;await r.connect(l,{signal:e,timeout:t})})();try{if(await v(u,e),e.throwIfAborted(),this.disposed)throw new Error("the mount is disposed")}catch(l){throw s.alive=!1,await T(r.close()),se(l,a.transport)}let p=a.transport;if(i={number:this.count+1,client:r,transport:p,instructions:r.getInstructions()??null,get alive(){return s.alive},set alive(l){s.alive=l}},!s.alive)throw se(new Error("the connection closed during initialization"),p);return this.count=i.number,this.live=i,o&&this.options.onToolsChanged(i),i}async invalidate(e){e.alive&&(e.alive=!1,await T(e.client.close()))}async dispose(){this.disposed=!0;let e=this.live;this.live=null,!(e===null||!e.alive)&&(e.alive=!1,await T(e.client.close()))}async createTransport(e){let t=this.options.transport;switch(t.kind){case"stdio":return new b({server:this.options.server,command:t.command,cwd:t.cwd,env:t.env,signal:this.options.lifetime});case"streamable-http":return new oe(new URL(t.url),{requestInit:{headers:t.headers}});case"custom":return await t.create(e)}}describeClose(e){if(!(e instanceof b))return"the connection closed";let t=e.exited,r=t===null?"its connection closed":t.exitCode!==null?`it exited with code ${t.exitCode}`:`it was ended by ${t.exitSignal??"a signal"}`;return ae(`the server process ended: ${r}`,e)}},ie=n=>n instanceof _e&&n.code===404;function Ce(n){let e=n.close.bind(n),t;return n.close=()=>t??=(async()=>{try{n instanceof oe&&await T(n.terminateSession()),await e()}catch(r){w.debug("MCP transport close failed: %s",r)}})(),n}async function T(n){let e;await Promise.race([n.catch(t=>w.debug("MCP cleanup failed: %s",t)),new Promise(t=>e=setTimeout(t,$e))]),clearTimeout(e)}function ae(n,e){let t=e instanceof b?e.stderrTail.trim():"";return t?`${n}; its stderr ended with:
2
+ ${t}`:n}function se(n,e){let t=n instanceof Error?n:new Error(String(n)),r=e===null?t.message:ae(t.message||t.name,e);return r===t.message?t:new Error(r,{cause:t})}var h=class extends Error{name="McpServerError";server;kind;tools;constructor(e,t,r,s={}){super(`MCP server '${e}': ${r}`,s.cause===void 0?{}:{cause:s.cause}),this.server=e,this.kind=t,this.tools=s.tools??[]}},f=n=>n instanceof Error?n.message||n.name:String(n);var E=class{active=0;waiters=[];limit;constructor(e){this.limit=e}acquire(e){return e.throwIfAborted(),this.active<this.limit?(this.active+=1,Promise.resolve(this.releaser())):new Promise((t,r)=>{let s={grant:()=>{e.removeEventListener("abort",a),this.active+=1,t(this.releaser())}},a=()=>{let i=this.waiters.indexOf(s);i>=0&&this.waiters.splice(i,1),r(e.reason)};e.addEventListener("abort",a,{once:!0}),this.waiters.push(s)})}get waiting(){return this.waiters.length}releaser(){let e=!1;return()=>{e||(e=!0,this.active-=1,this.waiters.shift()?.grant())}}};import{CallToolResultSchema as Re,ErrorCode as le,McpError as I}from"@modelcontextprotocol/sdk/types.js";var Ae="The tool returned content addressed to the user only; nothing in it is for you.",Ne="The tool returned no content.",Oe=new Set(["image/png","image/jpeg","image/webp","image/gif"]),Pe=n=>{let e=n.trim().toLowerCase();return e==="image/jpg"?"image/jpeg":e};function ce(n,e){let t=[],r=[],s=[],a=[],i=e.maxContentBytes,o=l=>l>i?!1:(i-=l,!0);for(let l of n.content){if(!ke(l)){s.push(Le(l,o));continue}switch(l.type){case"text":a.push(l.text),t.push(l.text);break;case"image":{let m=_(l.data),d=Pe(l.mimeType);Oe.has(d)?o(m)?(r.push({type:"image",url:null,data:l.data,media_type:d,detail:"auto"}),t.push(`[image: ${d}, ${x(m)}]`)):t.push(`[image omitted: ${l.mimeType}, ${x(m)}, over this result's limit]`):t.push(`[image not shown: ${l.mimeType}, ${x(m)}; only PNG, JPEG, WebP and GIF are shown]`);break}case"audio":t.push(`[audio not shown: ${l.mimeType}, ${x(_(l.data))}]`);break;case"resource_link":t.push(`[resource link: ${l.name} <${l.uri}>${l.mimeType?` (${l.mimeType})`:""}]`);break;case"resource":{let m=l.resource;if("text"in m)t.push(`[resource: ${m.uri}]
3
+ ${m.text}`);else{let d=m.mimeType?`${m.mimeType}, `:"";t.push(`[resource not shown: ${m.uri}, ${d}${x(_(m.blob))}]`)}break}}}let u=n.structuredContent;return u!==void 0&&!a.some(l=>Ie(l,u))&&t.push(JSON.stringify(u,null,2)),{output:t.join(`
4
+ `)||(s.length>0?Ae:Ne),...r.length>0?{content:r}:{},is_error:n.isError===!0,notes:null,metadata:{mcp_server:e.server,mcp_tool:e.remoteName,...s.length>0?{user_content:s}:{}}}}function ke(n){let e=n.annotations?.audience;return e===void 0||e.includes("assistant")}function Le(n,e){let t=(r,s)=>{let a=_(r);return e(a)?{...s,data:r}:{...s,bytes:a,omitted:!0}};switch(n.type){case"text":return{type:"text",text:n.text};case"image":case"audio":return t(n.data,{type:n.type,mime_type:n.mimeType});case"resource_link":return{type:"resource_link",uri:n.uri,name:n.name,mime_type:n.mimeType??null};case"resource":return"text"in n.resource?{type:"resource",uri:n.resource.uri,text:n.resource.text}:t(n.resource.blob,{type:"resource",uri:n.resource.uri,mime_type:n.resource.mimeType??null})}}function Ie(n,e){try{return g(JSON.parse(n))===g(e)}catch{return!1}}function _(n){let e=n.endsWith("==")?2:n.endsWith("=")?1:0;return Math.max(0,Math.floor(n.length*3/4)-e)}function x(n){return n<1024?`${n} B`:n<1024*1024?`${(n/1024).toFixed(1)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}var ue="work.leuduan.lagent/call",R="The connection to this MCP server was re-established; any session state the server held may have been reset.";function je(n,e){if(n==="report")return"report";if(n==="annotations"){let t=e.definition.annotations;return t?.readOnlyHint===!0||t?.idempotentHint===!0?"rerun":"report"}return n.rerun.includes(e.remoteName)?"rerun":"report"}var de=(n,e)=>B({name:e.name,description:e.spec.description,parameters:{jsonSchema:e.spec.input_schema},onInterrupted:je(n.config.onInterrupted,e),executionMode:"parallel",execute:(t,r)=>Ge(n,e,t,r)});async function Ge(n,e,t,r){let s=d=>({output:d,is_error:!0,metadata:{mcp_server:n.server,mcp_tool:e.remoteName}}),{maxCallSeconds:a,callTimeoutSeconds:i,maxContentBytes:o}=n.config,u=AbortSignal.timeout(a*1e3),p=AbortSignal.any([r.signal,u]),l=d=>s(r.signal.aborted?`The call was cancelled ${d}; it was never sent to the MCP server.`:`The call's ${a} s deadline passed ${d}; it was never sent to the MCP server.`),m;try{m=await n.slots.acquire(p)}catch{return l("while it waited for a free slot")}try{let d;try{d=await n.ready(p)}catch(C){return p.aborted?l("while the connection was being re-established"):s(`The call was not sent. ${f(C)}`)}let $=n.entry(e.name);if($===void 0||$.fingerprint!==e.fingerprint)return s($===void 0?`The MCP server no longer offers ${e.remoteName}, so the call was not sent.`:`The MCP server changed the definition of ${e.remoteName}, so the call was not sent. Review the new definition and call again if it still fits.`);if(!d.alive)return s("The connection to the MCP server closed before the call was sent.");let G;try{G=await d.client.request({method:"tools/call",params:{name:e.remoteName,arguments:t,_meta:{[ue]:`${r.threadId}#${r.callSeq}`}}},Re,{signal:p,timeout:i*1e3,resetTimeoutOnProgress:!0,onprogress:()=>{}})}catch(C){return s(qe(n,C,d,r.signal,u))}let q=ce(G,{server:n.server,remoteName:e.remoteName,maxContentBytes:o}),F=n.takeSessionNote(d);return F===null?q:{...q,notes:[F]}}finally{m()}}function qe(n,e,t,r,s){let a="The server may or may not have run it.";return r.aborted?`The call was cancelled after it was sent. ${a}`:s.aborted?`The call's ${n.config.maxCallSeconds} s deadline passed after it was sent. ${a}`:ie(e)?(n.invalidate(t),"The MCP server had ended its session, so the call did not run. A new session opens with the next call."):e instanceof I&&e.code===le.RequestTimeout?`The MCP server sent no response or progress for ${n.config.callTimeoutSeconds} s. ${a}`:e instanceof I&&e.code===le.ConnectionClosed?`The connection to the MCP server was lost while the call was in flight. ${a}`:e instanceof I?`The MCP server answered with an error: ${f(e)}`:`The request to the MCP server failed: ${f(e)}. ${a}`}var M=class{server;slots;connection;lifetime=new AbortController;catalog=K;listedFrom=null;published=new Map;known=new Map;reported=[];started=!1;changedWhileStarting=!1;runningFor=null;disposed=!1;running=null;queued=null;reconnecting=null;noteOwedTo=null;cachedInstructions=null;ctx;config;constructor(e,t){this.ctx=e,this.config=t,this.server=t.name,this.slots=new E(t.maxConcurrentCalls==="unbounded"?1/0:t.maxConcurrentCalls),this.connection=new y({server:t.name,transport:t.transport,lifetime:this.lifetime.signal,onToolsChanged:()=>{this.started?this.refresh():this.changedWhileStarting=!0},onLost:(r,s)=>this.report(new h(this.server,"disconnect",s))})}get connectTimeoutMs(){return this.config.connectTimeoutSeconds*1e3}async start(){let e=[this.lifetime.signal,AbortSignal.timeout(this.connectTimeoutMs)];this.config.signal!==void 0&&e.push(this.config.signal);let t=AbortSignal.any(e);try{let s=await this.connection.open(t,this.connectTimeoutMs);this.cachedInstructions=s.instructions}catch(s){throw new h(this.server,"connect",`could not connect: ${f(s)}`,{cause:s})}let r=await this.refresh(t);if(!r.ok)throw r.error;this.started=!0,this.changedWhileStarting&&this.refresh()}async ready(e){let t=this.connection.current;if(t===null){if(this.disposed)throw new Error("the mount is disposed");this.reconnecting??=this.reconnect().finally(()=>{this.reconnecting=null}),t=await v(this.reconnecting,e)}if(this.listedFrom!==t.number){let r=this.running!==null&&this.runningFor===t?this.running:this.refresh(),s=await v(r,e);if(!s.ok)throw s.error;if(this.listedFrom!==t.number||!t.alive)throw new h(this.server,"refresh","the connection changed while its tools were being listed")}return t}async reconnect(){let e;try{let t=AbortSignal.any([this.lifetime.signal,AbortSignal.timeout(this.connectTimeoutMs)]);e=await this.connection.open(t,this.connectTimeoutMs)}catch(t){let r=new h(this.server,"connect",`could not reconnect: ${f(t)}`,{cause:t});throw this.report(r),r}return this.cachedInstructions=e.instructions,this.noteOwedTo=e.number,e}entry(e){return this.catalog.entries.get(e)}takeSessionNote(e){return this.noteOwedTo!==e.number?null:(this.noteOwedTo=null,R)}invalidate(e){e.alive&&(this.report(new h(this.server,"disconnect","the server ended its session")),this.connection.invalidate(e))}remoteNameOf(e){return this.known.get(e)}get instructions(){return this.cachedInstructions}refresh(e){return this.queued!==null?this.queued:this.running===null?this.run(e):(this.queued=this.running.then(()=>(this.queued=null,this.run())),this.queued)}run(e){let t=this.refreshOnce(e);return this.running=t,this.runningFor=this.connection.current,t.finally(()=>{this.running===t&&(this.running=null,this.runningFor=null)}),t}async refreshOnce(e){try{return await this.listAndPublish(e)}catch(t){let r=new h(this.server,"refresh",`could not publish its tools: ${f(t)}`,{cause:t});return this.report(r),{ok:!1,error:r}}}async listAndPublish(e){let t=this.connection.current;if(t===null)return{ok:!1,error:new h(this.server,"refresh","not connected")};let r;try{let o=e??AbortSignal.any([this.lifetime.signal,AbortSignal.timeout(this.connectTimeoutMs)]);r=ee(this.config,await Q(t.client,o))}catch(o){let u=new h(this.server,"refresh",`could not list its tools: ${f(o)}`,{cause:o});return this.started&&this.live(t)&&this.report(u),{ok:!1,error:u}}if(!this.live(t))return{ok:!1,error:new h(this.server,"refresh","the listing is out of date")};if(this.config.tools!==void 0&&r.unexposable.length>0&&!this.started)return{ok:!1,error:new h(this.server,"unexposable",j(r.unexposable),{tools:r.unexposable})};let a=this.publish(r),i=this.catalog.unexposable;return a.length>0&&this.config.tools!==void 0&&!this.started?{ok:!1,error:new h(this.server,"unexposable",j(i),{tools:i})}:(this.listedFrom=t.number,ne(i,this.reported)||(this.reported=i,i.length>0&&this.report(new h(this.server,"unexposable",j(i),{tools:i}))),{ok:!0})}live(e){return!this.disposed&&this.ctx.fiber.uid!==null&&e===this.connection.current}publish(e){let t=[];for(let[i,o]of this.published)e.entries.get(i)?.fingerprint!==o.entry.fingerprint&&(this.published.delete(i),o.withdraw());let r=this.ctx,s=this.config.agents;for(let i of e.entries.values()){if(this.published.has(i.name))continue;let o;try{o=W(r,de(this,i),{agents:s})}catch(u){t.push({tool:i.remoteName,reason:`${i.name} cannot be registered: ${f(u)}`});continue}this.published.set(i.name,{entry:i,withdraw:o}),this.known.set(i.name,i.remoteName)}let a=new Map([...e.entries].filter(([i])=>this.published.has(i)));return this.catalog={entries:a,unexposable:L([...e.unexposable,...t])},t}report(e){this.disposed||this.ctx.fiber.uid===null||this.ctx.reportError(e)}async dispose(){this.disposed=!0,await this.connection.dispose(),this.lifetime.abort()}},j=n=>`cannot expose ${n.map(e=>`${e.tool} (${e.reason})`).join("; ")}`;var he=new WeakMap;function Ue(n,e){let t=Fe(n),r=he.get(n.tools);r===void 0&&he.set(n.tools,r=new Map);let s=r.get(t);if(s===void 0&&r.set(t,s=new Set),s.has(e))throw new Error(`Another mcp mount in this layer already uses the server name '${e}'`);let a=s;n.effect(()=>(a.add(e),()=>a.delete(e)))}function He(n,e){if(n.confirm==="all")return"confirm";if(n.confirm!=="none")return n.confirm.except.includes(e)?void 0:"confirm"}var Rt={name:"lagent:mcp",inject:["tools","prompts"],async apply(n,e){let t=k.parse(e);Ue(n,t.name);let r=new M(n,t);n.effect(()=>()=>r.dispose()),await n.plugin(Y,{confirm:s=>{let a=r.remoteNameOf(s);return a!==void 0&&He(t,a)==="confirm"}}),t.instructions&&z(n,{tag:`mcp:${t.name}`,slot:"instruction",agents:t.agents,render:()=>{let s=r.instructions?.trim();return s?`Instructions from the MCP server "${t.name}" about its tools:
5
+ ${s}`:null}}),await r.start()}};export{ue as CALL_META_KEY,D as MAX_SERVER_NAME_LENGTH,S as MAX_TOOL_NAME_LENGTH,k as McpConfigSchema,h as McpServerError,X as McpTransportSchema,R as SESSION_RESET_NOTE,Rt as mcp,O as mcpToolName};
@@ -0,0 +1,98 @@
1
+ import type { Context } from '@leuduan/cordis';
2
+ import { type CatalogEntry } from './catalog.js';
3
+ import type { McpConfig } from './config.js';
4
+ import { type Generation } from './connection.js';
5
+ import { McpServerError } from './errors.js';
6
+ import { CallSlots } from './slots.js';
7
+ import { type McpToolHost } from './tools.js';
8
+ type RefreshOutcome = {
9
+ readonly ok: true;
10
+ } | {
11
+ readonly ok: false;
12
+ readonly error: McpServerError;
13
+ };
14
+ /**
15
+ * One server's mount: its connection, its catalog, and the tools published from it.
16
+ *
17
+ * Refreshes are serialized: one runs at a time and at most one more waits, shared by everyone who
18
+ * asks meanwhile, so a burst of `list_changed` notifications never overlaps listings and the latest
19
+ * one wins. A refresh publishes only a complete listing, only for the generation it listed from,
20
+ * and only while the mount lives; a failed one keeps the last catalog. Reconnection is lazy and
21
+ * single-flight: the next call opens a new generation and refreshes before it is sent.
22
+ */
23
+ export declare class McpMount implements McpToolHost {
24
+ readonly server: string;
25
+ readonly slots: CallSlots;
26
+ private readonly connection;
27
+ private readonly lifetime;
28
+ private catalog;
29
+ /** The generation the published catalog was listed from; calls never run against another's. */
30
+ private listedFrom;
31
+ private readonly published;
32
+ /** Every lagent name this mount ever published, with its remote name, for the confirmation vote. */
33
+ private readonly known;
34
+ private reported;
35
+ private started;
36
+ /** A `list_changed` arrived before the first listing finished, which may have missed it. */
37
+ private changedWhileStarting;
38
+ /** The generation the running refresh lists from, for a call to join instead of queueing another. */
39
+ private runningFor;
40
+ private disposed;
41
+ private running;
42
+ private queued;
43
+ private reconnecting;
44
+ /** The generation whose first result still owes the session-reset note. */
45
+ private noteOwedTo;
46
+ /** The instructions of the latest successful initialization, kept through an outage. */
47
+ private cachedInstructions;
48
+ private readonly ctx;
49
+ readonly config: McpConfig;
50
+ constructor(ctx: Context, config: McpConfig);
51
+ private get connectTimeoutMs();
52
+ /**
53
+ * Connects, lists every tool, and publishes them. Rejects, having published nothing, when the
54
+ * server cannot be reached or initialized, its listing fails, or a tool the host listed cannot be
55
+ * exposed.
56
+ */
57
+ start(): Promise<void>;
58
+ /**
59
+ * The live generation, with a catalog listed from it. A generation that went away is replaced
60
+ * once, single-flight; a catalog listed from another generation, after a reconnection whose
61
+ * listing failed, is listed again first. Either failing fails the call before it is sent.
62
+ */
63
+ ready(signal: AbortSignal): Promise<Generation>;
64
+ /** Opens a new generation. Listing its tools is `ready`'s, so a failed listing is retried by the next call. */
65
+ private reconnect;
66
+ entry(name: string): CatalogEntry | undefined;
67
+ takeSessionNote(generation: Generation): string | null;
68
+ invalidate(generation: Generation): void;
69
+ /** The remote name behind a lagent name this mount published at any time, for the confirmation vote. */
70
+ remoteNameOf(name: string): string | undefined;
71
+ /**
72
+ * The server's `initialize` instructions, from the latest successful initialization. Kept through
73
+ * an outage, so a prompt rendered while the server is unreachable still carries them.
74
+ */
75
+ get instructions(): string | null;
76
+ /**
77
+ * Lists again, serialized with every other refresh; the latest request always wins. `signal`
78
+ * bounds the listing when this call starts one; joining one already running or queued keeps its
79
+ * bound.
80
+ */
81
+ refresh(signal?: AbortSignal): Promise<RefreshOutcome>;
82
+ private run;
83
+ /** Never rejects: both callers, a notification and the queue, would leave a rejection unhandled. */
84
+ private refreshOnce;
85
+ private listAndPublish;
86
+ /** Whether `generation` is still the live one of a mount that has not been disposed. */
87
+ private live;
88
+ /**
89
+ * Replaces the published tools with `catalog`'s. Each tool is one `registerTool` effect holding its
90
+ * registration and its grant, so withdrawing it releases both. A name another tool in this layer
91
+ * already holds cannot be registered; that tool is returned as unexposable.
92
+ */
93
+ private publish;
94
+ private report;
95
+ /** Closes the connection; the published tools go with the mount's other effects. */
96
+ dispose(): Promise<void>;
97
+ }
98
+ export {};
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Lagent names for MCP tools: `mcp__<server>__<tool>`. The MCP spec allows `A-Z a-z 0-9 _ - .` and
3
+ * up to 128 characters in a tool name; OpenAI function names allow `A-Z a-z 0-9 _ -` and at most 64.
4
+ * A remote name is mapped onto the narrower set, never truncated or hashed: the model, the journal
5
+ * and the policy lists all read it, so it must stay readable and identical across restarts.
6
+ */
7
+ /** The longest tool name every supported provider accepts. */
8
+ export declare const MAX_TOOL_NAME_LENGTH = 64;
9
+ /**
10
+ * A server name: in the narrow set already, never containing `__`, and neither starting nor ending
11
+ * with `_`. The first `__` after `mcp__` then always ends the server name, so two servers can never
12
+ * map tools onto the same lagent name: `docs` with `_search` and `docs_` with `search` would both
13
+ * be `mcp__docs___search`.
14
+ */
15
+ export declare const SERVER_NAME: RegExp;
16
+ /** An alias for a tool segment, which must already be in the narrow set. */
17
+ export declare const TOOL_SEGMENT: RegExp;
18
+ /** The tool segment a remote name maps to: every character outside the narrow set becomes `_`. */
19
+ export declare const toolSegment: (remoteName: string) => string;
20
+ /**
21
+ * The lagent name of a server's tool, for a tool policy's lists and host UIs. `alias`
22
+ * replaces the tool segment only; the server prefix always applies, so an alias never lands on a
23
+ * builtin. The result may be longer than {@link MAX_TOOL_NAME_LENGTH}, which makes it unexposable.
24
+ */
25
+ export declare const mcpToolName: (server: string, remoteName: string, alias?: string) => string;
@@ -0,0 +1,29 @@
1
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { ToolResultPayload } from '../../records/toolResult.js';
3
+ /** Said when nothing is left for the model because every item was addressed to the user. */
4
+ export declare const USER_ONLY_OUTPUT = "The tool returned content addressed to the user only; nothing in it is for you.";
5
+ export declare const EMPTY_OUTPUT = "The tool returned no content.";
6
+ /**
7
+ * The image types every provider lagent supports accepts as input: OpenAI takes PNG, JPEG, WebP
8
+ * and non-animated GIF. A part in any other type would be refused, and since the journal keeps it,
9
+ * every later request in the thread would be refused with it.
10
+ */
11
+ export declare const MODEL_IMAGE_TYPES: ReadonlySet<string>;
12
+ /** A MIME type as a part stores it: lowercased, and the common `image/jpg` as `image/jpeg`. */
13
+ export declare const imageMediaType: (mimeType: string) => string;
14
+ export type RenderOptions = {
15
+ readonly server: string;
16
+ readonly remoteName: string;
17
+ /** The most decoded bytes of non-text content the result keeps, for the model and the host. */
18
+ readonly maxContentBytes: number;
19
+ };
20
+ /**
21
+ * Renders a `tools/call` result as lagent's text-first payload. `output` is the canonical text;
22
+ * images become content parts within the byte budget; items whose audience excludes the assistant
23
+ * go to `metadata` for hosts and never reach the model. A result is not checked against the tool's
24
+ * output schema.
25
+ */
26
+ export declare function renderCallResult(result: CallToolResult, options: RenderOptions): ToolResultPayload;
27
+ /** The size of base64 data once decoded. */
28
+ export declare function decodedBytes(base64: string): number;
29
+ export declare function formatBytes(bytes: number): string;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The calls one server takes at once, in arrival order, shared by every thread its mount serves.
3
+ * A waiter whose signal aborts leaves the queue without ever holding a slot.
4
+ */
5
+ export declare class CallSlots {
6
+ private active;
7
+ private readonly waiters;
8
+ private readonly limit;
9
+ constructor(limit: number);
10
+ /** Resolves with the slot's release; rejects with the signal's reason if it aborts first. */
11
+ acquire(signal: AbortSignal): Promise<() => void>;
12
+ /** Calls queued for a slot. */
13
+ get waiting(): number;
14
+ private releaser;
15
+ }