@intutic/gate 1.10.1

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/actions.d.ts +86 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +239 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/client.d.ts +94 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +207 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/dsh.d.ts +162 -0
  12. package/dist/dsh.d.ts.map +1 -0
  13. package/dist/dsh.js +189 -0
  14. package/dist/dsh.js.map +1 -0
  15. package/dist/errors.d.ts +41 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +53 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/eve.d.ts +425 -0
  20. package/dist/eve.d.ts.map +1 -0
  21. package/dist/eve.js +378 -0
  22. package/dist/eve.js.map +1 -0
  23. package/dist/gate.d.ts +113 -0
  24. package/dist/gate.d.ts.map +1 -0
  25. package/dist/gate.js +274 -0
  26. package/dist/gate.js.map +1 -0
  27. package/dist/harness.d.ts +482 -0
  28. package/dist/harness.d.ts.map +1 -0
  29. package/dist/harness.js +504 -0
  30. package/dist/harness.js.map +1 -0
  31. package/dist/headers.d.ts +26 -0
  32. package/dist/headers.d.ts.map +1 -0
  33. package/dist/headers.js +30 -0
  34. package/dist/headers.js.map +1 -0
  35. package/dist/imagecheck.d.ts +93 -0
  36. package/dist/imagecheck.d.ts.map +1 -0
  37. package/dist/imagecheck.js +286 -0
  38. package/dist/imagecheck.js.map +1 -0
  39. package/dist/index.d.ts +26 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +19 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/managedAgents.d.ts +375 -0
  44. package/dist/managedAgents.d.ts.map +1 -0
  45. package/dist/managedAgents.js +446 -0
  46. package/dist/managedAgents.js.map +1 -0
  47. package/dist/mastra.d.ts +175 -0
  48. package/dist/mastra.d.ts.map +1 -0
  49. package/dist/mastra.js +161 -0
  50. package/dist/mastra.js.map +1 -0
  51. package/dist/openai.d.ts +392 -0
  52. package/dist/openai.d.ts.map +1 -0
  53. package/dist/openai.js +658 -0
  54. package/dist/openai.js.map +1 -0
  55. package/dist/shlex.d.ts +16 -0
  56. package/dist/shlex.d.ts.map +1 -0
  57. package/dist/shlex.js +78 -0
  58. package/dist/shlex.js.map +1 -0
  59. package/dist/snapshot.d.ts +111 -0
  60. package/dist/snapshot.d.ts.map +1 -0
  61. package/dist/snapshot.js +243 -0
  62. package/dist/snapshot.js.map +1 -0
  63. package/dist/soprules.d.ts +88 -0
  64. package/dist/soprules.d.ts.map +1 -0
  65. package/dist/soprules.js +176 -0
  66. package/dist/soprules.js.map +1 -0
  67. package/dist/trueforge.d.ts +191 -0
  68. package/dist/trueforge.d.ts.map +1 -0
  69. package/dist/trueforge.js +184 -0
  70. package/dist/trueforge.js.map +1 -0
  71. package/dist/vercel.d.ts +174 -0
  72. package/dist/vercel.d.ts.map +1 -0
  73. package/dist/vercel.js +157 -0
  74. package/dist/vercel.js.map +1 -0
  75. package/dist/workflow.d.ts +209 -0
  76. package/dist/workflow.d.ts.map +1 -0
  77. package/dist/workflow.js +254 -0
  78. package/dist/workflow.js.map +1 -0
  79. package/dist/wrapTools.d.ts +68 -0
  80. package/dist/wrapTools.d.ts.map +1 -0
  81. package/dist/wrapTools.js +95 -0
  82. package/dist/wrapTools.js.map +1 -0
  83. package/package.json +123 -0
