agent-contracts-runtime
Version:
Runtime bridge for executing agent-contracts workflows on Agent SDKs
239 lines • 8.33 kB
JavaScript
// src/adapters/openai-agents-sdk.ts
function buildInputGuardrails(guardrails) {
return [
{
name: "contract-runtime-guardrail",
execute: async ({ input }) => {
const inputStr = typeof input === "string" ? input : JSON.stringify(input);
const results = guardrails.runChecks({ command: inputStr });
const blocking = results.filter((r) => !r.passed && r.action === "block");
return {
outputInfo: { results },
tripwireTriggered: blocking.length > 0
};
}
}
];
}
var OpenAIAgentsSdkAdapter = class _OpenAIAgentsSdkAdapter {
model;
maxTurns;
guardrailHooks;
tools;
agentName;
signal;
cacheConfig;
lastResponseId = null;
lastAgent = null;
lastMemoryRef = null;
AgentClass = null;
runFn = null;
streamRunFn = null;
constructor(config = {}) {
this.model = config.model;
this.maxTurns = config.maxTurns;
this.guardrailHooks = config.guardrailHooks;
this.tools = config.tools;
this.agentName = config.agentName ?? "contract-agent";
this.signal = config.signal;
this.cacheConfig = config.cacheConfig ?? { enabled: true };
}
// -------------------------------------------------------------------------
// Internal helpers
// -------------------------------------------------------------------------
async resolveSdk() {
if (this.AgentClass && this.runFn) {
return { Agent: this.AgentClass, run: this.runFn, streamRun: this.streamRunFn ?? void 0 };
}
const sdk = await import("@openai/agents");
this.AgentClass = sdk.Agent;
this.runFn = sdk.run;
return { Agent: this.AgentClass, run: this.runFn };
}
createAgent(Agent, instructions, _readonly, agents) {
const opts = {
name: this.agentName,
instructions
};
if (this.model) opts.model = this.model;
if (this.tools) opts.tools = this.tools;
if (this.guardrailHooks) {
opts.inputGuardrails = buildInputGuardrails(this.guardrailHooks);
}
if (agents && agents.length > 0) {
opts.handoffs = agents.map((a) => {
const subOpts = { name: a.name, instructions: a.prompt };
if (a.model) subOpts.model = a.model;
if (a.tools) subOpts.tools = a.tools;
return new Agent(subOpts);
});
}
return new Agent(opts);
}
buildRunOptions(previousResponseId) {
const opts = {};
if (this.maxTurns !== void 0) opts.maxTurns = this.maxTurns;
if (this.signal) opts.signal = this.signal;
if (previousResponseId) opts.previousResponseId = previousResponseId;
return opts;
}
extractOutput(result) {
if (typeof result.finalOutput === "string") {
return result.finalOutput;
}
if (result.finalOutput !== void 0 && result.finalOutput !== null) {
return JSON.stringify(result.finalOutput, null, 2);
}
if (result.newItems) {
const textParts = [];
for (const item of result.newItems) {
if (item.type === "message_output_item" || item.type === "text") {
const rawItem = item.rawItem;
if (rawItem?.content) {
const content = rawItem.content;
if (Array.isArray(content)) {
for (const part of content) {
if (typeof part === "object" && part !== null && "text" in part) {
textParts.push(part.text);
}
}
} else if (typeof content === "string") {
textParts.push(content);
}
}
}
}
if (textParts.length > 0) return textParts.join("\n");
}
return "";
}
async runWithProgress(agent, input, runOpts, onProgress) {
const { run, streamRun } = await this.resolveSdk();
if (!onProgress || !streamRun) {
return run(agent, input, runOpts);
}
const streamResult = await streamRun(agent, input, runOpts);
for await (const event of streamResult.streamEvents()) {
emitProgressFromOpenAIEvent(event, onProgress);
}
return streamResult;
}
// -------------------------------------------------------------------------
// SdkAdapter interface
// -------------------------------------------------------------------------
async send(prompt, options) {
this.lastResponseId = null;
this.lastAgent = null;
this.lastMemoryRef = null;
const { Agent } = await this.resolveSdk();
const split = options.splitPrompt;
let instructions;
let runInput;
if (split && this.cacheConfig.enabled !== false) {
instructions = split.system.join("\n\n---\n\n");
runInput = split.user;
} else {
instructions = prompt;
runInput = prompt;
}
const agent = this.createAgent(Agent, instructions, options.readonly, options.agents);
const runOpts = this.buildRunOptions();
const result = await this.runWithProgress(agent, runInput, runOpts, options.onProgress);
this.lastResponseId = result.lastResponseId ?? null;
this.lastAgent = agent;
this.lastMemoryRef = this.lastResponseId ? {
id: this.lastResponseId,
provider: "openai-responses",
compat: "openai-agents-sdk@0.10",
created_at: (/* @__PURE__ */ new Date()).toISOString()
} : null;
return this.extractOutput(result);
}
async followUp(message) {
if (!this.lastResponseId) {
throw new Error("followUp() called before send() \u2014 no active session");
}
const { run } = await this.resolveSdk();
const agent = this.lastAgent;
const runOpts = this.buildRunOptions(this.lastResponseId);
const result = await run(agent, message, runOpts);
this.lastResponseId = result.lastResponseId ?? this.lastResponseId;
return this.extractOutput(result);
}
async sendExecution(request) {
this.lastResponseId = null;
this.lastAgent = null;
this.lastMemoryRef = null;
const { Agent } = await this.resolveSdk();
const split = request.splitPrompt;
let instructions;
let runInput;
if (split && this.cacheConfig.enabled !== false) {
instructions = split.system.join("\n\n---\n\n");
runInput = split.user;
} else {
instructions = request.prompt;
runInput = request.prompt;
}
const agents = request.options.agents ?? request.agents;
const agent = this.createAgent(Agent, instructions, request.options.readonly, agents);
const runOpts = this.buildRunOptions(request.memoryRef?.id);
const result = await this.runWithProgress(agent, runInput, runOpts, request.options.onProgress);
this.lastResponseId = result.lastResponseId ?? null;
this.lastAgent = agent;
this.lastMemoryRef = this.lastResponseId ? {
id: this.lastResponseId,
provider: "openai-responses",
compat: "openai-agents-sdk@0.10",
created_at: (/* @__PURE__ */ new Date()).toISOString(),
parent_run_id: request.memoryRef?.id
} : null;
return this.extractOutput(result);
}
getLastMemoryRef() {
return this.lastMemoryRef;
}
isCompatible(compat) {
return compat.startsWith("openai-agents-sdk@");
}
// -------------------------------------------------------------------------
// Test support
// -------------------------------------------------------------------------
/**
* Inject custom Agent constructor and run function for testing.
* Bypasses the dynamic import of @openai/agents.
*/
static withRunFn(AgentClass, runFn, config, streamRunFn) {
const adapter = new _OpenAIAgentsSdkAdapter(config);
adapter.AgentClass = AgentClass;
adapter.runFn = runFn;
adapter.streamRunFn = streamRunFn ?? null;
return adapter;
}
};
function emitProgressFromOpenAIEvent(event, onProgress) {
switch (event.type) {
case "tool_called":
if (event.item?.toolName) {
onProgress({ type: "tool_use", tool_name: event.item.toolName });
}
break;
case "tool_output":
onProgress({ type: "tool_result" });
break;
case "reasoning_item_created":
onProgress({ type: "text", message: "Reasoning..." });
break;
case "handoff_occurred":
if (event.item?.agent?.name) {
onProgress({ type: "status", message: `Handoff to ${event.item.agent.name}` });
}
break;
default:
break;
}
}
export {
OpenAIAgentsSdkAdapter
};
//# sourceMappingURL=openai-agents-sdk.js.map