gauss-ai 4.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 (232) hide show
  1. package/CHANGELOG.md +489 -0
  2. package/LICENSE +21 -0
  3. package/README.md +269 -0
  4. package/dist/a2a/index.cjs +7 -0
  5. package/dist/a2a/index.cjs.map +1 -0
  6. package/dist/a2a/index.d.cts +30 -0
  7. package/dist/a2a/index.d.ts +30 -0
  8. package/dist/a2a/index.js +7 -0
  9. package/dist/a2a/index.js.map +1 -0
  10. package/dist/agent-UIQDSYCE.js +16 -0
  11. package/dist/agent-UIQDSYCE.js.map +1 -0
  12. package/dist/agent-builder-8W3mBR-N.d.ts +1075 -0
  13. package/dist/agent-builder-GEMYdb1p.d.cts +1075 -0
  14. package/dist/agent-graph-AMQYAWNF.js +1422 -0
  15. package/dist/agent-graph-AMQYAWNF.js.map +1 -0
  16. package/dist/ai-sdk-mcp.adapter-SEN6KHNU.js +124 -0
  17. package/dist/ai-sdk-mcp.adapter-SEN6KHNU.js.map +1 -0
  18. package/dist/browser/index.js +10 -0
  19. package/dist/browser/index.js.map +1 -0
  20. package/dist/bun-runtime.adapter-MQDAJLQM.js +8 -0
  21. package/dist/bun-runtime.adapter-MQDAJLQM.js.map +1 -0
  22. package/dist/bun-runtime.adapter-XKOUXVAK.cjs +8 -0
  23. package/dist/bun-runtime.adapter-XKOUXVAK.cjs.map +1 -0
  24. package/dist/chat-A3XMRPJL.js +129 -0
  25. package/dist/chat-A3XMRPJL.js.map +1 -0
  26. package/dist/chunk-2ZRU47NC.js +91 -0
  27. package/dist/chunk-2ZRU47NC.js.map +1 -0
  28. package/dist/chunk-3LD3JTH4.cjs +18 -0
  29. package/dist/chunk-3LD3JTH4.cjs.map +1 -0
  30. package/dist/chunk-5FE5TG2W.cjs +16 -0
  31. package/dist/chunk-5FE5TG2W.cjs.map +1 -0
  32. package/dist/chunk-6XF673YC.cjs +436 -0
  33. package/dist/chunk-6XF673YC.cjs.map +1 -0
  34. package/dist/chunk-7CKWZJNS.js +230 -0
  35. package/dist/chunk-7CKWZJNS.js.map +1 -0
  36. package/dist/chunk-BI2G665F.js +4588 -0
  37. package/dist/chunk-BI2G665F.js.map +1 -0
  38. package/dist/chunk-C5NLWJS2.js +139 -0
  39. package/dist/chunk-C5NLWJS2.js.map +1 -0
  40. package/dist/chunk-CJZ66SU3.cjs +4321 -0
  41. package/dist/chunk-CJZ66SU3.cjs.map +1 -0
  42. package/dist/chunk-DAMT2CXW.cjs +91 -0
  43. package/dist/chunk-DAMT2CXW.cjs.map +1 -0
  44. package/dist/chunk-E7WG3MO5.js +18 -0
  45. package/dist/chunk-E7WG3MO5.js.map +1 -0
  46. package/dist/chunk-EFDM6R4J.js +99 -0
  47. package/dist/chunk-EFDM6R4J.js.map +1 -0
  48. package/dist/chunk-F7WIPPEO.js +256 -0
  49. package/dist/chunk-F7WIPPEO.js.map +1 -0
  50. package/dist/chunk-FAYDE67N.js +6927 -0
  51. package/dist/chunk-FAYDE67N.js.map +1 -0
  52. package/dist/chunk-GAE2KKCM.js +21 -0
  53. package/dist/chunk-GAE2KKCM.js.map +1 -0
  54. package/dist/chunk-INLNGRXM.cjs +130 -0
  55. package/dist/chunk-INLNGRXM.cjs.map +1 -0
  56. package/dist/chunk-JKXKXB5O.js +130 -0
  57. package/dist/chunk-JKXKXB5O.js.map +1 -0
  58. package/dist/chunk-K6SAETGP.js +375 -0
  59. package/dist/chunk-K6SAETGP.js.map +1 -0
  60. package/dist/chunk-KEASLAYR.js +157 -0
  61. package/dist/chunk-KEASLAYR.js.map +1 -0
  62. package/dist/chunk-KKJVNM6O.js +436 -0
  63. package/dist/chunk-KKJVNM6O.js.map +1 -0
  64. package/dist/chunk-KYIMVRIM.js +16 -0
  65. package/dist/chunk-KYIMVRIM.js.map +1 -0
  66. package/dist/chunk-MB7NXIZD.js +4321 -0
  67. package/dist/chunk-MB7NXIZD.js.map +1 -0
  68. package/dist/chunk-MHHDXPGE.js +209 -0
  69. package/dist/chunk-MHHDXPGE.js.map +1 -0
  70. package/dist/chunk-NE6JJA5W.js +401 -0
  71. package/dist/chunk-NE6JJA5W.js.map +1 -0
  72. package/dist/chunk-PF46XZBF.cjs +6927 -0
  73. package/dist/chunk-PF46XZBF.cjs.map +1 -0
  74. package/dist/chunk-PSJIAGDE.cjs +375 -0
  75. package/dist/chunk-PSJIAGDE.cjs.map +1 -0
  76. package/dist/chunk-PWOQDXNQ.js +16 -0
  77. package/dist/chunk-PWOQDXNQ.js.map +1 -0
  78. package/dist/chunk-QYOMQBBZ.cjs +230 -0
  79. package/dist/chunk-QYOMQBBZ.cjs.map +1 -0
  80. package/dist/chunk-UDFXLC4J.cjs +16 -0
  81. package/dist/chunk-UDFXLC4J.cjs.map +1 -0
  82. package/dist/chunk-UO4NGXRT.cjs +259 -0
  83. package/dist/chunk-UO4NGXRT.cjs.map +1 -0
  84. package/dist/chunk-UPFDFLEW.js +40 -0
  85. package/dist/chunk-UPFDFLEW.js.map +1 -0
  86. package/dist/chunk-V55JSQS7.cjs +16 -0
  87. package/dist/chunk-V55JSQS7.cjs.map +1 -0
  88. package/dist/chunk-VJADHXZL.cjs +16 -0
  89. package/dist/chunk-VJADHXZL.cjs.map +1 -0
  90. package/dist/chunk-VRWD7LCI.js +59 -0
  91. package/dist/chunk-VRWD7LCI.js.map +1 -0
  92. package/dist/chunk-WKKQ443C.js +487 -0
  93. package/dist/chunk-WKKQ443C.js.map +1 -0
  94. package/dist/chunk-X2GHUHAF.js +436 -0
  95. package/dist/chunk-X2GHUHAF.js.map +1 -0
  96. package/dist/chunk-XLGW3XNI.cjs +256 -0
  97. package/dist/chunk-XLGW3XNI.cjs.map +1 -0
  98. package/dist/chunk-ZFJKX4DP.js +16 -0
  99. package/dist/chunk-ZFJKX4DP.js.map +1 -0
  100. package/dist/chunk-ZM2OEWM2.js +259 -0
  101. package/dist/chunk-ZM2OEWM2.js.map +1 -0
  102. package/dist/chunk-ZNAIP2XV.js +16 -0
  103. package/dist/chunk-ZNAIP2XV.js.map +1 -0
  104. package/dist/chunk-ZYFAZYSL.js +42 -0
  105. package/dist/chunk-ZYFAZYSL.js.map +1 -0
  106. package/dist/cli/index.js +421 -0
  107. package/dist/cli/index.js.map +1 -0
  108. package/dist/config-4MHT6TQW.js +153 -0
  109. package/dist/config-4MHT6TQW.js.map +1 -0
  110. package/dist/config-REERQFK4.cjs +153 -0
  111. package/dist/config-REERQFK4.cjs.map +1 -0
  112. package/dist/cost-tracker-JLOU7IZJ.js +7 -0
  113. package/dist/cost-tracker-JLOU7IZJ.js.map +1 -0
  114. package/dist/demo-C52GMSYH.js +188 -0
  115. package/dist/demo-C52GMSYH.js.map +1 -0
  116. package/dist/deno/index.js +306 -0
  117. package/dist/deno/index.js.map +1 -0
  118. package/dist/deno-runtime.adapter-F744HY7K.js +8 -0
  119. package/dist/deno-runtime.adapter-F744HY7K.js.map +1 -0
  120. package/dist/deno-runtime.adapter-RFEVNSCV.cjs +8 -0
  121. package/dist/deno-runtime.adapter-RFEVNSCV.cjs.map +1 -0
  122. package/dist/dev-D7DDVDA4.js +218 -0
  123. package/dist/dev-D7DDVDA4.js.map +1 -0
  124. package/dist/edge/index.js +10 -0
  125. package/dist/edge/index.js.map +1 -0
  126. package/dist/edge-runtime.adapter-UQCW2F7X.js +8 -0
  127. package/dist/edge-runtime.adapter-UQCW2F7X.js.map +1 -0
  128. package/dist/edge-runtime.adapter-YED6F3AY.cjs +8 -0
  129. package/dist/edge-runtime.adapter-YED6F3AY.cjs.map +1 -0
  130. package/dist/graph-MGFAQZ5W.js +50 -0
  131. package/dist/graph-MGFAQZ5W.js.map +1 -0
  132. package/dist/graph-visualization-HBSVQXJK.js +9 -0
  133. package/dist/graph-visualization-HBSVQXJK.js.map +1 -0
  134. package/dist/index-BRgqNnh3.d.cts +982 -0
  135. package/dist/index-CZxpYUxZ.d.ts +982 -0
  136. package/dist/index.cjs +14789 -0
  137. package/dist/index.cjs.map +1 -0
  138. package/dist/index.d.cts +10275 -0
  139. package/dist/index.d.ts +10275 -0
  140. package/dist/index.js +14789 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/init-CFWXTQ35.js +133 -0
  143. package/dist/init-CFWXTQ35.js.map +1 -0
  144. package/dist/llm-VWO4MC7J.cjs +17 -0
  145. package/dist/llm-VWO4MC7J.cjs.map +1 -0
  146. package/dist/llm-XLXVSPBI.js +17 -0
  147. package/dist/llm-XLXVSPBI.js.map +1 -0
  148. package/dist/logging-WRAK5ZXT.js +33 -0
  149. package/dist/logging-WRAK5ZXT.js.map +1 -0
  150. package/dist/metrics-FAHZVVD4.js +47 -0
  151. package/dist/metrics-FAHZVVD4.js.map +1 -0
  152. package/dist/node/index.cjs +280 -0
  153. package/dist/node/index.cjs.map +1 -0
  154. package/dist/node/index.d.cts +51 -0
  155. package/dist/node/index.d.ts +51 -0
  156. package/dist/node/index.js +280 -0
  157. package/dist/node/index.js.map +1 -0
  158. package/dist/node-runtime.adapter-5L7PJ6W2.js +8 -0
  159. package/dist/node-runtime.adapter-5L7PJ6W2.js.map +1 -0
  160. package/dist/node-runtime.adapter-CCRZVGHB.cjs +8 -0
  161. package/dist/node-runtime.adapter-CCRZVGHB.cjs.map +1 -0
  162. package/dist/persist-usage-WTBTCWEF.js +7 -0
  163. package/dist/persist-usage-WTBTCWEF.js.map +1 -0
  164. package/dist/plugin-RCPBWUUA.js +207 -0
  165. package/dist/plugin-RCPBWUUA.js.map +1 -0
  166. package/dist/plugins/index.cjs +75 -0
  167. package/dist/plugins/index.cjs.map +1 -0
  168. package/dist/plugins/index.d.cts +8 -0
  169. package/dist/plugins/index.d.ts +8 -0
  170. package/dist/plugins/index.js +75 -0
  171. package/dist/plugins/index.js.map +1 -0
  172. package/dist/plugins-L4ING3CX.js +4625 -0
  173. package/dist/plugins-L4ING3CX.js.map +1 -0
  174. package/dist/providers/index.cjs +189 -0
  175. package/dist/providers/index.cjs.map +1 -0
  176. package/dist/providers/index.d.cts +168 -0
  177. package/dist/providers/index.d.ts +168 -0
  178. package/dist/providers/index.js +189 -0
  179. package/dist/providers/index.js.map +1 -0
  180. package/dist/providers-3RNQ5CKZ.js +59 -0
  181. package/dist/providers-3RNQ5CKZ.js.map +1 -0
  182. package/dist/providers-66GPXUGQ.cjs +59 -0
  183. package/dist/providers-66GPXUGQ.cjs.map +1 -0
  184. package/dist/repl-K6QN4I2S.js +678 -0
  185. package/dist/repl-K6QN4I2S.js.map +1 -0
  186. package/dist/rest/index.cjs +17 -0
  187. package/dist/rest/index.cjs.map +1 -0
  188. package/dist/rest/index.d.cts +102 -0
  189. package/dist/rest/index.d.ts +102 -0
  190. package/dist/rest/index.js +17 -0
  191. package/dist/rest/index.js.map +1 -0
  192. package/dist/runtime-deno.js +15 -0
  193. package/dist/runtime-deno.js.map +1 -0
  194. package/dist/runtime-edge.js +15 -0
  195. package/dist/runtime-edge.js.map +1 -0
  196. package/dist/runtime-node.js +15 -0
  197. package/dist/runtime-node.js.map +1 -0
  198. package/dist/scraping/index.cjs +11 -0
  199. package/dist/scraping/index.cjs.map +1 -0
  200. package/dist/scraping/index.d.cts +17 -0
  201. package/dist/scraping/index.d.ts +17 -0
  202. package/dist/scraping/index.js +11 -0
  203. package/dist/scraping/index.js.map +1 -0
  204. package/dist/semantic-scraping.port-CZWUea88.d.cts +54 -0
  205. package/dist/semantic-scraping.port-CZWUea88.d.ts +54 -0
  206. package/dist/server/index.js +166 -0
  207. package/dist/server/index.js.map +1 -0
  208. package/dist/testing/index.cjs +25 -0
  209. package/dist/testing/index.cjs.map +1 -0
  210. package/dist/testing/index.d.cts +63 -0
  211. package/dist/testing/index.d.ts +63 -0
  212. package/dist/testing/index.js +25 -0
  213. package/dist/testing/index.js.map +1 -0
  214. package/dist/token-counter.port-CRgxZZGe.d.ts +334 -0
  215. package/dist/token-counter.port-D7BHMCRR.d.cts +334 -0
  216. package/dist/tools-BZM33OBZ.js +10 -0
  217. package/dist/tools-BZM33OBZ.js.map +1 -0
  218. package/dist/tracing-XA3TEWP4.js +48 -0
  219. package/dist/tracing-XA3TEWP4.js.map +1 -0
  220. package/dist/types-CVsP7gFI.d.cts +235 -0
  221. package/dist/types-CVsP7gFI.d.ts +235 -0
  222. package/dist/virtual-fs.adapter-BBLS-3AY.d.ts +26 -0
  223. package/dist/virtual-fs.adapter-nb0CTYOj.d.cts +26 -0
  224. package/dist/workflow/index.cjs +9 -0
  225. package/dist/workflow/index.cjs.map +1 -0
  226. package/dist/workflow/index.d.cts +62 -0
  227. package/dist/workflow/index.d.ts +62 -0
  228. package/dist/workflow/index.js +9 -0
  229. package/dist/workflow/index.js.map +1 -0
  230. package/dist/workflow.port-BaCttxrw.d.cts +153 -0
  231. package/dist/workflow.port-BaCttxrw.d.ts +153 -0
  232. package/package.json +230 -0
