Something went wrong. Try again.
small gleam coding and persistent agent daemon with a detachable cli and a canvas ui forked from okami.mom/albedo
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212/// Legacy schema migrations preserve titles and event timestamps; E2E uses current schemas.import albedo/daemon/conversationimport albedo/daemon/storeimport albedo/daemon/transcriptimport albedo/harness/runtimeimport albedo/openai_api/typesimport gleam/listimport gleam/option.{None, Some}import gleeunit/shouldimport sqlight
@external(erlang, "albedo_runtime_test_support", "temporary_database")fn temporary_database() -> String
@external(erlang, "albedo_runtime_test_support", "cleanup")fn cleanup(path: String) -> Nil
fn session(id: String) -> conversation.Info { conversation.Info( id, "new session", "/tmp", "provider", "model", types.Responses, conversation.Idle, None, None, False, )}
pub fn latest_user_title_survives_restart_and_legacy_migration_test() -> Nil { let path = temporary_database() let assert Ok(host) = runtime.start(path) let ledger = runtime.ledger(host) let assert Ok(_) = conversation.initialise(ledger) let assert Ok(_) = conversation.create(ledger, session("session")) let assert Ok(_) = conversation.commit( ledger, "session", [types.User("earlier title"), types.Assistant("not the title")], conversation.Model, ) let assert Ok(_) = conversation.commit( ledger, "session", [types.User(" latest\naccepted 👩💻 ")], conversation.Model, ) let assert Ok(_) = conversation.commit( ledger, "session", [ types.Assistant("must not replace it"), types.ToolOutput("call", "output", []), ], conversation.Idle, ) let assert Ok([before]) = conversation.list(ledger) before.title |> should.equal("latest accepted 👩💻")
// Recreate the old schema shape; startup performs this transcript scan once. let assert Ok(_) = store.query(ledger, fn(db) { sqlight.exec( "ALTER TABLE sessions DROP COLUMN title; ALTER TABLE sessions DROP COLUMN last_assistant_at", db, ) }) runtime.stop(host)
let assert Ok(restarted) = runtime.start(path) let ledger = runtime.ledger(restarted) let assert Ok(_) = conversation.initialise(ledger) let assert Ok([after]) = conversation.list(ledger) after.title |> should.equal("latest accepted 👩💻") after.last_assistant_at |> should.equal(None) runtime.stop(restarted) cleanup(path)}
pub fn migration_recovers_placeholder_titles_and_activity_order_test() -> Nil { let path = temporary_database() let assert Ok(host) = runtime.start(path) let ledger = runtime.ledger(host) let assert Ok(_) = conversation.initialise(ledger) let assert Ok(_) = conversation.create(ledger, session("first")) let assert Ok(_) = conversation.create(ledger, session("second")) let assert Ok(_) = conversation.commit( ledger, "second", [types.User("older prompt")], conversation.Idle, ) let assert Ok(_) = conversation.commit( ledger, "first", [types.User("newest prompt")], conversation.Idle, ) let assert Ok(_) = store.query(ledger, fn(db) { sqlight.exec( "UPDATE sessions SET title='new session',activity_seq=NULL", db, ) })
// The null activity marker makes this a one-time legacy backfill. It also // distinguishes a placeholder title from a real current-session title. let assert Ok(_) = conversation.initialise(ledger) let assert Ok([first, second]) = conversation.list(ledger) first.id |> should.equal("first") first.title |> should.equal("newest prompt") second.id |> should.equal("second") second.title |> should.equal("older prompt") runtime.stop(host) cleanup(path)}
pub fn transcript_timestamps_migrate_without_invention_and_roundtrip_test() -> Nil { let path = temporary_database() let assert Ok(host) = runtime.start(path) let ledger = runtime.ledger(host) let assert Ok(_) = conversation.initialise(ledger) let assert Ok(_) = conversation.create(ledger, session("timestamped")) let assert Ok(_) = conversation.commit( ledger, "timestamped", [types.User("legacy")], conversation.Idle, )
// Recreate the legacy transcript shape. Migration adds a nullable column and // must not claim to know when this row was accepted. let assert Ok(_) = store.query(ledger, fn(db) { sqlight.exec( "ALTER TABLE transcript DROP COLUMN timestamp; ALTER TABLE transcript DROP COLUMN provider; ALTER TABLE transcript DROP COLUMN thought_ms", db, ) }) let assert Ok(_) = conversation.initialise(ledger) conversation.load_entries(ledger, "timestamped") |> should.equal( Ok([ transcript.Entry( types.User("legacy"), None, None, None, Some(transcript.SourceRef("timestamped", 1)), ), ]), )
let new_inputs = [types.User("current"), types.Assistant("answer")] let assert Ok(timestamp) = conversation.commit(ledger, "timestamped", new_inputs, conversation.Idle) let assert True = timestamp > 1_000_000_000_000 let assert Ok(entries) = conversation.load_entries(ledger, "timestamped") entries |> should.equal([ transcript.Entry( types.User("legacy"), None, None, None, Some(transcript.SourceRef("timestamped", 1)), ), transcript.Entry( types.User("current"), Some(timestamp), None, None, Some(transcript.SourceRef("timestamped", 2)), ), transcript.Entry( types.Assistant("answer"), Some(timestamp), None, None, Some(transcript.SourceRef("timestamped", 3)), ), ]) conversation.load(ledger, "timestamped") |> should.equal(Ok([types.User("legacy"), ..new_inputs]))
let assert Ok(snapshot) = conversation.snapshot(ledger, "timestamped") let range = conversation.Range(snapshot, conversation.After(0), 100, 0) let assert Ok(page) = conversation.read_range(ledger, range) list.map(page.entries, fn(sourced) { sourced.entry }) |> should.equal(entries) page.has_more |> should.be_false
runtime.stop(host) let assert Ok(restarted) = runtime.start(path) let ledger = runtime.ledger(restarted) let assert Ok(_) = conversation.initialise(ledger) conversation.load_entries(ledger, "timestamped") |> should.equal(Ok(entries)) conversation.read_range(ledger, range) |> should.equal(Ok(page)) runtime.stop(restarted) cleanup(path)}