Skip to content

FieldPersistence.kt

src/jvmMain/kotlin/afield/audio/ai/FieldPersistence.kt · 65 lines

@file:afield.runtime.completion.CompletionCategory("Audio AI")

package afield.audio.ai

import afield.document.graph.Box
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

How a Field document remembers audio work: ids and judgements in a box property, and not one sample of audio.

The rule this file enforces is that Python is a worker and Field is the authority. The service owns immutable, content-addressed assets; the document owns which of them it refers to and what you thought of them. That is why saved state is a FieldAudioProjectState of ids rather than audio, and why reopening a document and re-fetching those ids gets the same bytes back.

object FieldAudioPersistence

Persist only protocol data and asset IDs; Python remains a worker, never project authority.

object FieldAudioPersistence {

const val DEFAULT_PROPERTY = "audioAIProject"

The box property the project state lives in unless you name another one.

    private val json = Json {
        ignoreUnknownKeys = true
        encodeDefaults = true
        explicitNulls = false
        prettyPrint = true
    }

fun install(property: String = DEFAULT_PROPERTY)

Register property as persistent and JSON-sidecar-separated on this document.

Idempotent, and called for you by load and save, so you rarely need it directly. The sidecar registration is what keeps a large project state out of the document file itself and makes its diffs readable.

    fun install(property: String = DEFAULT_PROPERTY) {
        Box.ioPersistentProperties.add(property)
        Box.ioSeparateProperties.putIfAbsent(property, "json")
    }

fun load(box: Box, property: String = DEFAULT_PROPERTY): FieldAudioProjectState

Read the saved state out of box, or an empty FieldAudioProjectState if there is none yet.

Decodes with ignoreUnknownKeys, so a state written by a newer Field still loads.

    fun load(box: Box, property: String = DEFAULT_PROPERTY): FieldAudioProjectState {
        install(property)
        val encoded = box.properties[property] as? String ?: return FieldAudioProjectState()
        return json.decodeFromString(encoded)
    }

fun save(box: Box, state: FieldAudioProjectState, property: String = DEFAULT_PROPERTY)

Write state into box as pretty-printed JSON, replacing whatever was there.

Only ids and judgements are written, never audio; see SavedAudioOperation.

    fun save(box: Box, state: FieldAudioProjectState, property: String = DEFAULT_PROPERTY) {
        install(property)
        box.properties[property] = json.encodeToString(state)
    }
}