@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
package/dist/mastra.js ADDED
@@ -0,0 +1,161 @@
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 { active as activeGate } from './gate.js';
99
+ import { IntuticGateRefusal } from './errors.js';
100
+ function defaultDenialOutput(ctx) {
101
+ return {
102
+ error: true,
103
+ message: ctx.refusal.message,
104
+ code: ctx.refusal.code,
105
+ incidentId: ctx.refusal.incidentId,
106
+ };
107
+ }
108
+ /**
109
+ * Builds a `{ beforeToolCall }` object shaped for direct use in `@mastra/core`'s
110
+ * `Agent` constructor's `hooks` option:
111
+ *
112
+ * ```ts
113
+ * import { Agent } from '@mastra/core/agent'
114
+ * import { Gate, install } from '@intutic/gate'
115
+ * import { intuticHooks } from '@intutic/gate/mastra'
116
+ *
117
+ * install(new Gate({ workspaceId: process.env.INTUTIC_WORKSPACE_ID }))
118
+ *
119
+ * const agent = new Agent({
120
+ * id: 'my-agent',
121
+ * name: 'My Agent',
122
+ * model: 'openai/gpt-5-mini',
123
+ * tools: { deleteTool },
124
+ * hooks: intuticHooks(),
125
+ * })
126
+ * ```
127
+ *
128
+ * On refusal, returns `{ proceed: false, output }` — the real tool body
129
+ * never runs. On allow, returns `undefined`, Mastra's own "no opinion"
130
+ * value, so the real `execute` runs untouched.
131
+ *
132
+ * Requires a `Gate` — either passed via `{ gate }` here, or installed
133
+ * process-wide with `install(new Gate(...))`. A call with neither throws
134
+ * (via the underlying `beforeToolCall`), refusing to run tools unguarded
135
+ * rather than silently skipping enforcement — same posture as `wrapTool`.
136
+ *
137
+ * See the module doc's TAMPER NOTE: this only governs calls that do not
138
+ * override `hooks` at the `.generate()`/`.stream()` call site.
139
+ */
140
+ export function intuticHooks(opts = {}) {
141
+ const denialOutput = opts.denialOutput ?? defaultDenialOutput;
142
+ const beforeToolCall = async (ctx) => {
143
+ const g = opts.gate ?? activeGate();
144
+ if (g === null) {
145
+ throw new Error('No gate configured: call install(new Gate(...)) from @intutic/gate, or pass ' +
146
+ '{ gate } to intuticHooks(). Refusing to run the tool unguarded.');
147
+ }
148
+ try {
149
+ await g.guard(ctx.toolName, (ctx.input ?? {}));
150
+ return undefined;
151
+ }
152
+ catch (exc) {
153
+ if (exc instanceof IntuticGateRefusal) {
154
+ return { proceed: false, output: denialOutput({ toolName: ctx.toolName, refusal: exc }) };
155
+ }
156
+ throw exc;
157
+ }
158
+ };
159
+ return { beforeToolCall };
160
+ }
161
+ //# sourceMappingURL=mastra.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mastra.js","sourceRoot":"","sources":["../src/mastra.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgGG;AAEH,OAAO,EAAE,MAAM,IAAI,UAAU,EAAa,MAAM,WAAW,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AA6ChD,SAAS,mBAAmB,CAAC,GAAsD;IACjF,OAAO;QACL,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO;QAC5B,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI;QACtB,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,UAAU;KACnC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,YAAY,CAAC,OAA4B,EAAE;IACzD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,mBAAmB,CAAA;IAE7D,MAAM,cAAc,GAAyB,KAAK,EAAE,GAAG,EAAE,EAAE;QACzD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,UAAU,EAAE,CAAA;QACnC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,8EAA8E;gBAC5E,iEAAiE,CACpE,CAAA;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAA4B,CAAC,CAAA;YACzE,OAAO,SAAS,CAAA;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;gBACtC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAA;YAC3F,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC,CAAA;IAED,OAAO,EAAE,cAAc,EAAE,CAAA;AAC3B,CAAC"}
@@ -0,0 +1,392 @@
1
+ /**
2
+ * OpenAI Agents SDK (TypeScript) adapter: `intuticToolGuardrail()`,
3
+ * `wrapTools()`, `wrapAgent()`, `installOpenAiGate()`.
4
+ *
5
+ * `@intutic/gate/openai` — a framework-specific specialization of the same
6
+ * idea `wrapTools.ts` implements generically (see that file's module doc):
7
+ * wrap the framework's own veto point around this package's `Gate.guard()`.
8
+ * The TypeScript twin of the Python SDK's
9
+ * `intutic_clawde.gate.adapters.openai_agents` (`intutic_tool_guardrail`).
10
+ *
11
+ * ## The veto mechanism — CONFIRMED against a real install
12
+ *
13
+ * `@openai/agents@0.16.1` was installed as a devDependency of this package
14
+ * and its shipped `.d.ts`/compiled source read directly (not inferred from
15
+ * docs alone). `@openai/agents` is a meta-package (`export * from
16
+ * '@openai/agents-core'` + `'@openai/agents-openai'` + `export * as
17
+ * realtime`); the relevant surface lives in `@openai/agents-core`:
18
+ *
19
+ * The SDK's documented per-tool veto point is a **tool input guardrail**
20
+ * (`dist/toolGuardrail.d.ts`, present since `@openai/agents-core` 0.3.8,
21
+ * 2026-01-14):
22
+ *
23
+ * ```ts
24
+ * interface ToolInputGuardrailDefinition<TContext> {
25
+ * type: 'tool_input'
26
+ * name: string
27
+ * run: (data: { context: RunContext; agent: Agent; toolCall: protocol.FunctionCallItem })
28
+ * => Promise<ToolGuardrailFunctionOutput> // { behavior, outputInfo? }
29
+ * }
30
+ * // behavior: {type:'allow'} | {type:'rejectContent'; message} | {type:'throwException'}
31
+ * ```
32
+ *
33
+ * The runner (`dist/runner/toolExecution.js`) runs every guardrail in
34
+ * `FunctionTool.inputGuardrails` BEFORE `invoke` — on `rejectContent` the
35
+ * tool body never runs and `message` becomes the model-visible tool output
36
+ * (`resolveFunctionFailureOutput`). `protocol.FunctionCallItem.arguments` is
37
+ * the RAW, unparsed JSON arguments string (`z.ZodString`), same as the Python
38
+ * SDK's `ToolContext.tool_arguments` — hence {@link toolInputFromArguments}.
39
+ *
40
+ * Guardrail attachment is PER-TOOL: there is no run-level tool guardrail.
41
+ * That is what {@link wrapTools} and {@link wrapAgent} are for.
42
+ *
43
+ * Ordering caveat (documented, verified in `toolExecution.js`): for a tool
44
+ * whose `needsApproval` resolves true, input guardrails run AFTER the
45
+ * human-approval flow by default. Opt in to guardrails-before-approval with
46
+ * the run config `toolExecution: { preApprovalInputGuardrails: true }`
47
+ * (available since `@openai/agents-core` 0.11.8;
48
+ * `dist/runner/runConfig.d.ts`).
49
+ *
50
+ * ## The MCP materialization gotcha — why `wrapAgent` patches `getAllTools`
51
+ *
52
+ * Tools contributed by `agent.mcpServers` do NOT live in `agent.tools`: they
53
+ * are materialized per run by `agent.getAllTools()` → `getMcpTools()` →
54
+ * `mcpToFunctionTool()` (`dist/mcp.js`), which builds them with the same
55
+ * `tool()` factory — same guardrail path — but attaches NO guardrails of its
56
+ * own. Mapping over `agent.tools` alone therefore silently misses every
57
+ * MCP-sourced tool. {@link wrapAgent} closes that hole by patching the
58
+ * agent INSTANCE's `getAllTools` to inject the Intutic guardrail into every
59
+ * `FunctionTool` it returns, MCP-derived ones included (the runner resolves
60
+ * tools exclusively through `executionAgent.getAllTools(...)` —
61
+ * `dist/runner/modelPreparation.js`). Injection is idempotent (keyed on
62
+ * {@link GUARDRAIL_NAME}), so tools that are both in `agent.tools` and in the
63
+ * `getAllTools` result are gated exactly once.
64
+ *
65
+ * ## Non-function tools — what is and is not gateable
66
+ *
67
+ * * **hostedMcpTool** entries execute at OpenAI's side, but expose a
68
+ * client-visible approval loop: `providerData.require_approval` /
69
+ * `providerData.on_approval` (snake_case POST-construction — the
70
+ * camelCase `requireApproval`/`onApproval` exist only as `hostedMcpTool()`
71
+ * factory options; the runner reads only the snake_case fields,
72
+ * `dist/runner/mcpApprovals.js`). `wrapTools` rewrites these entries to
73
+ * `require_approval: 'always'` plus an Intutic `on_approval` that guards
74
+ * each call and composes any pre-existing handler. NOTE
75
+ * `hostedMcpTool()`'s own default is `require_approval: 'never'` — an
76
+ * unwrapped hosted MCP tool is entirely ungated.
77
+ * * **shellTool / applyPatchTool** (local) carry `needsApproval` +
78
+ * `onApproval` auto-resolvers. `wrapTools` forces `needsApproval` to
79
+ * always-true and installs a composed Intutic `onApproval`: gate refusal
80
+ * → reject (with the BLOCKED message); gate allow → the tool's ORIGINAL
81
+ * approval policy is replayed (original `needsApproval` false → approve;
82
+ * original `onApproval` present → delegated to). When the original
83
+ * policy demanded a human and no original `onApproval` exists, the
84
+ * decision is deliberately left undecided so the interruption still
85
+ * surfaces — see {@link OpenAiApprovalDecision} for the verified
86
+ * mechanism this relies on.
87
+ * * **computerTool** has NO `onApproval` — only a per-action
88
+ * `needsApproval` predicate (plus `onSafetyCheck`). `wrapTools` (and
89
+ * {@link intuticComputerNeedsApproval}) can therefore only turn a gate
90
+ * refusal into `needsApproval → true`, which surfaces as a pending
91
+ * interruption in `result.interruptions` that YOUR code must
92
+ * `state.reject(...)`. Stated honestly: a caller who `state.approve()`s
93
+ * that interruption overrides the gate — the SDK gives this adapter no
94
+ * reject-with-message hook for computer actions. (The refusal is still
95
+ * emitted to the control plane as `tool_blocked` telemetry either way.)
96
+ * * **Hosted tools** (`webSearchTool`, `fileSearchTool`,
97
+ * `codeInterpreterTool`, `imageGenerationTool`, ...) are bare
98
+ * `HostedTool` objects executed server-side at OpenAI: NO client-side
99
+ * guardrail, approval hook, or wrapper ever sees them. The
100
+ * hosted-environment variant of `shellTool` (`environment.type:
101
+ * 'container_*'`) is in the same bucket — its factory options type
102
+ * `needsApproval`/`onApproval` as `never`. `wrapTools` passes all of
103
+ * these through UNCHANGED rather than pretending they are gated.
104
+ *
105
+ * ## Realtime
106
+ *
107
+ * `@openai/agents-realtime` honours `FunctionTool.inputGuardrails` through
108
+ * the same `runToolInputGuardrails` helper (verified in its shipped
109
+ * `realtimeSession.js`), so a guardrail injected by this module also gates
110
+ * voice-agent tool calls.
111
+ *
112
+ * ## LLM egress and the tracing DLP leak
113
+ *
114
+ * Routing chat traffic through the Intutic proxy is env-only for this SDK:
115
+ * the underlying `openai` client (7.5.0, `client.js`) reads
116
+ * `OPENAI_BASE_URL` whenever no explicit `baseURL`/client is passed to
117
+ * `OpenAIProvider` — so a sourced `.env.intutic` governs egress with zero
118
+ * code, unlike the Vercel AI SDK (see vercel.ts's module doc). The default
119
+ * transport is the HTTP Responses API, whose wire shape the Intutic proxy
120
+ * already parses.
121
+ *
122
+ * BUT: `@openai/agents-openai`'s tracing exporter POSTs trace spans —
123
+ * including tool inputs/outputs — to a HARDCODED
124
+ * `https://api.openai.com/v1/traces/ingest` (`openaiTracingExporter.js`),
125
+ * bypassing `OPENAI_BASE_URL` entirely, and tracing is ON by default. That
126
+ * is a real DLP exfiltration path around the proxy.
127
+ * {@link suppressAgentsTracingExport} (called by {@link installOpenAiGate}
128
+ * unless opted out) sets the SDK's own kill-switch env
129
+ * `OPENAI_AGENTS_DISABLE_TRACING=1` (read lazily per run —
130
+ * `@openai/agents-core`'s `config.js`). Callers who need traces should
131
+ * instead re-point the exporter endpoint in code
132
+ * (`new OpenAITracingExporter({ endpoint })` + `setTraceProcessors`) at an
133
+ * approved collector and opt out with `{ tracingExport: 'keep' }`.
134
+ *
135
+ * ## What this module does NOT import
136
+ *
137
+ * Deliberately no runtime dependency on `@openai/agents`/
138
+ * `@openai/agents-core` — the `OpenAi*` types below are narrow structural
139
+ * copies of only the shapes this adapter touches, same policy as mastra.ts /
140
+ * vercel.ts / dsh.ts (see dsh.ts's module doc for the full rationale). The
141
+ * real packages are devDependencies used by `__tests__/openai.test.ts` to
142
+ * type-check these structural types against the real shipped ones and to
143
+ * drive the real runner machinery end to end.
144
+ *
145
+ * @module
146
+ */
147
+ import { Gate } from './gate.js';
148
+ import type { GateConfig, ToolInput } from './gate.js';
149
+ /** The `name` every guardrail this module builds carries. Also the
150
+ * idempotency key: a `FunctionTool` whose `inputGuardrails` already contains
151
+ * a guardrail with this name is never double-wrapped. */
152
+ export declare const GUARDRAIL_NAME = "intutic";
153
+ /** Slice of `protocol.FunctionCallItem` read by the guardrail: `arguments`
154
+ * is the RAW, unparsed JSON string (the full item also carries `callId`,
155
+ * `type: 'function_call'`, ...). */
156
+ export interface OpenAiFunctionCallLike {
157
+ name: string;
158
+ arguments: string;
159
+ }
160
+ /** Slice of `ToolInputGuardrailData` the guardrail reads. The real data also
161
+ * carries `context: RunContext` and `agent: Agent`, which pass through this
162
+ * (wider-parameter) structural type untouched. */
163
+ export interface OpenAiToolInputGuardrailData {
164
+ toolCall: OpenAiFunctionCallLike;
165
+ }
166
+ /** Structural copy of `ToolGuardrailFunctionOutput` — the subset of
167
+ * `behavior` values this adapter emits (`throwException` is never used:
168
+ * a refusal is a model-visible rejection, not a run-fatal tripwire). */
169
+ export interface OpenAiToolGuardrailFunctionOutput {
170
+ behavior: {
171
+ type: 'allow';
172
+ } | {
173
+ type: 'rejectContent';
174
+ message: string;
175
+ };
176
+ outputInfo?: unknown;
177
+ }
178
+ /** Structural copy of `ToolInputGuardrailDefinition` — directly assignable
179
+ * both to a built `FunctionTool.inputGuardrails` array and to the `tool()`
180
+ * factory's `inputGuardrails` option. */
181
+ export interface OpenAiToolInputGuardrail {
182
+ type: 'tool_input';
183
+ name: string;
184
+ run: (data: OpenAiToolInputGuardrailData) => Promise<OpenAiToolGuardrailFunctionOutput>;
185
+ }
186
+ /**
187
+ * Structural copy of the `{ approve, reason? }` decision `onApproval` /
188
+ * `on_approval` handlers resolve with — with one deliberate widening:
189
+ * `approve` is optional here.
190
+ *
191
+ * For SHELL and APPLY_PATCH tools the runner checks `decision.approve ===
192
+ * true` and `=== false` explicitly and treats anything else as "no decision
193
+ * made", leaving the approval pending so it surfaces as an interruption
194
+ * (VERIFIED against `@openai/agents-core@0.16.1`'s
195
+ * `dist/runner/toolExecution.js`, `resolveToolApproval()`). This adapter
196
+ * returns `{}` exactly once — when the gate allows a call whose ORIGINAL
197
+ * tool policy demanded a human and no original `onApproval` exists — so the
198
+ * caller's own interruption flow survives wrapping. That fall-through is
199
+ * real but UNDOCUMENTED SDK behaviour; see the TD entry this phase filed.
200
+ *
201
+ * Hosted MCP `on_approval` results are consumed with a TRUTHY check instead
202
+ * (`dist/runner/mcpApprovals.js`), so `{}` there would silently REJECT —
203
+ * the hosted-MCP wrapper never uses the fall-through.
204
+ */
205
+ export interface OpenAiApprovalDecision {
206
+ approve?: boolean;
207
+ reason?: string;
208
+ }
209
+ /** Slice of `RunToolApprovalItem` the approval handlers read. */
210
+ export interface OpenAiToolApprovalItemLike {
211
+ rawItem?: unknown;
212
+ }
213
+ /** Minimal structural slice of `Agent` needed by {@link wrapAgent}: the
214
+ * static tool list plus the per-run materializer the runner actually
215
+ * consumes (`dist/runner/modelPreparation.js`). */
216
+ export interface OpenAiAgentLike {
217
+ tools: object[];
218
+ getAllTools(...args: never[]): Promise<object[]>;
219
+ }
220
+ export interface OpenAiWrapOptions {
221
+ /** Overrides the process-wide installed gate (`install(new Gate(...))`). */
222
+ gate?: Gate;
223
+ }
224
+ /**
225
+ * Parse the raw JSON `arguments` string into the object `Gate.guard()`
226
+ * evaluates. Port of the Python adapter's `_tool_input_of` — same fallback
227
+ * keys (`raw`, `value`): a call the gate cannot parse should still reach a
228
+ * rule, not silently skip evaluation.
229
+ */
230
+ export declare function toolInputFromArguments(raw: string | null | undefined): ToolInput;
231
+ /**
232
+ * Builds the Intutic tool input guardrail — `{ type: 'tool_input', name:
233
+ * 'intutic', run }` — attachable to any `FunctionTool`, either at
234
+ * construction:
235
+ *
236
+ * ```ts
237
+ * import { tool } from '@openai/agents'
238
+ * import { Gate, install } from '@intutic/gate'
239
+ * import { intuticToolGuardrail } from '@intutic/gate/openai'
240
+ *
241
+ * install(new Gate({ workspaceId: process.env.INTUTIC_WORKSPACE_ID }))
242
+ *
243
+ * const shell = tool({
244
+ * name: 'shell',
245
+ * description: 'Run a shell command',
246
+ * parameters: z.object({ command: z.string() }),
247
+ * inputGuardrails: [intuticToolGuardrail()],
248
+ * execute: async ({ command }) => run(command),
249
+ * })
250
+ * ```
251
+ *
252
+ * or after the fact via {@link wrapTools}/{@link wrapAgent}. On refusal the
253
+ * guardrail resolves `{ behavior: { type: 'rejectContent', message } }` —
254
+ * the runner skips the tool body and hands `message` (the
255
+ * `[Intutic Governance] BLOCKED: ...` text) back to the model in place of a
256
+ * tool result. On an unexpected gate crash it rejects too (fail closed). On
257
+ * allow it resolves `{ behavior: { type: 'allow' } }`.
258
+ *
259
+ * Requires a `Gate` — either passed via `{ gate }`, or installed
260
+ * process-wide with `install(new Gate(...))`. A call with neither throws
261
+ * out of `run` (which the runner escalates into a run-fatal `ToolCallError`)
262
+ * rather than running the tool unguarded — same posture as
263
+ * `wrapTool`/`intuticHooks`/`intuticToolApproval`.
264
+ */
265
+ export declare function intuticToolGuardrail(opts?: OpenAiWrapOptions): OpenAiToolInputGuardrail;
266
+ /**
267
+ * Gate-driven `needsApproval` predicate for `computerTool` — the ONLY
268
+ * pre-execution hook that tool exposes (no guardrails, no `onApproval`):
269
+ *
270
+ * ```ts
271
+ * computerTool({ computer, needsApproval: intuticComputerNeedsApproval() })
272
+ * ```
273
+ *
274
+ * A gate-refused (or gate-crashed — fail closed) action resolves `true`,
275
+ * which the runner turns into a pending interruption in
276
+ * `result.interruptions`; your interruption handler must `state.reject(...)`
277
+ * it. This is honestly weaker than the guardrail path: the SDK offers no way
278
+ * for this adapter to auto-reject a computer action with a message, and a
279
+ * handler that `state.approve()`s the interruption overrides the gate. An
280
+ * allowed action defers to `fallback` (the predicate the tool would
281
+ * otherwise have used; defaults to no approval).
282
+ */
283
+ export declare function intuticComputerNeedsApproval(opts?: OpenAiWrapOptions & {
284
+ /** Tool name reported to the gate. Defaults to `computer_use_preview`. */
285
+ toolName?: string;
286
+ /** Original predicate to defer to when the gate allows. */
287
+ fallback?: (...args: unknown[]) => Promise<boolean> | boolean;
288
+ }): (runContext: unknown, action: unknown, callId?: unknown) => Promise<boolean>;
289
+ /**
290
+ * Wrap a list of OpenAI Agents SDK tools so `Gate.guard()` runs before each
291
+ * one executes — see the module doc for exactly what each tool `type` gets
292
+ * (and what hosted tools cannot get). Returns NEW tool objects (shallow
293
+ * copies); the ones passed in are not mutated. Wrapping twice is a no-op.
294
+ *
295
+ * NOTE: this covers only the tools you hand it. Tools materialized from
296
+ * `agent.mcpServers` do not exist yet at wrapping time — use
297
+ * {@link wrapAgent} for an agent with MCP servers.
298
+ */
299
+ export declare function wrapTools<T extends object>(tools: readonly T[], opts?: OpenAiWrapOptions): T[];
300
+ /**
301
+ * Gate every tool an agent can reach, MCP-sourced tools included.
302
+ *
303
+ * ```ts
304
+ * import { Agent, run } from '@openai/agents'
305
+ * import { installOpenAiGate, wrapAgent } from '@intutic/gate/openai'
306
+ *
307
+ * installOpenAiGate({ workspaceId: process.env.INTUTIC_WORKSPACE_ID })
308
+ *
309
+ * const agent = wrapAgent(new Agent({
310
+ * name: 'ops',
311
+ * tools: [shell],
312
+ * mcpServers: [filesystemServer],
313
+ * }))
314
+ * const result = await run(agent, prompt)
315
+ * ```
316
+ *
317
+ * Two things happen, both idempotent:
318
+ *
319
+ * 1. `agent.tools` is replaced with {@link wrapTools}' wrapped copies.
320
+ * 2. The agent INSTANCE's `getAllTools` — the materializer the runner
321
+ * actually consumes each turn, and the ONLY place `mcpServers`-derived
322
+ * tools ever appear (see module doc) — is patched to wrap everything it
323
+ * returns.
324
+ *
325
+ * MUTATES (and returns) the agent passed in.
326
+ *
327
+ * Scope, stated plainly: this wraps ONE agent. Agents reached via handoffs
328
+ * are separate objects — wrap each of them too.
329
+ */
330
+ export declare function wrapAgent<T extends OpenAiAgentLike>(agent: T, opts?: OpenAiWrapOptions): T;
331
+ /**
332
+ * Close the tracing DLP leak: set the SDK's own kill-switch env
333
+ * (`OPENAI_AGENTS_DISABLE_TRACING=1`) so the default exporter never POSTs
334
+ * trace spans — which carry tool inputs/outputs — to its HARDCODED
335
+ * `https://api.openai.com/v1/traces/ingest` endpoint (which ignores
336
+ * `OPENAI_BASE_URL`, i.e. bypasses the Intutic proxy). The SDK reads the env
337
+ * lazily per run, so calling this any time before `run(...)` is effective.
338
+ *
339
+ * To keep traces instead, re-point the exporter at an approved collector in
340
+ * your own code — `setTraceProcessors([new BatchTraceProcessor(new
341
+ * OpenAITracingExporter({ endpoint }))])` — and pass
342
+ * `{ tracingExport: 'keep' }` to {@link installOpenAiGate}.
343
+ */
344
+ export declare function suppressAgentsTracingExport(): void;
345
+ /** Config for {@link installOpenAiGate}. Extends the core {@link GateConfig}. */
346
+ export interface OpenAiGateConfig extends GateConfig {
347
+ /** Overrides the generated-per-process session id. Mirrors
348
+ * `INTUTIC_SESSION_ID` for callers that already have one to hand. */
349
+ sessionId?: string;
350
+ /**
351
+ * What to do about the tracing exporter's proxy bypass (see
352
+ * {@link suppressAgentsTracingExport}). `'disable'` (default) sets the
353
+ * SDK's kill-switch env; `'keep'` leaves tracing exactly as configured —
354
+ * choose it ONLY once the exporter endpoint is re-pointed somewhere
355
+ * approved, otherwise tool inputs/outputs leave via api.openai.com.
356
+ */
357
+ tracingExport?: 'disable' | 'keep' | 'intutic';
358
+ }
359
+ /**
360
+ * One-call setup: build a {@link Gate} (with a `GateClient` from the
361
+ * environment when credentials allow — degrading to a client-less gate, Tier
362
+ * B/A3 inactive, rather than throwing out of setup, same posture as dsh.ts's
363
+ * `apply()`), `install()` it process-wide so every guardrail/wrapper in this
364
+ * module picks it up, and close the tracing leak (unless `tracingExport:
365
+ * 'keep'`). Returns the gate.
366
+ *
367
+ * Session id: one per PROCESS (`sessionId` option, else
368
+ * `INTUTIC_SESSION_ID`, else a random UUID) — the SDK has no single "current
369
+ * session" readable at install time; see dsh.ts's `resolveSessionId` for the
370
+ * full rationale this mirrors.
371
+ */
372
+ /**
373
+ * Where to point `@openai/agents`' tracing exporter so traces stay governed
374
+ * (TD-405): the control plane's ingest route, authenticated with the same
375
+ * API key the gate uses. Pass the result to the SDK's own exporter —
376
+ *
377
+ * ```ts
378
+ * import { setTraceProcessors, BatchTraceProcessor, OpenAITracingExporter } from '@openai/agents'
379
+ * setTraceProcessors([new BatchTraceProcessor(new OpenAITracingExporter(intuticTracingExporterOptions()))])
380
+ * ```
381
+ *
382
+ * — and pass `{ tracingExport: 'intutic' }` to {@link installOpenAiGate}. No
383
+ * `@openai/agents` import here, so this module stays loadable without the SDK.
384
+ * Generation spans become traces in the ledger; tool spans are counted, not
385
+ * stored (the route's own doc says why).
386
+ */
387
+ export declare function intuticTracingExporterOptions(env?: NodeJS.ProcessEnv): {
388
+ endpoint: string;
389
+ apiKey: string;
390
+ };
391
+ export declare function installOpenAiGate(config?: OpenAiGateConfig): Gate;
392
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../src/openai.ts"],"names":[],"mappings":"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"}