kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
106 lines (104 loc) • 3.04 kB
JavaScript
// src/bus/write.ts
function serializeEvent(event) {
return JSON.stringify(event) + `
`;
}
function serializeBus(events) {
let out = "";
for (const ev of events)
out += serializeEvent(ev);
return out;
}
function canonicalEnvelope(seq, ev) {
const { ts, stream, type, ...payload } = ev;
return type === undefined ? { seq, ts, stream, ...payload } : { seq, ts, stream, type, ...payload };
}
class BusWriter {
#sink;
#seq = 0;
#closed = false;
constructor(path) {
this.#sink = Bun.file(path).writer();
}
get nextSeq() {
return this.#seq;
}
append(stream, type, payload, ts) {
if (this.#closed) {
throw new Error("BusWriter: append after close (single-writer, no reopen)");
}
const seq = this.#seq++;
const event = canonicalEnvelope(seq, { ts, stream, type, ...payload });
this.#sink.write(serializeEvent(event));
this.#sink.flush();
return event;
}
appendJournal(kind, body, ts) {
if (this.#closed) {
throw new Error("BusWriter: append after close (single-writer, no reopen)");
}
const seq = this.#seq++;
const event = { seq, ts, stream: "JOURNAL", kind, body };
this.#sink.write(serializeEvent(event));
this.#sink.flush();
return event;
}
async close() {
if (this.#closed)
return;
this.#closed = true;
await this.#sink.end();
}
}
// src/bus/plan-instances.ts
function sessionKey(name, ordinal) {
return `${name}\x00#${ordinal}`;
}
function groupPlanInstances(bus) {
const byKey = new Map;
const order = [];
const openByName = new Map;
const ordinalByName = new Map;
for (const e of bus) {
if (e.stream !== "PLAN")
continue;
const pe = e;
const name = pe.plan;
let key;
if (pe.plan_instance !== undefined) {
key = pe.plan_instance;
} else {
const open = openByName.get(name);
let openedNew;
if (open === undefined || open.terminal) {
const ordinal = (ordinalByName.get(name) ?? -1) + 1;
ordinalByName.set(name, ordinal);
key = sessionKey(name, ordinal);
openedNew = true;
} else {
key = open.key;
openedNew = false;
}
openByName.set(name, { key, terminal: (openedNew ? false : open.terminal) || pe.state === "done" });
}
let g = byKey.get(key);
if (g === undefined) {
g = { plan: name, instance: key, events: [], firstSeq: pe.seq };
byKey.set(key, g);
order.push(key);
}
g.events.push(pe);
}
return order.map((k) => byKey.get(k)).sort((a, b) => a.plan < b.plan ? -1 : a.plan > b.plan ? 1 : a.firstSeq - b.firstSeq).map((g) => ({ plan: g.plan, instance: g.instance, events: g.events }));
}
// src/bus/synthetic.ts
function mulberry32(seed) {
let a = seed >>> 0;
return () => {
a = a + 1831565813 | 0;
let t = Math.imul(a ^ a >>> 15, 1 | a);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
export { serializeBus, canonicalEnvelope, groupPlanInstances, mulberry32 };