@raindrop-ai/openai-managed-agents 0.0.1 → 0.0.3

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 CHANGED
@@ -68,15 +68,19 @@ For a runner that reconnects streams, use the public typed handler with an
68
68
  unwrapped native client. Keep one Raindrop client for the runner's lifetime:
69
69
 
70
70
  ```ts
71
+ import type { Turn } from "openai/resources/beta/agents/sessions/turns";
72
+
71
73
  raindrop.handler.onSession(session);
72
74
  raindrop.handler.onInput(session.id, userInput); // after successful submission
73
- // Recover missed item events before completing recovered turns.
75
+ // Snapshot turn statuses before recovering their items.
76
+ const recoveredTurns: Turn[] = [];
77
+ for await (const turn of client.beta.agents.sessions.turns.list(session.id, { order: "asc" })) {
78
+ recoveredTurns.push(turn);
79
+ }
74
80
  for await (const item of client.beta.agents.sessions.items.list(session.id, { order: "asc" })) {
75
81
  raindrop.handler.onItem(session.id, item);
76
82
  }
77
- for await (const turn of client.beta.agents.sessions.turns.list(session.id, { order: "asc" })) {
78
- raindrop.handler.onTurn(turn);
79
- }
83
+ for (const turn of recoveredTurns) raindrop.handler.onTurn(turn);
80
84
  for await (const event of events) raindrop.handler.onEvent(event);
81
85
  await raindrop.flush();
82
86
  // After all streams/recovery work are stopped:
@@ -84,8 +88,10 @@ raindrop.handler.forgetSession(session.id);
84
88
  await raindrop.shutdown();
85
89
  ```
86
90
 
87
- Open the stream before recovery so it can buffer live updates. Recover stored
88
- items, then stored turns, before consuming buffered events.
91
+ Open the stream before recovery so it can buffer live updates. Read and buffer
92
+ turn statuses first, recover items next, then pass the buffered turns to the
93
+ handler. A turn completed after the snapshot closes from its buffered live
94
+ terminal event. Process callbacks serially during recovery and consumption.
89
95
 
90
96
  `onInputEvents(sessionId, events)` records accepted message/tool-result submissions.
91
97
  Repeated terminal turns and tool receipts are deduplicated within this client.
@@ -93,11 +99,11 @@ Turn deduplication retains the latest 10,000 completed turns. Across process
93
99
  restarts, provide a stable `eventId: (turnId) => ...` and replay items before turns.
94
100
  No session or item listing is intercepted automatically.
95
101
 
96
- The wrapper closes unfinished captures in the iterator's `finally`, including
97
- early exit and transport failure. This marks capture interruption; it does not
102
+ The wrapper closes unfinished captures when the last iterator for a session
103
+ exits, including early exit and transport failure. This marks capture interruption; it does not
98
104
  cancel the backend turn. Session model and context remain available for later
99
105
  streams; the previous input is cleared. Metadata retains the latest 10,000 idle
100
- sessions plus sessions with active turns. Call `forgetSession` when
106
+ sessions plus sessions with active turns or streams. Call `forgetSession` when
101
107
  the session is no longer needed. Use the callback path when an unfinished turn
102
108
  must survive a reconnection.
103
109
 
@@ -114,6 +120,27 @@ responsibility.
114
120
  `users.identify`, and `signals.track` expose the shared core enrichment API.
115
121
  `flush()` ships current buffers; `shutdown()` also closes unfinished captures.
116
122
 
123
+ ## Tool catalog capture (`ai.prompt.tools`)
124
+
125
+ **Agent configuration, not exact per-call capture.** Model calls run inside
126
+ OpenAI's managed runtime, so the wrapper never sees individual requests. It
127
+ does see the resolved agent definition on the session (`session.agent.tools`)
128
+ and records it as `ai.prompt.tools` on every coordinator `openai.agent.turn`
129
+ span (one per model turn), together with
130
+ `ai.prompt.tools.source = "agent.config"` so consumers can tell this
131
+ configuration snapshot from exact capture. Function tools keep their JSON
132
+ Schema `parameters`; `mcp`, `web_search`, `tool_search` and
133
+ `programmatic_tool_calling` entries are provider-owned and recorded as
134
+ `{"type":"provider-defined",…}` without an invented schema. Subagent turns run
135
+ their own tool sets, so they only receive an explicit override. Absent
136
+ attribute = catalog unknown; `[]` = the agent has no tools. This package has no
137
+ separate prompt-content switch, so the attribute is recorded whenever tracing
138
+ is enabled.
139
+
140
+ | Option | Description |
141
+ | --- | --- |
142
+ | `tools` (on `createRaindropOpenAIManagedAgents({ tools })` or `wrap(client, { tools })`) | Overrides the tool catalog recorded as `ai.prompt.tools` on every model span. Use when the integration cannot see the tools the model was given. Replaces the agent definition entirely (`tools: []` records an empty catalog) and carries no `source` attribute. |
143
+
117
144
  ## Limits
118
145
 
119
146
  The service does not expose individual inference requests. Captures represent
@@ -133,5 +160,5 @@ configuration. Subagent model and inherited coordinator input stay absent unless
133
160
  their own input is recorded.
134
161
 
135
162
  See [RELEASING.md](RELEASING.md) for first-publication and verification steps.
