Description
In GET /doc (OpenCode 1.15.7) every session.next.* (EventV2) event schema declares its timestamp field as {"type": "number"}. The server actually sends timestamp as an ISO 8601 datetime string.
For example, EventSessionNextAgentSwitched's inner properties schema:
{
"type": "object",
"properties": {
"timestamp": { "type": "number" },
"sessionID": { "type": "string", "pattern": "^ses" },
"agent": { "type": "string" }
},
"required": ["timestamp", "sessionID", "agent"],
"additionalProperties": false
}
But opencode serve 1.15.7 emits this frame on GET /event (and GET /global/event):
{
"id": "evt_e4fd04f94001sMpdNAQBQMEwke",
"type": "session.next.agent.switched",
"properties": {
"sessionID": "ses_1b02fb8a3ffeI2yMKTwQF5dXBh",
"timestamp": "2026-05-22T13:11:52.466Z",
"agent": "build"
}
}
timestamp is declared a number but sent as a string.
This affects all 26 EventSessionNext* schemas - timestamp is the shared Base field of every EventV2 event (session.next.agent.switched, session.next.model.switched, session.next.prompted, etc.).
Net effect: a client generated from or validating against openapi.json cannot decode any session.next.* event. At least session.next.agent.switched and session.next.model.switched fire on every prompt, so a strict typed client treats the first one as a fatal decode error and the whole event stream dies on the first prompt.
Likely correct behavior
number is almost certainly the intended type - the fix belongs on the server, not the spec:
- The field's schema is
V2Schema.DateTimeUtcFromMillis (packages/core/src/v2-schema.ts); its encode step is DateTime.toEpochMillis - the wire form is meant to be epoch milliseconds.
- Every other timestamp in the API is epoch milliseconds (
Session.time.created, etc.); session.next.* timestamp is the only one sent as a string.
The ISO string looks like a serialization slip: the SSE path JSON.stringifys the event - so an Effect DateTime renders via toJSON() as an ISO string - instead of encoding through the schema, which would yield the epoch-millis number. Emitting timestamp as epoch milliseconds would make it match both its declared schema and the rest of the API.
Plugins
No response
OpenCode version
1.15.7
Steps to reproduce
opencode serve
- Subscribe to
GET /event (or GET /global/event).
- Prompt any session.
- The emitted
session.next.* frames carry timestamp as a string, matching no EventSessionNext* schema in GET /doc, which requires a number.
Spec side, in one command:
jq '[.components.schemas | to_entries[]
| select(.key | startswith("EventSessionNext"))
| .value.properties.properties.properties.timestamp] | unique' openapi.json
-> [{"type":"number"}] for all 26 event types.
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Description
In
GET /doc(OpenCode 1.15.7) everysession.next.*(EventV2) event schema declares itstimestampfield as{"type": "number"}. The server actually sendstimestampas an ISO 8601 datetime string.For example,
EventSessionNextAgentSwitched's innerpropertiesschema:{ "type": "object", "properties": { "timestamp": { "type": "number" }, "sessionID": { "type": "string", "pattern": "^ses" }, "agent": { "type": "string" } }, "required": ["timestamp", "sessionID", "agent"], "additionalProperties": false }But
opencode serve1.15.7 emits this frame onGET /event(andGET /global/event):{ "id": "evt_e4fd04f94001sMpdNAQBQMEwke", "type": "session.next.agent.switched", "properties": { "sessionID": "ses_1b02fb8a3ffeI2yMKTwQF5dXBh", "timestamp": "2026-05-22T13:11:52.466Z", "agent": "build" } }timestampis declared a number but sent as a string.This affects all 26
EventSessionNext*schemas -timestampis the sharedBasefield of every EventV2 event (session.next.agent.switched,session.next.model.switched,session.next.prompted, etc.).Net effect: a client generated from or validating against
openapi.jsoncannot decode anysession.next.*event. At leastsession.next.agent.switchedandsession.next.model.switchedfire on every prompt, so a strict typed client treats the first one as a fatal decode error and the whole event stream dies on the first prompt.Likely correct behavior
numberis almost certainly the intended type - the fix belongs on the server, not the spec:V2Schema.DateTimeUtcFromMillis(packages/core/src/v2-schema.ts); itsencodestep isDateTime.toEpochMillis- the wire form is meant to be epoch milliseconds.Session.time.created, etc.);session.next.*timestampis the only one sent as a string.The ISO string looks like a serialization slip: the SSE path
JSON.stringifys the event - so an EffectDateTimerenders viatoJSON()as an ISO string - instead of encoding through the schema, which would yield the epoch-millis number. Emittingtimestampas epoch milliseconds would make it match both its declared schema and the rest of the API.Plugins
No response
OpenCode version
1.15.7
Steps to reproduce
opencode serveGET /event(orGET /global/event).session.next.*frames carrytimestampas a string, matching noEventSessionNext*schema inGET /doc, which requires a number.Spec side, in one command:
->
[{"type":"number"}]for all 26 event types.Screenshot and/or share link
No response
Operating System
No response
Terminal
No response