44 lines
2.4 KiB
TypeScript
44 lines
2.4 KiB
TypeScript
/** Conversation metadata and lifecycle. Summaries remain disabled until the summary port supplies them. */
|
|
import { defineExtension, GenerationTask, hook, ROOT_CONVERSATION_ID } from '@earendil-works/pi-durable'
|
|
import { ConversationsApi, State, Concluded } from './api.ts'
|
|
export default function conversations(host: any) {
|
|
const concludedIn = async (tx: any) => new Set<number>((await tx.doc(Concluded)).ids)
|
|
host.implement(ConversationsApi, {
|
|
concludedIn,
|
|
concluded: async (context: any) => host.harness().commit(concludedIn,context),
|
|
concludeIn: async (tx: any, ids: number[]) => {
|
|
for (const id of ids) {
|
|
const record = await tx.conversation(id)
|
|
if (!record) throw new Error(`Unknown conversation ${id}`)
|
|
if (record.owner) throw new Error(`Conversation ${id} is owned`)
|
|
if (id === ROOT_CONVERSATION_ID || (await tx.doc(State,id)).standing) throw new Error(`Conversation ${id} is fixed`)
|
|
}
|
|
const state = await tx.doc(Concluded)
|
|
state.ids = [...new Set([...state.ids,...ids])]
|
|
},
|
|
setStanding: async (tx: any, id: number, standing: boolean) => { (await tx.doc(State,id)).standing = standing },
|
|
setAutomaticSummaries: async (tx: any, id: number, enabled: boolean) => { (await tx.doc(State,id)).automaticSummaries = enabled },
|
|
generatedTitle: async (tx: any, id: number, title: string) => {
|
|
const state = await tx.doc(State,id)
|
|
if (state.generatedTitle === undefined && (await tx.doc(host.metadata,id)).title === title) state.generatedTitle = title
|
|
},
|
|
subject: async (id: number, context: any) => {
|
|
const metadata = await host.harness().snapshot(host.metadata,id,context)
|
|
return metadata?.title ? {title:metadata.title} : {}
|
|
},
|
|
// Later summaries can supply these without changing lifecycle callers.
|
|
summaryModel: async () => undefined,
|
|
requestSummary: async () => {},
|
|
})
|
|
return defineExtension({name:'conversations',hooks:[hook(GenerationTask,{beforeInput:async (_input,{tx,conversationId})=>{
|
|
const ancestors = new Set<number>()
|
|
for (let id = conversationId; id !== undefined && !ancestors.has(id);) {
|
|
ancestors.add(id)
|
|
const record = await tx.conversation(id)
|
|
id = record?.owner?.conversationId ?? record?.parent?.conversationId
|
|
}
|
|
const state = await tx.doc(Concluded)
|
|
state.ids = state.ids.filter(id=>!ancestors.has(id))
|
|
}})]})
|
|
}
|