Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/bitworld/decision_trajectory.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ type
inputTokens*, outputTokens*: Option[int]
promptTokenIds*, sampledTokenIds*: Option[seq[int]]
behaviorLogprobs*: Option[seq[float]]
ControlEncoding* = enum
ceI8I8I8U8 = "i8-i8-i8-u8", ceU8 = "u8"
ExecutionEvidence* = object
controlEncoding*: ControlEncoding
startTick*, endTick*, tickHz*: int
seatControlsBase64*: string
DecisionTrajectory* = ref object
Expand Down Expand Up @@ -278,12 +281,18 @@ proc recordDecision*(trajectory: DecisionTrajectory, decisionId, seat: string,
var encodedExecution = newJNull()
if execution.isSome:
let physical = execution.get()
let controls = decode(physical.seatControlsBase64)
let stride = case physical.controlEncoding
of ceI8I8I8U8: 4
of ceU8: 1
if physical.startTick < 0 or physical.endTick <= physical.startTick or
physical.tickHz <= 0 or
decode(physical.seatControlsBase64).len != (physical.endTick - physical.startTick) * 4:
raise newException(ValueError, "execution needs four control bytes per tick and a positive tick rate")
controls.len != (physical.endTick - physical.startTick) * stride or
encode(controls) != physical.seatControlsBase64:
raise newException(ValueError,
"execution requires canonical base64, exact encoding stride and positive tick rate")
encodedExecution = %*{"start_tick": physical.startTick, "end_tick": physical.endTick,
"tick_hz": physical.tickHz, "control_encoding": "i8-i8-i8-u8",
"tick_hz": physical.tickHz, "control_encoding": $physical.controlEncoding,
"seat_controls_b64": physical.seatControlsBase64}
trajectory.decisions.add(copy(%*{
"schema_version": "1", "event_type": "decision",
Expand Down
22 changes: 21 additions & 1 deletion tests/test_decision_trajectory.nim
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ suite "private authoritative decision trajectories":

test "macro orders keep authoritative physical ticks separately from parsed action":
let record = episode()
let physical = ExecutionEvidence(startTick: 12, endTick: 14, tickHz: 24,
let physical = ExecutionEvidence(controlEncoding: ceI8I8I8U8, startTick: 12, endTick: 14, tickHz: 24,
seatControlsBase64: encode("\xff\x00\x7f\x03\x01\x02\x80\x00"))
record.recordDecision("d0", "0", %*{}, @[teacher()], some("d0-a0"),
%*{"move": 1}, asAccepted, execution = some(physical))
Expand Down Expand Up @@ -285,3 +285,23 @@ suite "private authoritative decision trajectories":
check readAttemptEvidence(wire).responseReaderJoined.isNone
wire["response_reader_joined"] = %"joined"
expect ValueError: discard readAttemptEvidence(wire)

test "u8 execution retains one actual control byte per tick":
let record = episode()
let attempt = teacher()
let controls = "\x00\x7f\xfe"
let physical = ExecutionEvidence(controlEncoding: ceU8,
startTick: 5, endTick: 8, tickHz: 24, seatControlsBase64: encode(controls))
record.recordDecision("u8", "0", %*{}, @[attempt], some(attempt.attemptId),
attempt.parsedAction, asAccepted, execution = some(physical))
record.finish(esCompleted, %*{}, %*{})
let event = parseJson(record.eventsJsonl().splitLines()[0])
check event["execution"]["control_encoding"].getStr() == "u8"
check decode(event["execution"]["seat_controls_b64"].getStr()) == controls
for invalid in [encode(controls & controls & controls & controls), "AH/+==="]:
var padded = physical
padded.seatControlsBase64 = invalid
expect ValueError:
episode().recordDecision("invalid", "0", %*{}, @[attempt],
some(attempt.attemptId), attempt.parsedAction, asAccepted,
execution = some(padded))
Loading