← Public packages
@kody/codex
Create and manage OpenAI Agents API (Codex harness) cloud agent sessions.
src/environments/self-hosted.ts
108 lines · 3.6 KB · TypeScriptimport { any, boolean, object, optional, parse, string } from 'remix/data-schema'
import { DOCS_DEFAULT_MODEL, DOCS_OVERVIEW } from '../client.ts'
const selfHostedInput = object(
{
workspaceDirectory: optional(string()),
capabilityDirectories: optional(any()),
/** Extra environment fields from docs */
environment: optional(any()),
/** Optional agent snippet for a create payload preview */
agent: optional(any()),
model: optional(string()),
instructions: optional(string()),
input: optional(any()),
/** When true, return a sessions/create-shaped body preview only */
asCreateBody: optional(boolean()),
dryRun: optional(boolean()),
},
{ unknownKeys: 'error' },
)
/**
* Self-hosted environment recipe metadata for Agents API
* (`environment.type: self_hosted`). Not a fake Puppeteer/browser runner —
* documents workspace_directory / capability_directories and returns a
* create-body preview you pass to `./sessions/create` from your own runtime.
*
* @param raw.workspaceDirectory - Default `/workspace`
* @param raw.capabilityDirectories - Skills/capability paths (string[])
* @param raw.environment - Extra self_hosted fields
* @param raw.agent / model / instructions / input - Optional create preview fields
* @param raw.asCreateBody - Include a ready sessions/create body preview
* @returns Recipe + optional create body (never calls OpenAI by itself)
*
* @example
* import selfHosted from 'kody:@kody/codex/environments/self-hosted'
* const recipe = await selfHosted({
* workspaceDirectory: '/workspace',
* capabilityDirectories: ['/workspace/capabilities/skills'],
* asCreateBody: true,
* input: 'Research MCP setup and summarize.',
* })
*/
export default async function selfHosted(raw: unknown = {}) {
const input = parse(selfHostedInput, raw ?? {})
const workspaceDirectory = (input.workspaceDirectory || '/workspace').trim()
let capabilityDirectories: string[] = ['/workspace/capabilities/skills']
if (Array.isArray(input.capabilityDirectories)) {
capabilityDirectories = input.capabilityDirectories.map((d) => String(d))
}
const envExtras =
input.environment &&
typeof input.environment === 'object' &&
!Array.isArray(input.environment)
? (input.environment as Record<string, unknown>)
: {}
const environment = {
...envExtras,
type: 'self_hosted',
workspace_directory: workspaceDirectory,
capability_directories: capabilityDirectories,
}
const agentExtras =
input.agent && typeof input.agent === 'object' && !Array.isArray(input.agent)
? (input.agent as Record<string, unknown>)
: {}
const agent = {
model: input.model || DOCS_DEFAULT_MODEL,
instructions:
input.instructions ||
'Use available tools and MCP servers. Delegate independent research to subagents when useful.',
...agentExtras,
}
const recipe = {
mode: 'recipe' as const,
docs: DOCS_OVERVIEW,
environment,
notes: [
'Your application (or OpenAI connector) must host/connect the environment — this export only shapes metadata.',
'Does not implement Puppeteer, CDP, or ChatGPT task scraping.',
'Pass the returned createBody to kody:@kody/codex/sessions/create when ready.',
'Self-hosted does not make the Agents API ZDR-eligible (OpenAI data controls).',
],
nextStep:
'import createSession from "kody:@kody/codex/sessions/create"; await createSession(createBody)',
}
const wantBody = input.asCreateBody === true || input.dryRun === true
if (!wantBody) {
return recipe
}
const createBody: Record<string, unknown> = {
agent,
environment,
}
if (input.input !== undefined) createBody.input = input.input
return {
...recipe,
createBody,
dryRun: true as const,
}
}