norns-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -626,6 +626,12 @@ interface LlmTask {
626
626
  summary?: string | null;
627
627
  date?: string | null;
628
628
  messages?: NeutralMessage[];
629
+ /** In place of `messages` once this worker holds the run's history (see HistoryCache). */
630
+ messages_delta?: {
631
+ base_count: number;
632
+ drop: number;
633
+ append: NeutralMessage[];
634
+ };
629
635
  tools?: NeutralTool[];
630
636
  context_policy?: unknown;
631
637
  max_tokens?: number | null;
package/dist/index.d.ts CHANGED
@@ -626,6 +626,12 @@ interface LlmTask {
626
626
  summary?: string | null;
627
627
  date?: string | null;
628
628
  messages?: NeutralMessage[];
629
+ /** In place of `messages` once this worker holds the run's history (see HistoryCache). */
630
+ messages_delta?: {
631
+ base_count: number;
632
+ drop: number;
633
+ append: NeutralMessage[];
634
+ };
629
635
  tools?: NeutralTool[];
630
636
  context_policy?: unknown;
631
637
  max_tokens?: number | null;
package/dist/index.js CHANGED
@@ -1113,6 +1113,51 @@ function neutralUsage(usage) {
1113
1113
  return out;
1114
1114
  }
1115
1115
 
1116
+ // src/history-cache.ts
1117
+ var HistoryCache = class {
1118
+ #runs = /* @__PURE__ */ new Map();
1119
+ #maxRuns;
1120
+ constructor(maxRuns = 256) {
1121
+ this.#maxRuns = maxRuns;
1122
+ }
1123
+ /** The task with `messages` filled in, or `undefined` on a miss. */
1124
+ resolve(task) {
1125
+ if (task.purpose === "compact") return task;
1126
+ const runId = task.run_id;
1127
+ const delta = task.messages_delta;
1128
+ if (delta === void 0) {
1129
+ if (runId !== void 0 && Array.isArray(task.messages)) this.#remember(runId, task.messages);
1130
+ return task;
1131
+ }
1132
+ const previous = runId === void 0 ? void 0 : this.#runs.get(runId);
1133
+ if (runId === void 0 || previous === void 0 || previous.length !== delta.base_count) {
1134
+ return void 0;
1135
+ }
1136
+ const messages = [...previous.slice(delta.drop), ...delta.append];
1137
+ this.#remember(runId, messages);
1138
+ const resolved = { ...task, messages };
1139
+ delete resolved.messages_delta;
1140
+ return resolved;
1141
+ }
1142
+ /** Forget everything: a new connection gets the full history anyway. */
1143
+ clear() {
1144
+ this.#runs.clear();
1145
+ }
1146
+ /** How many runs are held; for tests. */
1147
+ get size() {
1148
+ return this.#runs.size;
1149
+ }
1150
+ #remember(runId, messages) {
1151
+ this.#runs.delete(runId);
1152
+ this.#runs.set(runId, messages);
1153
+ while (this.#runs.size > this.#maxRuns) {
1154
+ const oldest = this.#runs.keys().next().value;
1155
+ if (oldest === void 0) break;
1156
+ this.#runs.delete(oldest);
1157
+ }
1158
+ }
1159
+ };
1160
+
1116
1161
  // src/worker.ts
1117
1162
  var TOPIC = "worker:lobby";
1118
1163
  var NornsWorker = class {
@@ -1133,6 +1178,7 @@ var NornsWorker = class {
1133
1178
  #client;
1134
1179
  #resolveModel;
1135
1180
  #inFlight = /* @__PURE__ */ new Set();
1181
+ #history = new HistoryCache();
1136
1182
  #state = "idle";
1137
1183
  #socket;
1138
1184
  #channel;
@@ -1225,7 +1271,10 @@ var NornsWorker = class {
1225
1271
  ...this.#socketOptions
1226
1272
  });
1227
1273
  this.#socket = socket;
1228
- socket.onOpen(() => this.#logger.info(`Connected to ${this.url}`));
1274
+ socket.onOpen(() => {
1275
+ this.#logger.info(`Connected to ${this.url}`);
1276
+ this.#history.clear();
1277
+ });
1229
1278
  socket.onError((err) => {
1230
1279
  if (this.#state === "starting" || this.#state === "running") {
1231
1280
  this.#logger.warn(`Connection error (${errorMessage(err)}); retrying`);
@@ -1284,7 +1333,10 @@ var NornsWorker = class {
1284
1333
  const params = {
1285
1334
  worker_id: this.workerId,
1286
1335
  tools: [...this.#tools.values()].map(toolRegistration),
1287
- capabilities: this.#capabilities
1336
+ capabilities: this.#capabilities,
1337
+ // This worker keeps the history it was last sent per run, so Norns may
1338
+ // send later steps as the change only (HistoryCache).
1339
+ features: ["message_cache"]
1288
1340
  };
1289
1341
  if (this.gard !== void 0) {
1290
1342
  params.gard = this.gard;
@@ -1413,7 +1465,14 @@ var NornsWorker = class {
1413
1465
  (resp) => this.#logger.warn(`Server rejected result for ${taskId}: ${errorMessage(resp)}`)
1414
1466
  );
1415
1467
  }
1416
- async #runLlm(task, signal) {
1468
+ async #runLlm(received, signal) {
1469
+ const task = this.#history.resolve(received);
1470
+ if (task === void 0) {
1471
+ this.#logger.info(
1472
+ "LLM task arrived as a delta on an unknown base; asking for the full history"
1473
+ );
1474
+ return { status: "error", error: "message_cache_miss" };
1475
+ }
1417
1476
  const model = task.model ?? "?";
1418
1477
  const tools = task.tools ?? [];
1419
1478
  this.#logger.info(