← Public packages
@kody/codex
Create and manage OpenAI Agents API (Codex harness) cloud agent sessions.
src/sessions/create.ts
140 lines · 4.5 KB · TypeScriptimport { any, boolean, number, object, optional, parse, string } from 'remix/data-schema'
import {
DOCS_DEFAULT_MODEL,
DOCS_QUICKSTART,
agentsFetch,
normalizeUserInput,
pickAuth,
sessionIdFromCreateResult,
} from '../client.ts'
const createInput = object(
{
/** Agent config: model, instructions, tools, multi_agent, … */
agent: optional(any()),
/** Environment: { type: 'openai_hosted' | 'self_hosted' | 'none', … } */
environment: optional(any()),
/** Initial task: string or message array */
input: optional(any()),
/** When true, request SSE from create (bounded collect). Default false for isolate-safe JSON. */
stream: optional(boolean()),
/** Max SSE events to collect when stream=true (default 100). */
maxEvents: optional(number()),
apiKeySecret: optional(string()),
dryRun: optional(boolean()),
/**
* Extra top-level create body fields from OpenAI docs (e.g. webhook config).
* Merged after known keys; unknownKeys on this object are still rejected —
* put extras here explicitly.
*/
body: optional(any()),
},
{ unknownKeys: 'error' },
)
/**
* Create an OpenAI Agents API session (`POST /v1/agents/sessions`).
* Main path: pass agent + environment + input. Defaults to non-streaming JSON;
* set `stream: true` to collect a bounded first-turn SSE event list.
*
* @param raw.agent - Agent config (model, instructions, tools, …)
* @param raw.environment - Environment object (`openai_hosted` | `self_hosted` | `none`)
* @param raw.input - Initial user task (string or message array)
* @param raw.stream - Collect first-turn SSE events (bounded)
* @param raw.maxEvents - Cap on SSE events when streaming
* @param raw.dryRun - Preview request without calling OpenAI
* @param raw.apiKeySecret - Optional alternate secret **name**
* @param raw.body - Extra documented create fields merged into the POST body
* @returns Session JSON and/or collected events; includes `sessionId` when found
*
* @example
* import createSession from 'kody:@kody/codex/sessions/create'
* const result = await createSession({
* agent: {
* model: 'gpt-6-astra',
* instructions: 'Write clean code, run it, and report the actual output.',
* },
* environment: { type: 'openai_hosted' },
* input: 'Create tree.py that prints a directory tree, run it, show output.',
* })
*/
export default async function createSession(raw: unknown = {}) {
const input = parse(createInput, raw ?? {})
const auth = pickAuth(input)
const stream = input.stream === true
const agent =
input.agent && typeof input.agent === 'object' && !Array.isArray(input.agent)
? (input.agent as Record<string, unknown>)
: undefined
const environment =
input.environment &&
typeof input.environment === 'object' &&
!Array.isArray(input.environment)
? (input.environment as Record<string, unknown>)
: undefined
const normalizedInput = normalizeUserInput(input.input)
const extras =
input.body && typeof input.body === 'object' && !Array.isArray(input.body)
? (input.body as Record<string, unknown>)
: {}
const body: Record<string, unknown> = { ...extras }
if (agent) body.agent = agent
if (environment) body.environment = environment
if (normalizedInput !== undefined) body.input = normalizedInput
if (stream) body.stream = true
if (input.dryRun === true) {
return {
dryRun: true as const,
method: 'POST' as const,
path: '/v1/agents/sessions',
headers: {
'OpenAI-Beta': 'agents=v1',
Authorization: 'Bearer {{secret:…}}',
},
body,
docs: DOCS_QUICKSTART,
modelPlaceholder: DOCS_DEFAULT_MODEL,
note: 'Would create an Agents API session. Prefer openai_hosted for the quickstart sandbox.',
}
}
if (!agent) {
throw new Error(
'agent is required (at least { model, instructions }). See ' + DOCS_QUICKSTART,
)
}
if (!environment) {
throw new Error(
'environment is required ({ type: "openai_hosted" | "self_hosted" | "none" }).',
)
}
if (environment.type === 'none' && normalizedInput === undefined) {
throw new Error(
'Sessions with environment.type "none" require initial input (OpenAI docs).',
)
}
const response = await agentsFetch('/agents/sessions', {
...auth,
method: 'POST',
body,
expectSse: stream,
maxSseEvents: input.maxEvents ?? 100,
})
const sessionId = sessionIdFromCreateResult(response.body, response.events)
return {
ok: true,
sessionId,
streamed: stream,
status: response.status,
kind: response.kind,
session: stream ? null : response.body,
events: response.events ?? null,
docs: DOCS_QUICKSTART,
}
}