@@ -0,0 +1,4625 @@
1
+ import {
2
+ CircuitBreaker,
3
+ PluginManager,
4
+ ToolCache
5
+ } from "./chunk-X2GHUHAF.js";
6
+ import {
7
+ tool
8
+ } from "./chunk-K6SAETGP.js";
9
+
10
+ // src/plugins/base.plugin.ts
11
+ var BasePlugin = class {
12
+ version = "1.0.0";
13
+ hooks;
14
+ constructor() {
15
+ this.hooks = this.buildHooks();
16
+ }
17
+ };
18
+
19
+ // src/plugins/agent-card.plugin.ts
20
+ import { z } from "zod";
21
+ var DEFAULT_AGENTS_PATH = "agents.md";
22
+ var DEFAULT_SKILLS_PATH = "skills.md";
23
+ var DEFAULT_ZONES = ["persistent", "transient"];
24
+ var AgentCardPlugin = class {
25
+ name = "agent-card";
26
+ version = "1.0.0";
27
+ tools;
28
+ options;
29
+ setupCtx;
30
+ latestCtx;
31
+ hooks = {
32
+ beforeRun: async (ctx, _params) => {
33
+ this.latestCtx = ctx;
34
+ },
35
+ afterRun: async (ctx, _params) => {
36
+ this.latestCtx = ctx;
37
+ }
38
+ };
39
+ constructor(options = {}) {
40
+ this.options = {
41
+ paths: {
42
+ agents: options.paths?.agents ?? DEFAULT_AGENTS_PATH,
43
+ skills: options.paths?.skills ?? DEFAULT_SKILLS_PATH
44
+ },
45
+ readZones: options.readZones ?? DEFAULT_ZONES,
46
+ overrides: options.overrides
47
+ };
48
+ this.tools = {
49
+ "agent-card:get": tool({
50
+ description: "Return generated or manual agent card documents.",
51
+ inputSchema: z.object({
52
+ target: z.enum(["agents", "skills", "all"]).default("all")
53
+ }),
54
+ execute: async (args) => {
55
+ const parsed = z.object({ target: z.enum(["agents", "skills", "all"]).default("all") }).parse(args ?? {});
56
+ const snapshot = await this.getAgentCard();
57
+ if (parsed.target === "agents") {
58
+ return {
59
+ target: "agents",
60
+ markdown: snapshot.agentsMd,
61
+ source: snapshot.source.agents
62
+ };
63
+ }
64
+ if (parsed.target === "skills") {
65
+ return {
66
+ target: "skills",
67
+ markdown: snapshot.skillsMd,
68
+ source: snapshot.source.skills
69
+ };
70
+ }
71
+ return snapshot;
72
+ }
73
+ })
74
+ };
75
+ }
76
+ setup(ctx) {
77
+ this.setupCtx = ctx;
78
+ }
79
+ async getAgentCard() {
80
+ const ctx = this.latestCtx ?? this.setupCtx;
81
+ if (!ctx) {
82
+ throw new Error("AgentCardPlugin has not been initialized by a Agent instance");
83
+ }
84
+ const agents = await this.resolveAgentsMarkdown(ctx);
85
+ const skills = await this.resolveSkillsMarkdown(ctx);
86
+ return {
87
+ agentsMd: agents.markdown,
88
+ skillsMd: skills.markdown,
89
+ source: {
90
+ agents: agents.source,
91
+ skills: skills.source
92
+ }
93
+ };
94
+ }
95
+ async resolveAgentsMarkdown(ctx) {
96
+ const manual = await this.tryReadManual(ctx, this.options.paths.agents);
97
+ if (manual) return { markdown: manual, source: "manual" };
98
+ const auto = this.createAutoAgentCard(ctx);
99
+ const override = this.options.overrides?.agents;
100
+ if (override !== void 0) {
101
+ if (typeof override === "string") {
102
+ return { markdown: override, source: "override" };
103
+ }
104
+ const merged = this.mergeAgentCard(auto, override);
105
+ return { markdown: this.renderAgentCard(merged), source: "override" };
106
+ }
107
+ return { markdown: this.renderAgentCard(auto), source: "auto" };
108
+ }
109
+ async resolveSkillsMarkdown(ctx) {
110
+ const manual = await this.tryReadManual(ctx, this.options.paths.skills);
111
+ if (manual) return { markdown: manual, source: "manual" };
112
+ const auto = this.createAutoSkillsCard(ctx);
113
+ const override = this.options.overrides?.skills;
114
+ if (override !== void 0) {
115
+ if (typeof override === "string") {
116
+ return { markdown: override, source: "override" };
117
+ }
118
+ const merged = this.mergeSkillsCard(auto, override);
119
+ return { markdown: this.renderSkillsCard(merged), source: "override" };
120
+ }
121
+ return { markdown: this.renderSkillsCard(auto), source: "auto" };
122
+ }
123
+ async tryReadManual(ctx, path) {
124
+ for (const zone of this.options.readZones) {
125
+ try {
126
+ const exists = await ctx.filesystem.exists(path, zone);
127
+ if (!exists) continue;
128
+ return await ctx.filesystem.read(path, zone);
129
+ } catch {
130
+ }
131
+ }
132
+ return null;
133
+ }
134
+ createAutoAgentCard(ctx) {
135
+ const name = ctx.agentName ?? "Agent";
136
+ const tools = [...ctx.toolNames].sort();
137
+ return {
138
+ title: "Agent Card",
139
+ name,
140
+ sessionId: ctx.sessionId,
141
+ maxSteps: ctx.config.maxSteps,
142
+ summary: `${name} exposes ${tools.length} tool${tools.length === 1 ? "" : "s"}.`,
143
+ instructions: ctx.config.instructions,
144
+ tools,
145
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
146
+ };
147
+ }
148
+ createAutoSkillsCard(ctx) {
149
+ const name = ctx.agentName ?? "Agent";
150
+ const skills = [...ctx.toolNames].sort();
151
+ return {
152
+ title: "Skills Card",
153
+ name,
154
+ summary: `${name} can invoke ${skills.length} callable skills/tools.`,
155
+ skills,
156
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
157
+ };
158
+ }
159
+ mergeAgentCard(base, override) {
160
+ return {
161
+ ...base,
162
+ ...override,
163
+ tools: override.tools ? [...override.tools] : base.tools
164
+ };
165
+ }
166
+ mergeSkillsCard(base, override) {
167
+ return {
168
+ ...base,
169
+ ...override,
170
+ skills: override.skills ? [...override.skills] : base.skills
171
+ };
172
+ }
173
+ renderAgentCard(doc) {
174
+ const tools = doc.tools.length > 0 ? doc.tools.map((toolName) => `- \`${toolName}\``) : ["- _No tools registered_"];
175
+ return [
176
+ `# ${doc.title}`,
177
+ "",
178
+ `- Name: ${doc.name}`,
179
+ `- Session: ${doc.sessionId}`,
180
+ `- Max Steps: ${doc.maxSteps}`,
181
+ `- Generated At: ${doc.generatedAt}`,
182
+ "",
183
+ "## Summary",
184
+ doc.summary,
185
+ "",
186
+ "## Instructions",
187
+ doc.instructions,
188
+ "",
189
+ "## Tools",
190
+ ...tools,
191
+ ""
192
+ ].join("\n");
193
+ }
194
+ renderSkillsCard(doc) {
195
+ const skills = doc.skills.length > 0 ? doc.skills.map((skill) => `- \`${skill}\``) : ["- _No skills registered_"];
196
+ return [
197
+ `# ${doc.title}`,
198
+ "",
199
+ `- Agent: ${doc.name}`,
200
+ `- Generated At: ${doc.generatedAt}`,
201
+ "",
202
+ "## Summary",
203
+ doc.summary,
204
+ "",
205
+ "## Skills",
206
+ ...skills,
207
+ ""
208
+ ].join("\n");
209
+ }
210
+ };
211
+ function createAgentCardPlugin(options) {
212
+ return new AgentCardPlugin(options);
213
+ }
214
+
215
+ // src/plugins/a2a.plugin.ts
216
+ import { z as z2 } from "zod";
217
+
218
+ // src/plugins/a2a-handler.ts
219
+ function createError(id, code, message, data) {
220
+ const error = data === void 0 ? { code, message } : { code, message, data };
221
+ return {
222
+ jsonrpc: "2.0",
223
+ id,
224
+ error
225
+ };
226
+ }
227
+ function asRecord(value) {
228
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
229
+ return null;
230
+ }
231
+ return value;
232
+ }
233
+ function asString(value) {
234
+ return typeof value === "string" && value.length > 0 ? value : null;
235
+ }
236
+ function createA2AJsonRpcHandler(handlers) {
237
+ return async (request) => {
238
+ const id = request.id ?? null;
239
+ if (request.jsonrpc !== "2.0" || typeof request.method !== "string") {
240
+ return createError(id, -32600, "Invalid Request");
241
+ }
242
+ try {
243
+ switch (request.method) {
244
+ case "tasks/send": {
245
+ const params = asRecord(request.params);
246
+ if (!params) {
247
+ return createError(id, -32602, "Invalid params: expected object");
248
+ }
249
+ const prompt = asString(params.prompt);
250
+ if (!prompt) {
251
+ return createError(id, -32602, "Invalid params: prompt is required");
252
+ }
253
+ const parsedTaskId = params.taskId === void 0 ? void 0 : asString(params.taskId);
254
+ if (params.taskId !== void 0 && !parsedTaskId) {
255
+ return createError(id, -32602, "Invalid params: taskId must be a non-empty string");
256
+ }
257
+ const taskId = parsedTaskId ?? void 0;
258
+ const metadata = params.metadata === void 0 ? void 0 : asRecord(params.metadata);
259
+ if (params.metadata !== void 0 && !metadata) {
260
+ return createError(id, -32602, "Invalid params: metadata must be an object");
261
+ }
262
+ const task = await handlers.sendTask({ prompt, taskId, metadata: metadata ?? void 0 });
263
+ return {
264
+ jsonrpc: "2.0",
265
+ id,
266
+ result: task
267
+ };
268
+ }
269
+ case "tasks/get": {
270
+ const params = asRecord(request.params);
271
+ if (!params) {
272
+ return createError(id, -32602, "Invalid params: expected object");
273
+ }
274
+ const taskId = asString(params.taskId);
275
+ if (!taskId) {
276
+ return createError(id, -32602, "Invalid params: taskId is required");
277
+ }
278
+ const task = await handlers.getTask(taskId);
279
+ if (!task) {
280
+ return createError(id, -32004, "Task not found", { taskId });
281
+ }
282
+ return {
283
+ jsonrpc: "2.0",
284
+ id,
285
+ result: task
286
+ };
287
+ }
288
+ case "tasks/list": {
289
+ if (!handlers.listTasks) {
290
+ return createError(id, -32601, "Method not found: tasks/list");
291
+ }
292
+ const tasks = await handlers.listTasks();
293
+ return {
294
+ jsonrpc: "2.0",
295
+ id,
296
+ result: { tasks }
297
+ };
298
+ }
299
+ case "tasks/cancel": {
300
+ if (!handlers.cancelTask) {
301
+ return createError(id, -32601, "Method not found: tasks/cancel");
302
+ }
303
+ const params = asRecord(request.params);
304
+ if (!params) {
305
+ return createError(id, -32602, "Invalid params: expected object");
306
+ }
307
+ const taskId = asString(params.taskId);
308
+ if (!taskId) {
309
+ return createError(id, -32602, "Invalid params: taskId is required");
310
+ }
311
+ const task = await handlers.cancelTask(taskId);
312
+ if (!task) {
313
+ return createError(id, -32004, "Task not found", { taskId });
314
+ }
315
+ return {
316
+ jsonrpc: "2.0",
317
+ id,
318
+ result: task
319
+ };
320
+ }
321
+ case "agent/card": {
322
+ if (!handlers.getAgentCard) {
323
+ return createError(id, -32601, "Method not found: agent/card");
324
+ }
325
+ const card = await handlers.getAgentCard();
326
+ return {
327
+ jsonrpc: "2.0",
328
+ id,
329
+ result: card
330
+ };
331
+ }
332
+ case "tasks/sendSubscribe": {
333
+ if (!handlers.sendTaskSubscribe) {
334
+ return createError(id, -32601, "Method not found: tasks/sendSubscribe");
335
+ }
336
+ const params = asRecord(request.params);
337
+ if (!params) {
338
+ return createError(id, -32602, "Invalid params: expected object");
339
+ }
340
+ const prompt = asString(params.prompt);
341
+ if (!prompt) {
342
+ return createError(id, -32602, "Invalid params: prompt is required");
343
+ }
344
+ const parsedTaskId = params.taskId === void 0 ? void 0 : asString(params.taskId);
345
+ if (params.taskId !== void 0 && !parsedTaskId) {
346
+ return createError(id, -32602, "Invalid params: taskId must be a non-empty string");
347
+ }
348
+ const taskId = parsedTaskId ?? void 0;
349
+ const metadata = params.metadata === void 0 ? void 0 : asRecord(params.metadata);
350
+ if (params.metadata !== void 0 && !metadata) {
351
+ return createError(id, -32602, "Invalid params: metadata must be an object");
352
+ }
353
+ return createError(id, -32601, "Use SSE endpoint for tasks/sendSubscribe");
354
+ }
355
+ case "health": {
356
+ return {
357
+ jsonrpc: "2.0",
358
+ id,
359
+ result: { ok: true }
360
+ };
361
+ }
362
+ default:
363
+ return createError(id, -32601, `Method not found: ${request.method}`);
364
+ }
365
+ } catch (error) {
366
+ return createError(
367
+ id,
368
+ -32603,
369
+ error instanceof Error ? error.message : "Internal error"
370
+ );
371
+ }
372
+ };
373
+ }
374
+ function createA2AHttpHandler(jsonRpcHandler, sseHandlers) {
375
+ return async (request) => {
376
+ const url = new URL(request.url);
377
+ if (request.method === "GET" && url.pathname === "/.well-known/agent.json") {
378
+ try {
379
+ const cardResponse = await jsonRpcHandler({
380
+ jsonrpc: "2.0",
381
+ id: "agent-discovery",
382
+ method: "agent/card"
383
+ });
384
+ if (cardResponse.error) {
385
+ return new Response(
386
+ JSON.stringify({ error: "Agent card not available" }),
387
+ { status: 500, headers: { "Content-Type": "application/json" } }
388
+ );
389
+ }
390
+ const agentCard = cardResponse.result;
391
+ const cardName = agentCard?.name ?? agentCard?.source?.name ?? "Agent";
392
+ const cardDescription = agentCard?.instructions ?? agentCard?.agentsMd ?? "A2A-compatible agent";
393
+ const cardTools = agentCard?.tools ?? [];
394
+ const cardSkills = agentCard?.skillsMd ? agentCard.skillsMd.split("\n").filter((l) => l.startsWith("- ")).map((l) => l.slice(2)) : [];
395
+ const allSkills = cardTools.length > 0 ? cardTools : cardSkills;
396
+ const discoveryCard = {
397
+ name: cardName,
398
+ description: cardDescription,
399
+ url: url.origin + "/a2a",
400
+ version: "1.0.0",
401
+ capabilities: {
402
+ streaming: true,
403
+ pushNotifications: true
404
+ },
405
+ skills: allSkills.map((skill, index) => ({
406
+ id: `skill-${index}`,
407
+ name: skill,
408
+ description: `Skill: ${skill}`
409
+ })),
410
+ authentication: { schemes: ["none"] }
411
+ };
412
+ return new Response(JSON.stringify(discoveryCard), {
413
+ status: 200,
414
+ headers: { "Content-Type": "application/json" }
415
+ });
416
+ } catch (error) {
417
+ return new Response(
418
+ JSON.stringify({ error: "Failed to generate agent card" }),
419
+ { status: 500, headers: { "Content-Type": "application/json" } }
420
+ );
421
+ }
422
+ }
423
+ if (request.method !== "POST") {
424
+ return new Response(null, { status: 405 });
425
+ }
426
+ let parsed;
427
+ try {
428
+ parsed = await request.json();
429
+ } catch {
430
+ return new Response(
431
+ JSON.stringify(createError(null, -32700, "Parse error")),
432
+ { status: 400, headers: { "Content-Type": "application/json" } }
433
+ );
434
+ }
435
+ if (sseHandlers?.sendTaskSubscribe) {
436
+ const requestObject2 = asRecord(parsed);
437
+ if (requestObject2?.method === "tasks/sendSubscribe") {
438
+ const params = asRecord(requestObject2.params);
439
+ if (!params) {
440
+ return new Response("Invalid params", { status: 400 });
441
+ }
442
+ const prompt = asString(params.prompt);
443
+ if (!prompt) {
444
+ return new Response("Prompt required", { status: 400 });
445
+ }
446
+ const taskId = params.taskId ? asString(params.taskId) : void 0;
447
+ const metadata = params.metadata ? asRecord(params.metadata) : void 0;
448
+ const eventStream = sseHandlers.sendTaskSubscribe({
449
+ prompt,
450
+ taskId: taskId ?? void 0,
451
+ metadata: metadata ?? void 0
452
+ });
453
+ return createSseResponse(eventStream);
454
+ }
455
+ }
456
+ if (Array.isArray(parsed)) {
457
+ return new Response(
458
+ JSON.stringify(createError(null, -32600, "Batch requests are not supported")),
459
+ { status: 400, headers: { "Content-Type": "application/json" } }
460
+ );
461
+ }
462
+ const requestObject = asRecord(parsed);
463
+ if (!requestObject) {
464
+ return new Response(
465
+ JSON.stringify(createError(null, -32600, "Invalid Request")),
466
+ { status: 400, headers: { "Content-Type": "application/json" } }
467
+ );
468
+ }
469
+ const hasId = "id" in requestObject;
470
+ const normalizedRequest = {
471
+ jsonrpc: requestObject.jsonrpc,
472
+ id: hasId ? requestObject.id ?? null : null,
473
+ method: requestObject.method,
474
+ params: requestObject.params
475
+ };
476
+ if (!hasId) {
477
+ await jsonRpcHandler({ ...normalizedRequest, id: null });
478
+ return new Response(null, { status: 202 });
479
+ }
480
+ const response = await jsonRpcHandler(normalizedRequest);
481
+ return new Response(
482
+ JSON.stringify(response),
483
+ {
484
+ status: response.error ? 400 : 200,
485
+ headers: { "Content-Type": "application/json" }
486
+ }
487
+ );
488
+ };
489
+ }
490
+ function createSseResponse(eventStream) {
491
+ const encoder = new TextEncoder();
492
+ const readableStream = new ReadableStream({
493
+ async start(controller) {
494
+ try {
495
+ for await (const event of eventStream) {
496
+ const sseData = `event: ${event.type}
497
+ data: ${JSON.stringify(event)}
498
+
499
+ `;
500
+ controller.enqueue(encoder.encode(sseData));
501
+ }
502
+ controller.close();
503
+ } catch (error) {
504
+ const errorEvent = `event: error
505
+ data: ${JSON.stringify({ error: String(error) })}
506
+
507
+ `;
508
+ controller.enqueue(encoder.encode(errorEvent));
509
+ controller.close();
510
+ }
511
+ }
512
+ });
513
+ return new Response(readableStream, {
514
+ status: 200,
515
+ headers: {
516
+ "Content-Type": "text/event-stream",
517
+ "Cache-Control": "no-cache",
518
+ "Connection": "keep-alive",
519
+ "Access-Control-Allow-Origin": "*",
520
+ "Access-Control-Allow-Headers": "Content-Type"
521
+ }
522
+ });
523
+ }
524
+ function createA2ASseHandler(handlers) {
525
+ return (params) => {
526
+ if (!handlers.sendTaskSubscribe) {
527
+ throw new Error("sendTaskSubscribe handler not available");
528
+ }
529
+ return handlers.sendTaskSubscribe(params);
530
+ };
531
+ }
532
+
533
+ // src/plugins/a2a-delegation.ts
534
+ var A2ADelegationManager = class {
535
+ agents = /* @__PURE__ */ new Map();
536
+ fetchImpl;
537
+ constructor(fetchImpl = globalThis.fetch) {
538
+ if (!fetchImpl) {
539
+ throw new Error("A2ADelegationManager requires a fetch implementation");
540
+ }
541
+ this.fetchImpl = fetchImpl;
542
+ }
543
+ register(agent) {
544
+ this.agents.set(agent.name, agent);
545
+ }
546
+ unregister(name) {
547
+ this.agents.delete(name);
548
+ }
549
+ listAgents() {
550
+ return Array.from(this.agents.values());
551
+ }
552
+ /**
553
+ * Find the best agent for a task based on required skills.
554
+ * Uses a simple skill overlap scoring system.
555
+ */
556
+ findAgent(requiredSkills) {
557
+ if (requiredSkills.length === 0) {
558
+ const agents = Array.from(this.agents.values());
559
+ return agents.length > 0 ? agents[0] : null;
560
+ }
561
+ let bestAgent = null;
562
+ let bestScore = 0;
563
+ for (const agent of this.agents.values()) {
564
+ const overlap = requiredSkills.filter(
565
+ (skill) => agent.skills.some(
566
+ (agentSkill) => agentSkill.toLowerCase().includes(skill.toLowerCase()) || skill.toLowerCase().includes(agentSkill.toLowerCase())
567
+ )
568
+ );
569
+ const score = overlap.length / requiredSkills.length;
570
+ if (score > bestScore) {
571
+ bestScore = score;
572
+ bestAgent = agent;
573
+ }
574
+ }
575
+ return bestAgent;
576
+ }
577
+ /**
578
+ * Delegate a task to the best matching agent.
579
+ */
580
+ async delegate(prompt, requiredSkills, fetchImpl = this.fetchImpl) {
581
+ const selectedAgent = this.findAgent(requiredSkills);
582
+ if (!selectedAgent) {
583
+ throw new Error("No suitable agent found for delegation");
584
+ }
585
+ const taskId = crypto.randomUUID();
586
+ const payload = {
587
+ jsonrpc: "2.0",
588
+ id: taskId,
589
+ method: "tasks/send",
590
+ params: {
591
+ prompt,
592
+ taskId,
593
+ metadata: { delegatedSkills: requiredSkills }
594
+ }
595
+ };
596
+ try {
597
+ const response = await fetchImpl(selectedAgent.endpoint, {
598
+ method: "POST",
599
+ headers: { "Content-Type": "application/json" },
600
+ body: JSON.stringify(payload)
601
+ });
602
+ if (!response.ok) {
603
+ throw new Error(`Agent endpoint returned HTTP ${response.status}`);
604
+ }
605
+ const result = await response.json();
606
+ if (result.error) {
607
+ throw new Error(`Agent error [${result.error.code}]: ${result.error.message}`);
608
+ }
609
+ return {
610
+ selectedAgent,
611
+ taskId,
612
+ result: result.result
613
+ };
614
+ } catch (error) {
615
+ throw new Error(`Delegation failed: ${error instanceof Error ? error.message : String(error)}`);
616
+ }
617
+ }
618
+ };
619
+
620
+ // src/plugins/a2a-push.ts
621
+ var A2APushNotifier = class _A2APushNotifier {
622
+ subscriptions = /* @__PURE__ */ new Map();
623
+ fetchImpl;
624
+ constructor(fetchImpl = globalThis.fetch) {
625
+ if (!fetchImpl) {
626
+ throw new Error("A2APushNotifier requires a fetch implementation");
627
+ }
628
+ this.fetchImpl = fetchImpl;
629
+ }
630
+ static BLOCKED_HEADERS = /* @__PURE__ */ new Set(["host", "authorization", "cookie", "content-type"]);
631
+ static LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "0.0.0.0"]);
632
+ subscribe(taskId, config) {
633
+ const parsed = new URL(config.url);
634
+ const isLocal = _A2APushNotifier.LOCAL_HOSTS.has(parsed.hostname) || parsed.hostname.startsWith("127.");
635
+ if (parsed.protocol !== "https:" && !isLocal) {
636
+ throw new Error("Push notification URL must use HTTPS");
637
+ }
638
+ if (parsed.protocol !== "https:" && isLocal && parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1") {
639
+ throw new Error("Push notification URL must use HTTPS for non-standard local addresses");
640
+ }
641
+ if (config.headers) {
642
+ for (const key of Object.keys(config.headers)) {
643
+ if (_A2APushNotifier.BLOCKED_HEADERS.has(key.toLowerCase())) {
644
+ throw new Error(`Header "${key}" is not allowed in push notifications`);
645
+ }
646
+ }
647
+ }
648
+ const existing = this.subscriptions.get(taskId) ?? [];
649
+ existing.push(config);
650
+ this.subscriptions.set(taskId, existing);
651
+ }
652
+ unsubscribe(taskId, url) {
653
+ const existing = this.subscriptions.get(taskId) ?? [];
654
+ const filtered = existing.filter((config) => config.url !== url);
655
+ if (filtered.length === 0) {
656
+ this.subscriptions.delete(taskId);
657
+ } else {
658
+ this.subscriptions.set(taskId, filtered);
659
+ }
660
+ }
661
+ async notify(event) {
662
+ const configs = this.subscriptions.get(event.taskId) ?? [];
663
+ const promises = configs.map(async (config) => {
664
+ if (config.events && !config.events.includes(event.type)) {
665
+ return;
666
+ }
667
+ try {
668
+ await this.fetchImpl(config.url, {
669
+ method: "POST",
670
+ headers: {
671
+ "Content-Type": "application/json",
672
+ ...config.headers
673
+ },
674
+ body: JSON.stringify(event)
675
+ });
676
+ } catch (error) {
677
+ console.warn(`Push notification failed for ${config.url}:`, error);
678
+ }
679
+ });
680
+ await Promise.allSettled(promises);
681
+ }
682
+ cleanup(taskId) {
683
+ this.subscriptions.delete(taskId);
684
+ }
685
+ };
686
+
687
+ // src/plugins/a2a-durable-task-queue.ts
688
+ var DEFAULT_RETRY_CONFIG = {
689
+ maxAttempts: 3,
690
+ initialBackoffMs: 250,
691
+ backoffMultiplier: 2,
692
+ maxBackoffMs: 3e4,
693
+ jitterRatio: 0
694
+ };
695
+ var DEFAULT_QUEUE_CONFIG = {
696
+ leaseDurationMs: 6e4,
697
+ retentionMs: 36e5,
698
+ maxTerminalTasks: 1e3,
699
+ retry: DEFAULT_RETRY_CONFIG
700
+ };
701
+ function cloneTask(task) {
702
+ return {
703
+ ...task,
704
+ metadata: task.metadata ? { ...task.metadata } : void 0
705
+ };
706
+ }
707
+ function isTerminalStatus(status) {
708
+ return status === "completed" || status === "failed" || status === "cancelled";
709
+ }
710
+ var A2ADurableTaskQueue = class {
711
+ entries = /* @__PURE__ */ new Map();
712
+ now;
713
+ idFactory;
714
+ config;
715
+ constructor(config = {}) {
716
+ const retry = {
717
+ ...DEFAULT_RETRY_CONFIG,
718
+ ...config.retry ?? {}
719
+ };
720
+ this.config = {
721
+ leaseDurationMs: config.leaseDurationMs ?? DEFAULT_QUEUE_CONFIG.leaseDurationMs,
722
+ retentionMs: config.retentionMs ?? DEFAULT_QUEUE_CONFIG.retentionMs,
723
+ maxTerminalTasks: config.maxTerminalTasks ?? DEFAULT_QUEUE_CONFIG.maxTerminalTasks,
724
+ retry,
725
+ now: config.now,
726
+ idFactory: config.idFactory
727
+ };
728
+ this.now = config.now ?? (() => Date.now());
729
+ this.idFactory = config.idFactory ?? (() => crypto.randomUUID());
730
+ }
731
+ get size() {
732
+ return this.entries.size;
733
+ }
734
+ enqueue(task, options = {}) {
735
+ if (this.entries.has(task.id)) {
736
+ throw new Error(`Task already exists: ${task.id}`);
737
+ }
738
+ const now = this.now();
739
+ const maxAttempts = Math.max(1, options.maxAttempts ?? this.config.retry.maxAttempts);
740
+ const normalizedTask = {
741
+ ...cloneTask(task),
742
+ status: "queued",
743
+ updatedAt: new Date(now).toISOString(),
744
+ completedAt: void 0
745
+ };
746
+ this.entries.set(task.id, {
747
+ task: normalizedTask,
748
+ attempts: 0,
749
+ maxAttempts,
750
+ nextAttemptAt: now
751
+ });
752
+ return cloneTask(normalizedTask);
753
+ }
754
+ get(taskId) {
755
+ this.resolveExpiredLeases();
756
+ const entry = this.entries.get(taskId);
757
+ if (!entry) return null;
758
+ return cloneTask(entry.task);
759
+ }
760
+ list() {
761
+ this.resolveExpiredLeases();
762
+ return [...this.entries.values()].map((entry) => cloneTask(entry.task));
763
+ }
764
+ acquire(taskId, workerId) {
765
+ this.resolveExpiredLeases();
766
+ const entry = this.entries.get(taskId);
767
+ if (!entry) return null;
768
+ const now = this.now();
769
+ if (entry.task.status !== "queued") return null;
770
+ if (entry.nextAttemptAt > now) return null;
771
+ entry.attempts += 1;
772
+ const leaseId = this.idFactory();
773
+ entry.lease = {
774
+ leaseId,
775
+ workerId,
776
+ expiresAt: now + this.config.leaseDurationMs
777
+ };
778
+ entry.task.status = "running";
779
+ entry.task.updatedAt = new Date(now).toISOString();
780
+ return {
781
+ taskId,
782
+ leaseId,
783
+ workerId,
784
+ expiresAt: new Date(entry.lease.expiresAt).toISOString(),
785
+ attempt: entry.attempts,
786
+ maxAttempts: entry.maxAttempts
787
+ };
788
+ }
789
+ extendLease(taskId, leaseId, leaseDurationMs) {
790
+ const entry = this.entries.get(taskId);
791
+ if (!entry || !entry.lease) return false;
792
+ if (entry.lease.leaseId !== leaseId) return false;
793
+ const duration = Math.max(1, leaseDurationMs ?? this.config.leaseDurationMs);
794
+ entry.lease.expiresAt = this.now() + duration;
795
+ return true;
796
+ }
797
+ complete(taskId, output, leaseId) {
798
+ const entry = this.entries.get(taskId);
799
+ if (!entry) return null;
800
+ if (isTerminalStatus(entry.task.status)) {
801
+ return cloneTask(entry.task);
802
+ }
803
+ if (!this.validateLease(entry, leaseId)) {
804
+ return null;
805
+ }
806
+ const nowIso = new Date(this.now()).toISOString();
807
+ entry.task.status = "completed";
808
+ entry.task.output = output;
809
+ entry.task.error = void 0;
810
+ entry.task.updatedAt = nowIso;
811
+ entry.task.completedAt = nowIso;
812
+ entry.lease = void 0;
813
+ entry.finishedAt = this.now();
814
+ return cloneTask(entry.task);
815
+ }
816
+ fail(taskId, error, leaseId) {
817
+ const entry = this.entries.get(taskId);
818
+ if (!entry) return null;
819
+ if (isTerminalStatus(entry.task.status)) {
820
+ return {
821
+ task: cloneTask(entry.task),
822
+ willRetry: false,
823
+ retryDelayMs: 0,
824
+ attempts: entry.attempts,
825
+ maxAttempts: entry.maxAttempts
826
+ };
827
+ }
828
+ if (!this.validateLease(entry, leaseId)) {
829
+ return null;
830
+ }
831
+ const now = this.now();
832
+ const nowIso = new Date(now).toISOString();
833
+ entry.task.error = error;
834
+ entry.task.updatedAt = nowIso;
835
+ entry.lease = void 0;
836
+ if (entry.attempts < entry.maxAttempts) {
837
+ const retryDelayMs = this.computeBackoffDelay(entry.attempts);
838
+ entry.task.status = "queued";
839
+ entry.task.completedAt = void 0;
840
+ entry.nextAttemptAt = now + retryDelayMs;
841
+ return {
842
+ task: cloneTask(entry.task),
843
+ willRetry: true,
844
+ retryDelayMs,
845
+ attempts: entry.attempts,
846
+ maxAttempts: entry.maxAttempts
847
+ };
848
+ }
849
+ entry.task.status = "failed";
850
+ entry.task.completedAt = nowIso;
851
+ entry.finishedAt = now;
852
+ return {
853
+ task: cloneTask(entry.task),
854
+ willRetry: false,
855
+ retryDelayMs: 0,
856
+ attempts: entry.attempts,
857
+ maxAttempts: entry.maxAttempts
858
+ };
859
+ }
860
+ cancel(taskId) {
861
+ const entry = this.entries.get(taskId);
862
+ if (!entry) return null;
863
+ if (isTerminalStatus(entry.task.status)) {
864
+ return cloneTask(entry.task);
865
+ }
866
+ const nowIso = new Date(this.now()).toISOString();
867
+ entry.task.status = "cancelled";
868
+ entry.task.updatedAt = nowIso;
869
+ entry.task.completedAt = nowIso;
870
+ entry.lease = void 0;
871
+ entry.finishedAt = this.now();
872
+ return cloneTask(entry.task);
873
+ }
874
+ evictExpired() {
875
+ const now = this.now();
876
+ this.resolveExpiredLeases();
877
+ const terminals = [];
878
+ for (const [taskId, entry] of this.entries) {
879
+ if (!isTerminalStatus(entry.task.status)) continue;
880
+ const finishedAt = entry.finishedAt ?? Date.parse(entry.task.updatedAt);
881
+ if (now - finishedAt > this.config.retentionMs) {
882
+ this.entries.delete(taskId);
883
+ continue;
884
+ }
885
+ terminals.push({ taskId, finishedAt });
886
+ }
887
+ if (terminals.length <= this.config.maxTerminalTasks) return;
888
+ terminals.sort((a, b) => a.finishedAt - b.finishedAt).slice(0, terminals.length - this.config.maxTerminalTasks).forEach(({ taskId }) => this.entries.delete(taskId));
889
+ }
890
+ snapshot() {
891
+ this.resolveExpiredLeases();
892
+ return {
893
+ version: 1,
894
+ entries: [...this.entries.values()].map((entry) => ({
895
+ task: cloneTask(entry.task),
896
+ attempts: entry.attempts,
897
+ maxAttempts: entry.maxAttempts,
898
+ nextAttemptAt: entry.nextAttemptAt,
899
+ finishedAt: entry.finishedAt,
900
+ lease: entry.lease ? {
901
+ leaseId: entry.lease.leaseId,
902
+ workerId: entry.lease.workerId,
903
+ expiresAt: entry.lease.expiresAt
904
+ } : void 0
905
+ }))
906
+ };
907
+ }
908
+ hydrate(snapshot) {
909
+ this.entries.clear();
910
+ if (!snapshot || snapshot.version !== 1) return;
911
+ for (const item of snapshot.entries) {
912
+ this.entries.set(item.task.id, {
913
+ task: cloneTask(item.task),
914
+ attempts: item.attempts,
915
+ maxAttempts: item.maxAttempts,
916
+ nextAttemptAt: item.nextAttemptAt,
917
+ finishedAt: item.finishedAt,
918
+ lease: item.lease ? {
919
+ leaseId: item.lease.leaseId,
920
+ workerId: item.lease.workerId,
921
+ expiresAt: item.lease.expiresAt
922
+ } : void 0
923
+ });
924
+ }
925
+ this.resolveExpiredLeases();
926
+ }
927
+ validateLease(entry, leaseId) {
928
+ if (!entry.lease) return true;
929
+ if (!leaseId) return false;
930
+ if (entry.lease.leaseId !== leaseId) return false;
931
+ if (entry.lease.expiresAt <= this.now()) return false;
932
+ return true;
933
+ }
934
+ resolveExpiredLeases() {
935
+ const now = this.now();
936
+ for (const entry of this.entries.values()) {
937
+ if (!entry.lease) continue;
938
+ if (entry.lease.expiresAt > now) continue;
939
+ if (entry.task.status !== "running") {
940
+ entry.lease = void 0;
941
+ continue;
942
+ }
943
+ entry.lease = void 0;
944
+ entry.task.error = "Task lease expired before completion";
945
+ entry.task.updatedAt = new Date(now).toISOString();
946
+ if (entry.attempts < entry.maxAttempts) {
947
+ const retryDelayMs = this.computeBackoffDelay(entry.attempts);
948
+ entry.task.status = "queued";
949
+ entry.task.completedAt = void 0;
950
+ entry.nextAttemptAt = now + retryDelayMs;
951
+ } else {
952
+ entry.task.status = "failed";
953
+ entry.task.completedAt = new Date(now).toISOString();
954
+ entry.finishedAt = now;
955
+ }
956
+ }
957
+ }
958
+ computeBackoffDelay(attempt) {
959
+ const base = Math.max(1, this.config.retry.initialBackoffMs);
960
+ const multiplier = Math.max(1, this.config.retry.backoffMultiplier);
961
+ const capped = Math.min(
962
+ this.config.retry.maxBackoffMs,
963
+ Math.round(base * Math.pow(multiplier, Math.max(0, attempt - 1)))
964
+ );
965
+ const jitterRatio = Math.max(0, Math.min(1, this.config.retry.jitterRatio));
966
+ if (jitterRatio === 0) return capped;
967
+ const jitterMax = Math.round(capped * jitterRatio);
968
+ const jitter = Math.floor(Math.random() * (jitterMax + 1));
969
+ return Math.min(this.config.retry.maxBackoffMs, capped + jitter);
970
+ }
971
+ };
972
+
973
+ // src/plugins/a2a.plugin.ts
974
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
975
+ var DEFAULT_RETRY_CONFIG2 = {
976
+ maxAttempts: 3,
977
+ initialBackoffMs: 250,
978
+ backoffMultiplier: 2,
979
+ maxBackoffMs: 3e4,
980
+ jitterRatio: 0
981
+ };
982
+ var A2A_CALL_SCHEMA = z2.object({
983
+ endpoint: z2.string().url(),
984
+ method: z2.enum(["tasks/send", "tasks/get", "tasks/list", "tasks/cancel", "agent/card", "health"]).default("tasks/send"),
985
+ prompt: z2.string().optional(),
986
+ taskId: z2.string().optional(),
987
+ params: z2.record(z2.string(), z2.unknown()).optional()
988
+ });
989
+ var A2A_DELEGATE_SCHEMA = z2.object({
990
+ prompt: z2.string(),
991
+ requiredSkills: z2.array(z2.string()).default([])
992
+ });
993
+ var A2A_DISCOVER_SCHEMA = z2.object({
994
+ endpoint: z2.string().url()
995
+ });
996
+ var A2A_SUBSCRIBE_SCHEMA = z2.object({
997
+ endpoint: z2.string().url(),
998
+ prompt: z2.string(),
999
+ taskId: z2.string().optional()
1000
+ });
1001
+ var A2APlugin = class _A2APlugin {
1002
+ name = "a2a";
1003
+ version = "1.0.0";
1004
+ tools;
1005
+ fetchImpl;
1006
+ requestTimeoutMs;
1007
+ agentCardProvider;
1008
+ taskQueue;
1009
+ persistQueueStateEnabled;
1010
+ delegationManager;
1011
+ pushNotifier;
1012
+ taskEventListeners = /* @__PURE__ */ new Set();
1013
+ static QUEUE_SNAPSHOT_KEY = "a2a:durable-task-queue:v1";
1014
+ static DEFAULT_MAX_TERMINAL_TASKS = 1e3;
1015
+ static DEFAULT_RETENTION_MS = 36e5;
1016
+ // 1 hour
1017
+ evictionTimer;
1018
+ queueHydrated = false;
1019
+ queueHydrationPromise = null;
1020
+ setupCtx;
1021
+ latestCtx;
1022
+ hooks = {
1023
+ beforeRun: async (ctx, _params) => {
1024
+ this.latestCtx = ctx;
1025
+ if (this.isQueueManagedRun(ctx)) return;
1026
+ const taskId = this.getTaskIdFromContext(ctx);
1027
+ if (!taskId) return;
1028
+ this.markTaskRunning(taskId, this.getLeaseIdFromContext(ctx));
1029
+ },
1030
+ afterRun: async (ctx, params) => {
1031
+ this.latestCtx = ctx;
1032
+ if (this.isQueueManagedRun(ctx)) return;
1033
+ const taskId = this.getTaskIdFromContext(ctx);
1034
+ if (!taskId) return;
1035
+ this.markTaskCompleted(taskId, params.result.text, this.getLeaseIdFromContext(ctx));
1036
+ },
1037
+ onError: async (ctx, params) => {
1038
+ if (this.isQueueManagedRun(ctx)) return;
1039
+ const taskId = this.getTaskIdFromContext(ctx);
1040
+ if (!taskId) return;
1041
+ this.markTaskFailed(taskId, params.error, this.getLeaseIdFromContext(ctx));
1042
+ }
1043
+ };
1044
+ constructor(options = {}) {
1045
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1046
+ if (!fetchImpl) {
1047
+ throw new Error("A2APlugin requires a fetch implementation");
1048
+ }
1049
+ this.fetchImpl = fetchImpl;
1050
+ this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
1051
+ this.agentCardProvider = options.agentCardProvider;
1052
+ this.persistQueueStateEnabled = options.persistQueueState ?? true;
1053
+ this.delegationManager = new A2ADelegationManager(fetchImpl);
1054
+ this.pushNotifier = new A2APushNotifier(fetchImpl);
1055
+ const normalizedRetry = options.retry ? {
1056
+ maxAttempts: options.retry.maxAttempts ?? DEFAULT_RETRY_CONFIG2.maxAttempts,
1057
+ initialBackoffMs: options.retry.initialBackoffMs ?? DEFAULT_RETRY_CONFIG2.initialBackoffMs,
1058
+ backoffMultiplier: options.retry.backoffMultiplier ?? DEFAULT_RETRY_CONFIG2.backoffMultiplier,
1059
+ maxBackoffMs: options.retry.maxBackoffMs ?? DEFAULT_RETRY_CONFIG2.maxBackoffMs,
1060
+ jitterRatio: options.retry.jitterRatio ?? DEFAULT_RETRY_CONFIG2.jitterRatio
1061
+ } : void 0;
1062
+ this.taskQueue = options.taskQueue ?? new A2ADurableTaskQueue({
1063
+ leaseDurationMs: options.queue?.leaseDurationMs,
1064
+ retentionMs: options.queue?.retentionMs ?? _A2APlugin.DEFAULT_RETENTION_MS,
1065
+ maxTerminalTasks: options.queue?.maxTerminalTasks ?? _A2APlugin.DEFAULT_MAX_TERMINAL_TASKS,
1066
+ retry: normalizedRetry
1067
+ });
1068
+ this.evictionTimer = setInterval(() => this.evictStaleTasks(), 6e4);
1069
+ this.tools = {
1070
+ "a2a:call": tool({
1071
+ description: "Call an external A2A-compatible JSON-RPC endpoint.",
1072
+ inputSchema: A2A_CALL_SCHEMA,
1073
+ execute: async (input) => {
1074
+ const args = A2A_CALL_SCHEMA.parse(input ?? {});
1075
+ const params = this.normalizeCallParams(args);
1076
+ const payload = {
1077
+ jsonrpc: "2.0",
1078
+ id: crypto.randomUUID(),
1079
+ method: args.method,
1080
+ params
1081
+ };
1082
+ const response = await this.callRemoteEndpoint(args.endpoint, payload);
1083
+ if (response.error) {
1084
+ throw new Error(`[A2A ${response.error.code}] ${response.error.message}`);
1085
+ }
1086
+ return response.result;
1087
+ }
1088
+ }),
1089
+ "a2a:delegate": tool({
1090
+ description: "Delegate a task to a registered agent based on required skills.",
1091
+ inputSchema: A2A_DELEGATE_SCHEMA,
1092
+ execute: async (input) => {
1093
+ const args = A2A_DELEGATE_SCHEMA.parse(input ?? {});
1094
+ return await this.delegationManager.delegate(args.prompt, args.requiredSkills, this.fetchImpl);
1095
+ }
1096
+ }),
1097
+ "a2a:discover": tool({
1098
+ description: "Discover agent capabilities at an A2A endpoint.",
1099
+ inputSchema: A2A_DISCOVER_SCHEMA,
1100
+ execute: async (input) => {
1101
+ const args = A2A_DISCOVER_SCHEMA.parse(input ?? {});
1102
+ return await this.discoverAgent(args.endpoint);
1103
+ }
1104
+ }),
1105
+ "a2a:subscribe": tool({
1106
+ description: "Subscribe to task status updates via Server-Sent Events.",
1107
+ inputSchema: A2A_SUBSCRIBE_SCHEMA,
1108
+ execute: async (input) => {
1109
+ const args = A2A_SUBSCRIBE_SCHEMA.parse(input ?? {});
1110
+ return await this.subscribeToTask(args.endpoint, args.prompt, args.taskId);
1111
+ }
1112
+ })
1113
+ };
1114
+ }
1115
+ setup(ctx) {
1116
+ this.setupCtx = ctx;
1117
+ void this.ensureQueueHydrated();
1118
+ }
1119
+ dispose() {
1120
+ if (this.evictionTimer) {
1121
+ clearInterval(this.evictionTimer);
1122
+ this.evictionTimer = void 0;
1123
+ }
1124
+ void this.persistQueueState();
1125
+ }
1126
+ createJsonRpcHandler(agent) {
1127
+ const plugin = this;
1128
+ const sendTaskSubscribe = async function* (params) {
1129
+ await plugin.ensureQueueHydrated();
1130
+ const taskId = params.taskId ?? crypto.randomUUID();
1131
+ const eventQueue = [];
1132
+ let completed = false;
1133
+ let pending;
1134
+ function createDeferred() {
1135
+ let resolve;
1136
+ const promise = new Promise((r) => {
1137
+ resolve = r;
1138
+ });
1139
+ return { promise, resolve };
1140
+ }
1141
+ pending = createDeferred();
1142
+ const eventListener = (event) => {
1143
+ if (event.taskId === taskId) {
1144
+ eventQueue.push(event);
1145
+ if (event.type === "task:completed" || event.type === "task:failed" || event.type === "task:cancelled") {
1146
+ completed = true;
1147
+ }
1148
+ pending.resolve();
1149
+ pending = createDeferred();
1150
+ }
1151
+ };
1152
+ plugin.taskEventListeners.add(eventListener);
1153
+ plugin.queueTask(taskId, params.prompt, params.metadata);
1154
+ try {
1155
+ const runPromise = plugin.executeTaskWithRetry(agent, taskId, params);
1156
+ let lastEventIndex = 0;
1157
+ while (!completed) {
1158
+ if (eventQueue.length <= lastEventIndex) {
1159
+ await pending.promise;
1160
+ }
1161
+ for (let i = lastEventIndex; i < eventQueue.length; i++) {
1162
+ yield eventQueue[i];
1163
+ }
1164
+ lastEventIndex = eventQueue.length;
1165
+ }
1166
+ await runPromise;
1167
+ if (eventQueue.length > lastEventIndex) {
1168
+ for (let i = lastEventIndex; i < eventQueue.length; i++) {
1169
+ yield eventQueue[i];
1170
+ }
1171
+ }
1172
+ } finally {
1173
+ plugin.taskEventListeners.delete(eventListener);
1174
+ }
1175
+ };
1176
+ const jsonRpcHandler = createA2AJsonRpcHandler({
1177
+ sendTask: async (params) => {
1178
+ await plugin.ensureQueueHydrated();
1179
+ const taskId = params.taskId ?? crypto.randomUUID();
1180
+ plugin.queueTask(taskId, params.prompt, params.metadata);
1181
+ await plugin.executeTaskWithRetry(agent, taskId, params);
1182
+ return plugin.cloneTask(taskId);
1183
+ },
1184
+ sendTaskSubscribe,
1185
+ getTask: async (taskId) => {
1186
+ await plugin.ensureQueueHydrated();
1187
+ return plugin.getTask(taskId);
1188
+ },
1189
+ listTasks: async () => {
1190
+ await plugin.ensureQueueHydrated();
1191
+ return plugin.listTasks();
1192
+ },
1193
+ cancelTask: async (taskId) => {
1194
+ await plugin.ensureQueueHydrated();
1195
+ const previous = plugin.taskQueue.get(taskId);
1196
+ if (!previous) return null;
1197
+ const cancelled = plugin.taskQueue.cancel(taskId);
1198
+ if (!cancelled) return null;
1199
+ if (previous.status !== "cancelled" && previous.status !== "completed" && previous.status !== "failed") {
1200
+ plugin.emitTaskEvent("task:cancelled", taskId);
1201
+ }
1202
+ void plugin.persistQueueState();
1203
+ return cancelled;
1204
+ },
1205
+ getAgentCard: async () => {
1206
+ return plugin.resolveAgentCard();
1207
+ }
1208
+ });
1209
+ jsonRpcHandler.sendTaskSubscribe = sendTaskSubscribe;
1210
+ return jsonRpcHandler;
1211
+ }
1212
+ createHttpHandler(agent) {
1213
+ const handler = this.createJsonRpcHandler(agent);
1214
+ return createA2AHttpHandler(handler, {
1215
+ sendTaskSubscribe: async function* (params) {
1216
+ for await (const event of handler.sendTaskSubscribe(params)) {
1217
+ yield event;
1218
+ }
1219
+ }
1220
+ });
1221
+ }
1222
+ getTask(taskId) {
1223
+ return this.taskQueue.get(taskId);
1224
+ }
1225
+ listTasks() {
1226
+ return this.taskQueue.list();
1227
+ }
1228
+ // Delegation methods
1229
+ registerAgent(agent) {
1230
+ this.delegationManager.register(agent);
1231
+ }
1232
+ unregisterAgent(name) {
1233
+ this.delegationManager.unregister(name);
1234
+ }
1235
+ listAgents() {
1236
+ return this.delegationManager.listAgents();
1237
+ }
1238
+ async delegateTask(prompt, requiredSkills) {
1239
+ return await this.delegationManager.delegate(prompt, requiredSkills, this.fetchImpl);
1240
+ }
1241
+ // Push notification methods
1242
+ subscribeToTaskNotifications(taskId, config) {
1243
+ this.pushNotifier.subscribe(taskId, config);
1244
+ }
1245
+ unsubscribeFromTaskNotifications(taskId, url) {
1246
+ this.pushNotifier.unsubscribe(taskId, url);
1247
+ }
1248
+ normalizeCallParams(args) {
1249
+ if (args.params) {
1250
+ return {
1251
+ ...args.params,
1252
+ ...args.prompt !== void 0 ? { prompt: args.prompt } : {},
1253
+ ...args.taskId !== void 0 ? { taskId: args.taskId } : {}
1254
+ };
1255
+ }
1256
+ if (args.method === "tasks/send") {
1257
+ if (!args.prompt) {
1258
+ throw new Error("a2a:call requires `prompt` for tasks/send requests");
1259
+ }
1260
+ return {
1261
+ prompt: args.prompt,
1262
+ ...args.taskId !== void 0 ? { taskId: args.taskId } : {}
1263
+ };
1264
+ }
1265
+ if (args.method === "tasks/get" || args.method === "tasks/cancel") {
1266
+ if (!args.taskId) {
1267
+ throw new Error(`a2a:call requires \`taskId\` for ${args.method}`);
1268
+ }
1269
+ return { taskId: args.taskId };
1270
+ }
1271
+ return {};
1272
+ }
1273
+ async callRemoteEndpoint(endpoint, payload) {
1274
+ const controller = new AbortController();
1275
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
1276
+ try {
1277
+ const response = await this.fetchImpl(endpoint, {
1278
+ method: "POST",
1279
+ headers: { "Content-Type": "application/json" },
1280
+ body: JSON.stringify(payload),
1281
+ signal: controller.signal
1282
+ });
1283
+ if (!response.ok) {
1284
+ throw new Error(`A2A endpoint returned HTTP ${response.status}`);
1285
+ }
1286
+ return await response.json();
1287
+ } finally {
1288
+ clearTimeout(timer);
1289
+ }
1290
+ }
1291
+ queueTask(taskId, prompt, metadata) {
1292
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1293
+ this.taskQueue.enqueue({
1294
+ id: taskId,
1295
+ status: "queued",
1296
+ prompt,
1297
+ metadata,
1298
+ createdAt: now,
1299
+ updatedAt: now
1300
+ });
1301
+ this.emitTaskEvent("task:queued", taskId);
1302
+ void this.persistQueueState();
1303
+ }
1304
+ markTaskRunning(taskId, _leaseId) {
1305
+ const lease = this.taskQueue.acquire(taskId, this.createWorkerId(taskId));
1306
+ if (!lease) return null;
1307
+ this.emitTaskEvent("task:running", taskId);
1308
+ void this.persistQueueState();
1309
+ return lease;
1310
+ }
1311
+ markTaskCompleted(taskId, output, leaseId) {
1312
+ const before = this.taskQueue.get(taskId);
1313
+ const completed = this.taskQueue.complete(taskId, output, leaseId);
1314
+ if (!completed) return;
1315
+ if (before?.status !== "completed") {
1316
+ this.emitTaskEvent("task:completed", taskId);
1317
+ }
1318
+ void this.persistQueueState();
1319
+ }
1320
+ markTaskFailed(taskId, error, leaseId) {
1321
+ const result = this.taskQueue.fail(taskId, this.normalizeError(error), leaseId);
1322
+ if (!result) return;
1323
+ if (result.willRetry) {
1324
+ this.emitTaskEvent("task:queued", taskId);
1325
+ } else {
1326
+ this.emitTaskEvent("task:failed", taskId);
1327
+ }
1328
+ void this.persistQueueState();
1329
+ }
1330
+ async executeTaskWithRetry(agent, taskId, params) {
1331
+ while (true) {
1332
+ const task = this.taskQueue.get(taskId);
1333
+ if (!task || task.status === "cancelled" || task.status === "completed" || task.status === "failed") {
1334
+ return;
1335
+ }
1336
+ const lease = this.markTaskRunning(taskId);
1337
+ if (!lease) {
1338
+ await this.sleep(10);
1339
+ continue;
1340
+ }
1341
+ const runMetadata = {
1342
+ ...params.metadata ?? {},
1343
+ a2aTaskId: taskId,
1344
+ a2aLeaseId: lease.leaseId,
1345
+ a2aAttempt: lease.attempt,
1346
+ a2aManagedByQueue: true
1347
+ };
1348
+ try {
1349
+ const result = await agent.run(params.prompt, { pluginMetadata: runMetadata });
1350
+ this.markTaskCompleted(taskId, result.text, lease.leaseId);
1351
+ return;
1352
+ } catch (error) {
1353
+ const failed = this.taskQueue.fail(taskId, this.normalizeError(error), lease.leaseId);
1354
+ if (!failed) return;
1355
+ if (!failed.willRetry) {
1356
+ this.emitTaskEvent("task:failed", taskId);
1357
+ void this.persistQueueState();
1358
+ return;
1359
+ }
1360
+ this.emitTaskEvent("task:queued", taskId);
1361
+ void this.persistQueueState();
1362
+ await this.sleep(failed.retryDelayMs);
1363
+ }
1364
+ }
1365
+ }
1366
+ evictStaleTasks() {
1367
+ const before = new Set(this.taskQueue.list().map((task) => task.id));
1368
+ this.taskQueue.evictExpired();
1369
+ const after = new Set(this.taskQueue.list().map((task) => task.id));
1370
+ for (const taskId of before) {
1371
+ if (!after.has(taskId)) {
1372
+ this.pushNotifier.cleanup(taskId);
1373
+ }
1374
+ }
1375
+ void this.persistQueueState();
1376
+ }
1377
+ emitTaskEvent(type, taskId) {
1378
+ const task = this.taskQueue.get(taskId);
1379
+ if (!task) return;
1380
+ const event = {
1381
+ type,
1382
+ taskId,
1383
+ task,
1384
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1385
+ };
1386
+ for (const listener of this.taskEventListeners) {
1387
+ try {
1388
+ listener(event);
1389
+ } catch (error) {
1390
+ console.warn("Task event listener error:", error);
1391
+ }
1392
+ }
1393
+ this.pushNotifier.notify(event).catch((error) => {
1394
+ console.warn("Push notification error:", error);
1395
+ });
1396
+ }
1397
+ createWorkerId(taskId) {
1398
+ const sessionId = this.latestCtx?.sessionId ?? this.setupCtx?.sessionId ?? "a2a";
1399
+ return `${sessionId}:${taskId}`;
1400
+ }
1401
+ normalizeError(error) {
1402
+ return error instanceof Error ? error.message : String(error);
1403
+ }
1404
+ async ensureQueueHydrated() {
1405
+ if (this.queueHydrated) return;
1406
+ if (this.queueHydrationPromise) {
1407
+ await this.queueHydrationPromise;
1408
+ return;
1409
+ }
1410
+ this.queueHydrationPromise = this.hydrateQueueFromMemory();
1411
+ try {
1412
+ await this.queueHydrationPromise;
1413
+ this.queueHydrated = true;
1414
+ } finally {
1415
+ this.queueHydrationPromise = null;
1416
+ }
1417
+ }
1418
+ async hydrateQueueFromMemory() {
1419
+ if (!this.persistQueueStateEnabled || !this.setupCtx) return;
1420
+ try {
1421
+ const snapshot = await this.setupCtx.memory.loadMetadata(
1422
+ this.setupCtx.sessionId,
1423
+ _A2APlugin.QUEUE_SNAPSHOT_KEY
1424
+ );
1425
+ if (snapshot) {
1426
+ this.taskQueue.hydrate(snapshot);
1427
+ }
1428
+ } catch (error) {
1429
+ console.warn("A2A queue hydration failed:", error);
1430
+ }
1431
+ }
1432
+ async persistQueueState() {
1433
+ if (!this.persistQueueStateEnabled || !this.setupCtx) return;
1434
+ try {
1435
+ await this.setupCtx.memory.saveMetadata(
1436
+ this.setupCtx.sessionId,
1437
+ _A2APlugin.QUEUE_SNAPSHOT_KEY,
1438
+ this.taskQueue.snapshot()
1439
+ );
1440
+ } catch (error) {
1441
+ console.warn("A2A queue persistence failed:", error);
1442
+ }
1443
+ }
1444
+ sleep(ms) {
1445
+ if (ms <= 0) return Promise.resolve();
1446
+ return new Promise((resolve) => setTimeout(resolve, ms));
1447
+ }
1448
+ async discoverAgent(endpoint) {
1449
+ try {
1450
+ const discoveryUrl = new URL("/.well-known/agent.json", endpoint).toString();
1451
+ const controller = new AbortController();
1452
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
1453
+ try {
1454
+ const discoveryResponse = await this.fetchImpl(discoveryUrl, { signal: controller.signal });
1455
+ if (discoveryResponse.ok) {
1456
+ const discoveryData = await discoveryResponse.json();
1457
+ return {
1458
+ name: discoveryData.name,
1459
+ description: discoveryData.description,
1460
+ skills: discoveryData.skills?.map((s) => s.name) ?? [],
1461
+ endpoint
1462
+ };
1463
+ }
1464
+ } finally {
1465
+ clearTimeout(timer);
1466
+ }
1467
+ } catch {
1468
+ }
1469
+ const payload = {
1470
+ jsonrpc: "2.0",
1471
+ id: crypto.randomUUID(),
1472
+ method: "agent/card"
1473
+ };
1474
+ const response = await this.callRemoteEndpoint(endpoint, payload);
1475
+ if (response.error) {
1476
+ throw new Error(`Failed to discover agent: ${response.error.message}`);
1477
+ }
1478
+ const card = response.result;
1479
+ return {
1480
+ name: card?.name ?? "Unknown Agent",
1481
+ description: card?.instructions ?? "No description",
1482
+ skills: card?.tools ?? [],
1483
+ endpoint
1484
+ };
1485
+ }
1486
+ async subscribeToTask(endpoint, prompt, taskId) {
1487
+ const payload = {
1488
+ jsonrpc: "2.0",
1489
+ id: crypto.randomUUID(),
1490
+ method: "tasks/sendSubscribe",
1491
+ params: { prompt, taskId }
1492
+ };
1493
+ const sseTimeoutMs = this.requestTimeoutMs * 5;
1494
+ const controller = new AbortController();
1495
+ const timer = setTimeout(() => controller.abort(), sseTimeoutMs);
1496
+ try {
1497
+ const response = await this.fetchImpl(endpoint, {
1498
+ method: "POST",
1499
+ headers: {
1500
+ "Content-Type": "application/json",
1501
+ "Accept": "text/event-stream"
1502
+ },
1503
+ body: JSON.stringify(payload),
1504
+ signal: controller.signal
1505
+ });
1506
+ if (!response.ok) {
1507
+ throw new Error(`SSE subscription failed with HTTP ${response.status}`);
1508
+ }
1509
+ const events = [];
1510
+ let sseCompleted = false;
1511
+ const reader = response.body?.getReader();
1512
+ const decoder = new TextDecoder();
1513
+ if (!reader) {
1514
+ throw new Error("No response body for SSE stream");
1515
+ }
1516
+ let buffer = "";
1517
+ try {
1518
+ while (true) {
1519
+ const { done, value } = await reader.read();
1520
+ if (done) break;
1521
+ buffer += decoder.decode(value, { stream: true });
1522
+ const segments = buffer.split("\n");
1523
+ buffer = segments.pop() ?? "";
1524
+ for (const line of segments) {
1525
+ if (line.startsWith("data: ")) {
1526
+ try {
1527
+ const eventData = JSON.parse(line.substring(6));
1528
+ events.push(eventData);
1529
+ if (eventData.type === "task:completed" || eventData.type === "task:failed" || eventData.type === "task:cancelled") {
1530
+ sseCompleted = true;
1531
+ }
1532
+ } catch {
1533
+ }
1534
+ }
1535
+ }
1536
+ if (sseCompleted) {
1537
+ break;
1538
+ }
1539
+ }
1540
+ } finally {
1541
+ reader.releaseLock();
1542
+ }
1543
+ return {
1544
+ message: "Task subscription completed",
1545
+ events
1546
+ };
1547
+ } finally {
1548
+ clearTimeout(timer);
1549
+ }
1550
+ }
1551
+ getTaskIdFromContext(ctx) {
1552
+ const raw = ctx.runMetadata?.a2aTaskId;
1553
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
1554
+ }
1555
+ getLeaseIdFromContext(ctx) {
1556
+ const raw = ctx.runMetadata?.a2aLeaseId;
1557
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
1558
+ }
1559
+ isQueueManagedRun(ctx) {
1560
+ return ctx.runMetadata?.a2aManagedByQueue === true;
1561
+ }
1562
+ async resolveAgentCard() {
1563
+ if (this.agentCardProvider) {
1564
+ return this.agentCardProvider.getAgentCard();
1565
+ }
1566
+ const ctx = this.latestCtx ?? this.setupCtx;
1567
+ if (!ctx) {
1568
+ return {
1569
+ name: "Agent",
1570
+ instructions: "",
1571
+ tools: []
1572
+ };
1573
+ }
1574
+ return {
1575
+ name: ctx.agentName ?? "Agent",
1576
+ sessionId: ctx.sessionId,
1577
+ instructions: ctx.config.instructions,
1578
+ maxSteps: ctx.config.maxSteps,
1579
+ tools: [...ctx.toolNames]
1580
+ };
1581
+ }
1582
+ cloneTask(taskId) {
1583
+ const task = this.taskQueue.get(taskId);
1584
+ if (!task) {
1585
+ throw new Error(`Task not found: ${taskId}`);
1586
+ }
1587
+ return task;
1588
+ }
1589
+ };
1590
+ function createA2APlugin(options) {
1591
+ return new A2APlugin(options);
1592
+ }
1593
+
1594
+ // src/adapters/validation/zod-validation.adapter.ts
1595
+ var ZodValidationAdapter = class {
1596
+ validate(schema, data) {
1597
+ const zodSchema = schema;
1598
+ const result = zodSchema.safeParse(data);
1599
+ if (result.success) {
1600
+ return { success: true, data: result.data };
1601
+ }
1602
+ return { success: false, error: result.error.message };
1603
+ }
1604
+ validateOrThrow(schema, data) {
1605
+ const zodSchema = schema;
1606
+ return zodSchema.parse(data);
1607
+ }
1608
+ };
1609
+
1610
+ // src/plugins/utils/get-validator.ts
1611
+ function getValidator(options) {
1612
+ return options.validator ?? new ZodValidationAdapter();
1613
+ }
1614
+
1615
+ // src/plugins/guardrails.plugin.ts
1616
+ var GuardrailsError = class extends Error {
1617
+ code;
1618
+ constructor(code, message) {
1619
+ super(message);
1620
+ this.name = "GuardrailsError";
1621
+ this.code = code;
1622
+ }
1623
+ };
1624
+ var GuardrailsPlugin = class extends BasePlugin {
1625
+ name = "guardrails";
1626
+ options;
1627
+ validator;
1628
+ constructor(options = {}) {
1629
+ super();
1630
+ this.validator = getValidator(options);
1631
+ this.options = {
1632
+ onFailure: options.onFailure ?? "throw",
1633
+ contentFilters: options.contentFilters ?? [],
1634
+ inputValidators: options.inputValidators ?? [],
1635
+ outputValidators: options.outputValidators ?? [],
1636
+ inputSchema: options.inputSchema,
1637
+ outputSchema: options.outputSchema,
1638
+ toolSchemas: options.toolSchemas
1639
+ };
1640
+ }
1641
+ buildHooks() {
1642
+ return {
1643
+ beforeRun: this.beforeRun.bind(this),
1644
+ afterRun: this.afterRun.bind(this),
1645
+ beforeTool: this.beforeTool.bind(this)
1646
+ };
1647
+ }
1648
+ // ── Hook implementations ──────────────────────────────────────────────────
1649
+ beforeRun(_ctx, params) {
1650
+ const { prompt } = params;
1651
+ for (const filter of this.options.contentFilters) {
1652
+ if (filter.test(prompt)) {
1653
+ this.fail("content_filter", `Content filter "${filter.name}" matched input`);
1654
+ }
1655
+ }
1656
+ for (const validator of this.options.inputValidators) {
1657
+ const error = validator(prompt);
1658
+ if (error) {
1659
+ this.fail("input_validation", error);
1660
+ }
1661
+ }
1662
+ if (this.options.inputSchema) {
1663
+ const result = this.validator.validate(this.options.inputSchema, prompt);
1664
+ if (!result.success) {
1665
+ this.fail("input_validation", `Input schema validation failed: ${result.error}`);
1666
+ }
1667
+ }
1668
+ return { prompt };
1669
+ }
1670
+ afterRun(_ctx, params) {
1671
+ const { text } = params.result;
1672
+ for (const filter of this.options.contentFilters) {
1673
+ if (filter.test(text)) {
1674
+ this.fail("content_filter", `Content filter "${filter.name}" matched output`);
1675
+ }
1676
+ }
1677
+ for (const validator of this.options.outputValidators) {
1678
+ const error = validator(text);
1679
+ if (error) {
1680
+ this.fail("output_validation", error);
1681
+ }
1682
+ }
1683
+ if (this.options.outputSchema) {
1684
+ const result = this.validator.validate(this.options.outputSchema, text);
1685
+ if (!result.success) {
1686
+ this.fail("output_validation", `Output schema validation failed: ${result.error}`);
1687
+ }
1688
+ }
1689
+ }
1690
+ beforeTool(_ctx, params) {
1691
+ const schema = this.options.toolSchemas?.[params.toolName];
1692
+ if (!schema) return;
1693
+ const result = this.validator.validate(schema, params.args);
1694
+ if (!result.success) {
1695
+ this.fail("tool_validation", `Tool "${params.toolName}" args validation failed: ${result.error}`);
1696
+ }
1697
+ }
1698
+ // ── Helpers ───────────────────────────────────────────────────────────────
1699
+ fail(code, message) {
1700
+ if (this.options.onFailure === "warn") {
1701
+ console.warn(`[guardrails] ${message}`);
1702
+ return;
1703
+ }
1704
+ throw new GuardrailsError(code, message);
1705
+ }
1706
+ };
1707
+ function createGuardrailsPlugin(options = {}) {
1708
+ return new GuardrailsPlugin(options);
1709
+ }
1710
+ function createPiiFilter() {
1711
+ return {
1712
+ name: "pii",
1713
+ test(content) {
1714
+ const patterns = [
1715
+ /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/,
1716
+ // email
1717
+ /\b\d{3}[-.]?\d{2}[-.]?\d{4}\b/,
1718
+ // SSN
1719
+ /\b\d{16}\b/
1720
+ // credit card (basic)
1721
+ ];
1722
+ return patterns.some((p) => p.test(content));
1723
+ }
1724
+ };
1725
+ }
1726
+
1727
+ // src/plugins/onecrawl.plugin.ts
1728
+ import { z as z3 } from "zod";
1729
+ var DEFAULT_REQUEST_TIMEOUT_MS2 = 3e4;
1730
+ var OneCrawlPlugin = class extends BasePlugin {
1731
+ name = "crawl";
1732
+ options;
1733
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1734
+ crawlerPromise = null;
1735
+ validator;
1736
+ constructor(options = {}) {
1737
+ super();
1738
+ this.options = options;
1739
+ this.validator = getValidator(options);
1740
+ }
1741
+ buildHooks() {
1742
+ return {};
1743
+ }
1744
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1745
+ getCrawler() {
1746
+ if (!this.crawlerPromise) {
1747
+ this.crawlerPromise = this.initCrawler();
1748
+ }
1749
+ return this.crawlerPromise;
1750
+ }
1751
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1752
+ async initCrawler() {
1753
+ if (this.options.crawler) {
1754
+ return this.options.crawler;
1755
+ }
1756
+ try {
1757
+ const mod = await import("onecrawl");
1758
+ const CrawlerClass = mod.Crawler ?? mod.default?.Crawler ?? mod.default;
1759
+ return new CrawlerClass({
1760
+ timeout: this.options.timeout ?? DEFAULT_REQUEST_TIMEOUT_MS2
1761
+ });
1762
+ } catch {
1763
+ throw new Error(
1764
+ 'OneCrawlPlugin requires "onecrawl" package. Install it: pnpm add onecrawl'
1765
+ );
1766
+ }
1767
+ }
1768
+ get tools() {
1769
+ const maxLen = this.options.maxContentLength ?? 1e4;
1770
+ const getCrawler = this.getCrawler.bind(this);
1771
+ const validator = this.validator;
1772
+ return {
1773
+ scrape: tool({
1774
+ description: "Scrape a web page and extract its text content",
1775
+ inputSchema: z3.object({
1776
+ url: z3.string().url().describe("The URL to scrape")
1777
+ }),
1778
+ execute: async (args) => {
1779
+ const { url } = validator.validateOrThrow(
1780
+ z3.object({ url: z3.string().url() }),
1781
+ args
1782
+ );
1783
+ const crawler = await getCrawler();
1784
+ const result = await crawler.crawl(url);
1785
+ const content = typeof result === "string" ? result : result?.content ?? result?.text ?? JSON.stringify(result);
1786
+ return content.length > maxLen ? content.slice(0, maxLen) + "\n...[truncated]" : content;
1787
+ }
1788
+ }),
1789
+ search: tool({
1790
+ description: "Search the web and return results",
1791
+ inputSchema: z3.object({
1792
+ query: z3.string().describe("The search query"),
1793
+ limit: z3.number().min(1).max(20).default(5).describe("Max results to return")
1794
+ }),
1795
+ execute: async (args) => {
1796
+ const { query, limit } = validator.validateOrThrow(
1797
+ z3.object({
1798
+ query: z3.string(),
1799
+ limit: z3.number().min(1).max(20).default(5)
1800
+ }),
1801
+ args
1802
+ );
1803
+ const crawler = await getCrawler();
1804
+ const results = await crawler.search(query, { limit });
1805
+ if (Array.isArray(results)) {
1806
+ return results.map((r) => ({
1807
+ title: r.title ?? "",
1808
+ url: r.url ?? r.link ?? "",
1809
+ snippet: r.snippet ?? r.description ?? ""
1810
+ }));
1811
+ }
1812
+ return results;
1813
+ }
1814
+ }),
1815
+ batch: tool({
1816
+ description: "Scrape multiple web pages in parallel",
1817
+ inputSchema: z3.object({
1818
+ urls: z3.array(z3.string().url()).min(1).max(10).describe("URLs to scrape")
1819
+ }),
1820
+ execute: async (args) => {
1821
+ const { urls } = validator.validateOrThrow(
1822
+ z3.object({ urls: z3.array(z3.string().url()).min(1).max(10) }),
1823
+ args
1824
+ );
1825
+ const crawler = await getCrawler();
1826
+ if (typeof crawler.batchCrawl === "function") {
1827
+ const results2 = await crawler.batchCrawl(urls);
1828
+ return Array.isArray(results2) ? results2.map((r, i) => ({
1829
+ url: urls[i],
1830
+ content: (typeof r === "string" ? r : r?.content ?? r?.text ?? "").slice(0, maxLen)
1831
+ })) : results2;
1832
+ }
1833
+ const results = await Promise.all(
1834
+ urls.map(async (u) => {
1835
+ try {
1836
+ const r = await crawler.crawl(u);
1837
+ const content = typeof r === "string" ? r : r?.content ?? r?.text ?? "";
1838
+ return { url: u, content: content.slice(0, maxLen) };
1839
+ } catch (error) {
1840
+ return { url: u, error: String(error) };
1841
+ }
1842
+ })
1843
+ );
1844
+ return results;
1845
+ }
1846
+ })
1847
+ };
1848
+ }
1849
+ async dispose() {
1850
+ if (this.crawlerPromise) {
1851
+ try {
1852
+ const crawler = await this.crawlerPromise;
1853
+ if (crawler && typeof crawler.close === "function") {
1854
+ await crawler.close();
1855
+ }
1856
+ } catch {
1857
+ }
1858
+ this.crawlerPromise = null;
1859
+ }
1860
+ }
1861
+ };
1862
+ function createOneCrawlPlugin(options = {}) {
1863
+ return new OneCrawlPlugin(options);
1864
+ }
1865
+
1866
+ // src/plugins/vectorless.plugin.ts
1867
+ import { z as z4 } from "zod";
1868
+
1869
+ // src/adapters/chunking/default-chunking.adapter.ts
1870
+ import { randomUUID } from "crypto";
1871
+ var DEFAULT_MAX_TOKENS = 512;
1872
+ var DEFAULT_OVERLAP = 50;
1873
+ var DEFAULT_SEPARATORS = ["\n\n", "\n", ". ", " "];
1874
+ function wordCount(text) {
1875
+ let count = 0;
1876
+ const re = /\S+/g;
1877
+ while (re.exec(text) !== null) count++;
1878
+ return count;
1879
+ }
1880
+ function makeChunk(text, index, startOffset, source) {
1881
+ return {
1882
+ id: randomUUID(),
1883
+ text,
1884
+ index,
1885
+ metadata: {
1886
+ startOffset,
1887
+ endOffset: startOffset + text.length,
1888
+ tokenCount: wordCount(text),
1889
+ source
1890
+ }
1891
+ };
1892
+ }
1893
+ function getWordPositions(text) {
1894
+ const positions = [];
1895
+ const regex = /\S+/g;
1896
+ let match;
1897
+ while ((match = regex.exec(text)) !== null) {
1898
+ positions.push({ word: match[0], start: match.index, end: match.index + match[0].length });
1899
+ }
1900
+ return positions;
1901
+ }
1902
+ function splitByWordsMax(text, maxTokens) {
1903
+ const words = text.split(/\s+/).filter(Boolean);
1904
+ const parts = [];
1905
+ for (let i = 0; i < words.length; i += maxTokens) {
1906
+ parts.push(words.slice(i, i + maxTokens).join(" "));
1907
+ }
1908
+ return parts;
1909
+ }
1910
+ function chunkFixed(text, maxTokens) {
1911
+ return splitByWordsMax(text, maxTokens);
1912
+ }
1913
+ function chunkSlidingWindow(text, maxTokens, overlap) {
1914
+ const words = text.split(/\s+/).filter(Boolean);
1915
+ if (words.length === 0) return [];
1916
+ const step = Math.max(1, maxTokens - overlap);
1917
+ const chunks = [];
1918
+ for (let i = 0; i < words.length; i += step) {
1919
+ chunks.push(words.slice(i, i + maxTokens).join(" "));
1920
+ if (i + maxTokens >= words.length) break;
1921
+ }
1922
+ return chunks;
1923
+ }
1924
+ function chunkSemantic(text, maxTokens) {
1925
+ const paragraphs = text.split(/\n\n+/).filter(Boolean);
1926
+ const chunks = [];
1927
+ let current = "";
1928
+ for (const para of paragraphs) {
1929
+ const candidate = current ? `${current}
1930
+
1931
+ ${para}` : para;
1932
+ const candidateWc = wordCount(candidate);
1933
+ if (candidateWc <= maxTokens) {
1934
+ current = candidate;
1935
+ } else {
1936
+ if (current) chunks.push(current);
1937
+ const paraWc = current ? wordCount(para) : candidateWc;
1938
+ if (paraWc > maxTokens) {
1939
+ const sentences = para.split(/(?<=[.!?])\s+/).filter(Boolean);
1940
+ let sentBuf = "";
1941
+ for (const s of sentences) {
1942
+ const next = sentBuf ? `${sentBuf} ${s}` : s;
1943
+ const nextWc = wordCount(next);
1944
+ if (nextWc <= maxTokens) {
1945
+ sentBuf = next;
1946
+ } else {
1947
+ if (sentBuf) chunks.push(sentBuf);
1948
+ const sWc = sentBuf ? wordCount(s) : nextWc;
1949
+ if (sWc > maxTokens) {
1950
+ chunks.push(...splitByWordsMax(s, maxTokens));
1951
+ sentBuf = "";
1952
+ } else {
1953
+ sentBuf = s;
1954
+ }
1955
+ }
1956
+ }
1957
+ current = sentBuf;
1958
+ } else {
1959
+ current = para;
1960
+ }
1961
+ }
1962
+ }
1963
+ if (current) chunks.push(current);
1964
+ return chunks;
1965
+ }
1966
+ function chunkRecursive(text, maxTokens, separators) {
1967
+ const wc = wordCount(text);
1968
+ if (wc <= maxTokens || separators.length === 0) {
1969
+ if (wc > maxTokens) return splitByWordsMax(text, maxTokens);
1970
+ return [text];
1971
+ }
1972
+ const sep = separators[0];
1973
+ const rest = separators.slice(1);
1974
+ const parts = text.split(sep).filter(Boolean);
1975
+ const results = [];
1976
+ let buffer = "";
1977
+ for (const part of parts) {
1978
+ const candidate = buffer ? `${buffer}${sep}${part}` : part;
1979
+ const candidateWc = wordCount(candidate);
1980
+ if (candidateWc <= maxTokens) {
1981
+ buffer = candidate;
1982
+ } else {
1983
+ if (buffer) results.push(buffer);
1984
+ const partWc = buffer ? wordCount(part) : candidateWc;
1985
+ if (partWc > maxTokens) {
1986
+ results.push(...chunkRecursive(part, maxTokens, rest));
1987
+ buffer = "";
1988
+ } else {
1989
+ buffer = part;
1990
+ }
1991
+ }
1992
+ }
1993
+ if (buffer) results.push(buffer);
1994
+ return results;
1995
+ }
1996
+ var DefaultChunkingAdapter = class {
1997
+ chunk(text, options) {
1998
+ if (!text || !text.trim()) return [];
1999
+ const strategy = options?.strategy ?? "fixed";
2000
+ const maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;
2001
+ const overlap = options?.overlap ?? DEFAULT_OVERLAP;
2002
+ const separators = options?.separators ?? DEFAULT_SEPARATORS;
2003
+ let rawChunks;
2004
+ switch (strategy) {
2005
+ case "fixed":
2006
+ rawChunks = chunkFixed(text, maxTokens);
2007
+ break;
2008
+ case "sliding-window":
2009
+ rawChunks = chunkSlidingWindow(text, maxTokens, overlap);
2010
+ break;
2011
+ case "semantic":
2012
+ rawChunks = chunkSemantic(text, maxTokens);
2013
+ break;
2014
+ case "recursive":
2015
+ rawChunks = chunkRecursive(text, maxTokens, separators);
2016
+ break;
2017
+ default:
2018
+ rawChunks = chunkFixed(text, maxTokens);
2019
+ }
2020
+ const wordPositions = getWordPositions(text);
2021
+ const chunks = [];
2022
+ let searchWordIdx = 0;
2023
+ for (let i = 0; i < rawChunks.length; i++) {
2024
+ const raw = rawChunks[i];
2025
+ const chunkWords = raw.split(/\s+/).filter(Boolean);
2026
+ if (chunkWords.length === 0) continue;
2027
+ let matchIdx = searchWordIdx;
2028
+ for (let j = searchWordIdx; j < wordPositions.length; j++) {
2029
+ if (wordPositions[j].word === chunkWords[0]) {
2030
+ matchIdx = j;
2031
+ break;
2032
+ }
2033
+ }
2034
+ const startPos = matchIdx < wordPositions.length ? wordPositions[matchIdx].start : 0;
2035
+ const lastWordIdx = Math.min(matchIdx + chunkWords.length - 1, wordPositions.length - 1);
2036
+ const endPos = lastWordIdx >= 0 ? wordPositions[lastWordIdx].end : startPos + raw.length;
2037
+ chunks.push(makeChunk(raw, i, startPos));
2038
+ chunks[chunks.length - 1].metadata.endOffset = endPos;
2039
+ searchWordIdx = matchIdx + 1;
2040
+ }
2041
+ return chunks;
2042
+ }
2043
+ };
2044
+
2045
+ // src/adapters/reranking/default-reranking.adapter.ts
2046
+ var K1 = 1.2;
2047
+ var B = 0.75;
2048
+ var PUNCTUATION_RE = /[^\w\s]/g;
2049
+ function tokenize(text) {
2050
+ return text.toLowerCase().replace(PUNCTUATION_RE, "").split(/\s+/).filter(Boolean);
2051
+ }
2052
+ function buildTermFrequencyMap(tokens) {
2053
+ const freq = /* @__PURE__ */ new Map();
2054
+ for (const t of tokens) {
2055
+ freq.set(t, (freq.get(t) ?? 0) + 1);
2056
+ }
2057
+ return freq;
2058
+ }
2059
+ function computeTfIdf(query, results) {
2060
+ const queryTokens = tokenize(query);
2061
+ const docTokenSets = results.map((r) => tokenize(r.text));
2062
+ const docFreqMaps = docTokenSets.map(buildTermFrequencyMap);
2063
+ const n = results.length;
2064
+ const idf = /* @__PURE__ */ new Map();
2065
+ for (const term of queryTokens) {
2066
+ let df = 0;
2067
+ for (const fm of docFreqMaps) {
2068
+ if (fm.has(term)) df++;
2069
+ }
2070
+ idf.set(term, Math.log((n + 1) / (df + 1)) + 1);
2071
+ }
2072
+ return results.map((r, i) => {
2073
+ const tokens = docTokenSets[i];
2074
+ const freqMap = docFreqMaps[i];
2075
+ let score = 0;
2076
+ for (const term of queryTokens) {
2077
+ const tf = (freqMap.get(term) ?? 0) / (tokens.length || 1);
2078
+ score += tf * (idf.get(term) ?? 0);
2079
+ }
2080
+ return { ...r, score };
2081
+ }).sort((a, b) => b.score - a.score);
2082
+ }
2083
+ function computeBm25(query, results) {
2084
+ const queryTokens = tokenize(query);
2085
+ const docTokenSets = results.map((r) => tokenize(r.text));
2086
+ const docFreqMaps = docTokenSets.map(buildTermFrequencyMap);
2087
+ const n = results.length;
2088
+ const avgDl = docTokenSets.reduce((sum, t) => sum + t.length, 0) / (n || 1) || 1;
2089
+ const idf = /* @__PURE__ */ new Map();
2090
+ for (const term of queryTokens) {
2091
+ let df = 0;
2092
+ for (const fm of docFreqMaps) {
2093
+ if (fm.has(term)) df++;
2094
+ }
2095
+ idf.set(term, Math.log((n - df + 0.5) / (df + 0.5) + 1));
2096
+ }
2097
+ return results.map((r, i) => {
2098
+ const tokens = docTokenSets[i];
2099
+ const freqMap = docFreqMaps[i];
2100
+ const dl = tokens.length;
2101
+ let score = 0;
2102
+ for (const term of queryTokens) {
2103
+ const tf = freqMap.get(term) ?? 0;
2104
+ const idfVal = idf.get(term) ?? 0;
2105
+ score += idfVal * (tf * (K1 + 1) / (tf + K1 * (1 - B + B * (dl / avgDl))));
2106
+ }
2107
+ return { ...r, score };
2108
+ }).sort((a, b) => b.score - a.score);
2109
+ }
2110
+ function cosineSimilarity(a, b) {
2111
+ const denom = a.norm * b.norm;
2112
+ if (denom === 0) return 0;
2113
+ const [small, large] = a.vec.size <= b.vec.size ? [a.vec, b.vec] : [b.vec, a.vec];
2114
+ let dot = 0;
2115
+ for (const [k, v] of small) {
2116
+ const other = large.get(k);
2117
+ if (other !== void 0) dot += v * other;
2118
+ }
2119
+ return dot / denom;
2120
+ }
2121
+ function toTfVector(tokens) {
2122
+ const freqMap = buildTermFrequencyMap(tokens);
2123
+ const len = tokens.length;
2124
+ let normSq = 0;
2125
+ for (const [k, v] of freqMap) {
2126
+ const tf = v / len;
2127
+ freqMap.set(k, tf);
2128
+ normSq += tf * tf;
2129
+ }
2130
+ return { vec: freqMap, norm: Math.sqrt(normSq) };
2131
+ }
2132
+ function computeMmr(query, results, lambda) {
2133
+ if (results.length === 0) return [];
2134
+ const queryVec = toTfVector(tokenize(query));
2135
+ const docVecs = results.map((r) => toTfVector(tokenize(r.text)));
2136
+ const relevances = docVecs.map((dv) => cosineSimilarity(queryVec, dv));
2137
+ const pairwiseSim = /* @__PURE__ */ new Map();
2138
+ const pairKey = (i, j) => i < j ? `${i},${j}` : `${j},${i}`;
2139
+ const selected = [];
2140
+ const remaining = new Set(results.map((_, i) => i));
2141
+ const reranked = [];
2142
+ while (remaining.size > 0) {
2143
+ let bestIdx = -1;
2144
+ let bestScore = -Infinity;
2145
+ for (const idx of remaining) {
2146
+ const rel = relevances[idx];
2147
+ let maxSim = 0;
2148
+ for (const selIdx of selected) {
2149
+ const key = pairKey(idx, selIdx);
2150
+ let sim = pairwiseSim.get(key);
2151
+ if (sim === void 0) {
2152
+ sim = cosineSimilarity(docVecs[idx], docVecs[selIdx]);
2153
+ pairwiseSim.set(key, sim);
2154
+ }
2155
+ if (sim > maxSim) maxSim = sim;
2156
+ }
2157
+ const mmrScore = lambda * rel - (1 - lambda) * maxSim;
2158
+ if (mmrScore > bestScore) {
2159
+ bestScore = mmrScore;
2160
+ bestIdx = idx;
2161
+ }
2162
+ }
2163
+ if (bestIdx >= 0) {
2164
+ selected.push(bestIdx);
2165
+ remaining.delete(bestIdx);
2166
+ reranked.push({ ...results[bestIdx], score: bestScore });
2167
+ }
2168
+ }
2169
+ return reranked;
2170
+ }
2171
+ var DefaultReRankingAdapter = class {
2172
+ rerank(query, results, options) {
2173
+ if (results.length === 0) return [];
2174
+ const strategy = options?.strategy ?? "bm25";
2175
+ switch (strategy) {
2176
+ case "tfidf":
2177
+ return computeTfIdf(query, results);
2178
+ case "bm25":
2179
+ return computeBm25(query, results);
2180
+ case "mmr":
2181
+ return computeMmr(query, results, options?.lambda ?? 0.7);
2182
+ default:
2183
+ return computeBm25(query, results);
2184
+ }
2185
+ }
2186
+ };
2187
+
2188
+ // src/plugins/vectorless.plugin.ts
2189
+ var DEFAULT_MAX_TOKENS_PER_CHUNK = 512;
2190
+ var VectorlessPlugin = class extends BasePlugin {
2191
+ name = "knowledge";
2192
+ options;
2193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2194
+ vectorlessPromise = null;
2195
+ currentKnowledge = null;
2196
+ validator;
2197
+ chunks = /* @__PURE__ */ new Map();
2198
+ chunkingAdapter;
2199
+ rerankingAdapter;
2200
+ _toolsCache;
2201
+ constructor(options = {}) {
2202
+ super();
2203
+ this.options = options;
2204
+ this.currentKnowledge = options.knowledgeBase ?? null;
2205
+ this.validator = getValidator(options);
2206
+ this.chunkingAdapter = options.chunkingAdapter ?? new DefaultChunkingAdapter();
2207
+ this.rerankingAdapter = options.rerankingAdapter ?? new DefaultReRankingAdapter();
2208
+ }
2209
+ buildHooks() {
2210
+ return {};
2211
+ }
2212
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2213
+ getVectorless() {
2214
+ if (!this.vectorlessPromise) {
2215
+ this.vectorlessPromise = this.initVectorless();
2216
+ }
2217
+ return this.vectorlessPromise;
2218
+ }
2219
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2220
+ async initVectorless() {
2221
+ if (this.options.vectorless) {
2222
+ return this.options.vectorless;
2223
+ }
2224
+ try {
2225
+ const mod = await import("@giulio-leone/gaussflow-vectorless");
2226
+ return mod.default ?? mod;
2227
+ } catch {
2228
+ throw new Error(
2229
+ 'VectorlessPlugin requires "@giulio-leone/gaussflow-vectorless" package. Install it: pnpm add @giulio-leone/gaussflow-vectorless'
2230
+ );
2231
+ }
2232
+ }
2233
+ get tools() {
2234
+ if (this._toolsCache) return this._toolsCache;
2235
+ const getVectorless = this.getVectorless.bind(this);
2236
+ const getKnowledge = () => this.currentKnowledge;
2237
+ const setKnowledge = (k) => {
2238
+ this.currentKnowledge = k;
2239
+ };
2240
+ const mergeKnowledge = (newK) => {
2241
+ const existing = this.currentKnowledge;
2242
+ const incoming = newK;
2243
+ if (!existing || !incoming) {
2244
+ this.currentKnowledge = incoming ?? existing;
2245
+ return;
2246
+ }
2247
+ const merged = { ...existing };
2248
+ for (const key of ["entities", "relations", "quotes"]) {
2249
+ const a = Array.isArray(existing[key]) ? existing[key] : [];
2250
+ const b = Array.isArray(incoming[key]) ? incoming[key] : [];
2251
+ if (a.length > 0 || b.length > 0) merged[key] = [...a, ...b];
2252
+ }
2253
+ this.currentKnowledge = merged;
2254
+ };
2255
+ const validator = this.validator;
2256
+ const chunks = this.chunks;
2257
+ const chunkingAdapter = this.chunkingAdapter;
2258
+ const rerankingAdapter = this.rerankingAdapter;
2259
+ const toolsMap = {
2260
+ generate: tool({
2261
+ description: "Extract knowledge (entities, relations, quotes) from text. Must be called before query/search.",
2262
+ inputSchema: z4.object({
2263
+ text: z4.string().describe("The text to extract knowledge from"),
2264
+ topic: z4.string().optional().describe("Optional topic to focus extraction on")
2265
+ }),
2266
+ execute: async (args) => {
2267
+ const { text, topic } = validator.validateOrThrow(
2268
+ z4.object({
2269
+ text: z4.string(),
2270
+ topic: z4.string().optional()
2271
+ }),
2272
+ args
2273
+ );
2274
+ const vl = await getVectorless();
2275
+ const generate = vl.generateKnowledge ?? vl.generate ?? vl.extract;
2276
+ if (!generate) throw new Error("vectorless: generateKnowledge function not found");
2277
+ const knowledge = await generate(text, { topic });
2278
+ setKnowledge(knowledge);
2279
+ const summary = {
2280
+ entities: Array.isArray(knowledge?.entities) ? knowledge.entities.length : 0,
2281
+ relations: Array.isArray(knowledge?.relations) ? knowledge.relations.length : 0,
2282
+ quotes: Array.isArray(knowledge?.quotes) ? knowledge.quotes.length : 0
2283
+ };
2284
+ return `Knowledge extracted: ${summary.entities} entities, ${summary.relations} relations, ${summary.quotes} quotes`;
2285
+ }
2286
+ }),
2287
+ query: tool({
2288
+ description: "Answer a question using the extracted knowledge base",
2289
+ inputSchema: z4.object({
2290
+ question: z4.string().describe("The question to answer")
2291
+ }),
2292
+ execute: async (args) => {
2293
+ const { question } = validator.validateOrThrow(
2294
+ z4.object({ question: z4.string() }),
2295
+ args
2296
+ );
2297
+ const knowledge = getKnowledge();
2298
+ if (!knowledge) return "No knowledge base loaded. Use knowledge:generate first.";
2299
+ const vl = await getVectorless();
2300
+ const query = vl.queryKnowledge ?? vl.query ?? vl.ask;
2301
+ if (!query) throw new Error("vectorless: queryKnowledge function not found");
2302
+ const result = await query(question, knowledge);
2303
+ return typeof result === "string" ? result : JSON.stringify(result);
2304
+ }
2305
+ }),
2306
+ "search-entities": tool({
2307
+ description: "Search for entities in the extracted knowledge base",
2308
+ inputSchema: z4.object({
2309
+ query: z4.string().describe("Search query for entities"),
2310
+ limit: z4.number().min(1).max(50).default(10).describe("Max results")
2311
+ }),
2312
+ execute: async (args) => {
2313
+ const { query, limit } = validator.validateOrThrow(
2314
+ z4.object({
2315
+ query: z4.string(),
2316
+ limit: z4.number().min(1).max(50).default(10)
2317
+ }),
2318
+ args
2319
+ );
2320
+ const knowledge = getKnowledge();
2321
+ if (!knowledge) return "No knowledge base loaded. Use knowledge:generate first.";
2322
+ const vl = await getVectorless();
2323
+ if (typeof vl.searchEntities === "function") {
2324
+ return await vl.searchEntities(query, knowledge, { limit });
2325
+ }
2326
+ const kb = knowledge;
2327
+ const entities = Array.isArray(kb?.entities) ? kb.entities : [];
2328
+ const lower = query.toLowerCase();
2329
+ return entities.filter((e) => (e.name ?? e.label ?? "").toLowerCase().includes(lower)).slice(0, limit);
2330
+ }
2331
+ }),
2332
+ list: tool({
2333
+ description: "List all entities in the current knowledge base",
2334
+ inputSchema: z4.object({}),
2335
+ execute: async () => {
2336
+ const knowledge = getKnowledge();
2337
+ if (!knowledge) return "No knowledge base loaded. Use knowledge:generate first.";
2338
+ const kb = knowledge;
2339
+ const entities = Array.isArray(kb.entities) ? kb.entities : [];
2340
+ return entities.map((e) => ({
2341
+ name: e.name ?? e.label ?? "unknown",
2342
+ type: e.type ?? e.category ?? "unknown"
2343
+ }));
2344
+ }
2345
+ }),
2346
+ // ─── Advanced RAG tools ──────────────────────────────────────────
2347
+ "rag:ingest": tool({
2348
+ description: "Chunk a document and extract knowledge from each chunk",
2349
+ inputSchema: z4.object({
2350
+ text: z4.string().describe("The document text to ingest"),
2351
+ source: z4.string().optional().describe("Source identifier for attribution"),
2352
+ chunkingStrategy: z4.enum(["fixed", "sliding-window", "semantic", "recursive"]).default("recursive").describe("Chunking strategy"),
2353
+ maxTokens: z4.number().min(1).default(DEFAULT_MAX_TOKENS_PER_CHUNK).describe("Max tokens per chunk"),
2354
+ overlap: z4.number().min(0).default(50).describe("Token overlap for sliding-window")
2355
+ }),
2356
+ execute: async (args) => {
2357
+ const { text, source, chunkingStrategy, maxTokens, overlap } = validator.validateOrThrow(
2358
+ z4.object({
2359
+ text: z4.string(),
2360
+ source: z4.string().optional(),
2361
+ chunkingStrategy: z4.enum(["fixed", "sliding-window", "semantic", "recursive"]).default("recursive"),
2362
+ maxTokens: z4.number().min(1).default(DEFAULT_MAX_TOKENS_PER_CHUNK),
2363
+ overlap: z4.number().min(0).default(50)
2364
+ }),
2365
+ args
2366
+ );
2367
+ const produced = chunkingAdapter.chunk(text, {
2368
+ strategy: chunkingStrategy,
2369
+ maxTokens,
2370
+ overlap
2371
+ });
2372
+ for (const c of produced) {
2373
+ c.metadata.source = source;
2374
+ chunks.set(c.id, c);
2375
+ }
2376
+ try {
2377
+ const vl = await getVectorless();
2378
+ const generate = vl.generateKnowledge ?? vl.generate ?? vl.extract;
2379
+ if (generate) {
2380
+ const knowledge = await generate(text, { topic: source });
2381
+ mergeKnowledge(knowledge);
2382
+ }
2383
+ } catch {
2384
+ }
2385
+ return `Ingested ${produced.length} chunks (strategy: ${chunkingStrategy}, maxTokens: ${maxTokens})${source ? ` from "${source}"` : ""}`;
2386
+ }
2387
+ }),
2388
+ "rag:search": tool({
2389
+ description: "Hybrid search: combine entity search + keyword search, then re-rank results",
2390
+ inputSchema: z4.object({
2391
+ query: z4.string().describe("Search query"),
2392
+ limit: z4.number().min(1).max(100).default(10).describe("Max results"),
2393
+ rerankerStrategy: z4.enum(["tfidf", "bm25", "mmr"]).default("bm25").describe("Re-ranking strategy"),
2394
+ includeAttribution: z4.boolean().default(true).describe("Include source attribution")
2395
+ }),
2396
+ execute: async (args) => {
2397
+ const { query, limit, rerankerStrategy, includeAttribution } = validator.validateOrThrow(
2398
+ z4.object({
2399
+ query: z4.string(),
2400
+ limit: z4.number().min(1).max(100).default(10),
2401
+ rerankerStrategy: z4.enum(["tfidf", "bm25", "mmr"]).default("bm25"),
2402
+ includeAttribution: z4.boolean().default(true)
2403
+ }),
2404
+ args
2405
+ );
2406
+ const candidates = [];
2407
+ const queryLower = query.toLowerCase();
2408
+ const queryWords = queryLower.split(/\s+/);
2409
+ const knowledge = getKnowledge();
2410
+ if (knowledge) {
2411
+ const kb = knowledge;
2412
+ const entities = Array.isArray(kb?.entities) ? kb.entities : [];
2413
+ for (const e of entities) {
2414
+ const name = (e.name ?? e.label ?? "").toLowerCase();
2415
+ if (name.includes(queryLower) || queryLower.includes(name)) {
2416
+ candidates.push({
2417
+ id: `entity:${e.name ?? e.label}`,
2418
+ text: `${e.name ?? e.label} (${e.type ?? e.category ?? "unknown"})`,
2419
+ score: 0
2420
+ });
2421
+ }
2422
+ }
2423
+ }
2424
+ for (const [, chunk] of chunks) {
2425
+ const chunkLower = chunk.text.toLowerCase();
2426
+ if (chunkLower.includes(queryLower) || queryWords.some((w) => chunkLower.includes(w))) {
2427
+ const result = {
2428
+ id: chunk.id,
2429
+ text: chunk.text,
2430
+ score: 0
2431
+ };
2432
+ if (includeAttribution) {
2433
+ result.source = {
2434
+ chunkId: chunk.id,
2435
+ chunkIndex: chunk.index,
2436
+ documentId: chunk.metadata.source,
2437
+ startOffset: chunk.metadata.startOffset,
2438
+ endOffset: chunk.metadata.endOffset,
2439
+ relevanceScore: 0
2440
+ };
2441
+ }
2442
+ candidates.push(result);
2443
+ }
2444
+ }
2445
+ if (candidates.length === 0) return [];
2446
+ const reranked = rerankingAdapter.rerank(query, candidates, {
2447
+ strategy: rerankerStrategy
2448
+ });
2449
+ const top = reranked.slice(0, limit);
2450
+ for (const r of top) {
2451
+ if (r.source) r.source.relevanceScore = r.score;
2452
+ }
2453
+ return top;
2454
+ }
2455
+ }),
2456
+ "rag:search-chunks": tool({
2457
+ description: "Search directly against stored chunks",
2458
+ inputSchema: z4.object({
2459
+ query: z4.string().describe("Search query"),
2460
+ limit: z4.number().min(1).max(100).default(10).describe("Max results")
2461
+ }),
2462
+ execute: async (args) => {
2463
+ const { query, limit } = validator.validateOrThrow(
2464
+ z4.object({
2465
+ query: z4.string(),
2466
+ limit: z4.number().min(1).max(100).default(10)
2467
+ }),
2468
+ args
2469
+ );
2470
+ const queryWords = query.toLowerCase().split(/\s+/).filter(Boolean);
2471
+ const results = [];
2472
+ for (const [, chunk] of chunks) {
2473
+ const chunkLower = chunk.text.toLowerCase();
2474
+ const matchCount = queryWords.filter((w) => chunkLower.includes(w)).length;
2475
+ if (matchCount > 0) {
2476
+ results.push({ ...chunk, matchScore: matchCount / queryWords.length });
2477
+ }
2478
+ }
2479
+ return results.sort((a, b) => b.matchScore - a.matchScore).slice(0, limit).map(({ matchScore, ...chunk }) => chunk);
2480
+ }
2481
+ })
2482
+ };
2483
+ this._toolsCache = toolsMap;
2484
+ return toolsMap;
2485
+ }
2486
+ async dispose() {
2487
+ this.currentKnowledge = null;
2488
+ this.vectorlessPromise = null;
2489
+ this.chunks.clear();
2490
+ this._toolsCache = void 0;
2491
+ }
2492
+ };
2493
+ function createVectorlessPlugin(options = {}) {
2494
+ return new VectorlessPlugin(options);
2495
+ }
2496
+
2497
+ // src/plugins/evals.plugin.ts
2498
+ var EvalsPlugin = class extends BasePlugin {
2499
+ name = "evals";
2500
+ options;
2501
+ results = [];
2502
+ runStates = /* @__PURE__ */ new Map();
2503
+ constructor(options = {}) {
2504
+ super();
2505
+ this.options = options;
2506
+ }
2507
+ buildHooks() {
2508
+ return {
2509
+ beforeRun: this.beforeRun.bind(this),
2510
+ afterRun: this.afterRun.bind(this),
2511
+ afterTool: this.afterTool.bind(this),
2512
+ onError: this.onError.bind(this)
2513
+ };
2514
+ }
2515
+ beforeRun(ctx, params) {
2516
+ this.runStates.set(ctx.sessionId, {
2517
+ startTime: Date.now(),
2518
+ prompt: params.prompt,
2519
+ toolCallCounts: {}
2520
+ });
2521
+ }
2522
+ async afterRun(ctx, params) {
2523
+ const state = this.runStates.get(ctx.sessionId);
2524
+ const latencyMs = state ? Date.now() - state.startTime : 0;
2525
+ const prompt = state?.prompt ?? "";
2526
+ const toolCalls = state ? { ...state.toolCallCounts } : {};
2527
+ this.runStates.delete(ctx.sessionId);
2528
+ const steps = params.result.steps;
2529
+ let promptTokens = 0;
2530
+ let completionTokens = 0;
2531
+ for (const step of steps) {
2532
+ const usage = step?.usage;
2533
+ if (usage) {
2534
+ promptTokens += usage.promptTokens ?? 0;
2535
+ completionTokens += usage.completionTokens ?? 0;
2536
+ }
2537
+ }
2538
+ const metrics = {
2539
+ latencyMs,
2540
+ stepCount: steps.length,
2541
+ toolCalls,
2542
+ tokenUsage: {
2543
+ prompt: promptTokens,
2544
+ completion: completionTokens,
2545
+ total: promptTokens + completionTokens
2546
+ },
2547
+ customScores: {}
2548
+ };
2549
+ for (const scorer of this.options.scorers ?? []) {
2550
+ try {
2551
+ metrics.customScores[scorer.name] = await scorer.score(
2552
+ prompt,
2553
+ params.result.text,
2554
+ metrics
2555
+ );
2556
+ } catch {
2557
+ metrics.customScores[scorer.name] = -1;
2558
+ }
2559
+ }
2560
+ const evalResult = {
2561
+ id: crypto.randomUUID(),
2562
+ sessionId: params.result.sessionId,
2563
+ prompt,
2564
+ output: params.result.text,
2565
+ metrics,
2566
+ createdAt: Date.now()
2567
+ };
2568
+ this.results.push(evalResult);
2569
+ if (this.options.persist) {
2570
+ await ctx.memory.saveMetadata(
2571
+ ctx.sessionId,
2572
+ `eval:${evalResult.id}`,
2573
+ evalResult
2574
+ );
2575
+ }
2576
+ if (this.options.onEval) {
2577
+ await this.options.onEval(evalResult);
2578
+ }
2579
+ }
2580
+ afterTool(ctx, params) {
2581
+ const state = this.runStates.get(ctx.sessionId);
2582
+ if (state) {
2583
+ state.toolCallCounts[params.toolName] = (state.toolCallCounts[params.toolName] ?? 0) + 1;
2584
+ }
2585
+ }
2586
+ onError(ctx, params) {
2587
+ if (params.phase === "run") {
2588
+ this.runStates.delete(ctx.sessionId);
2589
+ }
2590
+ }
2591
+ /** Get all collected eval results */
2592
+ getResults() {
2593
+ return this.results;
2594
+ }
2595
+ /** Get the most recent eval result */
2596
+ getLastResult() {
2597
+ return this.results[this.results.length - 1];
2598
+ }
2599
+ /** Clear collected results */
2600
+ clearResults() {
2601
+ this.results.length = 0;
2602
+ }
2603
+ };
2604
+ function createEvalsPlugin(options = {}) {
2605
+ return new EvalsPlugin(options);
2606
+ }
2607
+
2608
+ // src/adapters/workflow/default-workflow.engine.ts
2609
+ var DEFAULT_RETRY = {
2610
+ maxAttempts: 3,
2611
+ backoffMs: 1e3,
2612
+ backoffMultiplier: 2
2613
+ };
2614
+ var DEFAULT_MAX_ITERATIONS = 10;
2615
+ var DEFAULT_MAX_CONCURRENCY = 1;
2616
+ var DefaultWorkflowEngine = class {
2617
+ agentExecutor;
2618
+ onEvent;
2619
+ constructor(options = {}) {
2620
+ this.agentExecutor = options.agentExecutor;
2621
+ this.onEvent = options.onEvent;
2622
+ }
2623
+ async execute(definition, context) {
2624
+ const start = Date.now();
2625
+ let ctx = structuredClone(definition.initialContext ?? {});
2626
+ if (context) {
2627
+ ctx = { ...ctx, ...structuredClone(context) };
2628
+ }
2629
+ const completedSteps = [];
2630
+ const skippedSteps = [];
2631
+ const executedRegistry = /* @__PURE__ */ new Map();
2632
+ const timeoutMs = definition.maxDurationMs;
2633
+ const deadline = timeoutMs ? start + timeoutMs : void 0;
2634
+ for (const step of definition.steps) {
2635
+ if (deadline && Date.now() >= deadline) {
2636
+ await this.rollbackSteps(executedRegistry, completedSteps, ctx);
2637
+ return {
2638
+ status: "failed",
2639
+ context: ctx,
2640
+ completedSteps,
2641
+ skippedSteps,
2642
+ failedStep: step.id,
2643
+ error: `Workflow timeout exceeded (${timeoutMs}ms)`,
2644
+ totalDurationMs: Date.now() - start
2645
+ };
2646
+ }
2647
+ try {
2648
+ const stepResult = await this.executeStep(step, ctx, completedSteps, skippedSteps, executedRegistry, deadline);
2649
+ if (skippedSteps.includes(step.id)) {
2650
+ continue;
2651
+ }
2652
+ ctx = stepResult;
2653
+ completedSteps.push(step.id);
2654
+ } catch (error) {
2655
+ await this.rollbackSteps(executedRegistry, completedSteps, ctx);
2656
+ return {
2657
+ status: "failed",
2658
+ context: ctx,
2659
+ completedSteps,
2660
+ skippedSteps,
2661
+ failedStep: step.id,
2662
+ error: error instanceof Error ? error.message : String(error),
2663
+ totalDurationMs: Date.now() - start
2664
+ };
2665
+ }
2666
+ }
2667
+ return {
2668
+ status: "completed",
2669
+ context: ctx,
2670
+ completedSteps,
2671
+ skippedSteps,
2672
+ totalDurationMs: Date.now() - start
2673
+ };
2674
+ }
2675
+ validate(definition) {
2676
+ const errors = [];
2677
+ if (!definition.id) errors.push("Workflow must have an id");
2678
+ if (!definition.name) errors.push("Workflow must have a name");
2679
+ if (!definition.steps || !Array.isArray(definition.steps)) {
2680
+ errors.push("Workflow must have a steps array");
2681
+ } else if (definition.steps.length === 0) {
2682
+ errors.push("Workflow must have at least one step");
2683
+ }
2684
+ const ids = /* @__PURE__ */ new Set();
2685
+ for (const step of definition.steps ?? []) {
2686
+ if (!step.id) errors.push("Every step must have an id");
2687
+ if (!step.name) errors.push(`Step "${step.id}" must have a name`);
2688
+ if (ids.has(step.id)) errors.push(`Duplicate step id: "${step.id}"`);
2689
+ ids.add(step.id);
2690
+ this.validateStep(step, errors);
2691
+ }
2692
+ if (definition.maxDurationMs !== void 0 && definition.maxDurationMs <= 0) {
2693
+ errors.push("maxDurationMs must be positive");
2694
+ }
2695
+ return { valid: errors.length === 0, errors };
2696
+ }
2697
+ // ── Step execution ──────────────────────────────────────────────────────
2698
+ async executeStep(step, ctx, completedSteps, skippedSteps, registry, deadline) {
2699
+ this.emit({ type: "step:start", stepId: step.id, stepName: step.name, timestamp: Date.now() });
2700
+ try {
2701
+ let result;
2702
+ if (this.isParallelStep(step)) {
2703
+ result = await this.executeParallel(step, ctx, registry, deadline);
2704
+ } else if (this.isConditionalStep(step)) {
2705
+ result = await this.executeConditional(step, ctx, completedSteps, skippedSteps, registry, deadline);
2706
+ } else if (this.isLoopStep(step)) {
2707
+ result = await this.executeLoop(step, ctx, registry, deadline);
2708
+ } else if (this.isForeachStep(step)) {
2709
+ result = await this.executeForeach(step, ctx, registry, deadline);
2710
+ } else if (this.isMapStep(step)) {
2711
+ result = await this.executeMap(step, ctx, registry, deadline);
2712
+ } else if (this.isAgentStep(step)) {
2713
+ result = await this.executeAgent(step, ctx);
2714
+ if ("rollback" in step && typeof step.rollback === "function") {
2715
+ registry.set(step.id, step);
2716
+ }
2717
+ } else {
2718
+ const ws = step;
2719
+ if (ws.condition && !ws.condition(ctx)) {
2720
+ skippedSteps.push(step.id);
2721
+ this.emit({ type: "step:complete", stepId: step.id, stepName: step.name, timestamp: Date.now(), context: ctx });
2722
+ return ctx;
2723
+ }
2724
+ const projectedCtx = this.applyInputMapping(ws, ctx);
2725
+ const rawResult = await this.executeWithRetry(ws, projectedCtx);
2726
+ result = ws.inputMapping ? { ...ctx, ...rawResult } : rawResult;
2727
+ result = this.applyOutputMappings(ws, result);
2728
+ if (ws.rollback) {
2729
+ registry.set(step.id, ws);
2730
+ }
2731
+ }
2732
+ this.emit({ type: "step:complete", stepId: step.id, stepName: step.name, timestamp: Date.now(), context: result });
2733
+ return result;
2734
+ } catch (error) {
2735
+ const errMsg = error instanceof Error ? error.message : String(error);
2736
+ this.emit({ type: "step:error", stepId: step.id, stepName: step.name, timestamp: Date.now(), error: errMsg });
2737
+ throw error;
2738
+ }
2739
+ }
2740
+ async executeParallel(step, ctx, registry, deadline) {
2741
+ const strategy = step.mergeStrategy ?? "all";
2742
+ const branchCtx = structuredClone(ctx);
2743
+ const wrapWithTimeout = (promise) => {
2744
+ if (!deadline) return promise;
2745
+ const remaining = deadline - Date.now();
2746
+ if (remaining <= 0) return Promise.reject(new Error("Workflow timeout exceeded"));
2747
+ let timer;
2748
+ const timeoutPromise = new Promise((_, reject) => {
2749
+ timer = setTimeout(() => reject(new Error("Workflow timeout exceeded")), remaining);
2750
+ });
2751
+ return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timer));
2752
+ };
2753
+ const promises = step.branches.map((branch) => {
2754
+ if (branch.rollback) registry.set(branch.id, branch);
2755
+ return wrapWithTimeout(this.executeWithRetry(branch, structuredClone(branchCtx)));
2756
+ });
2757
+ if (strategy === "race") {
2758
+ return await Promise.race(promises);
2759
+ }
2760
+ if (strategy === "first") {
2761
+ return await Promise.any(promises);
2762
+ }
2763
+ const results = await Promise.all(promises);
2764
+ let merged = structuredClone(ctx);
2765
+ for (const r of results) {
2766
+ merged = { ...merged, ...r };
2767
+ }
2768
+ return merged;
2769
+ }
2770
+ async executeConditional(step, ctx, completedSteps, skippedSteps, registry, deadline) {
2771
+ if (step.condition(ctx)) {
2772
+ return this.executeStep(step.ifTrue, structuredClone(ctx), completedSteps, skippedSteps, registry, deadline);
2773
+ } else if (step.ifFalse) {
2774
+ return this.executeStep(step.ifFalse, structuredClone(ctx), completedSteps, skippedSteps, registry, deadline);
2775
+ }
2776
+ return ctx;
2777
+ }
2778
+ async executeLoop(step, ctx, registry, deadline) {
2779
+ const maxIter = step.maxIterations ?? DEFAULT_MAX_ITERATIONS;
2780
+ let current = structuredClone(ctx);
2781
+ if (step.body.rollback) {
2782
+ registry.set(step.body.id, step.body);
2783
+ }
2784
+ for (let i = 0; i < maxIter; i++) {
2785
+ if (!step.condition(current)) break;
2786
+ if (deadline && Date.now() >= deadline) {
2787
+ throw new Error("Workflow timeout exceeded");
2788
+ }
2789
+ current = await this.executeWithRetry(step.body, current);
2790
+ }
2791
+ return current;
2792
+ }
2793
+ async executeForeach(step, ctx, registry, deadline) {
2794
+ const iterable = this.getByPath(ctx, step.iterable);
2795
+ if (!Array.isArray(iterable)) {
2796
+ throw new Error(`Foreach step "${step.id}": iterable path "${step.iterable}" is not an array`);
2797
+ }
2798
+ const maxIter = step.maxIterations ? Math.min(step.maxIterations, iterable.length) : iterable.length;
2799
+ const items = iterable.slice(0, maxIter);
2800
+ const itemKey = step.itemKey ?? "item";
2801
+ const indexKey = step.indexKey ?? "index";
2802
+ const outputs = await this.executeItemsWithConcurrency(
2803
+ items,
2804
+ step.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY,
2805
+ async (item, index) => {
2806
+ if (deadline && Date.now() >= deadline) {
2807
+ throw new Error("Workflow timeout exceeded");
2808
+ }
2809
+ const itemCtx = {
2810
+ ...ctx,
2811
+ [itemKey]: item,
2812
+ [indexKey]: index
2813
+ };
2814
+ if (step.step.rollback) {
2815
+ registry.set(step.step.id, step.step);
2816
+ }
2817
+ const projectedCtx = this.applyInputMapping(step.step, itemCtx);
2818
+ const rawResult = await this.executeWithRetry(step.step, projectedCtx);
2819
+ const mergedResult = step.step.inputMapping ? { ...itemCtx, ...rawResult } : rawResult;
2820
+ const mappedResult = this.applyOutputMappings(step.step, mergedResult);
2821
+ return this.extractStepOutput(mappedResult, step.step.id);
2822
+ }
2823
+ );
2824
+ const aggregateKey = step.aggregateOutputKey ?? step.id;
2825
+ return {
2826
+ ...ctx,
2827
+ [aggregateKey]: this.aggregateOutputs(outputs, step.aggregationMode ?? "array")
2828
+ };
2829
+ }
2830
+ async executeMap(step, ctx, registry, deadline) {
2831
+ const source = this.getByPath(ctx, step.input);
2832
+ if (!Array.isArray(source)) {
2833
+ throw new Error(`Map step "${step.id}": input path "${step.input}" is not an array`);
2834
+ }
2835
+ const filtered = source.filter(
2836
+ (item, index) => step.filter ? step.filter(item, index, ctx) : true
2837
+ );
2838
+ const itemKey = step.itemKey ?? "item";
2839
+ const indexKey = step.indexKey ?? "index";
2840
+ const transformed = await this.executeItemsWithConcurrency(
2841
+ filtered,
2842
+ step.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY,
2843
+ async (item, index) => {
2844
+ if (deadline && Date.now() >= deadline) {
2845
+ throw new Error("Workflow timeout exceeded");
2846
+ }
2847
+ const itemCtx = {
2848
+ ...ctx,
2849
+ [itemKey]: item,
2850
+ [indexKey]: index
2851
+ };
2852
+ if (step.transform.rollback) {
2853
+ registry.set(step.transform.id, step.transform);
2854
+ }
2855
+ const projectedCtx = this.applyInputMapping(step.transform, itemCtx);
2856
+ const rawResult = await this.executeWithRetry(step.transform, projectedCtx);
2857
+ const mergedResult = step.transform.inputMapping ? { ...itemCtx, ...rawResult } : rawResult;
2858
+ const mappedResult = this.applyOutputMappings(step.transform, mergedResult);
2859
+ return this.extractStepOutput(mappedResult, step.transform.id);
2860
+ }
2861
+ );
2862
+ return {
2863
+ ...ctx,
2864
+ [step.outputKey]: transformed
2865
+ };
2866
+ }
2867
+ async executeAgent(step, ctx) {
2868
+ if (step.execute) {
2869
+ return this.executeWithRetry(step, ctx);
2870
+ }
2871
+ if (!this.agentExecutor) {
2872
+ throw new Error(`AgentStep "${step.id}" requires an agentExecutor`);
2873
+ }
2874
+ const prompt = typeof step.prompt === "function" ? step.prompt(ctx) : step.prompt;
2875
+ const retry = { ...DEFAULT_RETRY, ...step.retry };
2876
+ let lastError;
2877
+ for (let attempt = 1; attempt <= retry.maxAttempts; attempt++) {
2878
+ try {
2879
+ const result = await this.agentExecutor(prompt, structuredClone(ctx));
2880
+ return { ...ctx, [step.outputKey]: result };
2881
+ } catch (error) {
2882
+ lastError = error instanceof Error ? error : new Error(String(error));
2883
+ if (attempt < retry.maxAttempts) {
2884
+ const delay = retry.backoffMs * Math.pow(retry.backoffMultiplier, attempt - 1);
2885
+ await new Promise((r) => setTimeout(r, delay));
2886
+ }
2887
+ }
2888
+ }
2889
+ throw lastError;
2890
+ }
2891
+ // ── Retry ───────────────────────────────────────────────────────────────
2892
+ async executeWithRetry(step, ctx) {
2893
+ const retry = { ...DEFAULT_RETRY, ...step.retry };
2894
+ let lastError;
2895
+ for (let attempt = 1; attempt <= retry.maxAttempts; attempt++) {
2896
+ try {
2897
+ return await step.execute(structuredClone(ctx));
2898
+ } catch (error) {
2899
+ lastError = error instanceof Error ? error : new Error(String(error));
2900
+ if (attempt < retry.maxAttempts) {
2901
+ const delay = retry.backoffMs * Math.pow(retry.backoffMultiplier, attempt - 1);
2902
+ await new Promise((r) => setTimeout(r, delay));
2903
+ }
2904
+ }
2905
+ }
2906
+ throw lastError;
2907
+ }
2908
+ // ── Rollback ────────────────────────────────────────────────────────────
2909
+ async rollbackSteps(registry, completedStepIds, ctx) {
2910
+ const allIds = [...completedStepIds, ...Array.from(registry.keys())];
2911
+ const uniqueIds = [...new Set(allIds)].reverse();
2912
+ for (const stepId of uniqueIds) {
2913
+ const step = registry.get(stepId);
2914
+ if (step?.rollback) {
2915
+ try {
2916
+ await step.rollback(ctx);
2917
+ } catch {
2918
+ }
2919
+ }
2920
+ }
2921
+ }
2922
+ // ── Helpers ─────────────────────────────────────────────────────────────
2923
+ emit(event) {
2924
+ this.onEvent?.(event);
2925
+ }
2926
+ isParallelStep(step) {
2927
+ return step.type === "parallel";
2928
+ }
2929
+ isConditionalStep(step) {
2930
+ return step.type === "conditional";
2931
+ }
2932
+ isLoopStep(step) {
2933
+ return step.type === "loop";
2934
+ }
2935
+ isForeachStep(step) {
2936
+ return step.type === "foreach";
2937
+ }
2938
+ isMapStep(step) {
2939
+ return step.type === "map";
2940
+ }
2941
+ isAgentStep(step) {
2942
+ return step.type === "agent";
2943
+ }
2944
+ validateStep(step, errors) {
2945
+ if (this.isParallelStep(step)) {
2946
+ if (!step.branches || step.branches.length === 0) {
2947
+ errors.push(`Parallel step "${step.id}" must have at least one branch`);
2948
+ }
2949
+ } else if (this.isConditionalStep(step)) {
2950
+ if (!step.condition) errors.push(`Conditional step "${step.id}" must have a condition`);
2951
+ if (!step.ifTrue) errors.push(`Conditional step "${step.id}" must have an ifTrue step`);
2952
+ } else if (this.isLoopStep(step)) {
2953
+ if (!step.body) errors.push(`Loop step "${step.id}" must have a body`);
2954
+ if (!step.condition) errors.push(`Loop step "${step.id}" must have a condition`);
2955
+ } else if (this.isForeachStep(step)) {
2956
+ if (!step.iterable) errors.push(`Foreach step "${step.id}" must define iterable path`);
2957
+ if (!step.step) errors.push(`Foreach step "${step.id}" must define an item step`);
2958
+ if (step.maxConcurrency !== void 0 && step.maxConcurrency < 1) {
2959
+ errors.push(`Foreach step "${step.id}" maxConcurrency must be >= 1`);
2960
+ }
2961
+ if (step.maxIterations !== void 0 && step.maxIterations < 1) {
2962
+ errors.push(`Foreach step "${step.id}" maxIterations must be >= 1`);
2963
+ }
2964
+ } else if (this.isMapStep(step)) {
2965
+ if (!step.input) errors.push(`Map step "${step.id}" must define input path`);
2966
+ if (!step.transform) errors.push(`Map step "${step.id}" must define transform step`);
2967
+ if (!step.outputKey) errors.push(`Map step "${step.id}" must define outputKey`);
2968
+ if (step.maxConcurrency !== void 0 && step.maxConcurrency < 1) {
2969
+ errors.push(`Map step "${step.id}" maxConcurrency must be >= 1`);
2970
+ }
2971
+ } else if (this.isAgentStep(step)) {
2972
+ if (!step.prompt) errors.push(`Agent step "${step.id}" must have a prompt`);
2973
+ if (!step.outputKey) errors.push(`Agent step "${step.id}" must have an outputKey`);
2974
+ } else {
2975
+ const ws = step;
2976
+ if (!ws.execute) errors.push(`Step "${step.id}" must have an execute function`);
2977
+ }
2978
+ }
2979
+ getByPath(ctx, path) {
2980
+ if (!path) return void 0;
2981
+ const normalized = path.replace(/\[(\d+)\]/g, ".$1");
2982
+ const segments = normalized.split(".").filter(Boolean);
2983
+ let current = ctx;
2984
+ for (const segment of segments) {
2985
+ if (current === null || current === void 0) return void 0;
2986
+ if (Array.isArray(current)) {
2987
+ const index = Number(segment);
2988
+ if (!Number.isInteger(index)) return void 0;
2989
+ current = current[index];
2990
+ continue;
2991
+ }
2992
+ if (typeof current !== "object") return void 0;
2993
+ current = current[segment];
2994
+ }
2995
+ return current;
2996
+ }
2997
+ applyInputMapping(step, ctx) {
2998
+ const mapping = step.inputMapping;
2999
+ if (!mapping) {
3000
+ return ctx;
3001
+ }
3002
+ let projected = mapping.defaults ? { ...mapping.defaults } : {};
3003
+ if (mapping.keys) {
3004
+ for (const key of mapping.keys) {
3005
+ if (key in ctx) {
3006
+ projected[key] = ctx[key];
3007
+ }
3008
+ }
3009
+ }
3010
+ if (mapping.paths) {
3011
+ for (const [targetKey, path] of Object.entries(mapping.paths)) {
3012
+ projected[targetKey] = this.getByPath(ctx, path);
3013
+ }
3014
+ }
3015
+ if (mapping.overrides) {
3016
+ projected = {
3017
+ ...projected,
3018
+ ...mapping.overrides
3019
+ };
3020
+ }
3021
+ return projected;
3022
+ }
3023
+ applyOutputMappings(step, result) {
3024
+ if (!step.outputMapping || step.outputMapping.length === 0) {
3025
+ return result;
3026
+ }
3027
+ const mapped = { ...result };
3028
+ for (const mapping of step.outputMapping) {
3029
+ let value = this.getByPath(result, mapping.source);
3030
+ if (mapping.transform) {
3031
+ value = mapping.transform(value, result);
3032
+ }
3033
+ if (value === void 0) {
3034
+ value = mapping.defaultValue;
3035
+ }
3036
+ mapped[mapping.targetKey] = value;
3037
+ }
3038
+ return mapped;
3039
+ }
3040
+ extractStepOutput(result, stepId) {
3041
+ if (stepId in result) {
3042
+ return result[stepId];
3043
+ }
3044
+ return result;
3045
+ }
3046
+ aggregateOutputs(outputs, mode) {
3047
+ if (mode === "concat") {
3048
+ return outputs.flatMap(
3049
+ (output) => Array.isArray(output) ? output : [output]
3050
+ );
3051
+ }
3052
+ if (mode === "merge") {
3053
+ const merged = {};
3054
+ for (const output of outputs) {
3055
+ if (output && typeof output === "object" && !Array.isArray(output)) {
3056
+ Object.assign(merged, output);
3057
+ }
3058
+ }
3059
+ return merged;
3060
+ }
3061
+ return outputs;
3062
+ }
3063
+ async executeItemsWithConcurrency(items, concurrency, worker) {
3064
+ const safeConcurrency = Math.max(1, Math.floor(concurrency));
3065
+ if (safeConcurrency === 1 || items.length <= 1) {
3066
+ const sequential = [];
3067
+ for (let i = 0; i < items.length; i++) {
3068
+ sequential.push(await worker(items[i], i));
3069
+ }
3070
+ return sequential;
3071
+ }
3072
+ const results = new Array(items.length);
3073
+ let nextIndex = 0;
3074
+ const workers = Array.from(
3075
+ { length: Math.min(safeConcurrency, items.length) },
3076
+ async () => {
3077
+ while (true) {
3078
+ const current = nextIndex;
3079
+ nextIndex++;
3080
+ if (current >= items.length) return;
3081
+ results[current] = await worker(items[current], current);
3082
+ }
3083
+ }
3084
+ );
3085
+ await Promise.all(workers);
3086
+ return results;
3087
+ }
3088
+ };
3089
+
3090
+ // src/plugins/workflow.plugin.ts
3091
+ var DEFAULT_RETRY2 = {
3092
+ maxAttempts: 3,
3093
+ backoffMs: 1e3,
3094
+ backoffMultiplier: 2
3095
+ };
3096
+ var WorkflowError = class extends Error {
3097
+ result;
3098
+ constructor(message, result) {
3099
+ super(message);
3100
+ this.name = "WorkflowError";
3101
+ this.result = result;
3102
+ }
3103
+ };
3104
+ function isWorkflowDefinition(input) {
3105
+ return "id" in input && "name" in input;
3106
+ }
3107
+ var WorkflowPlugin = class extends BasePlugin {
3108
+ name = "workflow";
3109
+ steps;
3110
+ initialContext;
3111
+ definition;
3112
+ engine;
3113
+ lastResult;
3114
+ constructor(config, engine) {
3115
+ super();
3116
+ if (isWorkflowDefinition(config)) {
3117
+ this.definition = config;
3118
+ this.steps = config.steps;
3119
+ this.initialContext = config.initialContext ?? {};
3120
+ this.engine = engine ?? new DefaultWorkflowEngine();
3121
+ } else {
3122
+ this.steps = config.steps;
3123
+ this.initialContext = config.initialContext ?? {};
3124
+ }
3125
+ }
3126
+ buildHooks() {
3127
+ return {
3128
+ beforeRun: this.beforeRun.bind(this)
3129
+ };
3130
+ }
3131
+ getLastResult() {
3132
+ return this.lastResult;
3133
+ }
3134
+ // ── Hook implementation ─────────────────────────────────────────────────
3135
+ async beforeRun(_ctx, params) {
3136
+ const result = this.definition && this.engine ? await this.engine.execute(this.definition) : await this.executeWorkflow();
3137
+ this.lastResult = result;
3138
+ if (result.status === "failed") {
3139
+ throw new WorkflowError(
3140
+ `Workflow failed at step "${result.failedStep}": ${result.error}`,
3141
+ result
3142
+ );
3143
+ }
3144
+ const contextSummary = Object.entries(result.context).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join("\n");
3145
+ return {
3146
+ prompt: `${params.prompt}
3147
+
3148
+ --- Workflow Context ---
3149
+ ${contextSummary}`
3150
+ };
3151
+ }
3152
+ // ── Built-in workflow engine (backward compatible) ──────────────────────
3153
+ async executeWorkflow() {
3154
+ const start = Date.now();
3155
+ let context = structuredClone(this.initialContext);
3156
+ const completedSteps = [];
3157
+ const skippedSteps = [];
3158
+ for (const step of this.steps) {
3159
+ if (step.condition && !step.condition(context)) {
3160
+ skippedSteps.push(step.id);
3161
+ continue;
3162
+ }
3163
+ try {
3164
+ context = await this.executeWithRetry(step, context);
3165
+ completedSteps.push(step.id);
3166
+ } catch (error) {
3167
+ await this.rollback(completedSteps, context);
3168
+ return {
3169
+ status: "failed",
3170
+ context,
3171
+ completedSteps,
3172
+ skippedSteps,
3173
+ failedStep: step.id,
3174
+ error: error instanceof Error ? error.message : String(error),
3175
+ totalDurationMs: Date.now() - start
3176
+ };
3177
+ }
3178
+ }
3179
+ return {
3180
+ status: "completed",
3181
+ context,
3182
+ completedSteps,
3183
+ skippedSteps,
3184
+ totalDurationMs: Date.now() - start
3185
+ };
3186
+ }
3187
+ async executeWithRetry(step, context) {
3188
+ const retry = { ...DEFAULT_RETRY2, ...step.retry };
3189
+ let lastError;
3190
+ for (let attempt = 1; attempt <= retry.maxAttempts; attempt++) {
3191
+ try {
3192
+ return await step.execute(context);
3193
+ } catch (error) {
3194
+ lastError = error instanceof Error ? error : new Error(String(error));
3195
+ if (attempt < retry.maxAttempts) {
3196
+ const delay = retry.backoffMs * Math.pow(retry.backoffMultiplier, attempt - 1);
3197
+ await new Promise((r) => setTimeout(r, delay));
3198
+ }
3199
+ }
3200
+ }
3201
+ throw lastError;
3202
+ }
3203
+ async rollback(completedStepIds, context) {
3204
+ for (const stepId of [...completedStepIds].reverse()) {
3205
+ const step = this.steps.find((s) => s.id === stepId);
3206
+ if (step?.rollback) {
3207
+ try {
3208
+ await step.rollback(context);
3209
+ } catch {
3210
+ }
3211
+ }
3212
+ }
3213
+ }
3214
+ };
3215
+ function createWorkflowPlugin(config, engine) {
3216
+ return new WorkflowPlugin(config, engine);
3217
+ }
3218
+
3219
+ // src/plugins/utils/default-metrics.ts
3220
+ function createDefaultMetrics() {
3221
+ return {
3222
+ totalTokens: { input: 0, output: 0 },
3223
+ totalLatencyMs: 0,
3224
+ toolCalls: [],
3225
+ llmCalls: []
3226
+ };
3227
+ }
3228
+
3229
+ // src/plugins/observability.plugin.ts
3230
+ var ObservabilityPlugin = class extends BasePlugin {
3231
+ name = "observability";
3232
+ version = "1.0.0";
3233
+ config;
3234
+ spans = /* @__PURE__ */ new Map();
3235
+ rootSpans = [];
3236
+ activeSpans = /* @__PURE__ */ new Map();
3237
+ // sessionId → current root span
3238
+ sessionMetrics = /* @__PURE__ */ new Map();
3239
+ // sessionId → metrics
3240
+ sessionStartTimes = /* @__PURE__ */ new Map();
3241
+ // sessionId → run start time
3242
+ toolStartTimes = /* @__PURE__ */ new Map();
3243
+ // sessionId:toolName → start time stack (LIFO)
3244
+ toolSpanStack = /* @__PURE__ */ new Map();
3245
+ // sessionId:toolName → spanId stack (LIFO)
3246
+ maxSpans;
3247
+ constructor(config = {}) {
3248
+ super();
3249
+ this.config = {
3250
+ enableTracing: true,
3251
+ enableMetrics: true,
3252
+ enableCostEstimation: false,
3253
+ ...config
3254
+ };
3255
+ this.maxSpans = config.maxSpans ?? 1e4;
3256
+ }
3257
+ buildHooks() {
3258
+ return {
3259
+ beforeRun: this.onRequest.bind(this),
3260
+ afterRun: this.onResponse.bind(this),
3261
+ beforeTool: this.onToolStart.bind(this),
3262
+ afterTool: this.onToolEnd.bind(this),
3263
+ onError: this.onError.bind(this)
3264
+ };
3265
+ }
3266
+ generateId() {
3267
+ return Math.random().toString(36).substring(2, 15);
3268
+ }
3269
+ createSpan(name, traceId, parentId) {
3270
+ if (this.spans.size >= this.maxSpans) {
3271
+ const oldestKey = this.spans.keys().next().value;
3272
+ if (oldestKey) {
3273
+ const oldSpan = this.spans.get(oldestKey);
3274
+ this.spans.delete(oldestKey);
3275
+ if (oldSpan && !oldSpan.parentId) {
3276
+ const idx = this.rootSpans.indexOf(oldSpan);
3277
+ if (idx >= 0) this.rootSpans.splice(idx, 1);
3278
+ }
3279
+ }
3280
+ }
3281
+ const span = {
3282
+ id: this.generateId(),
3283
+ traceId,
3284
+ name,
3285
+ startTime: Date.now(),
3286
+ attributes: {},
3287
+ parentId,
3288
+ status: "ok",
3289
+ children: []
3290
+ };
3291
+ this.spans.set(span.id, span);
3292
+ if (parentId) {
3293
+ const parent = this.spans.get(parentId);
3294
+ if (parent) {
3295
+ parent.children.push(span);
3296
+ }
3297
+ } else {
3298
+ this.rootSpans.push(span);
3299
+ }
3300
+ return span;
3301
+ }
3302
+ endSpan(spanId, status = "ok") {
3303
+ const span = this.spans.get(spanId);
3304
+ if (span) {
3305
+ span.endTime = Date.now();
3306
+ span.status = status;
3307
+ }
3308
+ }
3309
+ getOrCreateMetrics(sessionId) {
3310
+ let metrics = this.sessionMetrics.get(sessionId);
3311
+ if (!metrics) {
3312
+ metrics = createDefaultMetrics();
3313
+ this.sessionMetrics.set(sessionId, metrics);
3314
+ }
3315
+ return metrics;
3316
+ }
3317
+ async onRequest(ctx, params) {
3318
+ if (!this.config.enableTracing && !this.config.enableMetrics) {
3319
+ return;
3320
+ }
3321
+ const sessionId = ctx.sessionId;
3322
+ if (this.config.enableTracing) {
3323
+ const traceId = this.generateId();
3324
+ const span = this.createSpan("agent.run", traceId);
3325
+ span.attributes = {
3326
+ sessionId,
3327
+ agentName: ctx.agentName,
3328
+ prompt: params.prompt,
3329
+ maxSteps: ctx.config.maxSteps
3330
+ };
3331
+ this.activeSpans.set(sessionId, span);
3332
+ }
3333
+ if (this.config.enableMetrics) {
3334
+ this.sessionStartTimes.set(sessionId, Date.now());
3335
+ this.sessionMetrics.set(sessionId, createDefaultMetrics());
3336
+ }
3337
+ }
3338
+ async onResponse(ctx, params) {
3339
+ if (!this.config.enableTracing && !this.config.enableMetrics) {
3340
+ return;
3341
+ }
3342
+ const sessionId = ctx.sessionId;
3343
+ const rootSpan = this.activeSpans.get(sessionId);
3344
+ if (this.config.enableTracing && rootSpan) {
3345
+ this.endSpan(rootSpan.id);
3346
+ rootSpan.attributes.result = params.result.text;
3347
+ rootSpan.attributes.steps = params.result.steps?.length || 0;
3348
+ }
3349
+ if (this.config.enableMetrics) {
3350
+ const metrics = this.getOrCreateMetrics(sessionId);
3351
+ const startTime = this.sessionStartTimes.get(sessionId);
3352
+ if (startTime) {
3353
+ metrics.totalLatencyMs = Date.now() - startTime;
3354
+ }
3355
+ if (this.config.enableCostEstimation && this.config.costPerInputToken && this.config.costPerOutputToken) {
3356
+ metrics.estimatedCostUsd = metrics.totalTokens.input * this.config.costPerInputToken + metrics.totalTokens.output * this.config.costPerOutputToken;
3357
+ }
3358
+ this.sessionStartTimes.delete(sessionId);
3359
+ }
3360
+ this.activeSpans.delete(sessionId);
3361
+ }
3362
+ async onToolStart(ctx, params) {
3363
+ if (!this.config.enableTracing && !this.config.enableMetrics) {
3364
+ return;
3365
+ }
3366
+ if (this.config.enableMetrics) {
3367
+ const metricsKey = `${ctx.sessionId}:${params.toolName}`;
3368
+ const stack = this.toolStartTimes.get(metricsKey) ?? [];
3369
+ stack.push(Date.now());
3370
+ this.toolStartTimes.set(metricsKey, stack);
3371
+ }
3372
+ if (this.config.enableTracing) {
3373
+ const rootSpan = this.activeSpans.get(ctx.sessionId);
3374
+ const traceId = rootSpan?.traceId ?? this.generateId();
3375
+ const toolSpan = this.createSpan(`tool.${params.toolName}`, traceId, rootSpan?.id);
3376
+ toolSpan.attributes = {
3377
+ toolName: params.toolName,
3378
+ args: params.args
3379
+ };
3380
+ const stackKey = `${ctx.sessionId}:${params.toolName}`;
3381
+ const stack = this.toolSpanStack.get(stackKey) ?? [];
3382
+ stack.push(toolSpan.id);
3383
+ this.toolSpanStack.set(stackKey, stack);
3384
+ }
3385
+ }
3386
+ async onToolEnd(ctx, params) {
3387
+ if (!this.config.enableTracing && !this.config.enableMetrics) {
3388
+ return;
3389
+ }
3390
+ if (this.config.enableTracing) {
3391
+ const spanKey = `${ctx.sessionId}:${params.toolName}`;
3392
+ const stack = this.toolSpanStack.get(spanKey);
3393
+ const spanId = stack?.pop();
3394
+ if (spanId) {
3395
+ const toolSpan = this.spans.get(spanId);
3396
+ if (toolSpan) {
3397
+ this.endSpan(toolSpan.id);
3398
+ toolSpan.attributes.result = params.result;
3399
+ }
3400
+ if (stack && stack.length === 0) {
3401
+ this.toolSpanStack.delete(spanKey);
3402
+ }
3403
+ }
3404
+ }
3405
+ if (this.config.enableMetrics) {
3406
+ const key = `${ctx.sessionId}:${params.toolName}`;
3407
+ const stack = this.toolStartTimes.get(key);
3408
+ const startTime = stack?.pop();
3409
+ const latencyMs = startTime ? Date.now() - startTime : 0;
3410
+ if (stack && stack.length === 0) {
3411
+ this.toolStartTimes.delete(key);
3412
+ }
3413
+ const metrics = this.getOrCreateMetrics(ctx.sessionId);
3414
+ metrics.toolCalls.push({
3415
+ name: params.toolName,
3416
+ latencyMs,
3417
+ success: true
3418
+ });
3419
+ }
3420
+ }
3421
+ async onError(ctx, params) {
3422
+ if (!this.config.enableTracing) {
3423
+ return;
3424
+ }
3425
+ const rootSpan = this.activeSpans.get(ctx.sessionId);
3426
+ const unfinishedSpans = Array.from(this.spans.values()).filter((s) => !s.endTime && s.traceId === rootSpan?.traceId).sort((a, b) => b.startTime - a.startTime);
3427
+ if (unfinishedSpans.length > 0) {
3428
+ const span = unfinishedSpans[0];
3429
+ this.endSpan(span.id, "error");
3430
+ span.attributes.error = {
3431
+ message: params.error instanceof Error ? params.error.message : String(params.error),
3432
+ phase: params.phase
3433
+ };
3434
+ }
3435
+ }
3436
+ // Public methods
3437
+ getTraces() {
3438
+ return this.config.enableTracing ? [...this.rootSpans] : [];
3439
+ }
3440
+ getMetrics(sessionId) {
3441
+ if (!this.config.enableMetrics) {
3442
+ return createDefaultMetrics();
3443
+ }
3444
+ if (sessionId) {
3445
+ const m = this.sessionMetrics.get(sessionId);
3446
+ return m ? this.deepCopyMetrics(m) : createDefaultMetrics();
3447
+ }
3448
+ const entries = Array.from(this.sessionMetrics.values());
3449
+ const last = entries[entries.length - 1];
3450
+ return last ? this.deepCopyMetrics(last) : createDefaultMetrics();
3451
+ }
3452
+ deepCopyMetrics(m) {
3453
+ return {
3454
+ totalTokens: { ...m.totalTokens },
3455
+ totalLatencyMs: m.totalLatencyMs,
3456
+ toolCalls: m.toolCalls.map((t) => ({ ...t })),
3457
+ llmCalls: m.llmCalls.map((l) => ({ ...l })),
3458
+ estimatedCostUsd: m.estimatedCostUsd
3459
+ };
3460
+ }
3461
+ exportOpenTelemetry() {
3462
+ if (!this.config.enableTracing) {
3463
+ return { resourceSpans: [] };
3464
+ }
3465
+ const spans = Array.from(this.spans.values()).map((span) => ({
3466
+ traceId: span.traceId,
3467
+ spanId: span.id,
3468
+ parentSpanId: span.parentId,
3469
+ name: span.name,
3470
+ startTimeUnixNano: span.startTime * 1e6,
3471
+ endTimeUnixNano: span.endTime ? span.endTime * 1e6 : void 0,
3472
+ attributes: Object.entries(span.attributes).map(([key, value]) => ({
3473
+ key,
3474
+ value: { stringValue: String(value) }
3475
+ })),
3476
+ status: {
3477
+ code: span.status === "ok" ? 1 : 2
3478
+ }
3479
+ }));
3480
+ return {
3481
+ resourceSpans: [{
3482
+ resource: {
3483
+ attributes: [
3484
+ { key: "service.name", value: { stringValue: "deepagent" } },
3485
+ { key: "service.version", value: { stringValue: this.version } }
3486
+ ]
3487
+ },
3488
+ scopeSpans: [{
3489
+ scope: {
3490
+ name: "deepagent-observability",
3491
+ version: this.version
3492
+ },
3493
+ spans
3494
+ }]
3495
+ }]
3496
+ };
3497
+ }
3498
+ reset() {
3499
+ this.spans.clear();
3500
+ this.rootSpans = [];
3501
+ this.activeSpans.clear();
3502
+ this.sessionMetrics.clear();
3503
+ this.sessionStartTimes.clear();
3504
+ this.toolStartTimes.clear();
3505
+ this.toolSpanStack.clear();
3506
+ }
3507
+ };
3508
+ function createObservabilityPlugin(config) {
3509
+ return new ObservabilityPlugin(config);
3510
+ }
3511
+
3512
+ // src/plugins/semantic-scraping.plugin.ts
3513
+ import { z as z5 } from "zod";
3514
+
3515
+ // src/adapters/semantic-scraping/semantic-scraping.adapter.ts
3516
+ function urlToPattern(url) {
3517
+ try {
3518
+ const u = new URL(url);
3519
+ const path = u.pathname.replace(/\/+$/, "") || "/";
3520
+ if (!u.search) return path;
3521
+ const params = new URLSearchParams(u.search);
3522
+ const wildcarded = [...params.keys()].sort().map((k) => `${k}=*`);
3523
+ return `${path}?${wildcarded.join("&")}`;
3524
+ } catch {
3525
+ return url;
3526
+ }
3527
+ }
3528
+ function hashTools(tools) {
3529
+ const keys = tools.map(
3530
+ (t) => `${t.name}:${t.description ?? ""}:${JSON.stringify(t.inputSchema ?? {})}`
3531
+ ).sort();
3532
+ let h = 0;
3533
+ const s = keys.join("|");
3534
+ for (let i = 0; i < s.length; i++) {
3535
+ h = (h << 5) - h + s.charCodeAt(i) | 0;
3536
+ }
3537
+ return h.toString(36);
3538
+ }
3539
+ function parseSchema(schema) {
3540
+ if (typeof schema === "string") {
3541
+ try {
3542
+ return JSON.parse(schema);
3543
+ } catch {
3544
+ return { type: "object", properties: {} };
3545
+ }
3546
+ }
3547
+ return schema;
3548
+ }
3549
+ function toManifestTool(tool2, pattern) {
3550
+ const schema = parseSchema(tool2.inputSchema);
3551
+ const annotations = tool2.annotations ? { ...tool2.annotations } : void 0;
3552
+ return {
3553
+ name: tool2.name,
3554
+ description: tool2.description,
3555
+ inputSchema: schema,
3556
+ category: tool2.category,
3557
+ annotations,
3558
+ pagePatterns: [pattern]
3559
+ };
3560
+ }
3561
+ function rebuildTools(pages, toolsByName) {
3562
+ const consolidated = /* @__PURE__ */ new Map();
3563
+ for (const [, entry] of toolsByName) {
3564
+ const existing = consolidated.get(entry.tool.name);
3565
+ if (existing) {
3566
+ for (const p of entry.patterns) existing.patterns.add(p);
3567
+ } else {
3568
+ consolidated.set(entry.tool.name, {
3569
+ tool: entry.tool,
3570
+ patterns: new Set(entry.patterns)
3571
+ });
3572
+ }
3573
+ }
3574
+ const activeToolNames = /* @__PURE__ */ new Set();
3575
+ for (const page of Object.values(pages)) {
3576
+ for (const name of page.tools) activeToolNames.add(name);
3577
+ }
3578
+ const result = [];
3579
+ for (const [name, entry] of consolidated) {
3580
+ if (!activeToolNames.has(name)) continue;
3581
+ result.push({
3582
+ ...entry.tool,
3583
+ pagePatterns: [...entry.patterns].sort()
3584
+ });
3585
+ }
3586
+ return result.sort((a, b) => a.name.localeCompare(b.name));
3587
+ }
3588
+ var SemanticScrapingAdapter = class {
3589
+ manifests = /* @__PURE__ */ new Map();
3590
+ getManifest(origin) {
3591
+ return this.manifests.get(origin)?.manifest ?? null;
3592
+ }
3593
+ updatePage(origin, url, tools) {
3594
+ const pattern = urlToPattern(url);
3595
+ const hash = hashTools(
3596
+ tools.map((t) => ({
3597
+ ...t,
3598
+ inputSchema: parseSchema(t.inputSchema)
3599
+ }))
3600
+ );
3601
+ const now = Date.now();
3602
+ const existing = this.manifests.get(origin);
3603
+ const toolIndex = existing?.toolIndex ?? /* @__PURE__ */ new Map();
3604
+ const oldPages = existing?.manifest.pages ?? {};
3605
+ const oldPage = oldPages[pattern];
3606
+ if (oldPage) {
3607
+ for (const toolName of oldPage.tools) {
3608
+ const entry = toolIndex.get(toolName);
3609
+ if (entry) {
3610
+ entry.patterns.delete(pattern);
3611
+ if (entry.patterns.size === 0) toolIndex.delete(toolName);
3612
+ }
3613
+ }
3614
+ }
3615
+ const toolNames = [];
3616
+ for (const tool2 of tools) {
3617
+ toolNames.push(tool2.name);
3618
+ const entry = toolIndex.get(tool2.name);
3619
+ if (entry) {
3620
+ entry.patterns.add(pattern);
3621
+ entry.tool = toManifestTool(tool2, pattern);
3622
+ } else {
3623
+ toolIndex.set(tool2.name, {
3624
+ tool: toManifestTool(tool2, pattern),
3625
+ patterns: /* @__PURE__ */ new Set([pattern])
3626
+ });
3627
+ }
3628
+ }
3629
+ const pageToolSet = {
3630
+ urlPattern: pattern,
3631
+ tools: toolNames,
3632
+ lastScanned: now,
3633
+ hash
3634
+ };
3635
+ const pages = {
3636
+ ...oldPages,
3637
+ [pattern]: pageToolSet
3638
+ };
3639
+ const deduped = rebuildTools(pages, toolIndex);
3640
+ const manifest = {
3641
+ origin,
3642
+ version: (existing?.manifest.version ?? 0) + 1,
3643
+ generatedAt: now,
3644
+ pages,
3645
+ tools: deduped
3646
+ };
3647
+ this.manifests.set(origin, { manifest, toolIndex });
3648
+ return manifest;
3649
+ }
3650
+ applyDiff(origin, url, added, removed) {
3651
+ const pattern = urlToPattern(url);
3652
+ const now = Date.now();
3653
+ const existing = this.manifests.get(origin);
3654
+ const toolIndex = existing?.toolIndex ?? /* @__PURE__ */ new Map();
3655
+ const oldPages = existing?.manifest.pages ?? {};
3656
+ const oldPage = oldPages[pattern];
3657
+ const currentTools = new Set(oldPage?.tools ?? []);
3658
+ for (const name of removed) {
3659
+ currentTools.delete(name);
3660
+ const entry = toolIndex.get(name);
3661
+ if (entry) {
3662
+ entry.patterns.delete(pattern);
3663
+ if (entry.patterns.size === 0) toolIndex.delete(name);
3664
+ }
3665
+ }
3666
+ for (const tool2 of added) {
3667
+ currentTools.add(tool2.name);
3668
+ const entry = toolIndex.get(tool2.name);
3669
+ if (entry) {
3670
+ entry.patterns.add(pattern);
3671
+ entry.tool = toManifestTool(tool2, pattern);
3672
+ } else {
3673
+ toolIndex.set(tool2.name, {
3674
+ tool: toManifestTool(tool2, pattern),
3675
+ patterns: /* @__PURE__ */ new Set([pattern])
3676
+ });
3677
+ }
3678
+ }
3679
+ const toolNames = [...currentTools];
3680
+ const hash = hashTools(
3681
+ toolNames.map((n) => toolIndex.get(n)?.tool).filter(Boolean).map((t) => ({
3682
+ name: t.name,
3683
+ description: t.description,
3684
+ inputSchema: t.inputSchema
3685
+ }))
3686
+ );
3687
+ const pageToolSet = {
3688
+ urlPattern: pattern,
3689
+ tools: toolNames,
3690
+ lastScanned: now,
3691
+ hash
3692
+ };
3693
+ const pages = {
3694
+ ...oldPages,
3695
+ [pattern]: pageToolSet
3696
+ };
3697
+ const deduped = rebuildTools(pages, toolIndex);
3698
+ const manifest = {
3699
+ origin,
3700
+ version: (existing?.manifest.version ?? 0) + 1,
3701
+ generatedAt: now,
3702
+ pages,
3703
+ tools: deduped
3704
+ };
3705
+ this.manifests.set(origin, { manifest, toolIndex });
3706
+ return manifest;
3707
+ }
3708
+ toMCPJson(origin) {
3709
+ const manifest = this.getManifest(origin);
3710
+ if (!manifest) return JSON.stringify({ tools: [] });
3711
+ const mcpTools = manifest.tools.map((t) => ({
3712
+ name: t.name,
3713
+ description: t.description,
3714
+ inputSchema: t.inputSchema,
3715
+ ...t.annotations ? { annotations: t.annotations } : {}
3716
+ }));
3717
+ return JSON.stringify({
3718
+ tools: mcpTools,
3719
+ _meta: {
3720
+ origin: manifest.origin,
3721
+ version: manifest.version,
3722
+ generatedAt: manifest.generatedAt,
3723
+ pageCount: Object.keys(manifest.pages).length,
3724
+ toolCount: manifest.tools.length
3725
+ }
3726
+ });
3727
+ }
3728
+ getToolsForUrl(origin, url) {
3729
+ const manifest = this.getManifest(origin);
3730
+ if (!manifest) return [];
3731
+ const pattern = urlToPattern(url);
3732
+ const page = manifest.pages[pattern];
3733
+ if (!page) return [];
3734
+ const toolNames = new Set(page.tools);
3735
+ return manifest.tools.filter((t) => toolNames.has(t.name));
3736
+ }
3737
+ };
3738
+
3739
+ // src/plugins/semantic-scraping.plugin.ts
3740
+ var SemanticToolSchema = z5.object({
3741
+ name: z5.string(),
3742
+ description: z5.string(),
3743
+ inputSchema: z5.union([z5.string(), z5.record(z5.string(), z5.unknown())]),
3744
+ confidence: z5.number().optional(),
3745
+ category: z5.string().optional(),
3746
+ annotations: z5.record(z5.string(), z5.boolean()).optional()
3747
+ });
3748
+ var ScanPageInputSchema = z5.object({
3749
+ url: z5.string().url().describe("The page URL that was scanned"),
3750
+ tools: z5.array(SemanticToolSchema).describe("Semantic tools extracted from the page HTML")
3751
+ });
3752
+ var GetManifestInputSchema = z5.object({
3753
+ origin: z5.string().describe("Site origin (e.g., https://example.com)")
3754
+ });
3755
+ var GetToolsForUrlInputSchema = z5.object({
3756
+ origin: z5.string().describe("Site origin (e.g., https://example.com)"),
3757
+ url: z5.string().url().describe("The URL to get tools for")
3758
+ });
3759
+ var SemanticScrapingPlugin = class extends BasePlugin {
3760
+ name = "semantic-scraping";
3761
+ adapter;
3762
+ constructor(options = {}) {
3763
+ super();
3764
+ this.adapter = options.adapter ?? new SemanticScrapingAdapter();
3765
+ }
3766
+ buildHooks() {
3767
+ return {};
3768
+ }
3769
+ get tools() {
3770
+ const adapter = this.adapter;
3771
+ return {
3772
+ semantic_scan_page: tool({
3773
+ description: "Register semantic tools extracted from a web page into the site manifest",
3774
+ inputSchema: ScanPageInputSchema,
3775
+ execute: async (args) => {
3776
+ const { url, tools: rawTools } = args;
3777
+ const origin = new URL(url).origin;
3778
+ const semanticTools = rawTools.map((t) => ({
3779
+ name: t.name,
3780
+ description: t.description,
3781
+ inputSchema: t.inputSchema,
3782
+ confidence: t.confidence,
3783
+ category: t.category,
3784
+ annotations: t.annotations
3785
+ }));
3786
+ const manifest = adapter.updatePage(origin, url, semanticTools);
3787
+ return {
3788
+ origin,
3789
+ version: manifest.version,
3790
+ toolCount: manifest.tools.length,
3791
+ pageCount: Object.keys(manifest.pages).length
3792
+ };
3793
+ }
3794
+ }),
3795
+ get_site_manifest: tool({
3796
+ description: "Get the MCP-compatible JSON manifest for a site",
3797
+ inputSchema: GetManifestInputSchema,
3798
+ execute: async (args) => {
3799
+ const { origin } = args;
3800
+ return adapter.toMCPJson(origin);
3801
+ }
3802
+ }),
3803
+ get_tools_for_url: tool({
3804
+ description: "Get the semantic tools available at a specific URL",
3805
+ inputSchema: GetToolsForUrlInputSchema,
3806
+ execute: async (args) => {
3807
+ const { origin, url } = args;
3808
+ return adapter.getToolsForUrl(origin, url);
3809
+ }
3810
+ })
3811
+ };
3812
+ }
3813
+ };
3814
+ function createSemanticScrapingPlugin(options = {}) {
3815
+ return new SemanticScrapingPlugin(options);
3816
+ }
3817
+
3818
+ // src/plugins/semantic-web-search.plugin.ts
3819
+ import { z as z6 } from "zod";
3820
+ var strategySchema = z6.enum(["tfidf", "bm25", "mmr"]);
3821
+ var SemanticWebSearchPlugin = class extends BasePlugin {
3822
+ constructor(options = {}) {
3823
+ super();
3824
+ this.options = options;
3825
+ this.reranker = options.reranker ?? new DefaultReRankingAdapter();
3826
+ this.telemetry = options.telemetry;
3827
+ this.costTracker = options.costTracker;
3828
+ this.costModel = options.costModel ?? "gpt-5.2-mini";
3829
+ this.emitTelemetry = options.emitTelemetry ?? true;
3830
+ this.cache = options.cache ?? new ToolCache();
3831
+ this.circuitBreaker = options.circuitBreaker ?? new CircuitBreaker();
3832
+ this.defaultLimit = options.defaultLimit ?? 5;
3833
+ this.defaultScrapeTopK = options.defaultScrapeTopK ?? 2;
3834
+ this.defaultStrategy = options.defaultStrategy ?? "bm25";
3835
+ this.fallbackStrategy = options.fallbackStrategy ?? "tfidf";
3836
+ this.fallbackOnRerankError = options.fallbackOnRerankError ?? true;
3837
+ this.requestTimeoutMs = options.requestTimeoutMs ?? 1e4;
3838
+ this.maxRetries = options.maxRetries ?? 2;
3839
+ this.retryDelayMs = options.retryDelayMs ?? 200;
3840
+ this.cacheTtlMs = options.cacheTtlMs ?? 6e4;
3841
+ }
3842
+ name = "Semantic Web Search";
3843
+ description = "Native search\u2192rerank\u2192citation pipeline for high-quality web evidence.";
3844
+ crawlerPromise = null;
3845
+ reranker;
3846
+ telemetry;
3847
+ costTracker;
3848
+ costModel;
3849
+ emitTelemetry;
3850
+ cache;
3851
+ circuitBreaker;
3852
+ defaultLimit;
3853
+ defaultScrapeTopK;
3854
+ defaultStrategy;
3855
+ fallbackStrategy;
3856
+ fallbackOnRerankError;
3857
+ requestTimeoutMs;
3858
+ maxRetries;
3859
+ retryDelayMs;
3860
+ cacheTtlMs;
3861
+ buildHooks() {
3862
+ return {};
3863
+ }
3864
+ get tools() {
3865
+ return {
3866
+ semantic_web_search: tool({
3867
+ description: "Search the web, rerank semantically and return ranked citations.",
3868
+ inputSchema: z6.object({
3869
+ query: z6.string().min(1),
3870
+ limit: z6.number().int().min(1).max(20).optional(),
3871
+ scrapeTopK: z6.number().int().min(0).max(10).optional(),
3872
+ strategy: strategySchema.optional()
3873
+ }),
3874
+ execute: async (input) => {
3875
+ const limit = input.limit ?? this.defaultLimit;
3876
+ const scrapeTopK = input.scrapeTopK ?? this.defaultScrapeTopK;
3877
+ const strategy = input.strategy ?? this.defaultStrategy;
3878
+ const startedAt = Date.now();
3879
+ const traceId = crypto.randomUUID();
3880
+ this.emitEvent("semantic_search_started", {
3881
+ traceId,
3882
+ query: input.query,
3883
+ limit,
3884
+ scrapeTopK,
3885
+ strategy
3886
+ });
3887
+ const cacheKey = `semantic-web:${input.query}:${limit}:${scrapeTopK}:${strategy}`;
3888
+ const cached = this.cache.get(cacheKey);
3889
+ if (cached) {
3890
+ const cacheResponse = {
3891
+ ...cached,
3892
+ quality: {
3893
+ ...cached.quality,
3894
+ traceId,
3895
+ cacheServed: true
3896
+ },
3897
+ cacheHit: true
3898
+ };
3899
+ this.emitEvent("semantic_search_cache_hit", {
3900
+ traceId,
3901
+ query: input.query,
3902
+ resultCount: cacheResponse.results.length
3903
+ });
3904
+ this.emitMetric("semantic_search_cache_hit", 1, {
3905
+ strategy
3906
+ });
3907
+ return {
3908
+ ...cacheResponse
3909
+ };
3910
+ }
3911
+ try {
3912
+ const crawler = await this.getCrawler();
3913
+ const {
3914
+ value: rawSearch,
3915
+ attempts: searchAttempts
3916
+ } = await this.executeWithRetry(
3917
+ "search",
3918
+ async () => crawler.search(input.query, { limit })
3919
+ );
3920
+ const normalized = this.normalizeResults(rawSearch, limit);
3921
+ const { failures: scrapeFailures, attempts: scrapeAttempts } = await this.enrichTopResults(normalized, scrapeTopK, crawler);
3922
+ const byId = new Map(normalized.map((candidate) => [candidate.id, candidate]));
3923
+ const toRank = normalized.map((candidate) => ({
3924
+ id: candidate.id,
3925
+ text: candidate.content,
3926
+ score: 1
3927
+ }));
3928
+ let reranked;
3929
+ let strategyUsed = strategy;
3930
+ let fallbackUsed = false;
3931
+ try {
3932
+ reranked = this.reranker.rerank(input.query, toRank, {
3933
+ strategy
3934
+ });
3935
+ } catch (error) {
3936
+ if (!this.fallbackOnRerankError || strategy === this.fallbackStrategy) {
3937
+ throw error;
3938
+ }
3939
+ reranked = this.reranker.rerank(input.query, toRank, {
3940
+ strategy: this.fallbackStrategy
3941
+ });
3942
+ strategyUsed = this.fallbackStrategy;
3943
+ fallbackUsed = true;
3944
+ }
3945
+ const results = reranked.slice(0, limit).map((result, index) => {
3946
+ const source = byId.get(result.id);
3947
+ const title = source?.title ?? result.id;
3948
+ const url = source?.url ?? "";
3949
+ const snippet = source?.snippet ?? result.text.slice(0, 300);
3950
+ const citation = `[${index + 1}] ${title} \u2014 ${url}`;
3951
+ return {
3952
+ rank: index + 1,
3953
+ score: result.score,
3954
+ title,
3955
+ url,
3956
+ snippet,
3957
+ citation
3958
+ };
3959
+ });
3960
+ const durationMs = Date.now() - startedAt;
3961
+ const quality = {
3962
+ traceId,
3963
+ cacheServed: false,
3964
+ durationMs,
3965
+ strategyRequested: strategy,
3966
+ strategyUsed,
3967
+ fallbackUsed,
3968
+ candidates: normalized.length,
3969
+ reranked: reranked.length,
3970
+ averageScore: this.calculateAverageScore(reranked),
3971
+ searchAttempts,
3972
+ scrapeAttempts,
3973
+ scrapeFailures
3974
+ };
3975
+ const cost = this.buildCostRecord(
3976
+ input.query,
3977
+ results,
3978
+ quality
3979
+ );
3980
+ const response = {
3981
+ query: input.query,
3982
+ results,
3983
+ citations: results.map((result) => result.citation),
3984
+ quality,
3985
+ ...cost ? {
3986
+ cost: {
3987
+ model: this.costModel,
3988
+ promptTokens: cost.promptTokens,
3989
+ completionTokens: cost.completionTokens,
3990
+ totalTokens: cost.totalTokens,
3991
+ totalCost: cost.totalCost,
3992
+ currency: "USD"
3993
+ }
3994
+ } : {},
3995
+ cacheHit: false
3996
+ };
3997
+ this.emitEvent("semantic_search_completed", {
3998
+ traceId,
3999
+ query: input.query,
4000
+ resultCount: results.length,
4001
+ durationMs,
4002
+ fallbackUsed,
4003
+ strategyUsed,
4004
+ cacheHit: false,
4005
+ ...cost ? { totalCost: cost.totalCost, totalTokens: cost.totalTokens } : {}
4006
+ });
4007
+ this.emitMetric("semantic_search_duration_ms", durationMs, {
4008
+ strategy: strategyUsed,
4009
+ fallback: fallbackUsed ? "true" : "false"
4010
+ });
4011
+ if (cost) {
4012
+ this.emitMetric("semantic_search_cost_usd", cost.totalCost, {
4013
+ model: this.costModel
4014
+ });
4015
+ }
4016
+ this.cache.set(cacheKey, response, this.cacheTtlMs);
4017
+ return response;
4018
+ } catch (error) {
4019
+ this.emitEvent("semantic_search_failed", {
4020
+ traceId,
4021
+ query: input.query,
4022
+ durationMs: Date.now() - startedAt,
4023
+ error: error instanceof Error ? error.message : String(error)
4024
+ }, "ERROR");
4025
+ this.emitMetric("semantic_search_failure", 1, {
4026
+ strategy
4027
+ });
4028
+ throw error;
4029
+ }
4030
+ }
4031
+ })
4032
+ };
4033
+ }
4034
+ async dispose() {
4035
+ if (!this.crawlerPromise) return;
4036
+ const crawler = await this.crawlerPromise;
4037
+ await crawler?.close?.();
4038
+ }
4039
+ getCrawler() {
4040
+ if (!this.crawlerPromise) {
4041
+ this.crawlerPromise = this.initCrawler();
4042
+ }
4043
+ return this.crawlerPromise;
4044
+ }
4045
+ async initCrawler() {
4046
+ if (this.options.crawler) {
4047
+ return this.options.crawler;
4048
+ }
4049
+ try {
4050
+ const mod = await import("onecrawl");
4051
+ const CrawlerClass = mod.Crawler ?? mod.default?.Crawler ?? mod.default;
4052
+ return new CrawlerClass({
4053
+ ...this.options.apiKey ? { apiKey: this.options.apiKey } : {}
4054
+ });
4055
+ } catch {
4056
+ throw new Error(
4057
+ 'SemanticWebSearchPlugin requires "onecrawl" package. Install it: pnpm add onecrawl'
4058
+ );
4059
+ }
4060
+ }
4061
+ normalizeResults(raw, limit) {
4062
+ if (!Array.isArray(raw)) {
4063
+ return [];
4064
+ }
4065
+ return raw.slice(0, limit).map((entry, index) => this.normalizeEntry(entry, index)).filter((entry) => entry !== null);
4066
+ }
4067
+ normalizeEntry(entry, index) {
4068
+ if (!entry || typeof entry !== "object") {
4069
+ return null;
4070
+ }
4071
+ const item = entry;
4072
+ const url = item.url ?? item.link;
4073
+ if (!url) {
4074
+ return null;
4075
+ }
4076
+ const title = item.title ?? `Result ${index + 1}`;
4077
+ const snippet = item.snippet ?? item.description ?? "";
4078
+ const content = item.content ?? item.text ?? snippet ?? title;
4079
+ return {
4080
+ id: `result-${index + 1}`,
4081
+ title,
4082
+ url,
4083
+ snippet,
4084
+ content
4085
+ };
4086
+ }
4087
+ async enrichTopResults(candidates, scrapeTopK, crawler) {
4088
+ if (!crawler.crawl || scrapeTopK <= 0) {
4089
+ return { failures: 0, attempts: 0 };
4090
+ }
4091
+ const targets = candidates.slice(0, Math.min(scrapeTopK, candidates.length));
4092
+ let failures = 0;
4093
+ let attempts = 0;
4094
+ await Promise.all(
4095
+ targets.map(async (candidate) => {
4096
+ try {
4097
+ const result = await this.executeWithRetry(
4098
+ "scrape",
4099
+ async () => crawler.crawl(candidate.url)
4100
+ );
4101
+ attempts += result.attempts;
4102
+ const raw = result.value;
4103
+ const normalized = this.normalizeCrawlContent(raw);
4104
+ if (normalized.length > 0) {
4105
+ candidate.content = normalized;
4106
+ }
4107
+ } catch {
4108
+ failures += 1;
4109
+ attempts += this.maxRetries + 1;
4110
+ }
4111
+ })
4112
+ );
4113
+ return { failures, attempts };
4114
+ }
4115
+ normalizeCrawlContent(raw) {
4116
+ if (typeof raw === "string") {
4117
+ return raw;
4118
+ }
4119
+ if (raw && typeof raw === "object") {
4120
+ const item = raw;
4121
+ return item.content ?? item.text ?? item.snippet ?? item.description ?? "";
4122
+ }
4123
+ return "";
4124
+ }
4125
+ async executeWithRetry(label, operation) {
4126
+ let lastError;
4127
+ for (let attempt = 1; attempt <= this.maxRetries + 1; attempt++) {
4128
+ try {
4129
+ const value = await this.circuitBreaker.execute(
4130
+ () => this.withTimeout(operation(), `${label} attempt ${attempt}`)
4131
+ );
4132
+ return { value, attempts: attempt };
4133
+ } catch (error) {
4134
+ lastError = error;
4135
+ if (attempt <= this.maxRetries) {
4136
+ await this.sleep(this.retryDelayMs * attempt);
4137
+ }
4138
+ }
4139
+ }
4140
+ throw lastError;
4141
+ }
4142
+ async withTimeout(promise, label) {
4143
+ return await new Promise((resolve, reject) => {
4144
+ const timer = setTimeout(() => {
4145
+ reject(new Error(`${label} timed out after ${this.requestTimeoutMs}ms`));
4146
+ }, this.requestTimeoutMs);
4147
+ promise.then((value) => {
4148
+ clearTimeout(timer);
4149
+ resolve(value);
4150
+ }).catch((error) => {
4151
+ clearTimeout(timer);
4152
+ reject(error);
4153
+ });
4154
+ });
4155
+ }
4156
+ async sleep(ms) {
4157
+ await new Promise((resolve) => setTimeout(resolve, ms));
4158
+ }
4159
+ calculateAverageScore(results) {
4160
+ if (results.length === 0) return 0;
4161
+ const sum = results.reduce((acc, item) => acc + item.score, 0);
4162
+ return sum / results.length;
4163
+ }
4164
+ buildCostRecord(query, results, quality) {
4165
+ if (!this.costTracker) {
4166
+ return void 0;
4167
+ }
4168
+ const promptTokens = this.estimateTokens(query);
4169
+ const completionText = results.map((result) => `${result.title}
4170
+ ${result.snippet}
4171
+ ${result.citation}`).join("\n\n");
4172
+ const completionTokens = this.estimateTokens(completionText);
4173
+ const totalTokens = promptTokens + completionTokens;
4174
+ const usage = {
4175
+ model: this.costModel,
4176
+ provider: "semantic-web-search",
4177
+ inputTokens: promptTokens,
4178
+ outputTokens: completionTokens,
4179
+ timestamp: Date.now()
4180
+ };
4181
+ const totalBefore = this.costTracker.getEstimate().totalCost;
4182
+ this.costTracker.recordUsage(usage);
4183
+ const totalAfter = this.costTracker.getEstimate().totalCost;
4184
+ const totalCost = Math.max(0, totalAfter - totalBefore);
4185
+ this.emitEvent("semantic_search_cost_recorded", {
4186
+ traceId: quality.traceId,
4187
+ model: this.costModel,
4188
+ promptTokens,
4189
+ completionTokens,
4190
+ totalTokens,
4191
+ totalCost
4192
+ });
4193
+ return {
4194
+ promptTokens,
4195
+ completionTokens,
4196
+ totalTokens,
4197
+ totalCost
4198
+ };
4199
+ }
4200
+ estimateTokens(text) {
4201
+ if (text.trim().length === 0) {
4202
+ return 0;
4203
+ }
4204
+ return Math.max(1, Math.ceil(text.length / 4));
4205
+ }
4206
+ emitEvent(name, properties, status = "OK") {
4207
+ if (!this.emitTelemetry || !this.telemetry) {
4208
+ return;
4209
+ }
4210
+ try {
4211
+ const span = this.telemetry.startSpan(name);
4212
+ for (const [key, value] of Object.entries(properties)) {
4213
+ span.setAttribute(key, this.toTelemetryAttribute(value));
4214
+ }
4215
+ span.setStatus(status);
4216
+ span.end();
4217
+ } catch {
4218
+ }
4219
+ }
4220
+ emitMetric(name, value, tags) {
4221
+ if (!this.emitTelemetry || !this.telemetry) {
4222
+ return;
4223
+ }
4224
+ try {
4225
+ this.telemetry.recordMetric(name, value, tags);
4226
+ } catch {
4227
+ }
4228
+ }
4229
+ toTelemetryAttribute(value) {
4230
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4231
+ return value;
4232
+ }
4233
+ if (value === null || value === void 0) {
4234
+ return "";
4235
+ }
4236
+ try {
4237
+ return JSON.stringify(value);
4238
+ } catch {
4239
+ return String(value);
4240
+ }
4241
+ }
4242
+ };
4243
+ function createSemanticWebSearchPlugin(options = {}) {
4244
+ return new SemanticWebSearchPlugin(options);
4245
+ }
4246
+
4247
+ // src/plugins/mcp-server.plugin.ts
4248
+ import { z as z7 } from "zod";
4249
+
4250
+ // src/adapters/mcp-server/default-mcp-server.adapter.ts
4251
+ import { createServer } from "http";
4252
+ import { randomUUID as randomUUID2 } from "crypto";
4253
+ var DefaultMcpServerAdapter = class _DefaultMcpServerAdapter {
4254
+ tools = [];
4255
+ toolsByName = /* @__PURE__ */ new Map();
4256
+ executor;
4257
+ options;
4258
+ // stdio
4259
+ stdinHandler;
4260
+ stdinBuffer = "";
4261
+ // sse
4262
+ httpServer;
4263
+ sseClients = /* @__PURE__ */ new Map();
4264
+ constructor(tools, executor) {
4265
+ this.tools = tools;
4266
+ this.rebuildToolIndex();
4267
+ this.executor = executor;
4268
+ }
4269
+ rebuildToolIndex() {
4270
+ this.toolsByName.clear();
4271
+ for (const t of this.tools) {
4272
+ this.toolsByName.set(t.name, t);
4273
+ }
4274
+ }
4275
+ // ── Public API ──────────────────────────────────────────────────────────
4276
+ getRegisteredTools() {
4277
+ return [...this.tools];
4278
+ }
4279
+ setTools(tools) {
4280
+ this.tools = tools;
4281
+ this.rebuildToolIndex();
4282
+ }
4283
+ async start(options) {
4284
+ this.options = options;
4285
+ const filtered = options.toolFilter ? this.tools.filter((t) => options.toolFilter.includes(t.name)) : this.tools;
4286
+ this.tools = filtered;
4287
+ this.rebuildToolIndex();
4288
+ if (options.transport === "stdio") {
4289
+ this.startStdio();
4290
+ } else {
4291
+ await this.startSse(options.port ?? 3100);
4292
+ }
4293
+ }
4294
+ async stop() {
4295
+ if (this.stdinHandler) {
4296
+ process.stdin.removeListener("data", this.stdinHandler);
4297
+ this.stdinHandler = void 0;
4298
+ this.stdinBuffer = "";
4299
+ }
4300
+ if (this.httpServer) {
4301
+ for (const [, client] of this.sseClients) {
4302
+ client.end();
4303
+ }
4304
+ this.sseClients.clear();
4305
+ await new Promise((resolve, reject) => {
4306
+ this.httpServer.close((err) => err ? reject(err) : resolve());
4307
+ });
4308
+ this.httpServer = void 0;
4309
+ }
4310
+ }
4311
+ // ── JSON-RPC handler ──────────────────────────────────────────────────
4312
+ async handleRequest(request) {
4313
+ const { id, method, params } = request;
4314
+ switch (method) {
4315
+ case "initialize":
4316
+ return {
4317
+ jsonrpc: "2.0",
4318
+ id,
4319
+ result: {
4320
+ protocolVersion: "2024-11-05",
4321
+ serverInfo: {
4322
+ name: this.options?.name ?? "gaussflow-mcp-server",
4323
+ version: this.options?.version ?? "1.0.0"
4324
+ },
4325
+ capabilities: {
4326
+ tools: { listChanged: false }
4327
+ }
4328
+ }
4329
+ };
4330
+ case "tools/list":
4331
+ return {
4332
+ jsonrpc: "2.0",
4333
+ id,
4334
+ result: {
4335
+ tools: this.tools.map((t) => ({
4336
+ name: t.name,
4337
+ description: t.description,
4338
+ inputSchema: t.inputSchema
4339
+ }))
4340
+ }
4341
+ };
4342
+ case "tools/call": {
4343
+ const toolName = params?.name ?? "";
4344
+ const toolArgs = params?.arguments ?? {};
4345
+ const toolDef = this.toolsByName.get(toolName);
4346
+ if (!toolDef) {
4347
+ return {
4348
+ jsonrpc: "2.0",
4349
+ id,
4350
+ error: { code: -32601, message: `Unknown tool: ${toolName}` }
4351
+ };
4352
+ }
4353
+ try {
4354
+ const result = await this.executor(toolName, toolArgs);
4355
+ return { jsonrpc: "2.0", id, result };
4356
+ } catch (err) {
4357
+ return {
4358
+ jsonrpc: "2.0",
4359
+ id,
4360
+ result: {
4361
+ content: [{ type: "text", text: String(err) }],
4362
+ isError: true
4363
+ }
4364
+ };
4365
+ }
4366
+ }
4367
+ case "notifications/initialized":
4368
+ return { jsonrpc: "2.0", id, result: {} };
4369
+ default:
4370
+ return {
4371
+ jsonrpc: "2.0",
4372
+ id,
4373
+ error: { code: -32601, message: `Method not found: ${method}` }
4374
+ };
4375
+ }
4376
+ }
4377
+ // ── Stdio transport ───────────────────────────────────────────────────
4378
+ startStdio() {
4379
+ this.stdinBuffer = "";
4380
+ this.stdinHandler = (data) => {
4381
+ this.stdinBuffer += data.toString("utf-8");
4382
+ let newlineIdx;
4383
+ while ((newlineIdx = this.stdinBuffer.indexOf("\n")) !== -1) {
4384
+ const line = this.stdinBuffer.slice(0, newlineIdx).trim();
4385
+ this.stdinBuffer = this.stdinBuffer.slice(newlineIdx + 1);
4386
+ if (!line) continue;
4387
+ this.processStdioLine(line).catch((err) => {
4388
+ console.warn("[mcp-stdio] Unhandled error processing line:", err instanceof Error ? err.message : String(err));
4389
+ });
4390
+ }
4391
+ };
4392
+ process.stdin.on("data", this.stdinHandler);
4393
+ }
4394
+ async processStdioLine(line) {
4395
+ let request;
4396
+ try {
4397
+ request = JSON.parse(line);
4398
+ } catch {
4399
+ const errResponse = {
4400
+ jsonrpc: "2.0",
4401
+ id: null,
4402
+ error: { code: -32700, message: "Parse error" }
4403
+ };
4404
+ process.stdout.write(JSON.stringify(errResponse) + "\n");
4405
+ return;
4406
+ }
4407
+ const response = await this.handleRequest(request);
4408
+ if (request.id !== null && request.id !== void 0) {
4409
+ process.stdout.write(JSON.stringify(response) + "\n");
4410
+ }
4411
+ }
4412
+ // ── SSE transport ─────────────────────────────────────────────────────
4413
+ startSse(port) {
4414
+ return new Promise((resolve, reject) => {
4415
+ this.httpServer = createServer((req, res) => {
4416
+ this.handleHttpRequest(req, res).catch((err) => {
4417
+ console.warn("[mcp-sse] Unhandled request error:", err instanceof Error ? err.message : String(err));
4418
+ if (!res.headersSent) {
4419
+ res.writeHead(500);
4420
+ res.end();
4421
+ }
4422
+ });
4423
+ });
4424
+ this.httpServer.once("error", reject);
4425
+ this.httpServer.listen(port, "127.0.0.1", () => resolve());
4426
+ });
4427
+ }
4428
+ async handleHttpRequest(req, res) {
4429
+ res.setHeader("Access-Control-Allow-Origin", "http://localhost");
4430
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
4431
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
4432
+ if (req.method === "OPTIONS") {
4433
+ res.writeHead(204);
4434
+ res.end();
4435
+ return;
4436
+ }
4437
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
4438
+ if (url.pathname === "/sse" && req.method === "GET") {
4439
+ const clientId = randomUUID2();
4440
+ res.writeHead(200, {
4441
+ "Content-Type": "text/event-stream",
4442
+ "Cache-Control": "no-cache",
4443
+ Connection: "keep-alive"
4444
+ });
4445
+ res.write(`data: ${JSON.stringify({ type: "endpoint", url: `/message?clientId=${clientId}` })}
4446
+
4447
+ `);
4448
+ this.sseClients.set(clientId, res);
4449
+ req.on("close", () => this.sseClients.delete(clientId));
4450
+ return;
4451
+ }
4452
+ if (url.pathname === "/message" && req.method === "POST") {
4453
+ const body = await this.readBody(req);
4454
+ let request;
4455
+ try {
4456
+ request = JSON.parse(body);
4457
+ } catch {
4458
+ res.writeHead(400, { "Content-Type": "application/json" });
4459
+ res.end(JSON.stringify({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }));
4460
+ return;
4461
+ }
4462
+ const response = await this.handleRequest(request);
4463
+ const responseJson = JSON.stringify(response);
4464
+ const clientId = url.searchParams.get("clientId");
4465
+ if (clientId) {
4466
+ const client = this.sseClients.get(clientId);
4467
+ if (client) client.write(`data: ${responseJson}
4468
+
4469
+ `);
4470
+ }
4471
+ res.writeHead(200, { "Content-Type": "application/json" });
4472
+ res.end(responseJson);
4473
+ return;
4474
+ }
4475
+ res.writeHead(404, { "Content-Type": "application/json" });
4476
+ res.end(JSON.stringify({ error: "Not found" }));
4477
+ }
4478
+ static MAX_BODY_SIZE = 1048576;
4479
+ // 1 MB
4480
+ readBody(req) {
4481
+ return new Promise((resolve, reject) => {
4482
+ const chunks = [];
4483
+ let size = 0;
4484
+ req.on("data", (chunk) => {
4485
+ size += chunk.length;
4486
+ if (size > _DefaultMcpServerAdapter.MAX_BODY_SIZE) {
4487
+ req.destroy(new Error("Request body too large"));
4488
+ return;
4489
+ }
4490
+ chunks.push(chunk);
4491
+ });
4492
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
4493
+ req.on("error", reject);
4494
+ });
4495
+ }
4496
+ };
4497
+
4498
+ // src/plugins/mcp-server.plugin.ts
4499
+ var START_SCHEMA = z7.object({
4500
+ transport: z7.enum(["stdio", "sse"]).default("stdio"),
4501
+ port: z7.number().optional(),
4502
+ toolFilter: z7.array(z7.string()).optional()
4503
+ });
4504
+ var STOP_SCHEMA = z7.object({});
4505
+ var McpServerPlugin = class {
4506
+ name = "mcp-server";
4507
+ version = "1.0.0";
4508
+ tools;
4509
+ adapter;
4510
+ pluginOptions;
4511
+ collectedTools = [];
4512
+ constructor(options = {}) {
4513
+ this.pluginOptions = options;
4514
+ this.tools = {
4515
+ "mcp:start-server": tool({
4516
+ description: "Start an MCP server that exposes the agent's tools via MCP protocol. Supports stdio (default) and sse transports.",
4517
+ inputSchema: START_SCHEMA,
4518
+ execute: async (input) => {
4519
+ const args = START_SCHEMA.parse(input ?? {});
4520
+ if (this.adapter) {
4521
+ await this.adapter.stop();
4522
+ }
4523
+ this.adapter = new DefaultMcpServerAdapter(
4524
+ this.collectedTools,
4525
+ this.pluginOptions.executor ?? this.defaultExecutor.bind(this)
4526
+ );
4527
+ await this.adapter.start({
4528
+ name: this.pluginOptions.name ?? "gaussflow-mcp-server",
4529
+ version: this.pluginOptions.version ?? "1.0.0",
4530
+ transport: args.transport,
4531
+ port: args.port,
4532
+ toolFilter: args.toolFilter
4533
+ });
4534
+ const tools = this.adapter.getRegisteredTools();
4535
+ return {
4536
+ status: "started",
4537
+ transport: args.transport,
4538
+ port: args.transport === "sse" ? args.port ?? 3100 : void 0,
4539
+ toolCount: tools.length,
4540
+ tools: tools.map((t) => t.name)
4541
+ };
4542
+ }
4543
+ }),
4544
+ "mcp:stop-server": tool({
4545
+ description: "Stop the running MCP server.",
4546
+ inputSchema: STOP_SCHEMA,
4547
+ execute: async () => {
4548
+ if (!this.adapter) {
4549
+ return { status: "not_running" };
4550
+ }
4551
+ await this.adapter.stop();
4552
+ this.adapter = void 0;
4553
+ return { status: "stopped" };
4554
+ }
4555
+ })
4556
+ };
4557
+ }
4558
+ async setup(ctx) {
4559
+ this.collectedTools = ctx.toolNames.map((name) => ({
4560
+ name,
4561
+ description: `Agent tool: ${name}`,
4562
+ inputSchema: { type: "object", properties: {} }
4563
+ }));
4564
+ if (this.pluginOptions.extraTools) {
4565
+ this.collectedTools.push(...this.pluginOptions.extraTools);
4566
+ }
4567
+ }
4568
+ async dispose() {
4569
+ if (this.adapter) {
4570
+ await this.adapter.stop();
4571
+ this.adapter = void 0;
4572
+ }
4573
+ }
4574
+ /** Expose the underlying adapter for testing */
4575
+ getAdapter() {
4576
+ return this.adapter;
4577
+ }
4578
+ /** Expose collected tools for testing */
4579
+ getCollectedTools() {
4580
+ return [...this.collectedTools];
4581
+ }
4582
+ async defaultExecutor(name, _args) {
4583
+ return {
4584
+ content: [{ type: "text", text: `Tool "${name}" executed (no custom executor provided)` }]
4585
+ };
4586
+ }
4587
+ };
4588
+ function createMcpServerPlugin(options) {
4589
+ return new McpServerPlugin(options);
4590
+ }
4591
+ export {
4592
+ A2ADelegationManager,
4593
+ A2APlugin,
4594
+ A2APushNotifier,
4595
+ AgentCardPlugin,
4596
+ BasePlugin,
4597
+ EvalsPlugin,
4598
+ GuardrailsError,
4599
+ GuardrailsPlugin,
4600
+ McpServerPlugin,
4601
+ ObservabilityPlugin,
4602
+ OneCrawlPlugin,
4603
+ PluginManager,
4604
+ SemanticScrapingPlugin,
4605
+ SemanticWebSearchPlugin,
4606
+ VectorlessPlugin,
4607
+ WorkflowError,
4608
+ WorkflowPlugin,
4609
+ createA2AHttpHandler,
4610
+ createA2AJsonRpcHandler,
4611
+ createA2APlugin,
4612
+ createA2ASseHandler,
4613
+ createAgentCardPlugin,
4614
+ createEvalsPlugin,
4615
+ createGuardrailsPlugin,
4616
+ createMcpServerPlugin,
4617
+ createObservabilityPlugin,
4618
+ createOneCrawlPlugin,
4619
+ createPiiFilter,
4620
+ createSemanticScrapingPlugin,
4621
+ createSemanticWebSearchPlugin,
4622
+ createVectorlessPlugin,
4623
+ createWorkflowPlugin
4624
+ };
4625
+ //# sourceMappingURL=plugins-L4ING3CX.js.map