136
- See the [integration docs](https://docs.raindrop.ai/integrations/openai-managed-agents)
163
+ See the [integration docs](https://www.raindrop.ai/docs/integrations/openai-managed-agents)
137
164
  for configuration details.
package/dist/index.d.mts CHANGED
@@ -506,9 +506,42 @@ declare global {
506
506
  var RAINDROP_CONTEXT_MANAGER: (new () => ContextManager) | undefined;
507
507
  var RAINDROP_ASYNC_LOCAL_STORAGE: (new <T>() => AsyncLocalStorageLike<T>) | undefined;
508
508
  }
509
+ type JsonSchema = Record<string, unknown>;
510
+ type FunctionToolDeclaration = {
511
+ type: "function";
512
+ name: string;
513
+ description?: string;
514
+ inputSchema?: JsonSchema;
515
+ };
516
+ type ProviderDefinedToolDeclaration = {
517
+ type: "provider-defined";
518
+ id?: string;
519
+ name: string;
520
+ args?: Record<string, unknown>;
521
+ };
522
+ type ToolDeclaration = FunctionToolDeclaration | ProviderDefinedToolDeclaration;
523
+ /**
524
+ * What callers hand to a `tools` override. The canonical `ToolDeclaration`
525
+ * shape is accepted as-is; so is any framework shape `normalizeToolDeclarations`
526
+ * recognizes (OpenAI, Anthropic, Bedrock, LangChain, Pi, Mastra, AI SDK).
527
+ */
528
+ type ToolDeclarationInput = ToolDeclaration | {
529
+ name: string;
530
+ description?: string;
531
+ inputSchema?: JsonSchema;
532
+ parameters?: JsonSchema;
533
+ };
534
+ type PromptToolsOverride = ReadonlyArray<ToolDeclarationInput | unknown>;
509
535
 
510
536
  type SessionContext = {
511
537
  [Key in keyof Pick<Patch, "userId" | "convoId" | "eventName" | "properties">]?: Patch[Key] | undefined;
538
+ } & {
539
+ /**
540
+ * Overrides the tool catalog recorded as `ai.prompt.tools` on every model
541
+ * span. Use when the integration cannot see the tools the model was given.
542
+ * Without it the agent definition on the session (`session.agent.tools`) is used.
543
+ */
544
+ tools?: PromptToolsOverride | undefined;
512
545
  };
513
546
  type OpenAIManagedAgentsOptions = SessionContext & {
514
547
  writeKey?: string | undefined;
package/dist/index.d.ts CHANGED
@@ -506,9 +506,42 @@ declare global {
506
506
  var RAINDROP_CONTEXT_MANAGER: (new () => ContextManager) | undefined;
507
507
  var RAINDROP_ASYNC_LOCAL_STORAGE: (new <T>() => AsyncLocalStorageLike<T>) | undefined;
508
508
  }
509
+ type JsonSchema = Record<string, unknown>;
510
+ type FunctionToolDeclaration = {
511
+ type: "function";
512
+ name: string;
513
+ description?: string;
514
+ inputSchema?: JsonSchema;
515
+ };
516
+ type ProviderDefinedToolDeclaration = {
517
+ type: "provider-defined";
518
+ id?: string;
519
+ name: string;
520
+ args?: Record<string, unknown>;
521
+ };
522
+ type ToolDeclaration = FunctionToolDeclaration | ProviderDefinedToolDeclaration;
523
+ /**
524
+ * What callers hand to a `tools` override. The canonical `ToolDeclaration`
525
+ * shape is accepted as-is; so is any framework shape `normalizeToolDeclarations`
526
+ * recognizes (OpenAI, Anthropic, Bedrock, LangChain, Pi, Mastra, AI SDK).
527
+ */
528
+ type ToolDeclarationInput = ToolDeclaration | {
529
+ name: string;
530
+ description?: string;
531
+ inputSchema?: JsonSchema;
532
+ parameters?: JsonSchema;
533
+ };
534
+ type PromptToolsOverride = ReadonlyArray<ToolDeclarationInput | unknown>;
509
535
 
510
536
  type SessionContext = {
511
537
  [Key in keyof Pick<Patch, "userId" | "convoId" | "eventName" | "properties">]?: Patch[Key] | undefined;
538
+ } & {
539
+ /**
540
+ * Overrides the tool catalog recorded as `ai.prompt.tools` on every model
541
+ * span. Use when the integration cannot see the tools the model was given.
542
+ * Without it the agent definition on the session (`session.agent.tools`) is used.
543
+ */
544
+ tools?: PromptToolsOverride | undefined;
512
545
  };
513
546
  type OpenAIManagedAgentsOptions = SessionContext & {
514
547
  writeKey?: string | undefined;
package/dist/index.js CHANGED
@@ -87,7 +87,7 @@ function evalScopeAttributes() {
87
87
  return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
88
88
  }
89
89
 
90
- // ../core/dist/chunk-WJOR6M7H.js
90
+ // ../core/dist/chunk-I6TVJQEC.js
91
91
  var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
92
92
  function state() {
93
93
  const holder = globalThis;
@@ -2169,6 +2169,158 @@ var TraceShipper = class {
2169
2169
  }
2170
2170
  }
2171
2171
  };
2172
+ var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
2173
+ function isRecord(value) {
2174
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2175
+ }
2176
+ var JSON_SCHEMA_KEYS = [
2177
+ "type",
2178
+ "properties",
2179
+ "$schema",
2180
+ "$ref",
2181
+ "anyOf",
2182
+ "oneOf",
2183
+ "allOf",
2184
+ "enum",
2185
+ "const",
2186
+ "items",
2187
+ "additionalProperties",
2188
+ "required"
2189
+ ];
2190
+ function isJsonSchema(value) {
2191
+ if (!isRecord(value)) return false;
2192
+ if (typeof value["~standard"] === "object") return false;
2193
+ if (isRecord(value._def) || isRecord(value._zod)) return false;
2194
+ if (Object.keys(value).length === 0) return true;
2195
+ return JSON_SCHEMA_KEYS.some((key) => key in value);
2196
+ }
2197
+ function toJsonSchema(value, options) {
2198
+ if (value === void 0 || value === null) return void 0;
2199
+ if (isJsonSchema(value)) return value;
2200
+ if (isRecord(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
2201
+ if (isRecord(value) && isJsonSchema(value.json)) return value.json;
2202
+ if (options == null ? void 0 : options.schema) {
2203
+ try {
2204
+ return options.schema(value);
2205
+ } catch (e) {
2206
+ return void 0;
2207
+ }
2208
+ }
2209
+ return void 0;
2210
+ }
2211
+ function pickString(value) {
2212
+ return typeof value === "string" && value.length > 0 ? value : void 0;
2213
+ }
2214
+ function functionTool(name, description, schema, options) {
2215
+ const tool = { type: "function", name };
2216
+ const desc = pickString(description);
2217
+ if (desc !== void 0) tool.description = desc;
2218
+ const inputSchema = toJsonSchema(schema, options);
2219
+ if (inputSchema !== void 0) tool.inputSchema = inputSchema;
2220
+ return tool;
2221
+ }
2222
+ function normalizeToolDeclaration(tool, options, fallbackName) {
2223
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2224
+ if (!isRecord(tool)) return void 0;
2225
+ if (tool.type === "provider-defined" || tool.type === "provider") {
2226
+ const name2 = (_b = (_a = pickString(tool.name)) != null ? _a : pickString(tool.id)) != null ? _b : fallbackName;
2227
+ if (name2 === void 0) return void 0;
2228
+ const declaration = { type: "provider-defined", name: name2 };
2229
+ const id = pickString(tool.id);
2230
+ if (id !== void 0) declaration.id = id;
2231
+ if (isRecord(tool.args)) declaration.args = tool.args;
2232
+ return declaration;
2233
+ }
2234
+ if (isRecord(tool.toolSpec)) {
2235
+ const spec = tool.toolSpec;
2236
+ const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
2237
+ if (name2 === void 0) return void 0;
2238
+ return functionTool(name2, spec.description, spec.inputSchema, options);
2239
+ }
2240
+ if (isRecord(tool.function)) {
2241
+ const fn = tool.function;
2242
+ const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
2243
+ if (name2 === void 0) return void 0;
2244
+ return functionTool(name2, fn.description, (_e = fn.parameters) != null ? _e : fn.input_schema, options);
2245
+ }
2246
+ const name = (_g = (_f = pickString(tool.name)) != null ? _f : pickString(tool.id)) != null ? _g : fallbackName;
2247
+ if (name === void 0) return void 0;
2248
+ const type = pickString(tool.type);
2249
+ if (type !== void 0 && type !== "function" && type !== "dynamic" && type !== "custom") {
2250
+ if (!("input_schema" in tool) && !("inputSchema" in tool) && !("parameters" in tool)) {
2251
+ return { type: "provider-defined", id: type, name };
2252
+ }
2253
+ }
2254
+ return functionTool(
2255
+ name,
2256
+ tool.description,
2257
+ (_j = (_i = (_h = tool.inputSchema) != null ? _h : tool.input_schema) != null ? _i : tool.parameters) != null ? _j : tool.schema,
2258
+ options
2259
+ );
2260
+ }
2261
+ var NOT_A_GEMINI_GROUP_KEYS = ["name", "id", "type", "function", "toolSpec", "cachePoint"];
2262
+ function isGeminiToolGroup(tool) {
2263
+ if (Array.isArray(tool.functionDeclarations)) return true;
2264
+ const keys = Object.keys(tool);
2265
+ if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool)) return false;
2266
+ return keys.every((key) => isRecord(tool[key]));
2267
+ }
2268
+ function expandGeminiTool(tool, options) {
2269
+ const declarations = [];
2270
+ for (const [key, value] of Object.entries(tool)) {
2271
+ if (key === "functionDeclarations" && Array.isArray(value)) {
2272
+ for (const declaration of value) {
2273
+ const normalized = normalizeToolDeclaration(declaration, options);
2274
+ if (normalized) declarations.push(normalized);
2275
+ }
2276
+ } else if (isRecord(value)) {
2277
+ declarations.push({ type: "provider-defined", id: key, name: key, args: value });
2278
+ }
2279
+ }
2280
+ return declarations;
2281
+ }
2282
+ function normalizeToolDeclarations(tools, options) {
2283
+ if (tools === void 0 || tools === null) return void 0;
2284
+ if (Array.isArray(tools)) {
2285
+ return tools.flatMap((tool) => {
2286
+ if (isRecord(tool) && isGeminiToolGroup(tool)) {
2287
+ return expandGeminiTool(tool, options);
2288
+ }
2289
+ const declaration = normalizeToolDeclaration(tool, options);
2290
+ return declaration ? [declaration] : [];
2291
+ });
2292
+ }
2293
+ if (!isRecord(tools)) return void 0;
2294
+ return Object.entries(tools).flatMap(([key, tool]) => {
2295
+ const declaration = normalizeToolDeclaration(tool, options, key);
2296
+ return declaration ? [declaration] : [];
2297
+ });
2298
+ }
2299
+ function resolvePromptTools(args) {
2300
+ var _a;
2301
+ if (args.override !== void 0) {
2302
+ return (_a = normalizeToolDeclarations(args.override, args.options)) != null ? _a : [];
2303
+ }
2304
+ return normalizeToolDeclarations(args.inferred, args.options);
2305
+ }
2306
+ function promptToolsAttribute(tools) {
2307
+ const values = promptToolsAttributeValue(tools);
2308
+ if (values === void 0) return void 0;
2309
+ return {
2310
+ key: PROMPT_TOOLS_ATTRIBUTE,
2311
+ value: { arrayValue: { values: values.map((stringValue) => ({ stringValue })) } }
2312
+ };
2313
+ }
2314
+ function promptToolsAttributeValue(tools) {
2315
+ if (tools === void 0) return void 0;
2316
+ return tools.map((tool) => {
2317
+ try {
2318
+ return JSON.stringify(tool);
2319
+ } catch (e) {
2320
+ return JSON.stringify({ type: tool.type, name: tool.name });
2321
+ }
2322
+ });
2323
+ }
2172
2324
 
2173
2325
  // ../core/dist/index.node.js
2174
2326
  var import_async_hooks = require("async_hooks");
@@ -2345,6 +2497,21 @@ function installTracingSuppressionHook() {
2345
2497
  installTracingSuppressionHook();
2346
2498
 
2347
2499
  // src/handler.ts
2500
+ var AGENT_CONFIG_SOURCE = {
2501
+ key: "ai.prompt.tools.source",
2502
+ value: { stringValue: "agent.config" }
2503
+ };
2504
+ function agentConfigTools(tools) {
2505
+ if (!Array.isArray(tools)) return void 0;
2506
+ return tools.map((tool) => {
2507
+ if (!isRecord2(tool)) return tool;
2508
+ const record = tool;
2509
+ if (typeof record.name === "string" || typeof record.type !== "string") return tool;
2510
+ const { type, ...args } = record;
2511
+ const name = typeof record.server_label === "string" ? record.server_label : type;
2512
+ return { type: "provider-defined", id: type, name, args };
2513
+ });
2514
+ }
2348
2515
  var RaindropManagedAgentsHandler = class {
2349
2516
  constructor(events, traces, opts) {
2350
2517
  this.events = events;
@@ -2369,13 +2536,13 @@ var RaindropManagedAgentsHandler = class {
2369
2536
  sessionCapture(sessionId) {
2370
2537
  const existing = this.sessions.get(sessionId);
2371
2538
  if (existing) return existing;
2372
- const session = { context: this.opts, turns: /* @__PURE__ */ new Map() };
2539
+ const session = { context: this.opts, turns: /* @__PURE__ */ new Map(), activeStreams: 0 };
2373
2540
  this.sessions.set(sessionId, session);
2374
2541
  return session;
2375
2542
  }
2376
2543
  cacheSession(sessionId, session) {
2377
2544
  this.idleSessions.delete(sessionId);
2378
- if (session.turns.size > 0) return;
2545
+ if (session.turns.size > 0 || session.activeStreams > 0) return;
2379
2546
  this.idleSessions.add(sessionId);
2380
2547
  if (this.idleSessions.size <= 1e4) return;
2381
2548
  const oldest = this.idleSessions.values().next().value;
@@ -2388,7 +2555,22 @@ var RaindropManagedAgentsHandler = class {
2388
2555
  try {
2389
2556
  const capture = this.sessionCapture(session.id);
2390
2557
  capture.model = session.agent.model;
2391
- capture.context = { ...this.opts, ...capture.context, ...context };
2558
+ capture.context = {
2559
+ ...this.opts,
2560
+ ...capture.context,
2561
+ ...context,
2562
+ properties: {
2563
+ ...this.opts.properties,
2564
+ ...capture.context.properties,
2565
+ ...context.properties
2566
+ }
2567
+ };
2568
+ const override = capture.context.tools;
2569
+ const toolsAttr = promptToolsAttribute(
2570
+ resolvePromptTools({ override, inferred: agentConfigTools(session.agent.tools) })
2571
+ );
2572
+ capture.promptToolsOverridden = override !== void 0;
2573
+ capture.promptTools = !toolsAttr ? void 0 : override !== void 0 ? [toolsAttr] : [toolsAttr, AGENT_CONFIG_SOURCE];
2392
2574
  this.cacheSession(session.id, capture);
2393
2575
  } catch (e) {
2394
2576
  }
@@ -2412,7 +2594,12 @@ var RaindropManagedAgentsHandler = class {
2412
2594
  const existing = session.turns.get(turnId);
2413
2595
  if (existing) return existing;
2414
2596
  const context = session.context;
2415
- const eventId = (_c = (_b = (_a = this.opts).eventId) == null ? void 0 : _b.call(_a, turnId)) != null ? _c : randomUUID();
2597
+ let eventId;
2598
+ try {
2599
+ eventId = (_c = (_b = (_a = this.opts).eventId) == null ? void 0 : _b.call(_a, turnId)) == null ? void 0 : _c.trim();
2600
+ } catch (e) {
2601
+ }
2602
+ eventId || (eventId = randomUUID());
2416
2603
  const patch = {
2417
2604
  userId: context.userId,
2418
2605
  convoId: (_d = context.convoId) != null ? _d : sessionId,
@@ -2465,8 +2652,8 @@ var RaindropManagedAgentsHandler = class {
2465
2652
  attrInt("openai.turn.started_at", (_a = turn.started_at) != null ? _a : void 0),
2466
2653
  attrInt("openai.turn.completed_at", (_b = turn.completed_at) != null ? _b : void 0)
2467
2654
  ]);
2655
+ const session = this.sessions.get(turn.session_id);
2468
2656
  if (turn.subagent_id === null) {
2469
- const session = this.sessions.get(turn.session_id);
2470
2657
  capture.patch.model = session == null ? void 0 : session.model;
2471
2658
  if (!capture.inputFromItem) capture.patch.input = session == null ? void 0 : session.input;
2472
2659
  this.setAttributes(capture.root, [
@@ -2475,6 +2662,9 @@ var RaindropManagedAgentsHandler = class {
2475
2662
  attrString("gen_ai.response.model", session == null ? void 0 : session.model)
2476
2663
  ]);
2477
2664
  }
2665
+ if ((session == null ? void 0 : session.promptTools) && (turn.subagent_id === null || session.promptToolsOverridden)) {
2666
+ this.setAttributes(capture.root, session.promptTools);
2667
+ }
2478
2668
  if (turn.subagent_id)
2479
2669
  capture.patch.properties = {
2480
2670
  ...capture.patch.properties,
@@ -2682,6 +2872,25 @@ var RaindropManagedAgentsHandler = class {
2682
2872
  }
2683
2873
  this.cacheSession(sessionId, session);
2684
2874
  }
2875
+ /** @internal */
2876
+ onStreamStart(sessionId) {
2877
+ try {
2878
+ const session = this.sessionCapture(sessionId);
2879
+ session.activeStreams++;
2880
+ this.cacheSession(sessionId, session);
2881
+ } catch (e) {
2882
+ }
2883
+ }
2884
+ /** @internal */
2885
+ onStreamEnd(sessionId) {
2886
+ try {
2887
+ const session = this.sessions.get(sessionId);
2888
+ if (!session) return;
2889
+ session.activeStreams = Math.max(0, session.activeStreams - 1);
2890
+ if (session.activeStreams === 0) this.closeSessionTurns(sessionId);
2891
+ } catch (e) {
2892
+ }
2893
+ }
2685
2894
  closeSessionTurns(sessionId, error) {
2686
2895
  try {
2687
2896
  const session = this.sessions.get(sessionId);
@@ -2710,19 +2919,22 @@ var RaindropManagedAgentsHandler = class {
2710
2919
  this.completed.clear();
2711
2920
  }
2712
2921
  };
2922
+ function isRecord2(value) {
2923
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2924
+ }
2713
2925
 
2714
2926
  // package.json
2715
2927
  var package_default = {
2716
2928
  name: "@raindrop-ai/openai-managed-agents",
2717
- version: "0.0.1",
2929
+ version: "0.0.3",
2718
2930
  description: "Raindrop tracing for the OpenAI Agents API",
2719
2931
  main: "dist/index.js",
2720
2932
  module: "dist/index.mjs",
2721
2933
  types: "dist/index.d.ts",
2722
2934
  license: "MIT",
2723
- homepage: "https://docs.raindrop.ai/integrations/openai-managed-agents",
2935
+ homepage: "https://www.raindrop.ai/docs/integrations/openai-managed-agents",
2724
2936
  bugs: {
2725
- url: "https://docs.raindrop.ai/support"
2937
+ url: "https://www.raindrop.ai/docs/support"
2726
2938
  },
2727
2939
  exports: {
2728
2940
  ".": {
@@ -2793,14 +3005,18 @@ var libraryVersion = package_default.version;
2793
3005
  // src/wrap.ts
2794
3006
  var import_streaming = require("openai/core/streaming");
2795
3007
  async function* observe(events, handler, sessionId) {
3008
+ if (sessionId) handler.onStreamStart(sessionId);
2796
3009
  try {
2797
3010
  for await (const event of events) {
2798
- if (event.type === "agent.session.created") sessionId = event.session.id;
3011
+ if (!sessionId && event.type === "agent.session.created") {
3012
+ sessionId = event.session.id;
3013
+ handler.onStreamStart(sessionId);
3014
+ }
2799
3015
  handler.onEvent(event);
2800
3016
  yield event;
2801
3017
  }
2802
3018
  } finally {
2803
- if (sessionId) handler.closeSessionTurns(sessionId);
3019
+ if (sessionId) handler.onStreamEnd(sessionId);
2804
3020
  }
2805
3021
  }
2806
3022
  function wrapManagedAgents(client, handler, context) {
@@ -2828,19 +3044,12 @@ function wrapManagedAgents(client, handler, context) {
2828
3044
  if (result instanceof import_streaming.Stream) {
2829
3045
  const source = result;
2830
3046
  async function* initialEvents() {
2831
- let sessionId;
2832
- try {
2833
- for await (const event of source) {
2834
- if (event.type === "agent.session.created") {
2835
- sessionId = event.session.id;
2836
- handler.onSession(event.session, context);
2837
- handler.onInput(event.session.id, params.input);
2838
- }
2839
- handler.onEvent(event);
2840
- yield event;
3047
+ for await (const event of observe(source, handler)) {
3048
+ if (event.type === "agent.session.created") {
3049
+ handler.onSession(event.session, context);
3050
+ handler.onInput(event.session.id, params.input);
2841
3051
  }
2842
- } finally {
2843
- if (sessionId) handler.closeSessionTurns(sessionId);
3052
+ yield event;
2844
3053
  }
2845
3054
  }
2846
3055
  return new import_streaming.Stream(initialEvents, result.controller);
@@ -2855,20 +3064,7 @@ function wrapManagedAgents(client, handler, context) {
2855
3064
  return session;
2856
3065
  });
2857
3066
  if (prop === "stream")
2858
- return (sessionId, params, options) => {
2859
- const stream = target.stream(sessionId, params, options);
2860
- return new Proxy(stream, {
2861
- get(obj, key) {
2862
- if (key === Symbol.asyncIterator)
2863
- return () => {
2864
- handler.onInput(sessionId, params.input);
2865
- return observe(stream, handler, sessionId);
2866
- };
2867
- const value2 = Reflect.get(obj, key, obj);
2868
- return typeof value2 === "function" ? value2.bind(obj) : value2;
2869
- }
2870
- });
2871
- };
3067
+ return (sessionId, params, options) => target.stream.call(wrappedSessions, sessionId, params, options);
2872
3068
  const value = Reflect.get(target, prop, target);
2873
3069
  return typeof value === "function" ? value.bind(target) : value;
2874
3070
  }
package/dist/index.mjs CHANGED
@@ -60,7 +60,7 @@ function evalScopeAttributes() {
60
60
  return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
61
61
  }
62
62
 
63
- // ../core/dist/chunk-WJOR6M7H.js
63
+ // ../core/dist/chunk-I6TVJQEC.js
64
64
  var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
65
65
  function state() {
66
66
  const holder = globalThis;
@@ -2142,6 +2142,158 @@ var TraceShipper = class {
2142
2142
  }
2143
2143
  }
2144
2144
  };
2145
+ var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
2146
+ function isRecord(value) {
2147
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2148
+ }
2149
+ var JSON_SCHEMA_KEYS = [
2150
+ "type",
2151
+ "properties",
2152
+ "$schema",
2153
+ "$ref",
2154
+ "anyOf",
2155
+ "oneOf",
2156
+ "allOf",
2157
+ "enum",
2158
+ "const",
2159
+ "items",
2160
+ "additionalProperties",
2161
+ "required"
2162
+ ];
2163
+ function isJsonSchema(value) {
2164
+ if (!isRecord(value)) return false;
2165
+ if (typeof value["~standard"] === "object") return false;
2166
+ if (isRecord(value._def) || isRecord(value._zod)) return false;
2167
+ if (Object.keys(value).length === 0) return true;
2168
+ return JSON_SCHEMA_KEYS.some((key) => key in value);
2169
+ }
2170
+ function toJsonSchema(value, options) {
2171
+ if (value === void 0 || value === null) return void 0;
2172
+ if (isJsonSchema(value)) return value;
2173
+ if (isRecord(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
2174
+ if (isRecord(value) && isJsonSchema(value.json)) return value.json;
2175
+ if (options == null ? void 0 : options.schema) {
2176
+ try {
2177
+ return options.schema(value);
2178
+ } catch (e) {
2179
+ return void 0;
2180
+ }
2181
+ }
2182
+ return void 0;
2183
+ }
2184
+ function pickString(value) {
2185
+ return typeof value === "string" && value.length > 0 ? value : void 0;
2186
+ }
2187
+ function functionTool(name, description, schema, options) {
2188
+ const tool = { type: "function", name };
2189
+ const desc = pickString(description);
2190
+ if (desc !== void 0) tool.description = desc;
2191
+ const inputSchema = toJsonSchema(schema, options);
2192
+ if (inputSchema !== void 0) tool.inputSchema = inputSchema;
2193
+ return tool;
2194
+ }
2195
+ function normalizeToolDeclaration(tool, options, fallbackName) {
2196
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2197
+ if (!isRecord(tool)) return void 0;
2198
+ if (tool.type === "provider-defined" || tool.type === "provider") {
2199
+ const name2 = (_b = (_a = pickString(tool.name)) != null ? _a : pickString(tool.id)) != null ? _b : fallbackName;
2200
+ if (name2 === void 0) return void 0;
2201
+ const declaration = { type: "provider-defined", name: name2 };
2202
+ const id = pickString(tool.id);
2203
+ if (id !== void 0) declaration.id = id;
2204
+ if (isRecord(tool.args)) declaration.args = tool.args;
2205
+ return declaration;
2206
+ }
2207
+ if (isRecord(tool.toolSpec)) {
2208
+ const spec = tool.toolSpec;
2209
+ const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
2210
+ if (name2 === void 0) return void 0;
2211
+ return functionTool(name2, spec.description, spec.inputSchema, options);
2212
+ }
2213
+ if (isRecord(tool.function)) {
2214
+ const fn = tool.function;
2215
+ const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
2216
+ if (name2 === void 0) return void 0;
2217
+ return functionTool(name2, fn.description, (_e = fn.parameters) != null ? _e : fn.input_schema, options);
2218
+ }
2219
+ const name = (_g = (_f = pickString(tool.name)) != null ? _f : pickString(tool.id)) != null ? _g : fallbackName;
2220
+ if (name === void 0) return void 0;
2221
+ const type = pickString(tool.type);
2222
+ if (type !== void 0 && type !== "function" && type !== "dynamic" && type !== "custom") {
2223
+ if (!("input_schema" in tool) && !("inputSchema" in tool) && !("parameters" in tool)) {
2224
+ return { type: "provider-defined", id: type, name };
2225
+ }
2226
+ }
2227
+ return functionTool(
2228
+ name,
2229
+ tool.description,
2230
+ (_j = (_i = (_h = tool.inputSchema) != null ? _h : tool.input_schema) != null ? _i : tool.parameters) != null ? _j : tool.schema,
2231
+ options
2232
+ );
2233
+ }
2234
+ var NOT_A_GEMINI_GROUP_KEYS = ["name", "id", "type", "function", "toolSpec", "cachePoint"];
2235
+ function isGeminiToolGroup(tool) {
2236
+ if (Array.isArray(tool.functionDeclarations)) return true;
2237
+ const keys = Object.keys(tool);
2238
+ if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool)) return false;
2239
+ return keys.every((key) => isRecord(tool[key]));
2240
+ }
2241
+ function expandGeminiTool(tool, options) {
2242
+ const declarations = [];
2243
+ for (const [key, value] of Object.entries(tool)) {
2244
+ if (key === "functionDeclarations" && Array.isArray(value)) {
2245
+ for (const declaration of value) {
2246
+ const normalized = normalizeToolDeclaration(declaration, options);
2247
+ if (normalized) declarations.push(normalized);
2248
+ }
2249
+ } else if (isRecord(value)) {
2250
+ declarations.push({ type: "provider-defined", id: key, name: key, args: value });
2251
+ }
2252
+ }
2253
+ return declarations;
2254
+ }
2255
+ function normalizeToolDeclarations(tools, options) {
2256
+ if (tools === void 0 || tools === null) return void 0;
2257
+ if (Array.isArray(tools)) {
2258
+ return tools.flatMap((tool) => {
2259
+ if (isRecord(tool) && isGeminiToolGroup(tool)) {
2260
+ return expandGeminiTool(tool, options);
2261
+ }
2262
+ const declaration = normalizeToolDeclaration(tool, options);
2263
+ return declaration ? [declaration] : [];
2264
+ });
2265
+ }
2266
+ if (!isRecord(tools)) return void 0;
2267
+ return Object.entries(tools).flatMap(([key, tool]) => {
2268
+ const declaration = normalizeToolDeclaration(tool, options, key);
2269
+ return declaration ? [declaration] : [];
2270
+ });
2271
+ }
2272
+ function resolvePromptTools(args) {
2273
+ var _a;
2274
+ if (args.override !== void 0) {
2275
+ return (_a = normalizeToolDeclarations(args.override, args.options)) != null ? _a : [];
2276
+ }
2277
+ return normalizeToolDeclarations(args.inferred, args.options);
2278
+ }
2279
+ function promptToolsAttribute(tools) {
2280
+ const values = promptToolsAttributeValue(tools);
2281
+ if (values === void 0) return void 0;
2282
+ return {
2283
+ key: PROMPT_TOOLS_ATTRIBUTE,
2284
+ value: { arrayValue: { values: values.map((stringValue) => ({ stringValue })) } }
2285
+ };
2286
+ }
2287
+ function promptToolsAttributeValue(tools) {
2288
+ if (tools === void 0) return void 0;
2289
+ return tools.map((tool) => {
2290
+ try {
2291
+ return JSON.stringify(tool);
2292
+ } catch (e) {
2293
+ return JSON.stringify({ type: tool.type, name: tool.name });
2294
+ }
2295
+ });
2296
+ }
2145
2297
 
2146
2298
  // ../core/dist/index.node.js
2147
2299
  import { AsyncLocalStorage } from "async_hooks";
@@ -2318,6 +2470,21 @@ function installTracingSuppressionHook() {
2318
2470
  installTracingSuppressionHook();
2319
2471
 
2320
2472
  // src/handler.ts
2473
+ var AGENT_CONFIG_SOURCE = {
2474
+ key: "ai.prompt.tools.source",
2475
+ value: { stringValue: "agent.config" }
2476
+ };
2477
+ function agentConfigTools(tools) {
2478
+ if (!Array.isArray(tools)) return void 0;
2479
+ return tools.map((tool) => {
2480
+ if (!isRecord2(tool)) return tool;
2481
+ const record = tool;
2482
+ if (typeof record.name === "string" || typeof record.type !== "string") return tool;
2483
+ const { type, ...args } = record;
2484
+ const name = typeof record.server_label === "string" ? record.server_label : type;
2485
+ return { type: "provider-defined", id: type, name, args };
2486
+ });
2487
+ }
2321
2488
  var RaindropManagedAgentsHandler = class {
2322
2489
  constructor(events, traces, opts) {
2323
2490
  this.events = events;
@@ -2342,13 +2509,13 @@ var RaindropManagedAgentsHandler = class {
2342
2509
  sessionCapture(sessionId) {
2343
2510
  const existing = this.sessions.get(sessionId);
2344
2511
  if (existing) return existing;
2345
- const session = { context: this.opts, turns: /* @__PURE__ */ new Map() };
2512
+ const session = { context: this.opts, turns: /* @__PURE__ */ new Map(), activeStreams: 0 };
2346
2513
  this.sessions.set(sessionId, session);
2347
2514
  return session;
2348
2515
  }
2349
2516
  cacheSession(sessionId, session) {
2350
2517
  this.idleSessions.delete(sessionId);
2351
- if (session.turns.size > 0) return;
2518
+ if (session.turns.size > 0 || session.activeStreams > 0) return;
2352
2519
  this.idleSessions.add(sessionId);
2353
2520
  if (this.idleSessions.size <= 1e4) return;
2354
2521
  const oldest = this.idleSessions.values().next().value;
@@ -2361,7 +2528,22 @@ var RaindropManagedAgentsHandler = class {
2361
2528
  try {
2362
2529
  const capture = this.sessionCapture(session.id);
2363
2530
  capture.model = session.agent.model;
2364
- capture.context = { ...this.opts, ...capture.context, ...context };
2531
+ capture.context = {
2532
+ ...this.opts,
2533
+ ...capture.context,
2534
+ ...context,
2535
+ properties: {
2536
+ ...this.opts.properties,
2537
+ ...capture.context.properties,
2538
+ ...context.properties
2539
+ }
2540
+ };
2541
+ const override = capture.context.tools;
2542
+ const toolsAttr = promptToolsAttribute(
2543
+ resolvePromptTools({ override, inferred: agentConfigTools(session.agent.tools) })
2544
+ );
2545
+ capture.promptToolsOverridden = override !== void 0;
2546
+ capture.promptTools = !toolsAttr ? void 0 : override !== void 0 ? [toolsAttr] : [toolsAttr, AGENT_CONFIG_SOURCE];
2365
2547
  this.cacheSession(session.id, capture);
2366
2548
  } catch (e) {
2367
2549
  }
@@ -2385,7 +2567,12 @@ var RaindropManagedAgentsHandler = class {
2385
2567
  const existing = session.turns.get(turnId);
2386
2568
  if (existing) return existing;
2387
2569
  const context = session.context;
2388
- const eventId = (_c = (_b = (_a = this.opts).eventId) == null ? void 0 : _b.call(_a, turnId)) != null ? _c : randomUUID();
2570
+ let eventId;
2571
+ try {
2572
+ eventId = (_c = (_b = (_a = this.opts).eventId) == null ? void 0 : _b.call(_a, turnId)) == null ? void 0 : _c.trim();
2573
+ } catch (e) {
2574
+ }
2575
+ eventId || (eventId = randomUUID());
2389
2576
  const patch = {
2390
2577
  userId: context.userId,
2391
2578
  convoId: (_d = context.convoId) != null ? _d : sessionId,
@@ -2438,8 +2625,8 @@ var RaindropManagedAgentsHandler = class {
2438
2625
  attrInt("openai.turn.started_at", (_a = turn.started_at) != null ? _a : void 0),
2439
2626
  attrInt("openai.turn.completed_at", (_b = turn.completed_at) != null ? _b : void 0)
2440
2627
  ]);
2628
+ const session = this.sessions.get(turn.session_id);
2441
2629
  if (turn.subagent_id === null) {
2442
- const session = this.sessions.get(turn.session_id);
2443
2630
  capture.patch.model = session == null ? void 0 : session.model;
2444
2631
  if (!capture.inputFromItem) capture.patch.input = session == null ? void 0 : session.input;
2445
2632
  this.setAttributes(capture.root, [
@@ -2448,6 +2635,9 @@ var RaindropManagedAgentsHandler = class {
2448
2635
  attrString("gen_ai.response.model", session == null ? void 0 : session.model)
2449
2636
  ]);
2450
2637
  }
2638
+ if ((session == null ? void 0 : session.promptTools) && (turn.subagent_id === null || session.promptToolsOverridden)) {
2639
+ this.setAttributes(capture.root, session.promptTools);
2640
+ }
2451
2641
  if (turn.subagent_id)
2452
2642
  capture.patch.properties = {
2453
2643
  ...capture.patch.properties,
@@ -2655,6 +2845,25 @@ var RaindropManagedAgentsHandler = class {
2655
2845
  }
2656
2846
  this.cacheSession(sessionId, session);
2657
2847
  }
2848
+ /** @internal */
2849
+ onStreamStart(sessionId) {
2850
+ try {
2851
+ const session = this.sessionCapture(sessionId);
2852
+ session.activeStreams++;
2853
+ this.cacheSession(sessionId, session);
2854
+ } catch (e) {
2855
+ }
2856
+ }
2857
+ /** @internal */
2858
+ onStreamEnd(sessionId) {
2859
+ try {
2860
+ const session = this.sessions.get(sessionId);
2861
+ if (!session) return;
2862
+ session.activeStreams = Math.max(0, session.activeStreams - 1);
2863
+ if (session.activeStreams === 0) this.closeSessionTurns(sessionId);
2864
+ } catch (e) {
2865
+ }
2866
+ }
2658
2867
  closeSessionTurns(sessionId, error) {
2659
2868
  try {
2660
2869
  const session = this.sessions.get(sessionId);
@@ -2683,19 +2892,22 @@ var RaindropManagedAgentsHandler = class {
2683
2892
  this.completed.clear();
2684
2893
  }
2685
2894
  };
2895
+ function isRecord2(value) {
2896
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2897
+ }
2686
2898
 
2687
2899
  // package.json
2688
2900
  var package_default = {
2689
2901
  name: "@raindrop-ai/openai-managed-agents",
2690
- version: "0.0.1",
2902
+ version: "0.0.3",
2691
2903
  description: "Raindrop tracing for the OpenAI Agents API",
2692
2904
  main: "dist/index.js",
2693
2905
  module: "dist/index.mjs",
2694
2906
  types: "dist/index.d.ts",
2695
2907
  license: "MIT",
2696
- homepage: "https://docs.raindrop.ai/integrations/openai-managed-agents",
2908
+ homepage: "https://www.raindrop.ai/docs/integrations/openai-managed-agents",
2697
2909
  bugs: {
2698
- url: "https://docs.raindrop.ai/support"
2910
+ url: "https://www.raindrop.ai/docs/support"
2699
2911
  },
2700
2912
  exports: {
2701
2913
  ".": {
@@ -2766,14 +2978,18 @@ var libraryVersion = package_default.version;
2766
2978
  // src/wrap.ts
2767
2979
  import { Stream } from "openai/core/streaming";
2768
2980
  async function* observe(events, handler, sessionId) {
2981
+ if (sessionId) handler.onStreamStart(sessionId);
2769
2982
  try {
2770
2983
  for await (const event of events) {
2771
- if (event.type === "agent.session.created") sessionId = event.session.id;
2984
+ if (!sessionId && event.type === "agent.session.created") {
2985
+ sessionId = event.session.id;
2986
+ handler.onStreamStart(sessionId);
2987
+ }
2772
2988
  handler.onEvent(event);
2773
2989
  yield event;
2774
2990
  }
2775
2991
  } finally {
2776
- if (sessionId) handler.closeSessionTurns(sessionId);
2992
+ if (sessionId) handler.onStreamEnd(sessionId);
2777
2993
  }
2778
2994
  }
2779
2995
  function wrapManagedAgents(client, handler, context) {
@@ -2801,19 +3017,12 @@ function wrapManagedAgents(client, handler, context) {
2801
3017
  if (result instanceof Stream) {
2802
3018
  const source = result;
2803
3019
  async function* initialEvents() {
2804
- let sessionId;
2805
- try {
2806
- for await (const event of source) {
2807
- if (event.type === "agent.session.created") {
2808
- sessionId = event.session.id;
2809
- handler.onSession(event.session, context);
2810
- handler.onInput(event.session.id, params.input);
2811
- }
2812
- handler.onEvent(event);
2813
- yield event;
3020
+ for await (const event of observe(source, handler)) {
3021
+ if (event.type === "agent.session.created") {
3022
+ handler.onSession(event.session, context);
3023
+ handler.onInput(event.session.id, params.input);
2814
3024
  }
2815
- } finally {
2816
- if (sessionId) handler.closeSessionTurns(sessionId);
3025
+ yield event;
2817
3026
  }
2818
3027
  }
2819
3028
  return new Stream(initialEvents, result.controller);
@@ -2828,20 +3037,7 @@ function wrapManagedAgents(client, handler, context) {
2828
3037
  return session;
2829
3038
  });
2830
3039
  if (prop === "stream")
2831
- return (sessionId, params, options) => {
2832
- const stream = target.stream(sessionId, params, options);
2833
- return new Proxy(stream, {
2834
- get(obj, key) {
2835
- if (key === Symbol.asyncIterator)
2836
- return () => {
2837
- handler.onInput(sessionId, params.input);
2838
- return observe(stream, handler, sessionId);
2839
- };
2840
- const value2 = Reflect.get(obj, key, obj);
2841
- return typeof value2 === "function" ? value2.bind(obj) : value2;
2842
- }
2843
- });
2844
- };
3040
+ return (sessionId, params, options) => target.stream.call(wrappedSessions, sessionId, params, options);
2845
3041
  const value = Reflect.get(target, prop, target);
2846
3042
  return typeof value === "function" ? value.bind(target) : value;
2847
3043
  }
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@raindrop-ai/openai-managed-agents",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Raindrop tracing for the OpenAI Agents API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "license": "MIT",
9
- "homepage": "https://docs.raindrop.ai/integrations/openai-managed-agents",
9
+ "homepage": "https://www.raindrop.ai/docs/integrations/openai-managed-agents",
10
10
  "bugs": {
11
- "url": "https://docs.raindrop.ai/support"
11
+ "url": "https://www.raindrop.ai/docs/support"
12
12
  },
13
13
  "exports": {
14
14
  ".": {
@@ -38,7 +38,7 @@
38
38
  "vitest": "^2.1.9",
39
39
  "openai": "7.15.0",
40
40
  "zod": "^3.23.8",
41
- "@raindrop-ai/core": "0.3.0"
41
+ "@raindrop-ai/core": "0.3.1"
42
42
  },
43
43
  "tsup": {
44
44
  "entry": [