Continue an objective
Send the next turn to an objective that answered and is waiting. This is how an objective becomes a conversation.
STATE_WAITING with its context window open, holding everything it learned. Continue it and the agent picks up mid-thought, with every tool result and memory read from the previous turns still in front of it.
That is the difference between a conversation and a series of unrelated requests.
userMessage event it appended, not the agent’s reply. The objective drops back to STATE_PENDING and starts working. Read the answer by streaming events or waiting for STATE_WAITING again.
Only a waiting objective accepts a turn
This is the whole contract, and it is strict:message is required. An empty body is a 400.
So a chat UI where the user types while the agent is still answering has to wait. There is no fire-and-forget: you poll or stream until the objective is waiting, then send.
enqueue flag, described as buffering the message until the agent loop is free. It has no effect today. A STATE_RUNNING objective rejects the call with or without it.What carries across a turn
Everything. That is the point. The context window persists, so previous tool results, memory reads, and assistant reasoning stay available. Compaction handles the window filling up: old turns get summarized or their tool bodies stripped, and the objective keeps going rather than failing. What you cannot change mid-conversation: the variation, the system prompt, the assigned tools, or the memory cascade. All of that was snapshotted intoconfigSnapshot when the objective was created. A turn is a message, not a reconfiguration. Publish a new variation and existing conversations keep running the old one, which is usually what you want.
Driving a conversation
The full loop, with the first turn and every turn after it looking almost the same:metadata.externalId on the objective and your session ID becomes the handle. A web server handling turn seventeen needs nothing in its database beyond the session.
To end a conversation, cancel it. A waiting objective holds its context window until something closes it, and an idle objective is eventually finalized as STATE_TIMED_OUT by the variation’s inactivityTimeout, or by the system-wide 24-hour sweep.
Related
Create an objective
Stream objective events
Compaction
Use your own IDs
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
"workspace_01HXKD2E5NQM3T9AYWCF133E3Q"
The ID of the objective. If you have assigned an external ID to the objective, you can prefix the ID with "external_id:". For example, "external_id:1234567890". Otherwise, the ID assigned by Cadenya should be used.
"obj_01HXKD2E5NQM3T9AYWCFQAZGFV"
Body
Response
OK
Metadata for ephemeral operations and activities (e.g., objectives, executions, runs)
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
- Option 8
- Option 9
- Option 10
- Option 11
- Option 12
- Option 13
- Option 14
- Option 15
- Option 16
- Option 17
"objwin_01HXKD2E5NQM3T9AYWCFN7BSTR"
Elapsed time of the work this event records, when it is known at write time (e.g. assistant message generation, tool execution for result/error events). Unset means the event is instantaneous or the duration is not measurable. Serialized as a canonical duration string (e.g. "4.1s"). Always set together with started_at.
^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$When the work this event records began. Set together with duration, so the work interval is [started_at, started_at + duration]. The event's created_at remains the time the event was persisted.