48 lines
2.0 KiB
TypeScript
48 lines
2.0 KiB
TypeScript
/** Durable delivery of goal start cards and passive report cards. */
|
|
import { defineTask } from '@earendil-works/pi-durable'
|
|
import type { ConversationId, Tx } from '@earendil-works/pi-durable'
|
|
import type { Host } from '../../host/js/extensions.ts'
|
|
|
|
/** A goal card for the standing agent: `goal.started` as an input that wakes it, `goal.report` as a write. */
|
|
type Card = { to: number; goal: number; kind: 'goal.started' | 'goal.report'; content: string }
|
|
|
|
/** Created in the commit that changes the goal, so a crash cannot lose the card; the request id makes retries harmless. */
|
|
export const deliverTask = (host: Pick<Host, 'harness'>) =>
|
|
defineTask<Card, { phase: 'submit' }, null>({
|
|
name: 'goal.deliver',
|
|
version: 1,
|
|
initial: () => ({ phase: 'submit' }),
|
|
phases: {
|
|
submit: async (task, runtime, ctx) => {
|
|
const { to, goal, kind, content } = task.input
|
|
const requestId = `${kind}:${goal}`
|
|
const data = { goal }
|
|
// The host handle, unlike the task runtime's, admits passive writes.
|
|
const target = (await host.harness().conversation(to as ConversationId, ctx))!
|
|
await target.submit(
|
|
kind === 'goal.started'
|
|
? { type: 'input', requestId, content, entry: { kind, data }, whenBusy: 'followUp' }
|
|
: {
|
|
type: 'write',
|
|
requestId,
|
|
entry: { kind, data, model: [{ role: 'user', content, timestamp: Date.now() }] },
|
|
},
|
|
ctx,
|
|
)
|
|
await runtime.commit(
|
|
() => ({ status: 'terminal', outcome: { status: 'completed', result: null } }),
|
|
ctx,
|
|
)
|
|
},
|
|
},
|
|
abort: (_task, runtime, ctx) =>
|
|
runtime.commit(() => ({ status: 'terminal', outcome: { status: 'aborted' } }), ctx),
|
|
})
|
|
|
|
export const deliver = (host: Pick<Host, 'harness'>, tx: Tx, card: Card) =>
|
|
tx.createTask(deliverTask(host), card, {
|
|
conversationId: card.to as ConversationId,
|
|
ownership: { kind: 'conversation' },
|
|
background: true,
|
|
})
|