refactor(todo): effectify session todo (#20595)

pull/20733/head^2
Kit Langton 2026-04-02 15:11:23 -04:00 committed by GitHub
parent f549fde874
commit 5e1b513527
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 65 additions and 27 deletions

View File

@ -1,6 +1,8 @@
import { BusEvent } from "@/bus/bus-event" import { BusEvent } from "@/bus/bus-event"
import { Bus } from "@/bus" import { Bus } from "@/bus"
import { makeRuntime } from "@/effect/run-service"
import { SessionID } from "./schema" import { SessionID } from "./schema"
import { Effect, Layer, ServiceMap } from "effect"
import z from "zod" import z from "zod"
import { Database, eq, asc } from "../storage/db" import { Database, eq, asc } from "../storage/db"
import { TodoTable } from "./session.sql" import { TodoTable } from "./session.sql"
@ -25,7 +27,20 @@ export namespace Todo {
), ),
} }
export function update(input: { sessionID: SessionID; todos: Info[] }) { export interface Interface {
readonly update: (input: { sessionID: SessionID; todos: Info[] }) => Effect.Effect<void>
readonly get: (sessionID: SessionID) => Effect.Effect<Info[]>
}
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionTodo") {}
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const bus = yield* Bus.Service
const update = Effect.fn("Todo.update")(function* (input: { sessionID: SessionID; todos: Info[] }) {
yield* Effect.sync(() =>
Database.transaction((db) => { Database.transaction((db) => {
db.delete(TodoTable).where(eq(TodoTable.session_id, input.sessionID)).run() db.delete(TodoTable).where(eq(TodoTable.session_id, input.sessionID)).run()
if (input.todos.length === 0) return if (input.todos.length === 0) return
@ -40,18 +55,41 @@ export namespace Todo {
})), })),
) )
.run() .run()
}),
)
yield* bus.publish(Event.Updated, input)
}) })
Bus.publish(Event.Updated, input)
}
export function get(sessionID: SessionID) { const get = Effect.fn("Todo.get")(function* (sessionID: SessionID) {
const rows = Database.use((db) => const rows = yield* Effect.sync(() =>
db.select().from(TodoTable).where(eq(TodoTable.session_id, sessionID)).orderBy(asc(TodoTable.position)).all(), Database.use((db) =>
db
.select()
.from(TodoTable)
.where(eq(TodoTable.session_id, sessionID))
.orderBy(asc(TodoTable.position))
.all(),
),
) )
return rows.map((row) => ({ return rows.map((row) => ({
content: row.content, content: row.content,
status: row.status, status: row.status,
priority: row.priority, priority: row.priority,
})) }))
})
return Service.of({ update, get })
}),
)
const defaultLayer = layer.pipe(Layer.provide(Bus.layer))
const { runPromise } = makeRuntime(Service, defaultLayer)
export async function update(input: { sessionID: SessionID; todos: Info[] }) {
return runPromise((svc) => svc.update(input))
}
export async function get(sessionID: SessionID) {
return runPromise((svc) => svc.get(sessionID))
} }
} }

View File

@ -16,7 +16,7 @@ export const TodoWriteTool = Tool.define("todowrite", {
metadata: {}, metadata: {},
}) })
Todo.update({ await Todo.update({
sessionID: ctx.sessionID, sessionID: ctx.sessionID,
todos: params.todos, todos: params.todos,
}) })