Skip to content

First Turn

This page walks through creating an agent, submitting a turn, and consuming the event stream.

Create an agent

ts
import { 
createAgent
} from 'apeira'
import {
responses
} from 'apeira/responses'
const
agent
=
createAgent
({
instructions
: 'You are a concise assistant.',
runner
:
responses
({
apiKey
:
process
.
env
.
OPENAI_API_KEY
,
baseURL
: 'https://api.openai.com/v1/',
model
: 'gpt-5.5',
}), })

responses() configures the Responses backend. See Runners for choosing between responses() and chat(), or using provider presets. Apeira manages input, instructions, and abortSignal internally.

Run a turn

run() submits one user turn and returns a ReadableStream of events for that turn.

ts
import { 
createAgent
,
run
} from 'apeira'
import {
responses
} from 'apeira/responses'
const
agent
=
createAgent
({
instructions
: 'You are a concise assistant.',
runner
:
responses
({
apiKey
:
process
.
env
.
OPENAI_API_KEY
,
baseURL
: 'https://api.openai.com/v1/',
model
: 'gpt-5.5',
}), }) const
stream
=
run
(
agent
, {
content
: 'Say hello.',
role
: 'user',
type
: 'message',
}) for await (const
event
of
stream
) {
console
.
log
(
event
.
turnId
,
event
.
type
)
}

The stream emits model events (text.delta, tool-call.start, etc.) and lifecycle events (turn.start, turn.done). It closes after turn.done, turn.failed, or turn.aborted.

Fire-and-forget with send

Use send() when you only want the turn ID and plan to observe events through a global subscription.

ts
import { 
createAgent
} from 'apeira'
import {
responses
} from 'apeira/responses'
const
agent
=
createAgent
({
instructions
: 'You are a concise assistant.',
runner
:
responses
({
apiKey
:
process
.
env
.
OPENAI_API_KEY
,
baseURL
: 'https://api.openai.com/v1/',
model
: 'gpt-5.5',
}), }) const
unsubscribe
=
agent
.
subscribe
('apeira', (
event
) => {
console
.
log
(
event
.
turnId
,
event
.
type
)
}) const
turnId
=
agent
.
send
({
content
: 'Say hello.',
role
: 'user',
type
: 'message',
}) // later
unsubscribe
()

If a turn is already active, send() queues the input for that turn and returns the existing turn ID. If no turn is active, it creates a new top-level turn.

Per-turn abort

Pass an AbortSignal to abort a specific turn:

ts
import { 
createAgent
,
run
} from 'apeira'
import {
responses
} from 'apeira/responses'
const
agent
=
createAgent
({
instructions
: 'You are a concise assistant.',
runner
:
responses
({
apiKey
:
process
.
env
.
OPENAI_API_KEY
,
baseURL
: 'https://api.openai.com/v1/',
model
: 'gpt-5.5',
}), }) const
controller
= new
AbortController
()
run
(
agent
, {
content
: 'Say hello.',
role
: 'user',
type
: 'message',
}, {
signal
:
controller
.
signal
})
controller
.
abort
('cancelled')

Cancelling the ReadableStream reader only stops reading events. It does not abort the running turn.