feat(core): add embedded v2 session runtime and tool foundation (#30632)
This commit is contained in:
parent
c35267776a
commit
76ee87ead8
215 changed files with 31398 additions and 3332 deletions
4
packages/core/src/database/migration.gen.ts
generated
4
packages/core/src/database/migration.gen.ts
generated
|
|
@ -27,5 +27,9 @@ export const migrations = (
|
|||
import("./migration/20260601202201_amazing_prowler"),
|
||||
import("./migration/20260602002951_lowly_union_jack"),
|
||||
import("./migration/20260602182828_add_project_directories"),
|
||||
import("./migration/20260603001617_session_message_projection_indexes"),
|
||||
import("./migration/20260603040000_session_message_projection_order"),
|
||||
import("./migration/20260603141458_session_input_inbox"),
|
||||
import("./migration/20260603160727_jittery_ezekiel_stane"),
|
||||
])
|
||||
).map((module) => module.default) satisfies DatabaseMigration.Migration[]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
export * as DatabaseMigration from "./migration"
|
||||
|
||||
import { sql } from "drizzle-orm"
|
||||
import { Effect } from "effect"
|
||||
import { Effect, Semaphore } from "effect"
|
||||
import type { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
|
||||
import { migrations } from "./migration.gen"
|
||||
|
||||
type Database = EffectDrizzleSqlite.EffectSQLiteDatabase
|
||||
type Transaction = Parameters<Parameters<Database["transaction"]>[0]>[0]
|
||||
const lock = Semaphore.makeUnsafe(1)
|
||||
|
||||
export type Migration = {
|
||||
id: string
|
||||
|
|
@ -14,7 +15,7 @@ export type Migration = {
|
|||
}
|
||||
|
||||
export function apply(db: Database) {
|
||||
return applyOnly(db, migrations)
|
||||
return lock.withPermit(applyOnly(db, migrations))
|
||||
}
|
||||
|
||||
export function applyOnly(db: Database, input: Migration[]) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260603001617_session_message_projection_indexes",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`DROP INDEX IF EXISTS \`session_message_session_idx\`;`)
|
||||
yield* tx.run(`DROP INDEX IF EXISTS \`session_message_session_type_idx\`;`)
|
||||
yield* tx.run(`CREATE INDEX \`event_aggregate_seq_idx\` ON \`event\` (\`aggregate_id\`,\`seq\`);`)
|
||||
yield* tx.run(`CREATE INDEX \`session_message_session_time_created_id_idx\` ON \`session_message\` (\`session_id\`,\`time_created\`,\`id\`);`)
|
||||
yield* tx.run(`CREATE INDEX \`session_message_session_type_time_created_id_idx\` ON \`session_message\` (\`session_id\`,\`type\`,\`time_created\`,\`id\`);`)
|
||||
})
|
||||
},
|
||||
} satisfies DatabaseMigration.Migration
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260603040000_session_message_projection_order",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`ALTER TABLE \`session_message\` ADD COLUMN \`seq\` integer NOT NULL DEFAULT 0;`)
|
||||
yield* tx.run(`UPDATE \`session_message\` SET \`seq\` = COALESCE((SELECT \`seq\` + 1 FROM \`event\` WHERE \`event\`.\`id\` = \`session_message\`.\`id\`), 0);`)
|
||||
const unmatched = yield* tx.get<{ count: number }>(`SELECT COUNT(*) AS \`count\` FROM \`session_message\` WHERE \`seq\` = 0;`)
|
||||
if ((unmatched?.count ?? 0) > 0) return yield* Effect.die("Cannot migrate session_message projections without matching durable events")
|
||||
yield* tx.run(`UPDATE \`session_message\` SET \`seq\` = \`seq\` - 1;`)
|
||||
yield* tx.run(`DROP INDEX IF EXISTS \`session_message_session_type_time_created_id_idx\`;`)
|
||||
yield* tx.run(`CREATE INDEX \`session_message_session_seq_idx\` ON \`session_message\` (\`session_id\`,\`seq\`);`)
|
||||
yield* tx.run(`CREATE INDEX \`session_message_session_type_seq_idx\` ON \`session_message\` (\`session_id\`,\`type\`,\`seq\`);`)
|
||||
})
|
||||
},
|
||||
} satisfies DatabaseMigration.Migration
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260603141458_session_input_inbox",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`
|
||||
CREATE TABLE \`session_input\` (
|
||||
\`seq\` integer PRIMARY KEY AUTOINCREMENT,
|
||||
\`id\` text NOT NULL UNIQUE,
|
||||
\`session_id\` text NOT NULL,
|
||||
\`prompt\` text NOT NULL,
|
||||
\`delivery\` text NOT NULL,
|
||||
\`promoted_seq\` integer,
|
||||
\`time_created\` integer NOT NULL,
|
||||
CONSTRAINT \`fk_session_input_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE
|
||||
);
|
||||
`)
|
||||
yield* tx.run(
|
||||
`CREATE INDEX \`session_input_session_pending_seq_idx\` ON \`session_input\` (\`session_id\`,\`promoted_seq\`,\`seq\`);`,
|
||||
)
|
||||
})
|
||||
},
|
||||
} satisfies DatabaseMigration.Migration
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration"
|
||||
|
||||
export default {
|
||||
id: "20260603160727_jittery_ezekiel_stane",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`DROP INDEX IF EXISTS \`session_input_session_pending_seq_idx\`;`)
|
||||
yield* tx.run(`CREATE INDEX IF NOT EXISTS \`event_aggregate_type_seq_idx\` ON \`event\` (\`aggregate_id\`,\`type\`,\`seq\`);`)
|
||||
yield* tx.run(
|
||||
`CREATE INDEX IF NOT EXISTS \`session_input_session_pending_delivery_seq_idx\` ON \`session_input\` (\`session_id\`,\`promoted_seq\`,\`delivery\`,\`seq\`);`,
|
||||
)
|
||||
yield* tx.run(
|
||||
`CREATE INDEX IF NOT EXISTS \`session_message_session_time_created_id_idx\` ON \`session_message\` (\`session_id\`,\`time_created\`,\`id\`);`,
|
||||
)
|
||||
})
|
||||
},
|
||||
} satisfies DatabaseMigration.Migration
|
||||
|
|
@ -175,8 +175,9 @@ const drizzleLayer = Layer.effect(
|
|||
}),
|
||||
)
|
||||
|
||||
export const layer = (config: Config) =>
|
||||
Layer.merge(
|
||||
nativeLayer(config),
|
||||
Layer.merge(sqliteLayer(config), drizzleLayer).pipe(Layer.provide(nativeLayer(config))),
|
||||
).pipe(Layer.provide(Reactivity.layer))
|
||||
export const layer = (config: Config) => {
|
||||
const native = nativeLayer(config)
|
||||
return Layer.merge(native, Layer.merge(sqliteLayer(config), drizzleLayer).pipe(Layer.provide(native))).pipe(
|
||||
Layer.provide(Reactivity.layer),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,8 +170,9 @@ const drizzleLayer = Layer.effect(
|
|||
}),
|
||||
)
|
||||
|
||||
export const layer = (config: Config) =>
|
||||
Layer.merge(
|
||||
nativeLayer(config),
|
||||
Layer.merge(sqliteLayer(config), drizzleLayer).pipe(Layer.provide(nativeLayer(config))),
|
||||
).pipe(Layer.provide(Reactivity.layer))
|
||||
export const layer = (config: Config) => {
|
||||
const native = nativeLayer(config)
|
||||
return Layer.merge(native, Layer.merge(sqliteLayer(config), drizzleLayer).pipe(Layer.provide(native))).pipe(
|
||||
Layer.provide(Reactivity.layer),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue