Skip to content
Night Owls.dev
Jump to a page

@nightowlsdev/engine-openai-agents

EngineNative

The third native engine, a governed @openai/agents run() loop with full governance (fail-closed tool gate, cost caps, secrets), native handoffs/guardrails. Single-agent v1 (multi-agent handoffs planned v1.1).

What it does

**Use this when:** you want the OpenAI Agents SDK's `run()` loop (`@openai/agents`) as your engine, fully governed in your own process — and one agent per swarm is enough for now. **How.** `openAiAgentsEngine()` into `defineSwarm({ engine })` (or `owl install engine-openai-agents`). `openAiAgentsEngine({ durable: true })` turns on durable park/resume when your storage persists the SDK's `RunState` snapshot across processes. Requires Node ≥ 22; peers `ai@^7` (provide it yourself) and bundles the `@openai/agents` family (pinned `0.12.0`) as direct dependencies. **What you get / what it can't do yet.** The full governance plane, same as its native siblings: fail-closed tool gate, cost caps, secrets, and telemetry (OTel spans). Tool approvals map onto the SDK's native approve/reject interruption; cancellation is mid-stream. The `preGeneration` veto isn't a leap of faith — a spike verified the SDK's `callModelInputFilter` fires exactly once per model launch and a thrown error aborts cleanly. The one real limit is that **v1 is single-agent** (`delegation`/`workflows` are `false`); the SDK's native handoffs become Night Owls delegation in v1.1.

Install

pnpm add @nightowlsdev/engine-openai-agents

Key exports

  • openAiAgentsEngine
  • OpenAiAgentsEngine
  • OPENAI_AGENTS_ENGINE_CAPABILITIES
  • nightOwlsPlugin

Usage

engine-openai-agents.ts
import { defineSwarm } from "@nightowlsdev/core";
import { openAiAgentsEngine, OPENAI_AGENTS_ENGINE_CAPABILITIES } from "@nightowlsdev/engine-openai-agents";

// The third native engine, a governed @openai/agents run() loop. Single-agent v1: no
// delegation/workflows yet (native handoffs become multi-agent delegation in v1.1).
const swarm = defineSwarm({ agents, engine: openAiAgentsEngine() });

// Same full-governance posture as engine-mastra/engine-ai-sdk, verified, not assumed.
console.log(OPENAI_AGENTS_ENGINE_CAPABILITIES.governance.preGeneration); // true
console.log(OPENAI_AGENTS_ENGINE_CAPABILITIES.kind); // "native"

What it provides

engine-openai-agents is the third NATIVE engine: a from-scratch swarm loop built directly on the OpenAI Agents SDK (@openai/agents' run()) instead of Mastra or the raw AI SDK. It reuses the SAME governance plane as its native siblings — pre-generation reserve, fail-closed tool gate, cost caps, secrets, tier routing, telemetry — and its full-governance claim is verified, not assumed: a spike confirmed the SDK's RunConfig.callModelInputFilter fires exactly once per model launch and a thrown error aborts the run cleanly. v1 is deliberately single-agent (delegation and workflows both false); tool approvals map onto the SDK's native approve/reject interruption and telemetry emits OTel spans.

When to use it

  • You want the loop built on the OpenAI Agents SDK (run()) — you already use @openai/agents, its guardrails, or its tracing.
  • Your swarm is single-agent and you want full governance plus OTel telemetry on this stack rather than Mastra.
  • You want tool approvals expressed as the SDK's native boolean approve/reject interruption, backstopped by Night Owls' fail-closed gate.

When not to

  • Your pack is multi-agent — delegation is false here; the SDK's native handoffs become Night Owls delegation in v1.1, not v1.
  • You send PDFs or text-class document attachments — the aisdk() bridge throws on file inputs, so multimodal is image-only (pdf:false, text:false) at this version.
  • You need client-tool suspend/resume (camera, selection, apply-to-scene) — hitl.clientTools is false; the SDK's only pause primitive is the boolean tool-approval interruption.

Alternatives

  • engine-mastra (the default)You need delegation, workflows, or semantic recall — only there today.
  • engine-ai-sdkYou want a native single-agent loop but on the raw Vercel AI SDK (streamText) rather than the OpenAI Agents SDK — same full-governance posture, and it supports PDF/text attachments this engine can't.
  • @openai/agents directlyYou want the OpenAI Agents SDK with no Night Owls governance plane, cost caps, secrets boundary, or swappable-engine contract — a plain run() with none of the gating.

Strengths

  • Full governance verified against the SDK: a spike proved callModelInputFilter fires once per launch and a throw aborts cleanly (never a stranded/partial generation), so governance.preGeneration: true is honest.
  • Native tool-approval interruption mapped onto Night Owls' fail-closed gate; mid-stream cancellation; OTel spans (telemetry: true — the only adapter/native split where an adapter can't match).
  • The RunState.toString() snapshot is genuinely cross-process-serializable (JSON, schema v1.13), so durable resume can legitimately earn true when you opt in.
  • Same swarm description as every other engine — swap the factory, keep the crew definition.

