@buoy-gg/agent-core 7.0.40 → 7.0.42

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 (202) hide show
  1. package/lib/commonjs/blocks/receipts.js +1 -761
  2. package/lib/commonjs/blocks/runId.js +1 -31
  3. package/lib/commonjs/blocks/types.js +1 -140
  4. package/lib/commonjs/blocks/uiTool.js +6 -1405
  5. package/lib/commonjs/catalog/catalog.g.js +5 -4207
  6. package/lib/commonjs/catalog/catalog.source.json +656 -12
  7. package/lib/commonjs/catalog/catalog.types.g.js +1 -44
  8. package/lib/commonjs/catalog/normalizeParams.js +2 -332
  9. package/lib/commonjs/catalog/signature.js +1 -68
  10. package/lib/commonjs/catalog/snapshotReads.js +1 -263
  11. package/lib/commonjs/catalog/toProviderTools.js +2 -145
  12. package/lib/commonjs/catalog/validateParams.js +1 -129
  13. package/lib/commonjs/context/buildContextPack.js +1 -489
  14. package/lib/commonjs/effects/digest.js +1 -34
  15. package/lib/commonjs/effects/ledger.js +1 -325
  16. package/lib/commonjs/engine/askGate.js +1 -287
  17. package/lib/commonjs/engine/effectFor.js +1 -176
  18. package/lib/commonjs/engine/evidence.js +3 -111
  19. package/lib/commonjs/engine/historyBudget.js +1 -363
  20. package/lib/commonjs/engine/retrieve.js +1 -214
  21. package/lib/commonjs/engine/runAgentTurn.js +8 -1803
  22. package/lib/commonjs/engine/systemPrompt.js +54 -163
  23. package/lib/commonjs/engine/textToolCalls.js +1 -276
  24. package/lib/commonjs/engine/tokenCalibration.js +1 -81
  25. package/lib/commonjs/engine/verify.js +4 -297
  26. package/lib/commonjs/index.js +1 -384
  27. package/lib/commonjs/policy/labels.js +1 -319
  28. package/lib/commonjs/policy/policy.js +1 -148
  29. package/lib/commonjs/policy/redact.js +1 -172
  30. package/lib/commonjs/providers/anthropic.js +3 -445
  31. package/lib/commonjs/providers/openai.js +4 -324
  32. package/lib/commonjs/providers/problem.js +1 -98
  33. package/lib/commonjs/providers/sse.js +1 -240
  34. package/lib/commonjs/providers/streamTimer.js +1 -123
  35. package/lib/commonjs/providers/transport.js +1 -123
  36. package/lib/commonjs/providers/types.js +1 -6
  37. package/lib/commonjs/providers/xhrStream.js +1 -212
  38. package/lib/commonjs/realNow.js +1 -0
  39. package/lib/commonjs/session.js +1 -393
  40. package/lib/commonjs/types.js +0 -1
  41. package/lib/module/blocks/receipts.js +1 -755
  42. package/lib/module/blocks/runId.js +1 -26
  43. package/lib/module/blocks/types.js +1 -134
  44. package/lib/module/blocks/uiTool.js +6 -1396
  45. package/lib/module/catalog/catalog.g.js +5 -4203
  46. package/lib/module/catalog/catalog.source.json +656 -12
  47. package/lib/module/catalog/catalog.types.g.js +1 -40
  48. package/lib/module/catalog/normalizeParams.js +2 -326
  49. package/lib/module/catalog/signature.js +1 -63
  50. package/lib/module/catalog/snapshotReads.js +1 -259
  51. package/lib/module/catalog/toProviderTools.js +2 -139
  52. package/lib/module/catalog/validateParams.js +1 -124
  53. package/lib/module/context/buildContextPack.js +1 -485
  54. package/lib/module/effects/digest.js +1 -29
  55. package/lib/module/effects/ledger.js +1 -319
  56. package/lib/module/engine/askGate.js +1 -280
  57. package/lib/module/engine/effectFor.js +1 -173
  58. package/lib/module/engine/evidence.js +3 -105
  59. package/lib/module/engine/historyBudget.js +1 -355
  60. package/lib/module/engine/retrieve.js +1 -210
  61. package/lib/module/engine/runAgentTurn.js +8 -1794
  62. package/lib/module/engine/systemPrompt.js +54 -157
  63. package/lib/module/engine/textToolCalls.js +1 -270
  64. package/lib/module/engine/tokenCalibration.js +1 -75
  65. package/lib/module/engine/verify.js +4 -289
  66. package/lib/module/index.js +1 -35
  67. package/lib/module/policy/labels.js +1 -312
  68. package/lib/module/policy/policy.js +1 -142
  69. package/lib/module/policy/redact.js +1 -165
  70. package/lib/module/providers/anthropic.js +3 -441
  71. package/lib/module/providers/openai.js +4 -320
  72. package/lib/module/providers/problem.js +1 -92
  73. package/lib/module/providers/sse.js +1 -231
  74. package/lib/module/providers/streamTimer.js +1 -118
  75. package/lib/module/providers/transport.js +1 -119
  76. package/lib/module/providers/types.js +1 -4
  77. package/lib/module/providers/xhrStream.js +1 -207
  78. package/lib/module/realNow.js +1 -0
  79. package/lib/module/session.js +1 -369
  80. package/lib/module/types.js +0 -1
  81. package/lib/typescript/catalog/catalog.g.d.ts +3 -3
  82. package/lib/typescript/catalog/catalog.types.g.d.ts +7 -4
  83. package/lib/typescript/effects/ledger.d.ts +16 -1
  84. package/lib/typescript/providers/problem.d.ts +0 -20
  85. package/lib/typescript/providers/streamTimer.d.ts +0 -24
  86. package/lib/typescript/realNow.d.ts +18 -0
  87. package/lib/web/index.mjs +152 -0
  88. package/package.json +24 -3
  89. package/lib/commonjs/blocks/receipts.js.map +0 -1
  90. package/lib/commonjs/blocks/runId.js.map +0 -1
  91. package/lib/commonjs/blocks/types.js.map +0 -1
  92. package/lib/commonjs/blocks/uiTool.js.map +0 -1
  93. package/lib/commonjs/catalog/catalog.g.js.map +0 -1
  94. package/lib/commonjs/catalog/catalog.types.g.js.map +0 -1
  95. package/lib/commonjs/catalog/normalizeParams.js.map +0 -1
  96. package/lib/commonjs/catalog/signature.js.map +0 -1
  97. package/lib/commonjs/catalog/snapshotReads.js.map +0 -1
  98. package/lib/commonjs/catalog/toProviderTools.js.map +0 -1
  99. package/lib/commonjs/catalog/validateParams.js.map +0 -1
  100. package/lib/commonjs/context/buildContextPack.js.map +0 -1
  101. package/lib/commonjs/effects/digest.js.map +0 -1
  102. package/lib/commonjs/effects/ledger.js.map +0 -1
  103. package/lib/commonjs/engine/askGate.js.map +0 -1
  104. package/lib/commonjs/engine/effectFor.js.map +0 -1
  105. package/lib/commonjs/engine/evidence.js.map +0 -1
  106. package/lib/commonjs/engine/historyBudget.js.map +0 -1
  107. package/lib/commonjs/engine/retrieve.js.map +0 -1
  108. package/lib/commonjs/engine/runAgentTurn.js.map +0 -1
  109. package/lib/commonjs/engine/systemPrompt.js.map +0 -1
  110. package/lib/commonjs/engine/textToolCalls.js.map +0 -1
  111. package/lib/commonjs/engine/tokenCalibration.js.map +0 -1
  112. package/lib/commonjs/engine/verify.js.map +0 -1
  113. package/lib/commonjs/index.js.map +0 -1
  114. package/lib/commonjs/policy/labels.js.map +0 -1
  115. package/lib/commonjs/policy/policy.js.map +0 -1
  116. package/lib/commonjs/policy/redact.js.map +0 -1
  117. package/lib/commonjs/providers/anthropic.js.map +0 -1
  118. package/lib/commonjs/providers/openai.js.map +0 -1
  119. package/lib/commonjs/providers/problem.js.map +0 -1
  120. package/lib/commonjs/providers/sse.js.map +0 -1
  121. package/lib/commonjs/providers/streamTimer.js.map +0 -1
  122. package/lib/commonjs/providers/transport.js.map +0 -1
  123. package/lib/commonjs/providers/types.js.map +0 -1
  124. package/lib/commonjs/providers/xhrStream.js.map +0 -1
  125. package/lib/commonjs/session.js.map +0 -1
  126. package/lib/commonjs/types.js.map +0 -1
  127. package/lib/module/blocks/receipts.js.map +0 -1
  128. package/lib/module/blocks/runId.js.map +0 -1
  129. package/lib/module/blocks/types.js.map +0 -1
  130. package/lib/module/blocks/uiTool.js.map +0 -1
  131. package/lib/module/catalog/catalog.g.js.map +0 -1
  132. package/lib/module/catalog/catalog.types.g.js.map +0 -1
  133. package/lib/module/catalog/normalizeParams.js.map +0 -1
  134. package/lib/module/catalog/signature.js.map +0 -1
  135. package/lib/module/catalog/snapshotReads.js.map +0 -1
  136. package/lib/module/catalog/toProviderTools.js.map +0 -1
  137. package/lib/module/catalog/validateParams.js.map +0 -1
  138. package/lib/module/context/buildContextPack.js.map +0 -1
  139. package/lib/module/effects/digest.js.map +0 -1
  140. package/lib/module/effects/ledger.js.map +0 -1
  141. package/lib/module/engine/askGate.js.map +0 -1
  142. package/lib/module/engine/effectFor.js.map +0 -1
  143. package/lib/module/engine/evidence.js.map +0 -1
  144. package/lib/module/engine/historyBudget.js.map +0 -1
  145. package/lib/module/engine/retrieve.js.map +0 -1
  146. package/lib/module/engine/runAgentTurn.js.map +0 -1
  147. package/lib/module/engine/systemPrompt.js.map +0 -1
  148. package/lib/module/engine/textToolCalls.js.map +0 -1
  149. package/lib/module/engine/tokenCalibration.js.map +0 -1
  150. package/lib/module/engine/verify.js.map +0 -1
  151. package/lib/module/index.js.map +0 -1
  152. package/lib/module/policy/labels.js.map +0 -1
  153. package/lib/module/policy/policy.js.map +0 -1
  154. package/lib/module/policy/redact.js.map +0 -1
  155. package/lib/module/providers/anthropic.js.map +0 -1
  156. package/lib/module/providers/openai.js.map +0 -1
  157. package/lib/module/providers/problem.js.map +0 -1
  158. package/lib/module/providers/sse.js.map +0 -1
  159. package/lib/module/providers/streamTimer.js.map +0 -1
  160. package/lib/module/providers/transport.js.map +0 -1
  161. package/lib/module/providers/types.js.map +0 -1
  162. package/lib/module/providers/xhrStream.js.map +0 -1
  163. package/lib/module/session.js.map +0 -1
  164. package/lib/module/types.js.map +0 -1
  165. package/lib/typescript/blocks/receipts.d.ts.map +0 -1
  166. package/lib/typescript/blocks/runId.d.ts.map +0 -1
  167. package/lib/typescript/blocks/types.d.ts.map +0 -1
  168. package/lib/typescript/blocks/uiTool.d.ts.map +0 -1
  169. package/lib/typescript/catalog/catalog.g.d.ts.map +0 -1
  170. package/lib/typescript/catalog/catalog.types.g.d.ts.map +0 -1
  171. package/lib/typescript/catalog/normalizeParams.d.ts.map +0 -1
  172. package/lib/typescript/catalog/signature.d.ts.map +0 -1
  173. package/lib/typescript/catalog/snapshotReads.d.ts.map +0 -1
  174. package/lib/typescript/catalog/toProviderTools.d.ts.map +0 -1
  175. package/lib/typescript/catalog/validateParams.d.ts.map +0 -1
  176. package/lib/typescript/context/buildContextPack.d.ts.map +0 -1
  177. package/lib/typescript/effects/digest.d.ts.map +0 -1
  178. package/lib/typescript/effects/ledger.d.ts.map +0 -1
  179. package/lib/typescript/engine/askGate.d.ts.map +0 -1
  180. package/lib/typescript/engine/effectFor.d.ts.map +0 -1
  181. package/lib/typescript/engine/evidence.d.ts.map +0 -1
  182. package/lib/typescript/engine/historyBudget.d.ts.map +0 -1
  183. package/lib/typescript/engine/retrieve.d.ts.map +0 -1
  184. package/lib/typescript/engine/runAgentTurn.d.ts.map +0 -1
  185. package/lib/typescript/engine/systemPrompt.d.ts.map +0 -1
  186. package/lib/typescript/engine/textToolCalls.d.ts.map +0 -1
  187. package/lib/typescript/engine/tokenCalibration.d.ts.map +0 -1
  188. package/lib/typescript/engine/verify.d.ts.map +0 -1
  189. package/lib/typescript/index.d.ts.map +0 -1
  190. package/lib/typescript/policy/labels.d.ts.map +0 -1
  191. package/lib/typescript/policy/policy.d.ts.map +0 -1
  192. package/lib/typescript/policy/redact.d.ts.map +0 -1
  193. package/lib/typescript/providers/anthropic.d.ts.map +0 -1
  194. package/lib/typescript/providers/openai.d.ts.map +0 -1
  195. package/lib/typescript/providers/problem.d.ts.map +0 -1
  196. package/lib/typescript/providers/sse.d.ts.map +0 -1
  197. package/lib/typescript/providers/streamTimer.d.ts.map +0 -1
  198. package/lib/typescript/providers/transport.d.ts.map +0 -1
  199. package/lib/typescript/providers/types.d.ts.map +0 -1
  200. package/lib/typescript/providers/xhrStream.d.ts.map +0 -1
  201. package/lib/typescript/session.d.ts.map +0 -1
  202. package/lib/typescript/types.d.ts.map +0 -1
