watchmyagents 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -0
- package/docs/adapters/openai-agents-js.md +230 -0
- package/examples/adapters/capture-fixtures.ts +193 -0
- package/examples/adapters/openai-agents-js-quickstart.ts +118 -0
- package/package.json +23 -1
- package/src/anonymizer.js +48 -0
- package/src/index.js +52 -0
- package/src/logger.js +17 -1
- package/src/openai-agents.js +202 -0
- package/src/shield/decisions.js +12 -2
- package/src/sources/contract.js +31 -1
- package/src/sources/openai-agents-js.d.ts +278 -0
- package/src/sources/openai-agents-js.js +872 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// TypeScript types for the OpenAI Agents SDK adapter — v1.3.0.
|
|
2
|
+
//
|
|
3
|
+
// These types pin the PUBLIC surface customers consume. The runtime
|
|
4
|
+
// (openai-agents-js.js) is plain JS to preserve the zero-runtime-deps
|
|
5
|
+
// invariant; this .d.ts is consumed by tsc only and never executed.
|
|
6
|
+
//
|
|
7
|
+
// The guardrail return shape and the EventEmitter event signatures
|
|
8
|
+
// mirror @openai/agents v0.x — we don't import from it (also to avoid
|
|
9
|
+
// dragging it as a runtime dep here), we re-declare the minimal subset
|
|
10
|
+
// we need.
|
|
11
|
+
|
|
12
|
+
// ── @openai/agents shapes we reference (minimal re-declaration) ────────
|
|
13
|
+
|
|
14
|
+
/** Mirrors @openai/agents `ToolGuardrailBehavior`. */
|
|
15
|
+
export type WMAToolGuardrailBehavior =
|
|
16
|
+
| { type: 'allow' }
|
|
17
|
+
| { type: 'rejectContent'; message: string }
|
|
18
|
+
| { type: 'throwException' };
|
|
19
|
+
|
|
20
|
+
/** Mirrors @openai/agents `ToolGuardrailFunctionOutput`. */
|
|
21
|
+
export interface WMAToolGuardrailFunctionOutput {
|
|
22
|
+
behavior: WMAToolGuardrailBehavior;
|
|
23
|
+
outputInfo?: unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Mirrors @openai/agents `ToolInputGuardrailData`. */
|
|
27
|
+
export interface WMAToolInputGuardrailData {
|
|
28
|
+
context?: unknown;
|
|
29
|
+
agent?: { name?: string; model?: string; instructions?: string };
|
|
30
|
+
toolCall?: {
|
|
31
|
+
id?: string;
|
|
32
|
+
callId?: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
arguments?: string | object;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Return value of {@link wmaToolInputGuardrail}. Shape-compatible with
|
|
40
|
+
* @openai/agents `ToolInputGuardrailDefinition`. Drop into an Agent's
|
|
41
|
+
* `toolInputGuardrails: [...]` array.
|
|
42
|
+
*/
|
|
43
|
+
export interface WMAToolInputGuardrail {
|
|
44
|
+
readonly type: 'tool_input';
|
|
45
|
+
readonly name: string;
|
|
46
|
+
run: (data: WMAToolInputGuardrailData) => Promise<WMAToolGuardrailFunctionOutput>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Adapter-specific types ─────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
/** Minimal Logger surface — for advanced injection in tests. */
|
|
52
|
+
export interface WMALogger {
|
|
53
|
+
write(event: unknown): Promise<unknown>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Minimal DecisionLogger surface. */
|
|
57
|
+
export interface WMADecisionLogger {
|
|
58
|
+
record(args: {
|
|
59
|
+
sourceEvent: unknown;
|
|
60
|
+
decision: string;
|
|
61
|
+
ruleId: string | null;
|
|
62
|
+
ruleName: string | null;
|
|
63
|
+
message: string | null;
|
|
64
|
+
decidedInMs: number | null;
|
|
65
|
+
mode: 'enforce' | 'shadow';
|
|
66
|
+
}): Promise<unknown>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Minimal ContextTracker surface. */
|
|
70
|
+
export interface WMAContextTracker {
|
|
71
|
+
compute(event: unknown, at?: number): {
|
|
72
|
+
hour_of_day_utc: number;
|
|
73
|
+
day_of_week_utc: number;
|
|
74
|
+
agent_age_minutes: number;
|
|
75
|
+
session_duration_ms: number;
|
|
76
|
+
recent_error_rate: number;
|
|
77
|
+
event_count_recent: number;
|
|
78
|
+
event_count_total: number;
|
|
79
|
+
};
|
|
80
|
+
record(event: unknown, opts?: { isError?: boolean }): void;
|
|
81
|
+
reset(): void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Minimal team tracker for handoff propagation. */
|
|
85
|
+
export interface WMATeamTracker {
|
|
86
|
+
resolve(sessionId: string): string | null;
|
|
87
|
+
bootstrap(sessionId: string): string;
|
|
88
|
+
recordHandoff(fromAgent: unknown, toAgent: unknown, sessionId: string): string | null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Options for {@link wmaToolInputGuardrail}. */
|
|
92
|
+
export interface WMAGuardrailOptions {
|
|
93
|
+
/** Path to a local JSON policy file. Loaded lazily on first invocation. */
|
|
94
|
+
policiesPath?: string;
|
|
95
|
+
/** In-memory ruleset (overrides policiesPath). Useful for tests. */
|
|
96
|
+
ruleset?: { policies: unknown[]; default?: { action: string } };
|
|
97
|
+
/** Directory for NDJSON logs. Defaults to env WMA_LOG_DIR or ./watchmyagents-logs. */
|
|
98
|
+
logDir?: string;
|
|
99
|
+
/** Override the session id. Defaults to an auto-minted UUID. */
|
|
100
|
+
sessionId?: string;
|
|
101
|
+
/** Trailing window for `ctx.recent_error_rate` etc. Default: 20. */
|
|
102
|
+
recentWindowSize?: number;
|
|
103
|
+
/** On Shield internal error, allow vs deny. Default: false (fail-CLOSED). */
|
|
104
|
+
failOpen?: boolean;
|
|
105
|
+
/** Custom team id resolver — overrides env + handoff propagation. */
|
|
106
|
+
getTeamId?: () => string | null;
|
|
107
|
+
/** Inject an existing Logger (testing). */
|
|
108
|
+
logger?: WMALogger;
|
|
109
|
+
/** Inject an existing DecisionLogger (testing). */
|
|
110
|
+
decisionLogger?: WMADecisionLogger;
|
|
111
|
+
/** Inject an existing ContextTracker (testing). */
|
|
112
|
+
tracker?: WMAContextTracker;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Build the WMA Shield as an @openai/agents Tool Input Guardrail.
|
|
117
|
+
*
|
|
118
|
+
* Usage:
|
|
119
|
+
* ```typescript
|
|
120
|
+
* import { Agent } from '@openai/agents';
|
|
121
|
+
* import { wmaToolInputGuardrail } from 'watchmyagents';
|
|
122
|
+
*
|
|
123
|
+
* const wmaShield = wmaToolInputGuardrail({
|
|
124
|
+
* policiesPath: './policies/mitre-starter.json',
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* const agent = new Agent({
|
|
128
|
+
* name: 'Support bot',
|
|
129
|
+
* instructions: '...',
|
|
130
|
+
* tools: [...],
|
|
131
|
+
* toolInputGuardrails: [wmaShield],
|
|
132
|
+
* });
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function wmaToolInputGuardrail(options?: WMAGuardrailOptions): WMAToolInputGuardrail;
|
|
136
|
+
|
|
137
|
+
// ── Watch ──────────────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
/** Minimal Runner surface (the part of @openai/agents we touch). */
|
|
140
|
+
export interface WMARunnerLike {
|
|
141
|
+
on(event: string, listener: (...args: any[]) => void): unknown;
|
|
142
|
+
off?(event: string, listener: (...args: any[]) => void): unknown;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Minimal Agent surface — same shape as Runner from an EventEmitter
|
|
146
|
+
* perspective. The methods are identical; the difference is the listener
|
|
147
|
+
* signatures (see attachWmaWatchToAgent). */
|
|
148
|
+
export interface WMAAgentLike {
|
|
149
|
+
on(event: string, listener: (...args: any[]) => void): unknown;
|
|
150
|
+
off?(event: string, listener: (...args: any[]) => void): unknown;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Options for {@link attachWmaWatch}. */
|
|
154
|
+
export interface WMAWatchOptions {
|
|
155
|
+
logDir?: string;
|
|
156
|
+
sessionId?: string;
|
|
157
|
+
logger?: WMALogger;
|
|
158
|
+
teamTracker?: WMATeamTracker;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Attach WMA Watch listeners to an @openai/agents Runner. Returns a
|
|
163
|
+
* detach function the customer can call on shutdown.
|
|
164
|
+
*
|
|
165
|
+
* USE THIS when the customer creates a Runner explicitly:
|
|
166
|
+
* ```typescript
|
|
167
|
+
* import { Runner } from '@openai/agents';
|
|
168
|
+
* import { attachWmaWatch } from 'watchmyagents';
|
|
169
|
+
*
|
|
170
|
+
* const runner = new Runner();
|
|
171
|
+
* const detach = attachWmaWatch(runner);
|
|
172
|
+
*
|
|
173
|
+
* await runner.run(agent, input);
|
|
174
|
+
*
|
|
175
|
+
* detach(); // optional, on process shutdown
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* If the customer uses the convenience `run(agent, ...)` function
|
|
179
|
+
* (no explicit Runner), use {@link attachWmaWatchToAgent} instead.
|
|
180
|
+
*/
|
|
181
|
+
export function attachWmaWatch(
|
|
182
|
+
runner: WMARunnerLike,
|
|
183
|
+
options?: WMAWatchOptions,
|
|
184
|
+
): () => void;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Attach WMA Watch listeners to an @openai/agents Agent (AgentHooks
|
|
188
|
+
* pattern). Use this when the customer uses the convenience
|
|
189
|
+
* `run(agent, ...)` function rather than creating an explicit Runner.
|
|
190
|
+
*
|
|
191
|
+
* The AgentHooks event signatures differ slightly from RunHooks:
|
|
192
|
+
* agent_end, agent_handoff, agent_tool_start, agent_tool_end do NOT
|
|
193
|
+
* pass the agent in their args — it's captured via closure here.
|
|
194
|
+
*
|
|
195
|
+
* Usage:
|
|
196
|
+
* ```typescript
|
|
197
|
+
* import { Agent, run } from '@openai/agents';
|
|
198
|
+
* import { attachWmaWatchToAgent } from 'watchmyagents';
|
|
199
|
+
*
|
|
200
|
+
* const myAgent = new Agent({ name: 'support_bot', tools: [...] });
|
|
201
|
+
* const detach = attachWmaWatchToAgent(myAgent);
|
|
202
|
+
*
|
|
203
|
+
* await run(myAgent, 'help me reset my password');
|
|
204
|
+
*
|
|
205
|
+
* detach(); // optional, on process shutdown
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export function attachWmaWatchToAgent(
|
|
209
|
+
agent: WMAAgentLike,
|
|
210
|
+
options?: WMAWatchOptions,
|
|
211
|
+
): () => void;
|
|
212
|
+
|
|
213
|
+
// ── Normalizers (exported for advanced users / tests) ──────────────────
|
|
214
|
+
|
|
215
|
+
/** Mirrors the WMA contract `WMAAction` shape. */
|
|
216
|
+
export interface WMAAction {
|
|
217
|
+
id: string;
|
|
218
|
+
provider: string;
|
|
219
|
+
agent_id: string;
|
|
220
|
+
agent_name: string | null;
|
|
221
|
+
session_id: string;
|
|
222
|
+
session_thread_id: string | null;
|
|
223
|
+
action_type: string;
|
|
224
|
+
timestamp: string;
|
|
225
|
+
status: 'ok' | 'error' | 'blocked';
|
|
226
|
+
tool_name: string | null;
|
|
227
|
+
model: string | null;
|
|
228
|
+
duration_ms: number | null;
|
|
229
|
+
parent_agent_id: string | null;
|
|
230
|
+
composition_pattern: 'solo' | 'hierarchy' | 'graph' | 'peer';
|
|
231
|
+
team_id: string | null;
|
|
232
|
+
input: object | null;
|
|
233
|
+
output: object | null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface NormalizeArgs<T extends string> {
|
|
237
|
+
sessionId: string;
|
|
238
|
+
teamId: string | null;
|
|
239
|
+
agent?: { name?: string; model?: string };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function normalizeAgentStart(args: NormalizeArgs<'agent_start'> & { turnInput?: unknown[] }): Readonly<WMAAction>;
|
|
243
|
+
export function normalizeAgentEnd(args: NormalizeArgs<'agent_end'> & { output?: string }): Readonly<WMAAction>;
|
|
244
|
+
export function normalizeAgentHandoff(args: NormalizeArgs<'agent_handoff'> & {
|
|
245
|
+
fromAgent?: { name?: string; model?: string };
|
|
246
|
+
toAgent?: { name?: string; model?: string };
|
|
247
|
+
}): Readonly<WMAAction>;
|
|
248
|
+
export function normalizeToolStart(args: NormalizeArgs<'tool_start'> & {
|
|
249
|
+
tool?: { name?: string };
|
|
250
|
+
toolCall?: { id?: string; callId?: string; name?: string; arguments?: string | object };
|
|
251
|
+
}): Readonly<WMAAction>;
|
|
252
|
+
export function normalizeToolEnd(args: NormalizeArgs<'tool_end'> & {
|
|
253
|
+
tool?: { name?: string };
|
|
254
|
+
toolCall?: { id?: string; callId?: string; name?: string; arguments?: string | object };
|
|
255
|
+
result?: unknown;
|
|
256
|
+
}): Readonly<WMAAction>;
|
|
257
|
+
|
|
258
|
+
// ── Adapter metadata ───────────────────────────────────────────────────
|
|
259
|
+
|
|
260
|
+
export interface WMAAdapterMeta {
|
|
261
|
+
readonly provider: 'openai-agents';
|
|
262
|
+
readonly displayName: string;
|
|
263
|
+
readonly enforcement: 'sync_confirm' | 'sync_interrupt' | 'detect_only';
|
|
264
|
+
readonly compositionDefault: 'solo' | 'hierarchy' | 'graph' | 'peer';
|
|
265
|
+
readonly customerInstrumented: true;
|
|
266
|
+
readonly peerPackage: '@openai/agents';
|
|
267
|
+
readonly minPeerVersion: string;
|
|
268
|
+
readonly capabilities: Readonly<{
|
|
269
|
+
watch: boolean;
|
|
270
|
+
shield: boolean;
|
|
271
|
+
preToolDeny: boolean;
|
|
272
|
+
postToolFilter: boolean;
|
|
273
|
+
teamIdAutoDetect: boolean;
|
|
274
|
+
streamingSupported: boolean | string;
|
|
275
|
+
}>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export const adapterMeta: WMAAdapterMeta;
|