UNPKG

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
// 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 };