Limits & trade-offs

  • Single-agent only in v1 — delegation and workflows are both false; native handoffs become delegation in v1.1.
  • Multimodal is image-only: the @openai/agents-extensions aisdk() bridge throws UserError on file inputs, so PDFs and text-class documents are unreachable (pdf:false, text:false), not merely unwired.
  • No client-tool path (clientTools:false), so browser-executed tools and the resolved swarm.client_action fields don't apply here.
  • Heavy dependency surface: Node >= 22 and a peer on ai@^7 (you provide it), plus the pinned @openai/agents / -core / -extensions / -openai family bundled as direct dependencies.

How it works

openAiAgentsEngine({ durable }) returns (opts) => new OpenAiAgentsEngine(opts, { durable }) from the fully-assembled AssembledEngineOpts. The loop drives @openai/agents' run(); pre-generation gating rides RunConfig.callModelInputFilter (verified to fire once per model launch), tool approvals ride the SDK's native approve/reject interruption backstopped by the fail-closed gate, and cancellation is mid-stream. durableResume is a per-INSTANCE flip (default false) that earns true only when the injected StorageAdapter persists the SDK's RunState.toString() snapshot across processes. OPENAI_AGENTS_ENGINE_CAPABILITIES is the static descriptor: tier 3 with swarm.handoff and swarm.client_action absent from emits (single-agent, no client-tool path).

Examples

Wire the OpenAI-Agents engine

Same swarm description; the loop runs on @openai/agents' run(). Needs Node >= 22 and a peer ai@^7; the @openai/agents family is bundled.

engine-openai-agents-example-1.ts
import { defineSwarm } from "@nightowlsdev/core";
import { openAiAgentsEngine } from "@nightowlsdev/engine-openai-agents";

export default defineSwarm({
  agents,
  engine: openAiAgentsEngine(),
});

Confirm the full-governance posture

The preGeneration:true claim is spike-verified, not assumed. Durable resume opts in when your storage persists the RunState snapshot cross-process.

engine-openai-agents-example-2.ts
import { openAiAgentsEngine, OPENAI_AGENTS_ENGINE_CAPABILITIES } from "@nightowlsdev/engine-openai-agents";

const swarm = defineSwarm({ agents, engine: openAiAgentsEngine({ durable: true }) });

console.log(OPENAI_AGENTS_ENGINE_CAPABILITIES.governance.preGeneration); // true
console.log(OPENAI_AGENTS_ENGINE_CAPABILITIES.telemetry); // true (OTel spans)

Doing the parts it doesn't support

  • Multi-agent delegation and workflowsNot in v1 (delegation: false, workflows: false). Run multi-agent packs on engine-mastra; the SDK's native handoffs become Night Owls delegation in v1.1.
  • PDF / text-class document attachmentsThe aisdk() bridge throws on file inputs at this version, so only images reach the model. Use engine-ai-sdk (native file transport for image/pdf/text) or feed documents as host-extracted advisory text, which works on every engine.
  • Browser-executed client toolsclientTools is false — the SDK exposes only a boolean tool-approval interruption. Use engine-mastra (or engine-ai-sdk's approval path) if you need the client_action suspend/resume protocol.

Related

  • coreThe required base — this engine reuses core's governance plane (hooks, CostGovernor, secrets) verbatim.
  • engine-ai-sdkThe sibling native engine on the raw AI SDK — same governance posture, and it supports the attachment classes this engine can't.
  • engine-mastraThe default engine — the delegation / workflow / semantic-recall path this engine defers to.
  • provider-openaiThe OpenAI model provider you'd typically route this engine's agents through.
  • approval-modesHow the tool-approval gate this engine backstops is configured for a deployment.