mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
Submissions with request-ID deduplication and handles, the pi.live run control and presentation document, the built-in pi.generation task (system prompt preparation, streamed durable partials, retries, deferred polling, abort), typed entry tokens, stream options and retry policy, TaskRuntime reads, Tx.settleSubmission, registry conversation setups, Storage.scanSubmissions, Harness.inspect, and byTaskId attribution. Waiting calls enable scheduling. The scratch tour is split into test/examples.
55 lines
2.2 KiB
TypeScript
55 lines
2.2 KiB
TypeScript
// Fork a conversation.
|
|
// Run from packages/durable:
|
|
// node --conditions=source --experimental-strip-types test/examples/02-forks.ts
|
|
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
import { createSession, defineDoc, MemoryStorage } from "../../src/index.ts";
|
|
|
|
const context = BACKGROUND_CONTEXT;
|
|
const session = createSession(new MemoryStorage());
|
|
|
|
const Notes = defineDoc<{ text: string }>({
|
|
kind: "example.notes",
|
|
version: 1,
|
|
scope: "conversation",
|
|
history: "rewindable",
|
|
fork: "asOf",
|
|
initial: () => ({ text: "" }),
|
|
});
|
|
|
|
const chat = await session.commit((tx) => tx.createConversation({ ownership: { kind: "ownerless" } }), context);
|
|
const firstEntry = await session.commit(async (tx) => {
|
|
const entry = await tx.appendEntry(chat.id, { kind: "note", data: "hello" });
|
|
(await tx.doc(Notes, chat.id)).text = "after hello";
|
|
return entry;
|
|
}, context);
|
|
await session.commit(async (tx) => {
|
|
await tx.appendEntry(chat.id, { kind: "note", data: "goodbye" });
|
|
(await tx.doc(Notes, chat.id)).text = "after goodbye";
|
|
}, context);
|
|
|
|
// A fork is a new conversation that continues from one entry of another. It
|
|
// sees the parent's transcript up to that entry, and each document follows its
|
|
// own `fork` setting. Notes uses "asOf", so the fork starts with the notes
|
|
// value from the fork entry.
|
|
const branch = await session.commit(
|
|
(tx) => tx.forkConversation(chat.id, firstEntry.id, { ownership: { kind: "ownerless" } }),
|
|
context,
|
|
);
|
|
|
|
// scanEntries() pages through visible entries, newest first. The fork sees
|
|
// "hello" (inherited from the parent) but not "goodbye", which came later.
|
|
const branchEntries = await session.commit((tx) => tx.scanEntries({ conversationId: branch.id }, 10), context);
|
|
console.log(
|
|
"fork transcript:",
|
|
branchEntries.items.map((entry) => entry.data),
|
|
);
|
|
console.log("fork notes:", await session.snapshot(Notes, branch.id, context));
|
|
|
|
// The fork's copy is independent: editing it leaves the parent unchanged.
|
|
await session.commit(async (tx) => {
|
|
(await tx.doc(Notes, branch.id)).text = "changed only in the fork";
|
|
}, context);
|
|
console.log("fork notes after edit:", await session.snapshot(Notes, branch.id, context));
|
|
console.log("parent notes after edit:", await session.snapshot(Notes, chat.id, context));
|
|
|
|
await session.close(context);
|