@@ -0,0 +1,446 @@
1
+ /**
2
+ * Anthropic Managed Agents (public beta since 2026-04-08) — a session
3
+ * confirmation responder, plus guidance for the two execution surfaces this
4
+ * adapter does NOT cover the same way.
5
+ *
6
+ * `@intutic/gate/managed-agents` — the TypeScript twin of the Python SDK's
7
+ * `intutic_clawde.gate.adapters.managed_agents`. See that module's doc for
8
+ * the full research trail; this header covers only what differs for the
9
+ * TypeScript SDK.
10
+ *
11
+ * Managed Agents is architecturally different from every other adapter in
12
+ * this package: the customer's process does not run the tool-call loop.
13
+ * Anthropic hosts a "session" that emits an event stream, and the customer's
14
+ * backend answers it. There is no local function call to wrap the way
15
+ * `wrapTools()` wraps a Mastra tool.
16
+ *
17
+ * ## The veto mechanism — CONFIRMED against a real install
18
+ *
19
+ * `@anthropic-ai/sdk@0.117.1` (the latest published release at the time this
20
+ * adapter was built) was installed as a devDependency of this package and its
21
+ * shipped `.d.ts` read directly (not inferred from docs alone; the Python
22
+ * twin was checked the same way against `anthropic==0.122.0`, its own
23
+ * latest):
24
+ *
25
+ * * `resources/beta/sessions/events.d.ts` — every request this module
26
+ * issues (`.list()`, `.send()`, `.stream()`) carries
27
+ * `anthropic-beta: managed-agents-2026-04-01` automatically (the real
28
+ * client sets it); {@link MANAGED_AGENTS_BETA} documents the value for a
29
+ * caller building a raw request.
30
+ * * `BetaManagedAgentsUserToolConfirmationEventParams` — the wire shape
31
+ * this module builds: `{ type: 'user.tool_confirmation', tool_use_id,
32
+ * result: 'allow' | 'deny', deny_message?, session_thread_id? }`.
33
+ * * `BetaManagedAgentsAgentToolUseEvent` and
34
+ * `BetaManagedAgentsAgentMCPToolUseEvent` both carry
35
+ * `evaluated_permission?: 'allow' | 'ask' | 'deny'`. A call the server
36
+ * evaluated to `'ask'` (e.g. because its `permission_policy` is
37
+ * `always_ask` — Anthropic's docs mark MCP toolsets as `always_ask` by
38
+ * default; the SDK types do not encode a default for built-in
39
+ * agent-toolset tools, so check current docs) PAUSES the session —
40
+ * Anthropic's own docs: "Denied tools do not run." A `'deny'` verdict
41
+ * means the SERVER already denied the call (no confirmation is expected
42
+ * or accepted); `'allow'` or unset means the call never paused at all.
43
+ * **This is the real, documented pre-execution veto this module answers
44
+ * — it is not observe-only.**
45
+ * * `lib/tools/SessionToolRunner.d.ts` is Anthropic's OWN reference
46
+ * dispatcher: it executes `agent.tool_use` / `agent.custom_tool_use`
47
+ * calls and posts results, but it does **not** decide `allow`/`deny` for
48
+ * an `ask`-gated call itself — it holds until *something* sends the
49
+ * matching `user.tool_confirmation` event. That "something" is what this
50
+ * module provides: {@link confirmationForEvent} /
51
+ * {@link IntuticSessionConfirmer} turn a paused `agent.tool_use` /
52
+ * `agent.mcp_tool_use` event into a `Gate.guard()`-driven verdict.
53
+ * * `lib/environments/worker.d.ts`'s `EnvironmentWorker` (the self-hosted
54
+ * sandbox driver) is built on `SessionToolRunner` for built-in
55
+ * agent-toolset tools (bash, edit, read, write, glob, grep, web_fetch,
56
+ * web_search). **Self-hosted built-in tools therefore pause and resolve
57
+ * through the IDENTICAL `agent.tool_use` / `evaluated_permission` /
58
+ * `user.tool_confirmation` mechanism as hosted ones** — this adapter
59
+ * covers them the same way. What differs for self-hosted is only WHERE
60
+ * the tool body executes (the customer's own worker process), not how
61
+ * the pre-execution veto works.
62
+ * * `agent.mcp_tool_use` is explicitly excluded from `SessionToolRunner`'s
63
+ * own dispatch (its own doc comment: "Server-side `agent.mcp_tool_use`
64
+ * calls are intentionally excluded — the runner does not handle them" —
65
+ * MCP tools run server-side at Anthropic). But the confirmation gate is a
66
+ * SEPARATE mechanism from execution: `BetaManagedAgentsAgentMCPToolUseEvent`
67
+ * carries `evaluated_permission` exactly like the built-in event does, so
68
+ * this module answers MCP pauses too, even though nothing in the official
69
+ * SDK dispatches their execution locally.
70
+ *
71
+ * ## What this module does NOT cover the same way — custom tools
72
+ *
73
+ * `BetaManagedAgentsAgentCustomToolUseEvent` has **no** `evaluated_permission`
74
+ * field and no `permission_policy` concept at all: a custom tool always
75
+ * executes wherever the client that owns its name is listening, with no
76
+ * pause. It is answered with `user.custom_tool_result`
77
+ * (`custom_tool_use_id` + `content` + `is_error`), not
78
+ * `user.tool_confirmation`. This is the "customer's own process runs the
79
+ * call" surface the phase brief anticipated — the natural integration point
80
+ * IS this package's `wrapTools()`/`wrapTool()`, exactly as the brief
81
+ * guessed. BUT verify the shape, because the generic helper does not apply
82
+ * as-is: `BetaRunnableTool` (`lib/tools/BetaRunnableTool.d.ts`, what
83
+ * `SessionToolRunner` dispatches against) exposes a `run(args, context)`
84
+ * method, not the `execute(input)` method `wrapTools()`'s object branch looks
85
+ * for (`wrapTools.ts` only recognises `.execute`) — handing it a
86
+ * `BetaRunnableTool` throws a `TypeError` rather than silently skipping
87
+ * governance, but it still means the generic helper needs a `.run`-aware
88
+ * sibling rather than "just works". {@link wrapManagedAgentsCustomTool} /
89
+ * {@link wrapManagedAgentsCustomTools} are that sibling — same throw-based
90
+ * refusal contract, applied to `.run` instead of `.execute`.
91
+ *
92
+ * ## What this module does NOT cover at all — the sandbox tool BODY
93
+ *
94
+ * The self-hosted `EnvironmentWorker` gates tool PAUSES exactly like the
95
+ * hosted path (see above) — but the tool's actual execution runs inside the
96
+ * customer's own worker process, outside this adapter's reach, same as every
97
+ * other Intutic adapter's posture toward a framework's built-in tool bodies
98
+ * (see openai.ts's module doc for the precedent). This module governs
99
+ * WHETHER the call runs; it does not — and cannot — inspect or modify what
100
+ * the tool body does once allowed.
101
+ *
102
+ * ## Webhook vs. streamed/polled delivery — both are real, verified live
103
+ *
104
+ * `resources/beta/webhooks.d.ts`: `client.beta.webhooks.unwrap(body, {
105
+ * headers, key })` verifies the HMAC signature and returns a typed event
106
+ * (synchronously — no network call); for a pause it is
107
+ * `session.requires_action`, which carries only `id` (the session id),
108
+ * `organization_id`, `workspace_id` — NOT the tool call itself. A webhook is
109
+ * therefore a NOTIFICATION to re-poll, not a self-contained payload —
110
+ * {@link IntuticSessionConfirmer.handleWebhook} does exactly that: re-lists
111
+ * the session's unanswered events and answers them. `events.stream()` /
112
+ * `events.list()` are the poll/stream alternative this module also supports
113
+ * directly via {@link IntuticSessionConfirmer.poll} /
114
+ * {@link IntuticSessionConfirmer.watch}.
115
+ *
116
+ * ## Fail-closed posture
117
+ *
118
+ * Matches every other adapter in this package: no gate configured, or an
119
+ * unexpected exception out of `Gate.guard()`, both produce a `'deny'` verdict
120
+ * — never a silently-allowed, unevaluated call. Only `IntuticGateRefusal` is
121
+ * distinguished (its own message becomes `deny_message`); anything else is
122
+ * wrapped in a generic "gate crashed" `deny_message`.
123
+ *
124
+ * ## What this module does NOT import
125
+ *
126
+ * Deliberately no runtime dependency on `@anthropic-ai/sdk` — the types below
127
+ * are narrow structural copies of only the shapes this adapter touches, same
128
+ * policy as openai.ts / mastra.ts / vercel.ts (see openai.ts's module doc for
129
+ * the full rationale). The real package is a devDependency used by
130
+ * `__tests__/managedAgents.test.ts` to type-check these structural types
131
+ * against the real shipped ones.
132
+ *
133
+ * @module
134
+ */
135
+ import { active as activeGate } from './gate.js';
136
+ import { IntuticGateRefusal } from './errors.js';
137
+ // ---------------------------------------------------------------------------
138
+ // Structural copies of the @anthropic-ai/sdk shapes this adapter touches.
139
+ // Confirmed field-for-field against @anthropic-ai/sdk@0.117.1's shipped
140
+ // resources/beta/sessions/events.d.ts (see module doc). This package does
141
+ // not depend on the SDK at runtime, so the shapes are declared here rather
142
+ // than imported.
143
+ // ---------------------------------------------------------------------------
144
+ /** The beta header every Sessions-API request needs. The real SDK sets this
145
+ * on every `.list()`/`.send()`/`.stream()` call automatically — this
146
+ * constant exists for callers building their own request against the
147
+ * endpoint directly. */
148
+ export const MANAGED_AGENTS_BETA = 'managed-agents-2026-04-01';
149
+ const CONFIRMABLE_EVENT_TYPES = new Set(['agent.tool_use', 'agent.mcp_tool_use']);
150
+ const TERMINAL_EVENT_TYPES = new Set(['session.status_terminated', 'session.deleted']);
151
+ /** Read a field off any session event by key, regardless of which member of
152
+ * {@link ManagedAgentsSessionEventLike} it structurally is — e.g.
153
+ * `tool_use_id`, which only `user.tool_confirmation` events carry. Mirrors
154
+ * the Python adapter's `_field` helper. */
155
+ function eventField(event, key) {
156
+ return event[key];
157
+ }
158
+ function resolveGate(explicit, what) {
159
+ const g = explicit ?? activeGate();
160
+ if (g === null) {
161
+ throw new Error('No gate configured: call install(new Gate(...)) from @intutic/gate, or pass ' +
162
+ `{ gate } to ${what}. Refusing to run the tool unguarded.`);
163
+ }
164
+ return g;
165
+ }
166
+ function crashMessage(err) {
167
+ const detail = err instanceof Error ? err.message : String(err);
168
+ return `[Intutic Governance] BLOCKED: gate crashed (${detail}) — failing closed rather than allowing an unevaluated call.`;
169
+ }
170
+ /**
171
+ * Build the `user.tool_confirmation` params answering `event`, or `null` if
172
+ * `event` needs no answer from this module.
173
+ *
174
+ * `null` covers three cases, all correct to send nothing for: the event
175
+ * isn't `agent.tool_use`/`agent.mcp_tool_use` (including
176
+ * `agent.custom_tool_use` — see the module doc); its `evaluated_permission`
177
+ * is `'allow'` or unset (the call never paused); or it is already `'deny'`
178
+ * (the SERVER already resolved it — sending a confirmation for an id the
179
+ * server considers closed would just error).
180
+ *
181
+ * Anything else — `'ask'`, or a permission value this module doesn't
182
+ * recognise — is treated as a pause needing a verdict, matching
183
+ * `SessionToolRunner`'s own fail-closed handling of unrecognised wire values
184
+ * (hold/deny rather than dispatch).
185
+ *
186
+ * ASYNC: `Gate.guard()` is async in this package (unlike the Python SDK's
187
+ * synchronous twin) — every caller must `await` this.
188
+ */
189
+ export async function confirmationForEvent(event, opts = {}) {
190
+ if (!CONFIRMABLE_EVENT_TYPES.has(event.type))
191
+ return null;
192
+ const typed = event;
193
+ const permission = typed.evaluated_permission ?? null;
194
+ if (permission === null || permission === 'allow' || permission === 'deny')
195
+ return null;
196
+ const eventId = typed.id;
197
+ if (!eventId)
198
+ return null;
199
+ const toolName = typed.name || 'tool';
200
+ const toolInput = { ...typed.input };
201
+ if (typed.type === 'agent.mcp_tool_use' && typed.mcp_server_name) {
202
+ if (!('mcp_server_name' in toolInput)) {
203
+ toolInput.mcp_server_name = typed.mcp_server_name;
204
+ }
205
+ }
206
+ const result = {
207
+ type: 'user.tool_confirmation',
208
+ tool_use_id: eventId,
209
+ result: 'allow',
210
+ };
211
+ if (typed.session_thread_id) {
212
+ result.session_thread_id = typed.session_thread_id;
213
+ }
214
+ let g;
215
+ try {
216
+ g = resolveGate(opts.gate, 'confirmationForEvent()');
217
+ }
218
+ catch (err) {
219
+ result.result = 'deny';
220
+ result.deny_message = err instanceof Error ? `[Intutic Governance] BLOCKED: ${err.message}` : String(err);
221
+ return result;
222
+ }
223
+ try {
224
+ await g.guard(toolName, toolInput);
225
+ }
226
+ catch (err) {
227
+ result.result = 'deny';
228
+ result.deny_message = err instanceof IntuticGateRefusal ? err.message : crashMessage(err);
229
+ }
230
+ return result;
231
+ }
232
+ class IdleTimeout extends Error {
233
+ constructor() { super('watch(): stream idle'); }
234
+ }
235
+ /** 400–499 except 408 (timeout) and 429 (rate limit): a retry cannot help. */
236
+ export function isFatal4xx(err) {
237
+ const status = err?.status;
238
+ return typeof status === 'number' && status >= 400 && status < 500 && status !== 408 && status !== 429;
239
+ }
240
+ function sleep(ms, signal) {
241
+ return new Promise((resolve) => {
242
+ const t = setTimeout(done, ms);
243
+ function done() { signal?.removeEventListener('abort', done); resolve(); }
244
+ signal?.addEventListener('abort', done, { once: true });
245
+ });
246
+ }
247
+ /** Yields the stream's events; throws IdleTimeout when none arrives within `ms`. */
248
+ async function* withIdleTimeout(stream, ms, signal) {
249
+ const it = stream[Symbol.asyncIterator]();
250
+ try {
251
+ while (true) {
252
+ if (signal?.aborted)
253
+ return;
254
+ const next = it.next();
255
+ const result = ms === undefined
256
+ ? await next
257
+ : await Promise.race([
258
+ next,
259
+ new Promise((_, reject) => { const t = setTimeout(() => reject(new IdleTimeout()), ms); void next.finally(() => clearTimeout(t)); }),
260
+ ]);
261
+ if (result.done)
262
+ return;
263
+ yield result.value;
264
+ }
265
+ }
266
+ finally {
267
+ // Not awaited: after an idle timeout the generator is still suspended
268
+ // inside its own pending `next()`, and `return()` queues behind it — an
269
+ // await here would hang exactly as long as the dead stream does.
270
+ void Promise.resolve(it.return?.()).catch(() => undefined);
271
+ }
272
+ }
273
+ export class IntuticSessionConfirmer {
274
+ sessionId;
275
+ client;
276
+ gate;
277
+ /** Tool-call event ids already answered (by this instance), so a `poll()`
278
+ * that overlaps a live `watch()` — or a re-delivered webhook — never
279
+ * double-sends a confirmation for the same id. */
280
+ answered = new Set();
281
+ constructor(client, sessionId, opts = {}) {
282
+ this.client = client;
283
+ this.sessionId = sessionId;
284
+ this.gate = opts.gate;
285
+ }
286
+ noteConfirmationEvent(event) {
287
+ const toolUseId = eventField(event, 'tool_use_id');
288
+ if (typeof toolUseId === 'string' && toolUseId)
289
+ this.answered.add(toolUseId);
290
+ }
291
+ /** Answer one event if it needs an answer; returns the sent params, or
292
+ * `null` if nothing was sent (already answered, or
293
+ * {@link confirmationForEvent} returned `null` — see its doc). */
294
+ async handleEvent(event) {
295
+ const eventId = event.id;
296
+ if (!eventId || this.answered.has(eventId))
297
+ return null;
298
+ const confirmation = await confirmationForEvent(event, { gate: this.gate });
299
+ if (confirmation === null)
300
+ return null;
301
+ await this.client.beta.sessions.events.send(this.sessionId, { events: [confirmation] });
302
+ this.answered.add(eventId);
303
+ return confirmation;
304
+ }
305
+ /**
306
+ * List recent events and answer every unanswered
307
+ * `agent.tool_use`/`agent.mcp_tool_use` pause found. Returns the sent
308
+ * confirmations, in event order.
309
+ */
310
+ async poll(opts = {}) {
311
+ const sent = [];
312
+ const events = this.client.beta.sessions.events.list(this.sessionId, {
313
+ limit: opts.limit ?? 1000,
314
+ types: ['agent.tool_use', 'agent.mcp_tool_use', 'user.tool_confirmation'],
315
+ });
316
+ for await (const event of events) {
317
+ if (event.type === 'user.tool_confirmation') {
318
+ this.noteConfirmationEvent(event);
319
+ continue;
320
+ }
321
+ const confirmation = await this.handleEvent(event);
322
+ if (confirmation !== null)
323
+ sent.push(confirmation);
324
+ }
325
+ return sent;
326
+ }
327
+ /**
328
+ * Answer the pause a `session.requires_action` webhook signalled.
329
+ *
330
+ * `unwrapped` is what `client.beta.webhooks.unwrap(rawBody, { headers })`
331
+ * returns (or its `.data`, or a plain object of the same shape). Anything
332
+ * other than a `session.requires_action` payload is a no-op (`[]`): this
333
+ * module only ever answers tool-confirmation pauses, so every other
334
+ * webhook event type is intentionally ignored here.
335
+ *
336
+ * The webhook payload carries only the session id — it does NOT carry the
337
+ * tool call itself — so this always falls through to a {@link poll}.
338
+ */
339
+ async handleWebhook(unwrapped) {
340
+ const data = unwrapped.data ?? unwrapped;
341
+ if (data.type !== 'session.requires_action')
342
+ return [];
343
+ if (data.id !== undefined && data.id !== this.sessionId) {
344
+ throw new Error(`webhook session id ${JSON.stringify(data.id)} does not match this confirmer's ` +
345
+ `sessionId ${JSON.stringify(this.sessionId)}; construct a confirmer per session ` +
346
+ 'rather than reusing one across sessions');
347
+ }
348
+ return this.poll();
349
+ }
350
+ /**
351
+ * Catch up on anything already pending, then follow the live event
352
+ * stream, yielding each confirmation as it is sent, reconnecting when the
353
+ * stream drops (TD-428).
354
+ *
355
+ * Modelled on the SDK's own `SessionToolRunner#streamLoop`: open the
356
+ * stream FIRST, then reconcile with `poll()` — an event emitted in the gap
357
+ * is buffered on the stream rather than lost, and `answered` dedups
358
+ * anything that shows up on both. On end or error the loop sleeps
359
+ * (backoff doubling from `backoffStartMs` to `backoffCapMs`, reset on any
360
+ * received event) and reopens. A fatal 4xx (anything 400–499 other than
361
+ * 408 and 429) rethrows: the session is gone or the key is wrong, and
362
+ * retrying would loop forever. `idleTimeoutMs` drops a stream that has
363
+ * gone silent and reopens it, which re-polls. Ends only on a terminal
364
+ * event, `signal` abort, or `maxReconnects` exhausted (unbounded by
365
+ * default, the SDK's own choice).
366
+ */
367
+ async *watch(opts = {}) {
368
+ const backoffStart = opts.backoffStartMs ?? 500;
369
+ const backoffCap = opts.backoffCapMs ?? 10_000;
370
+ const maxReconnects = opts.maxReconnects ?? Number.POSITIVE_INFINITY;
371
+ let backoff = backoffStart;
372
+ let reconnects = 0;
373
+ while (!opts.signal?.aborted) {
374
+ let terminal = false;
375
+ try {
376
+ const stream = await this.client.beta.sessions.events.stream(this.sessionId);
377
+ for (const confirmation of await this.poll())
378
+ yield confirmation;
379
+ for await (const event of withIdleTimeout(stream, opts.idleTimeoutMs, opts.signal)) {
380
+ backoff = backoffStart;
381
+ if (TERMINAL_EVENT_TYPES.has(event.type)) {
382
+ terminal = true;
383
+ break;
384
+ }
385
+ if (event.type === 'user.tool_confirmation') {
386
+ this.noteConfirmationEvent(event);
387
+ continue;
388
+ }
389
+ const confirmation = await this.handleEvent(event);
390
+ if (confirmation)
391
+ yield confirmation;
392
+ }
393
+ }
394
+ catch (err) {
395
+ if (opts.signal?.aborted)
396
+ return;
397
+ if (err instanceof IdleTimeout) {
398
+ // fall through: reconnect and re-poll
399
+ }
400
+ else if (isFatal4xx(err)) {
401
+ throw err;
402
+ }
403
+ }
404
+ if (terminal || opts.signal?.aborted)
405
+ return;
406
+ if (reconnects >= maxReconnects) {
407
+ throw new Error(`watch(): stream ended ${reconnects + 1} time(s) and maxReconnects (${maxReconnects}) is exhausted`);
408
+ }
409
+ reconnects += 1;
410
+ await sleep(backoff, opts.signal);
411
+ backoff = Math.min(backoff * 2, backoffCap);
412
+ }
413
+ }
414
+ }
415
+ const CUSTOM_TOOL_GUARDED = Symbol.for('intutic.gate.managedAgents.customToolGuarded');
416
+ /**
417
+ * Wrap one Managed Agents custom tool (`BetaRunnableTool` shape) so
418
+ * `Gate.guard()` runs before `run()` executes.
419
+ *
420
+ * Returns a NEW object (a shallow copy with `run` replaced); does not mutate
421
+ * the one passed in. On refusal the wrapped `run()` THROWS
422
+ * `IntuticGateRefusal` before the real implementation ever runs — the same
423
+ * throw-based contract `wrapTool()` uses. Already-wrapped tools pass through
424
+ * unchanged.
425
+ */
426
+ export function wrapManagedAgentsCustomTool(tool, opts = {}) {
427
+ const marked = tool;
428
+ if (marked[CUSTOM_TOOL_GUARDED] === true)
429
+ return tool;
430
+ const originalRun = tool.run;
431
+ const toolName = tool.name || 'tool';
432
+ const guardedRun = async (args, context) => {
433
+ const g = resolveGate(opts.gate, 'wrapManagedAgentsCustomTool()');
434
+ await g.guard(toolName, args ?? {});
435
+ return originalRun.call(tool, args, context);
436
+ };
437
+ const wrapped = { ...tool, run: guardedRun };
438
+ Object.defineProperty(wrapped, CUSTOM_TOOL_GUARDED, { value: true, enumerable: false });
439
+ return wrapped;
440
+ }
441
+ /** Wrap a collection of Managed Agents custom tools in one call — see
442
+ * {@link wrapManagedAgentsCustomTool}. */
443
+ export function wrapManagedAgentsCustomTools(tools, opts = {}) {
444
+ return tools.map((t) => wrapManagedAgentsCustomTool(t, opts));
445
+ }
446
+ //# sourceMappingURL=managedAgents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managedAgents.js","sourceRoot":"","sources":["../src/managedAgents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Mastra adapter: `intuticHooks()`.
3
+ *
4
+ * `@intutic/gate/mastra` — a framework-specific specialization of the same
5
+ * idea `wrapTools.ts` implements generically (see that file's module doc):
6
+ * wrap the framework's own veto point around this package's `Gate.guard()`,
7
+ * throwing/vetoing before the real tool body ever runs.
8
+ *
9
+ * Mastra (`@mastra/core`) exposes a documented pre-execution veto point: an
10
+ * `Agent`'s `hooks.beforeToolCall`. It runs for every tool in the agent's
11
+ * assembled tool dictionary — natively defined tools AND MCP-sourced tools
12
+ * registered through `@mastra/mcp`, since both are merged into the same
13
+ * `CoreTool` record before hook-wrapping happens (`wrapToolsWithHooks`
14
+ * operates generically over `Object.entries(tools)`, with no source-specific
15
+ * branch). Returning `{ proceed: false, output }` from `beforeToolCall` skips
16
+ * the tool's real `execute` entirely and hands `output` back to the model IN
17
+ * PLACE OF the tool's result.
18
+ *
19
+ * ## Confirmed against a real install
20
+ *
21
+ * `@mastra/core@1.59.0` was installed in a scratch directory and its shipped
22
+ * `.d.ts`/compiled source read directly (not inferred from docs alone):
23
+ *
24
+ * `dist/tools/types.d.ts`:
25
+ * ```ts
26
+ * export interface ToolHookContext<TInput, TContext, TMetadata> {
27
+ * toolName: string
28
+ * input: TInput
29
+ * context: TContext
30
+ * metadata?: TMetadata
31
+ * }
32
+ * export interface ToolBeforeHookResult<TOutput> {
33
+ * proceed: false
34
+ * output: TOutput
35
+ * }
36
+ * export interface ToolHooks<TInput, TOutput, TContext, TMetadata> {
37
+ * beforeToolCall?: (context: ToolHookContext<TInput, TContext, TMetadata>) =>
38
+ * void | ToolBeforeHookResult<TOutput> | Promise<void | ToolBeforeHookResult<TOutput>>
39
+ * afterToolCall?: (context: ToolAfterHookContext<...>) => void | Promise<void>
40
+ * }
41
+ * ```
42
+ * `void`/`undefined` means "proceed" (allow); only an explicit
43
+ * `{ proceed: false, output }` vetoes — this adapter's `beforeToolCall`
44
+ * therefore returns `undefined` on allow, matching the framework's own
45
+ * "no opinion" contract rather than a synthetic allow value.
46
+ *
47
+ * `dist/agent-CKAVuxKN.js`'s `wrapToolWithHooks` (the actual wrapping the
48
+ * `.d.ts` above only declares the shape of) confirms the consumption side:
49
+ * ```js
50
+ * const beforeResult = await hooks.beforeToolCall?.(hookContext)
51
+ * if (beforeResult?.proceed === false) return beforeResult.output
52
+ * ```
53
+ * `output` is returned AS the tool's own `execute` return value at this
54
+ * layer, with no schema check performed by the hook wrapper itself — but a
55
+ * tool with a strict Zod `outputSchema` may still validate/reject that value
56
+ * further downstream, and `beforeToolCall` is never told what that schema
57
+ * is (the hook context carries no `outputSchema`/tool-definition reference).
58
+ * This adapter therefore cannot GUARANTEE a schema-conformant denial payload
59
+ * for an arbitrary tool; see {@link IntuticHooksOptions.denialOutput} to
60
+ * shape it per your own tools when the generic default will not validate.
61
+ *
62
+ * ## TAMPER NOTE — per-call hooks OVERRIDE agent-level hooks, they do not merge
63
+ *
64
+ * Also confirmed against the same install — `dist/agent.d.ts`'s
65
+ * `getConfiguredToolHooks()` doc comment:
66
+ *
67
+ * > Run-level hooks override these via {@link resolveToolHooks}, so callers
68
+ * > that need to preserve the configured hooks must read and compose them
69
+ * > explicitly.
70
+ *
71
+ * Concretely: `new Agent({ hooks: intuticHooks() })` installs this gate at
72
+ * the agent level, but ANY caller of `.generate()`/`.stream()` who passes
73
+ * their own `hooks` option — even `{}`, or a `hooks` object with no
74
+ * `beforeToolCall` — REPLACES the agent-level hooks wholesale for that call.
75
+ * This gate silently does not run: no error, no warning, just an unguarded
76
+ * tool call. This is Mastra's own documented behaviour, not a defect this
77
+ * package can work around from outside the framework — there is no hook
78
+ * inheritance or merge to opt into. See `gateRegistry.ts`'s `mastra` row for
79
+ * the same note surfaced to the registry, and
80
+ * `apps/docs/integrations/mastra.md` for the operator-facing version.
81
+ *
82
+ * If your application passes call-level `hooks` anywhere, compose this
83
+ * gate's `beforeToolCall` into that call's hooks yourself:
84
+ *
85
+ * ```ts
86
+ * const intutic = intuticHooks()
87
+ * await agent.generate(prompt, {
88
+ * hooks: {
89
+ * beforeToolCall: async (ctx) => {
90
+ * const denied = await intutic.beforeToolCall(ctx)
91
+ * if (denied) return denied
92
+ * return myOwnBeforeToolCall(ctx)
93
+ * },
94
+ * },
95
+ * })
96
+ * ```
97
+ */
98
+ import { type Gate } from './gate.js';
99
+ import { IntuticGateRefusal } from './errors.js';
100
+ /** Structural copy of `@mastra/core`'s `ToolHookContext` — this package does
101
+ * not depend on `@mastra/core` at runtime, so the shape is declared here
102
+ * rather than imported. Confirmed field-for-field against
103
+ * `@mastra/core@1.59.0`'s `dist/tools/types.d.ts` (see module doc). */
104
+ export interface MastraToolHookContext {
105
+ /** The name exposed to the model for this tool call. */
106
+ toolName: string;
107
+ /** Input passed to the tool — this is what `Gate.guard()` evaluates. */
108
+ input: unknown;
109
+ /** Execution context passed to the tool. Not read by this adapter. */
110
+ context?: unknown;
111
+ /** Optional adapter-specific metadata (e.g. `agentId`/`agentName`). */
112
+ metadata?: Record<string, unknown>;
113
+ }
114
+ /** Structural copy of `@mastra/core`'s `ToolBeforeHookResult`. */
115
+ export interface MastraToolBeforeHookResult {
116
+ proceed: false;
117
+ output: unknown;
118
+ }
119
+ /** Structural copy of `@mastra/core`'s `ToolHooks['beforeToolCall']` — the
120
+ * slice of the real type this adapter implements. Assignable directly to
121
+ * `Agent`'s `hooks` constructor option. */
122
+ export type MastraBeforeToolCall = (context: MastraToolHookContext) => Promise<void | MastraToolBeforeHookResult>;
123
+ export interface IntuticHooksOptions {
124
+ /** Overrides the process-wide installed gate (`install(new Gate(...))`). */
125
+ gate?: Gate;
126
+ /**
127
+ * Shapes the `output` handed back to the model on a refusal. The default
128
+ * produces `{ error: true, message, code, incidentId? }` — reasonable for
129
+ * an unstructured/text-ish tool output, but NOT guaranteed to satisfy an
130
+ * arbitrary tool's own Zod `outputSchema` (this hook is never told what
131
+ * that schema is — see the module doc's "Confirmed against a real
132
+ * install" section). Supply this when your tools declare strict output
133
+ * schemas the default shape would fail.
134
+ */
135
+ denialOutput?: (ctx: {
136
+ toolName: string;
137
+ refusal: IntuticGateRefusal;
138
+ }) => unknown;
139
+ }
140
+ /**
141
+ * Builds a `{ beforeToolCall }` object shaped for direct use in `@mastra/core`'s
142
+ * `Agent` constructor's `hooks` option:
143
+ *
144
+ * ```ts
145
+ * import { Agent } from '@mastra/core/agent'
146
+ * import { Gate, install } from '@intutic/gate'
147
+ * import { intuticHooks } from '@intutic/gate/mastra'
148
+ *
149
+ * install(new Gate({ workspaceId: process.env.INTUTIC_WORKSPACE_ID }))
150
+ *
151
+ * const agent = new Agent({
152
+ * id: 'my-agent',
153
+ * name: 'My Agent',
154
+ * model: 'openai/gpt-5-mini',
155
+ * tools: { deleteTool },
156
+ * hooks: intuticHooks(),
157
+ * })
158
+ * ```
159
+ *
160
+ * On refusal, returns `{ proceed: false, output }` — the real tool body
161
+ * never runs. On allow, returns `undefined`, Mastra's own "no opinion"
162
+ * value, so the real `execute` runs untouched.
163
+ *
164
+ * Requires a `Gate` — either passed via `{ gate }` here, or installed
165
+ * process-wide with `install(new Gate(...))`. A call with neither throws
166
+ * (via the underlying `beforeToolCall`), refusing to run tools unguarded
167
+ * rather than silently skipping enforcement — same posture as `wrapTool`.
168
+ *
169
+ * See the module doc's TAMPER NOTE: this only governs calls that do not
170
+ * override `hooks` at the `.generate()`/`.stream()` call site.
171
+ */
172
+ export declare function intuticHooks(opts?: IntuticHooksOptions): {
173
+ beforeToolCall: MastraBeforeToolCall;
174
+ };
175
+ //# sourceMappingURL=mastra.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mastra.d.ts","sourceRoot":"","sources":["../src/mastra.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgGG;AAEH,OAAO,EAAwB,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD;;;wEAGwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,wEAAwE;IACxE,KAAK,EAAE,OAAO,CAAA;IACd,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,kEAAkE;AAClE,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,KAAK,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAED;;4CAE4C;AAC5C,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,IAAI,GAAG,0BAA0B,CAAC,CAAA;AAE/C,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,IAAI,CAAC,EAAE,IAAI,CAAA;IACX;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,kBAAkB,CAAA;KAAE,KAAK,OAAO,CAAA;CACnF;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG;IAAE,cAAc,EAAE,oBAAoB,CAAA;CAAE,CAuBrG"}