@@ -1,259 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * The other half of Buoy's read surface.
5
- *
6
- * Every Buoy adapter answers in two ways, and only one of them is an action.
7
- * `listQueries`, `async.getAllKeys` and `getState` are actions; console
8
- * entries, network events, the route sitemap and the env table are NOT — they
9
- * exist only inside the adapter's `getSnapshot`, which the sync layer polls and
10
- * puts on the wire for MCP's `get_snapshot` / `get_console` /
11
- * `get_network_requests` / `get_routes`.
12
- *
13
- * `dispatchToolAction` reaches only the first half. So an agent driving tools
14
- * on the device could read storage, stores and the query cache, and was blind
15
- * to the app's logs, its HTTP traffic, its routes and its environment — the
16
- * four things a QA person is most likely to ask about, and two of which the
17
- * empty state advertises as suggestions. The catalog even tells the model to
18
- * "use get_console", which is an MCP tool that does not exist on this path.
19
- *
20
- * This module closes that half. `getSnapshot` is a RESERVED action name: the
21
- * engine intercepts it before dispatch and routes it to the registry's
22
- * snapshot reader instead.
23
- *
24
- * WHY THE PROJECTIONS. A raw snapshot is the heaviest payload in the system —
25
- * measured at ~1.1KB per console entry with up to 1000 retained, and network
26
- * events carry bodies. Handing that to a token-metered model truncated at 24K
27
- * chars produces a torn JSON object and a wasted turn. Each projector here
28
- * does what the matching MCP tool does: newest-first, filtered, and only the
29
- * fields worth spending tokens on. Bodies stay behind `network.getEventBody`,
30
- * which already exists.
31
- */
32
-
33
- import { isSelfTraffic } from "../policy/redact";
34
-
35
- /** Reserved action name. Not a real adapter action anywhere. */
36
- export const SNAPSHOT_ACTION = "getSnapshot";
37
- const SEVERITY = {
38
- verbose: 0,
39
- debug: 0,
40
- trace: 0,
41
- log: 1,
42
- info: 1,
43
- warn: 2,
44
- warning: 2,
45
- error: 3
46
- };
47
- function asArray(value) {
48
- return Array.isArray(value) ? value : [];
49
- }
50
- function rec(value) {
51
- return value && typeof value === "object" ? value : {};
52
- }
53
- function num(value, fallback) {
54
- return typeof value === "number" && value > 0 ? value : fallback;
55
- }
56
-
57
- /**
58
- * The newest N. Every Buoy event store (BaseEventStore, which network,
59
- * console, sentry and route events all sit on) PREPENDS, so the list arrives
60
- * newest-FIRST and the newest N are the first N. An earlier version took the
61
- * LAST N here — the oldest — so once more than N were captured, RIGHT NOW
62
- * showed the stalest requests and a crash that had just happened fell out of
63
- * the console projection. Order is preserved: newest first.
64
- */
65
- function newest(items, limit) {
66
- return items.length <= limit ? items : items.slice(0, limit);
67
- }
68
- function projectConsole(payload, params) {
69
- const entries = asArray(rec(payload).entries);
70
- const minSeverity = typeof params.level === "string" ? SEVERITY[params.level] ?? 0 : 0;
71
- const pattern = typeof params.pattern === "string" ? params.pattern.toLowerCase() : undefined;
72
- const matched = entries.filter(raw => {
73
- const e = rec(raw);
74
- const level = String(e.level ?? "log");
75
- if ((SEVERITY[level] ?? 1) < minSeverity) return false;
76
- if (!pattern) return true;
77
- return String(e.message ?? "").toLowerCase().includes(pattern);
78
- });
79
- const shown = newest(matched, num(params.limit, 40));
80
- return {
81
- totalCaptured: entries.length,
82
- shown: shown.length,
83
- // Pre-rendered message only. Full args and stacks stay on the device;
84
- // `get_snapshot('console')` is the MCP escape hatch and has no equivalent
85
- // here on purpose — it is the payload that blows the prompt.
86
- entries: shown.map(raw => {
87
- const e = rec(raw);
88
- return {
89
- at: e.timestamp,
90
- level: e.level,
91
- message: e.message
92
- };
93
- })
94
- };
95
- }
96
- function projectNetwork(payload, params) {
97
- const p = rec(payload);
98
- // The agent's own POSTs to the model endpoint are dropped HERE, not only by
99
- // the engine's later pass, so the counts the model is given match the rows
100
- // it is given. Reporting "4 requests" above a list of 3 is its own small lie.
101
- const events = asArray(p.events).filter(raw => !isSelfTraffic(rec(raw).url));
102
- const failedOnly = params.failedOnly === true;
103
- const pattern = typeof params.pattern === "string" ? params.pattern.toLowerCase() : undefined;
104
- const matched = events.filter(raw => {
105
- const e = rec(raw);
106
- const status = typeof e.status === "number" ? e.status : undefined;
107
- if (failedOnly && !(e.error || status !== undefined && status >= 400)) return false;
108
- if (!pattern) return true;
109
- return String(e.url ?? "").toLowerCase().includes(pattern);
110
- });
111
- const shown = newest(matched, num(params.limit, 25));
112
- return {
113
- totalCaptured: events.length,
114
- shown: shown.length,
115
- // No bodies. `network.getEventBody` fetches one on demand, which is the
116
- // difference between a readable list and a truncated blob.
117
- requests: shown.map(raw => {
118
- const e = rec(raw);
119
- return {
120
- id: e.id,
121
- method: e.method,
122
- url: e.url,
123
- status: e.status,
124
- durationMs: e.duration,
125
- error: e.error,
126
- // An override rule served this response. Carried through so neither
127
- // the model nor the receipt can present mocked data as live.
128
- overridden: e.override ? true : undefined
129
- };
130
- }),
131
- hint: "Read one response with network.getEventBody({ id })."
132
- };
133
- }
134
-
135
- /**
136
- * The sitemap arrives as a NESTED RouteInfo tree, not a list. A model asked
137
- * "what screens exist" needs the leaf paths, so flatten and keep the paths.
138
- */
139
- function flattenRoutes(nodes, out = [], cap = 80) {
140
- for (const raw of asArray(nodes)) {
141
- if (out.length >= cap) break;
142
- const node = rec(raw);
143
- if (node.isInternal !== true && typeof node.path === "string") out.push(node.path);
144
- flattenRoutes(node.children, out, cap);
145
- }
146
- return out;
147
- }
148
- function projectRoutes(payload, params) {
149
- const p = rec(payload);
150
- const sitemap = rec(p.sitemap);
151
-
152
- // Route events are stored newest-FIRST, and a stack item's screen path is
153
- // `pathname` (`path` does not exist on it). Getting either wrong is not a
154
- // crash, it is a confident wrong answer: an early version of this read told
155
- // the user they were on the Pokedex while the shop was on screen.
156
- const stackRaw = asArray(p.stack).map(rec);
157
- const eventsRaw = asArray(p.events).map(rec);
158
- const stack = stackRaw.map(s => ({
159
- name: s.name,
160
- path: s.pathname,
161
- focused: s.isFocused === true ? true : undefined
162
- }));
163
- const recentNavigations = eventsRaw.slice(0, num(params.limit, 15)).map(e => ({
164
- at: e.timestamp,
165
- from: e.previousPathname,
166
- to: e.pathname
167
- }));
168
-
169
- // Mirrors the adapter's own `getCurrentRoute`: the newest navigation event
170
- // wins, and with no history yet — a freshly launched app — the FOCUSED stack
171
- // item does, which is not always the last one in the array.
172
- const focused = stackRaw.find(s => s.isFocused === true) ?? stackRaw[stackRaw.length - 1];
173
- const currentRoute = eventsRaw.length ? {
174
- path: eventsRaw[0].pathname,
175
- source: "event"
176
- } : typeof focused?.pathname === "string" ? {
177
- path: focused.pathname,
178
- source: "stack"
179
- } : undefined;
180
- return {
181
- currentRoute,
182
- stack,
183
- routes: flattenRoutes(sitemap.routes),
184
- sitemapSource: sitemap.source,
185
- recentNavigations
186
- };
187
- }
188
- function projectEnv(payload) {
189
- const p = rec(payload);
190
- return {
191
- env: p.env ?? p.variables,
192
- requiredEnvVars: p.requiredEnvVars
193
- };
194
- }
195
-
196
- /**
197
- * Sentry envelopes are the fattest payloads any Buoy tool captures (a single
198
- * event with breadcrumbs is tens of KB), so only the item SUMMARIES travel —
199
- * the one-line human read the adapter already computes. The status field is
200
- * load-bearing: an empty list with "sdk-not-found" means the app has no
201
- * Sentry client, which is a different answer from "nothing errored".
202
- */
203
- function projectSentry(payload, params) {
204
- const p = rec(payload);
205
- const envelopes = asArray(p.envelopes).map(rec);
206
- const typeFilter = typeof params.type === "string" ? params.type : undefined;
207
- const pattern = typeof params.pattern === "string" ? params.pattern.toLowerCase() : undefined;
208
- const matched = envelopes.filter(e => {
209
- const items = asArray(e.items).map(rec);
210
- if (typeFilter && !items.some(i => i.type === typeFilter)) return false;
211
- if (!pattern) return true;
212
- return items.some(i => String(i.summary ?? "").toLowerCase().includes(pattern));
213
- });
214
- const shown = newest(matched, num(params.limit, 10));
215
- return {
216
- status: p.status,
217
- totalCaptured: envelopes.length,
218
- shown: shown.length,
219
- envelopes: shown.map(e => ({
220
- id: e.id,
221
- at: e.timestamp,
222
- origin: e.origin,
223
- eventId: e.eventId,
224
- totalBytes: e.totalBytes,
225
- items: asArray(e.items).map(raw => {
226
- const i = rec(raw);
227
- return {
228
- type: i.type,
229
- summary: i.summary,
230
- spanCount: i.spanCount,
231
- bytes: i.bytes
232
- };
233
- })
234
- })),
235
- hint: "For crash stack traces, console's [FATAL] entries carry the component stacks."
236
- };
237
- }
238
-
239
- /**
240
- * Trim one snapshot to something worth sending. Unknown tools pass through —
241
- * the engine's 24K truncation is still the backstop.
242
- */
243
- export function projectSnapshot(toolId, payload, params = {}) {
244
- switch (toolId) {
245
- case "console":
246
- return projectConsole(payload, params);
247
- case "network":
248
- return projectNetwork(payload, params);
249
- case "route-events":
250
- return projectRoutes(payload, params);
251
- case "env":
252
- return projectEnv(payload);
253
- case "sentry":
254
- return projectSentry(payload, params);
255
- default:
256
- return payload;
257
- }
258
- }
259
- //# sourceMappingURL=snapshotReads.js.map
1
+ "use strict";import{isSelfTraffic as y}from"../policy/redact";export const SNAPSHOT_ACTION="getSnapshot";const m={verbose:0,debug:0,trace:0,log:1,info:1,warn:2,warning:2,error:3};function l(e){return Array.isArray(e)?e:[]}function u(e){return e&&typeof e==="object"?e:{}}function d(e,t){return typeof e==="number"&&e>0?e:t}function h(e,t){return e.length<=t?e:e.slice(0,t)}function v(e,t){const o=l(u(e).entries);const c=typeof t.level==="string"?m[t.level]??0:0;const i=typeof t.pattern==="string"?t.pattern.toLowerCase():void 0;const a=o.filter(f=>{const n=u(f);const r=String(n.level??"log");if((m[r]??1)<c)return false;if(!i)return true;return String(n.message??"").toLowerCase().includes(i)});const p=h(a,d(t.limit,40));return{totalCaptured:o.length,shown:p.length,entries:p.map(f=>{const n=u(f);return{at:n.timestamp,level:n.level,message:n.message}})}}function w(e,t){const o=u(e);const c=l(o.events).filter(n=>!y(u(n).url));const i=t.failedOnly===true;const a=typeof t.pattern==="string"?t.pattern.toLowerCase():void 0;const p=c.filter(n=>{const r=u(n);const s=typeof r.status==="number"?r.status:void 0;if(i&&!(r.error||s!==void 0&&s>=400))return false;if(!a)return true;return String(r.url??"").toLowerCase().includes(a)});const f=h(p,d(t.limit,25));return{totalCaptured:c.length,shown:f.length,requests:f.map(n=>{const r=u(n);return{id:r.id,method:r.method,url:r.url,status:r.status,durationMs:r.duration,error:r.error,overridden:r.override?true:void 0}}),hint:"Read one response with network.getEventBody({ id })."}}function g(e,t=[],o=80){for(const c of l(e)){if(t.length>=o)break;const i=u(c);if(i.isInternal!==true&&typeof i.path==="string")t.push(i.path);g(i.children,t,o)}return t}function C(e,t){const o=u(e);const c=u(o.sitemap);const i=l(o.stack).map(u);const a=l(o.events).map(u);const p=i.map(s=>({name:s.name,path:s.pathname,focused:s.isFocused===true?true:void 0}));const f=a.slice(0,d(t.limit,15)).map(s=>({at:s.timestamp,from:s.previousPathname,to:s.pathname}));const n=i.find(s=>s.isFocused===true)??i[i.length-1];const r=a.length?{path:a[0].pathname,source:"event"}:typeof n?.pathname==="string"?{path:n.pathname,source:"stack"}:void 0;return{currentRoute:r,stack:p,routes:g(c.routes),sitemapSource:c.source,recentNavigations:f}}function S(e){const t=u(e);return{env:t.env??t.variables,requiredEnvVars:t.requiredEnvVars}}function k(e,t){const o=u(e);const c=l(o.envelopes).map(u);const i=typeof t.type==="string"?t.type:void 0;const a=typeof t.pattern==="string"?t.pattern.toLowerCase():void 0;const p=c.filter(n=>{const r=l(n.items).map(u);if(i&&!r.some(s=>s.type===i))return false;if(!a)return true;return r.some(s=>String(s.summary??"").toLowerCase().includes(a))});const f=h(p,d(t.limit,10));return{status:o.status,totalCaptured:c.length,shown:f.length,envelopes:f.map(n=>({id:n.id,at:n.timestamp,origin:n.origin,eventId:n.eventId,totalBytes:n.totalBytes,items:l(n.items).map(r=>{const s=u(r);return{type:s.type,summary:s.summary,spanCount:s.spanCount,bytes:s.bytes}})})),hint:"For crash stack traces, console's [FATAL] entries carry the component stacks."}}export function projectSnapshot(e,t,o={}){switch(e){case"console":return v(t,o);case"network":return w(t,o);case"route-events":return C(t,o);case"env":return S(t);case"sentry":return k(t,o);default:return t}}
@@ -1,139 +1,2 @@
1
- "use strict";
2
-
3
- /**
4
- * Catalog -> provider tool definitions.
5
- *
6
- * WHY ONE TOOL PER BUOY TOOL, NOT ONE PER ACTION: tool-selection accuracy
7
- * degrades past roughly 30-50 tools. Buoy has ~179 actions across 22 tools, so
8
- * a 1:1 mapping is far past the point where the model starts picking wrong.
9
- * Each Buoy tool therefore becomes ONE provider tool whose `action` property is
10
- * an enum, with the per-action summaries folded into that enum's description.
11
- *
12
- * `params` stays an open object at the provider boundary — a discriminated
13
- * union across 179 branches is unusable by any model and unreadable by a human.
14
- * The real per-action schema is enforced one layer in, by `validateParams`,
15
- * which returns a structured error the model can correct on the next turn.
16
- * That is strictly stronger than the MCP server's `z.record(z.unknown())`,
17
- * which validates nothing.
18
- */
19
- import { paramsLine } from "./signature";
20
-
21
- /**
22
- * Provider-agnostic tool definition; the adapters reshape it per protocol.
23
- *
24
- * The description comes in three forms because the two protocols cap it
25
- * differently. Anthropic takes `description` whole. OpenAI (and Azure, and
26
- * every OpenAI-compatible gateway) caps a function description at 1024
27
- * chars, and the catalog renders the summary first and the `Actions:` list
28
- * LAST — so trimming `description` to fit dropped every action line for 23
29
- * of 24 tools (the 24th kept one line of sixteen), and a model on that
30
- * protocol saw a summary cut mid-sentence plus a bare `action` enum. Hence
31
- * the split: `summaryDescription` is the part that fits the cap,
32
- * `actionsBlock` goes into the `action` property's description, which
33
- * nothing caps. `description` stays their concatenation
34
- * so the Anthropic request is byte-identical to what it was.
35
- */
36
-
37
- /**
38
- * Both Anthropic and OpenAI cap tool names at `[a-zA-Z0-9_-]`, so Buoy's
39
- * dashed ids survive but the `custom:<id>` sync namespace does not. Anthropic's
40
- * docs say 64 chars while its reference schema says 128 — we code to 64.
41
- */
42
- const MAX_TOOL_NAME = 64;
43
- export function toProviderToolName(toolId) {
44
- return `buoy_${toolId.replace(/[^a-zA-Z0-9_-]/g, "_")}`.slice(0, MAX_TOOL_NAME);
45
- }
46
-
47
- /** Reverse of {@link toProviderToolName}, resolved against the live catalog. */
48
- export function fromProviderToolName(name, catalog) {
49
- return catalog.find(t => toProviderToolName(t.toolId) === name)?.toolId;
50
- }
51
-
52
- /**
53
- * One line per action, in the `action` enum's description. This is where the
54
- * model actually learns what each action does, so it carries the effect and
55
- * the release caveat inline rather than hiding them in a separate field the
56
- * model never sees.
57
- */
58
- function actionLine(a, isRelease) {
59
- const bits = [`${a.action} — ${a.summary}`];
60
- if (a.effect === "destructive") bits.push("[DESTRUCTIVE]");else if (a.effect === "write") bits.push("[changes state]");
61
- if (isRelease && a.release !== "works") {
62
- bits.push(`[UNAVAILABLE in this build: ${a.release}]`);
63
- }
64
- if (a.requires?.length) bits.push(`[needs: ${a.requires.join(", ")}]`);
65
- // The field names, from the SAME schema `validateParams` enforces. Without
66
- // them the model reconstructs parameter names from prose and invents one on
67
- // ~18% of param-carrying calls (measured across three agents); five of the
68
- // commonest misses are patched up by `normalizeParams`, the rest just fail.
69
- // `buoy_ui` already ships its signatures for exactly this reason — see the
70
- // note above `signature()` in catalog/signature.ts.
71
- const sig = paramsLine(a.params);
72
- return sig ? `${bits.join(" ")}\n ${sig}` : bits.join(" ");
73
- }
74
- export function toProviderTools(catalog, opts = {}) {
75
- const {
76
- availableToolIds,
77
- availableActions,
78
- isRelease = false,
79
- hideUnavailable = false
80
- } = opts;
81
- const tools = [];
82
- for (const tool of catalog) {
83
- if (availableToolIds && !availableToolIds.includes(tool.toolId)) continue;
84
- const live = availableActions?.[tool.toolId];
85
- // An engine-served action needs no adapter to advertise it — the engine
86
- // is the adapter — so it rides with the tool whenever the tool is here.
87
- let actions = live ? tool.actions.filter(a => live.includes(a.action) || a.servedBy === "engine") : tool.actions;
88
- if (isRelease && hideUnavailable) {
89
- actions = actions.filter(a => a.release === "works");
90
- }
91
- if (actions.length === 0) continue;
92
-
93
- // The summary ALONE is what has to fit OpenAI's 1024-char cap (it does for
94
- // 23 of 24 tools); the availability caveat rides with the actions block,
95
- // which nothing caps. Concatenated they are the same bytes as before.
96
- const summaryDescription = tool.summary;
97
- // These prose lines look like the expensive part of the catalog and are
98
- // the CHEAPEST part of it. Measured against a real tokenizer (fal ->
99
- // gpt-4o-mini): the whole catalog is 79,601 chars but only 7,902 tokens
100
- // — 10.1 chars/token, because English prose is what BPE compresses best.
101
- // An index that replaced these lines with a bare list of action names
102
- // sent 48% fewer characters and cost MORE tokens (7,986), since dotted
103
- // camelCase identifiers tokenize at ~5 chars/token. Do not "shrink" this
104
- // by counting characters; measure tokens or leave it alone.
105
- const actionsBlock = [tool.unavailableWhen ? `Unavailable when: ${tool.unavailableWhen}` : "", "Actions:", ...actions.map(a => `- ${actionLine(a, isRelease)}`)].join("\n");
106
- // No blank line between the two: the single-list render this replaced
107
- // filtered its "" separator out, and this string is the prefix Anthropic
108
- // caches — it must not move by a byte.
109
- const desc = [summaryDescription, actionsBlock].filter(Boolean).join("\n");
110
- const inputExamples = actions.flatMap(a => a.inputExamples ?? []);
111
- tools.push({
112
- name: toProviderToolName(tool.toolId),
113
- ...(inputExamples.length ? {
114
- inputExamples
115
- } : {}),
116
- description: desc,
117
- summaryDescription,
118
- actionsBlock,
119
- inputSchema: {
120
- type: "object",
121
- properties: {
122
- action: {
123
- type: "string",
124
- enum: actions.map(a => a.action),
125
- description: "Which action to run. See the list in this tool's description."
126
- },
127
- params: {
128
- type: "object",
129
- description: "Arguments for the action. Each action's `params:` line in this tool's description lists its exact fields — `*` marks a required one. Send EXACTLY those names; a field that is not listed is rejected."
130
- }
131
- },
132
- required: ["action"],
133
- additionalProperties: false
134
- }
135
- });
136
- }
137
- return tools;
138
- }
139
- //# sourceMappingURL=toProviderTools.js.map
1
+ "use strict";import{paramsLine as h}from"./signature";const v=64;export function toProviderToolName(e){return`buoy_${e.replace(/[^a-zA-Z0-9_-]/g,"_")}`.slice(0,v)}export function fromProviderToolName(e,s){return s.find(t=>toProviderToolName(t.toolId)===e)?.toolId}function b(e,s){const t=[`${e.action} \u2014 ${e.summary}`];if(e.effect==="destructive")t.push("[DESTRUCTIVE]");else if(e.effect==="write")t.push("[changes state]");if(s&&e.release!=="works"){t.push(`[UNAVAILABLE in this build: ${e.release}]`)}if(e.requires?.length)t.push(`[needs: ${e.requires.join(", ")}]`);const r=h(e.params);return r?`${t.join(" ")}
2
+ ${r}`:t.join(" ")}export function toProviderTools(e,s={}){const{availableToolIds:t,availableActions:r,isRelease:a=false,hideUnavailable:f=false}=s;const l=[];for(const o of e){if(t&&!t.includes(o.toolId))continue;const c=r?.[o.toolId];let n=c?o.actions.filter(i=>c.includes(i.action)||i.servedBy==="engine"):o.actions;if(a&&f){n=n.filter(i=>i.release==="works")}if(n.length===0)continue;const u=o.summary;const p=[o.unavailableWhen?`Unavailable when: ${o.unavailableWhen}`:"","Actions:",...n.map(i=>`- ${b(i,a)}`)].join("\n");const m=[u,p].filter(Boolean).join("\n");const d=n.flatMap(i=>i.inputExamples??[]);l.push({name:toProviderToolName(o.toolId),...d.length?{inputExamples:d}:{},description:m,summaryDescription:u,actionsBlock:p,inputSchema:{type:"object",properties:{action:{type:"string",enum:n.map(i=>i.action),description:"Which action to run. See the list in this tool's description."},params:{type:"object",description:"Arguments for the action. Each action's `params:` line in this tool's description lists its exact fields \u2014 `*` marks a required one. Send EXACTLY those names; a field that is not listed is rejected."}},required:["action"],additionalProperties:false}})}return l}
@@ -1,124 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * A deliberately small JSON Schema validator.
5
- *
6
- * Buoy's adapters validate nothing — every handler takes `params?: unknown` and
7
- * hand-casts (`(params as { id?: string })?.id`), so a wrong shape becomes an
8
- * undefined read, and an LLM omitting an optional flag can do real damage:
9
- * `zustand.setState` defaults `replace ?? true`, so calling it without
10
- * `replace` REPLACES the entire store rather than merging it.
11
- *
12
- * So the agent validates before it dispatches. The point is not spec
13
- * compliance — it is that a rejection comes back to the model as a readable
14
- * error naming the expected schema, which it can fix on the next turn. That is
15
- * why this covers exactly the subset `JsonSchema` describes and nothing more:
16
- * a rule the validator silently skips is a rule that isn't enforced.
17
- */
18
-
19
- function typeOf(v) {
20
- if (v === null) return "null";
21
- if (Array.isArray(v)) return "array";
22
- return typeof v;
23
- }
24
- function checkType(value, type) {
25
- switch (type) {
26
- case "integer":
27
- return typeof value === "number" && Number.isInteger(value);
28
- case "number":
29
- return typeof value === "number" && Number.isFinite(value);
30
- case "null":
31
- return value === null;
32
- case "array":
33
- return Array.isArray(value);
34
- case "object":
35
- return typeOf(value) === "object";
36
- default:
37
- return typeof value === type;
38
- }
39
- }
40
- function validate(value, schema, path, errors) {
41
- if (schema.anyOf?.length) {
42
- const anyOk = schema.anyOf.some(s => {
43
- const sub = [];
44
- validate(value, s, path, sub);
45
- return sub.length === 0;
46
- });
47
- if (!anyOk) {
48
- const kinds = schema.anyOf.map(s => s.type ?? "?").join(" | ");
49
- errors.push(`${path}: expected ${kinds}, got ${typeOf(value)}`);
50
- }
51
- return;
52
- }
53
- if (schema.type && !checkType(value, schema.type)) {
54
- errors.push(`${path}: expected ${schema.type}, got ${typeOf(value)}`);
55
- return;
56
- }
57
- if (schema.enum && !schema.enum.includes(value)) {
58
- errors.push(`${path}: expected one of ${schema.enum.map(e => JSON.stringify(e)).join(", ")}, got ${JSON.stringify(value)}`);
59
- return;
60
- }
61
- if (schema.type === "array" && Array.isArray(value)) {
62
- if (schema.minItems !== undefined && value.length < schema.minItems) {
63
- errors.push(`${path}: expected at least ${schema.minItems} item(s), got ${value.length}`);
64
- }
65
- if (schema.maxItems !== undefined && value.length > schema.maxItems) {
66
- errors.push(`${path}: expected at most ${schema.maxItems} item(s), got ${value.length}`);
67
- }
68
- if (schema.items) {
69
- value.forEach((item, i) => validate(item, schema.items, `${path}[${i}]`, errors));
70
- }
71
- return;
72
- }
73
- if (schema.type === "object" && typeOf(value) === "object") {
74
- const obj = value;
75
- for (const key of schema.required ?? []) {
76
- if (obj[key] === undefined) errors.push(`${path}.${key}: required`);
77
- }
78
- if (schema.properties) {
79
- for (const [key, sub] of Object.entries(schema.properties)) {
80
- if (obj[key] !== undefined) validate(obj[key], sub, `${path}.${key}`, errors);
81
- }
82
- // Only flag unknown keys when the schema says so. Several adapters read
83
- // params they never documented, and rejecting an extra key the handler
84
- // happens to use would break a call that would have worked.
85
- if (schema.additionalProperties === false) {
86
- const known = new Set(Object.keys(schema.properties));
87
- for (const key of Object.keys(obj)) {
88
- if (!known.has(key)) errors.push(`${path}.${key}: unexpected property`);
89
- }
90
- }
91
- }
92
- }
93
- }
94
- export function validateParams(params, schema) {
95
- const errors = [];
96
- // A no-param action called with nothing is the common case, not an error.
97
- const value = params === undefined || params === null ? {} : params;
98
- validate(value, schema, "params", errors);
99
- return {
100
- ok: errors.length === 0,
101
- errors
102
- };
103
- }
104
-
105
- /**
106
- * Fill in documented defaults the model left out.
107
- *
108
- * This is the counter-measure to the omitted-flag class of bug. Several Buoy
109
- * actions invert the usual assumption — `focus-inspector.setTracking` reads
110
- * `params?.enabled !== false`, so calling it with `{}` turns tracking ON — and
111
- * the catalog records the real default. Applying it explicitly means the model
112
- * omitting a flag produces the documented behaviour rather than the accidental
113
- * one.
114
- */
115
- export function applyDefaults(params, schema) {
116
- const out = typeOf(params) === "object" ? {
117
- ...params
118
- } : {};
119
- for (const [key, sub] of Object.entries(schema.properties ?? {})) {
120
- if (out[key] === undefined && sub.default !== undefined) out[key] = sub.default;
121
- }
122
- return out;
123
- }
124
- //# sourceMappingURL=validateParams.js.map
1
+ "use strict";function u(t){if(t===null)return"null";if(Array.isArray(t))return"array";return typeof t}function s(t,e){switch(e){case"integer":return typeof t==="number"&&Number.isInteger(t);case"number":return typeof t==="number"&&Number.isFinite(t);case"null":return t===null;case"array":return Array.isArray(t);case"object":return u(t)==="object";default:return typeof t===e}}function y(t,e,n,i){if(e.anyOf?.length){const f=e.anyOf.some(r=>{const o=[];y(t,r,n,o);return o.length===0});if(!f){const r=e.anyOf.map(o=>o.type??"?").join(" | ");i.push(`${n}: expected ${r}, got ${u(t)}`)}return}if(e.type&&!s(t,e.type)){i.push(`${n}: expected ${e.type}, got ${u(t)}`);return}if(e.enum&&!e.enum.includes(t)){i.push(`${n}: expected one of ${e.enum.map(f=>JSON.stringify(f)).join(", ")}, got ${JSON.stringify(t)}`);return}if(e.type==="array"&&Array.isArray(t)){if(e.minItems!==void 0&&t.length<e.minItems){i.push(`${n}: expected at least ${e.minItems} item(s), got ${t.length}`)}if(e.maxItems!==void 0&&t.length>e.maxItems){i.push(`${n}: expected at most ${e.maxItems} item(s), got ${t.length}`)}if(e.items){t.forEach((f,r)=>y(f,e.items,`${n}[${r}]`,i))}return}if(e.type==="object"&&u(t)==="object"){const f=t;for(const r of e.required??[]){if(f[r]===void 0)i.push(`${n}.${r}: required`)}if(e.properties){for(const[r,o]of Object.entries(e.properties)){if(f[r]!==void 0)y(f[r],o,`${n}.${r}`,i)}if(e.additionalProperties===false){const r=new Set(Object.keys(e.properties));for(const o of Object.keys(f)){if(!r.has(o))i.push(`${n}.${o}: unexpected property`)}}}}}export function validateParams(t,e){const n=[];const i=t===void 0||t===null?{}:t;y(i,e,"params",n);return{ok:n.length===0,errors:n}}export function applyDefaults(t,e){const n=u(t)==="object"?{...t}:{};for(const[i,f]of Object.entries(e.properties??{})){if(n[i]===void 0&&f.default!==void 0)n[i]=f.default}return n}