Files
pi/packages/durable/test/examples/14-chat.ts
T
Mario Zechner 837d8a16bd feat(durable): first runnable chat turn (Package 15)
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.
2026-09-29 14:08:28 +02:00

44 lines
1.9 KiB
TypeScript

// A chat turn.
// Run from packages/durable:
// node --conditions=source --experimental-strip-types test/examples/14-chat.ts
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
import { createModels, fauxAssistantMessage, fauxProvider } from "@earendil-works/pi-ai";
import { AssistantEntry, ConversationConfig, createRegistry, Harness, MemoryStorage } from "../../src/index.ts";
const context = BACKGROUND_CONTEXT;
// The faux provider stands in for a real model (see 16-real-model.ts).
const faux = fauxProvider();
const models = createModels();
models.setProvider(faux.provider);
faux.setResponses([fauxAssistantMessage("Paris.")]);
const registry = createRegistry();
registry.systemPrompt.section("preamble", () => "You answer in one word.", { tag: false });
const harness = await Harness.open(new MemoryStorage(), { models, registry }, context);
const root = await harness.root(context, {
init: async (tx, id) => {
(await tx.doc(ConversationConfig, id)).model = { provider: "faux", modelId: "faux-1" };
},
});
// submit() durably admits user input and returns a Submission. The built-in
// pi.generation task prepares the system prompt from the registry's sections,
// calls the model, and appends the answer; wait() resolves once the input is
// answered or has failed.
const capital = await root.submit({ type: "input", content: "Capital of France?" }, context);
const answered = await capital.wait(context);
if (answered.status === "done" && answered.type === "input") {
const entry = await root.commit((tx) => tx.entry(AssistantEntry, answered.answer), context);
const reply = entry?.model?.[0];
console.log("answer:", reply?.role === "assistant" ? reply.content : reply);
}
// The transcript holds the user input, the positional system prompt, and the answer.
const transcript = await root.entries({}, 10, undefined, context);
console.log(
"transcript:",
[...transcript.items].reverse().map((entry) => entry.kind),
);
await harness.close(context);