@kuralle-syrinx/server-workers-mastra 2.1.1 → 3.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuralle-syrinx/server-workers-mastra",
3
- "version": "2.1.1",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,9 +11,9 @@
11
11
  "@mastra/cloudflare": "^1.4.1",
12
12
  "@mastra/core": "^1.41.0",
13
13
  "zod": "^4.1.8",
14
- "@kuralle-syrinx/core": "2.1.1",
15
- "@kuralle-syrinx/aisdk": "2.1.1",
16
- "@kuralle-syrinx/mastra": "2.1.1"
14
+ "@kuralle-syrinx/core": "3.1.0",
15
+ "@kuralle-syrinx/aisdk": "3.1.0",
16
+ "@kuralle-syrinx/mastra": "3.1.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@cloudflare/workers-types": "^4.20260601.0",
@@ -1,7 +1,11 @@
1
1
  // SPDX-License-Identifier: MIT
2
+ //
3
+ // RunStore for the mastra HITL suspend/resume flow, backed by the Durable Object's
4
+ // SQLite (the storage Mastra's own CloudflareDOStorage uses). Stale run pointers
5
+ // expire lazily on read — no scheduled-alarm cleanup needed, so the DO does not
6
+ // re-implement a task scheduler.
2
7
 
3
8
  import type { RunPointer, RunStore } from "@kuralle-syrinx/aisdk";
4
- import type { DurableObjectAlarmScheduler } from "./alarm-scheduler.js";
5
9
 
6
10
  type SqlCursor<T> = Iterable<T>;
7
11
 
@@ -18,7 +22,6 @@ export const DEFAULT_RUN_POINTER_TTL_MS = 15 * 60 * 1000;
18
22
  export class DurableObjectRunStore implements RunStore {
19
23
  constructor(
20
24
  private readonly storage: DurableRunStorage,
21
- private readonly scheduler: DurableObjectAlarmScheduler,
22
25
  private readonly ttlMs = DEFAULT_RUN_POINTER_TTL_MS,
23
26
  ) {
24
27
  this.storage.sql.exec(
@@ -37,21 +40,23 @@ export class DurableObjectRunStore implements RunStore {
37
40
  runId,
38
41
  Date.now(),
39
42
  );
40
- this.scheduler.schedule(`run.ttl:${contextId}`, this.ttlMs, () => {
41
- this.discard(contextId);
42
- });
43
43
  }
44
44
 
45
45
  takePending(contextId: string): RunPointer | null {
46
46
  const [row] = [...this.storage.sql.exec(
47
- "SELECT run_id FROM reasoning_run_pointers WHERE context_id = ?",
47
+ "SELECT run_id, created_at_ms FROM reasoning_run_pointers WHERE context_id = ?",
48
48
  contextId,
49
- )] as Array<{ run_id: string }>;
50
- return row ? { runId: row.run_id } : null;
49
+ )] as Array<{ run_id: string; created_at_ms: number }>;
50
+ if (!row) return null;
51
+ // Lazy TTL: a pointer past its window is treated as absent and swept on read.
52
+ if (Date.now() - Number(row.created_at_ms) > this.ttlMs) {
53
+ this.discard(contextId);
54
+ return null;
55
+ }
56
+ return { runId: row.run_id };
51
57
  }
52
58
 
53
59
  discard(contextId: string): void {
54
- this.scheduler.cancel(`run.ttl:${contextId}`);
55
60
  this.storage.sql.exec("DELETE FROM reasoning_run_pointers WHERE context_id = ?", contextId);
56
61
  }
57
62
  }
package/src/worker.ts CHANGED
@@ -11,7 +11,6 @@ import { PipelineBusImpl, Route } from "@kuralle-syrinx/core";
11
11
  import type { EndOfSpeechPacket } from "@kuralle-syrinx/core";
12
12
  import { ReasoningBridge } from "@kuralle-syrinx/aisdk";
13
13
  import { fromMastraAgent, type MastraAgentLike } from "@kuralle-syrinx/mastra";
14
- import { DurableObjectAlarmScheduler } from "./alarm-scheduler.js";
15
14
  import { DurableObjectRunStore } from "./durable-run-store.js";
16
15
  import { createSpikeMockModel, resetMockModelCalls } from "./mock-model.js";
17
16
 
@@ -140,8 +139,7 @@ async function driveTurn(
140
139
  pointer: { runId: string } | null;
141
140
  mastraTables: string[];
142
141
  }> {
143
- const scheduler = new DurableObjectAlarmScheduler(storage);
144
- const runStore = new DurableObjectRunStore(storage, scheduler);
142
+ const runStore = new DurableObjectRunStore(storage);
145
143
  const { agent } = createMastra(storage.sql, apiKey);
146
144
  const bridge = new ReasoningBridge(fromMastraAgent(toMastraAgentLike(agent)), {
147
145
  runStore,
@@ -227,11 +225,6 @@ export class MastraAgentDO extends DurableObject<Env> {
227
225
  return Response.json({ error: message }, { status: 500 });
228
226
  }
229
227
  }
230
-
231
- async alarm(): Promise<void> {
232
- const scheduler = new DurableObjectAlarmScheduler(this.ctx.storage);
233
- await scheduler.runDue();
234
- }
235
228
  }
236
229
 
237
230
  export default {
@@ -1,67 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
-
3
- import type { ScheduledCallback, Scheduler } from "@kuralle-syrinx/core";
4
-
5
- type SqlCursor<T> = Iterable<T>;
6
-
7
- interface SqlStorage {
8
- exec(query: string, ...bindings: unknown[]): SqlCursor<Record<string, unknown>>;
9
- }
10
-
11
- export interface DurableSchedulerStorage {
12
- readonly sql: SqlStorage;
13
- setAlarm(scheduledTime: number | Date): Promise<void>;
14
- deleteAlarm(): Promise<void>;
15
- }
16
-
17
- export class DurableObjectAlarmScheduler implements Scheduler {
18
- private readonly callbacks = new Map<string, ScheduledCallback>();
19
-
20
- constructor(private readonly storage: DurableSchedulerStorage) {
21
- this.storage.sql.exec(
22
- "CREATE TABLE IF NOT EXISTS scheduled_tasks (key TEXT PRIMARY KEY, deadline_ms INTEGER NOT NULL)",
23
- );
24
- }
25
-
26
- schedule(key: string, delayMs: number, cb: ScheduledCallback): void {
27
- const deadlineMs = Date.now() + Math.max(0, delayMs);
28
- this.callbacks.set(key, cb);
29
- this.storage.sql.exec(
30
- "INSERT OR REPLACE INTO scheduled_tasks (key, deadline_ms) VALUES (?, ?)",
31
- key,
32
- deadlineMs,
33
- );
34
- void this.armNext();
35
- }
36
-
37
- cancel(key: string): void {
38
- this.callbacks.delete(key);
39
- this.storage.sql.exec("DELETE FROM scheduled_tasks WHERE key = ?", key);
40
- void this.armNext();
41
- }
42
-
43
- async runDue(nowMs = Date.now()): Promise<void> {
44
- const due = [...this.storage.sql.exec(
45
- "SELECT key FROM scheduled_tasks WHERE deadline_ms <= ? ORDER BY deadline_ms ASC",
46
- nowMs,
47
- )] as Array<{ key: string }>;
48
- for (const row of due) {
49
- this.storage.sql.exec("DELETE FROM scheduled_tasks WHERE key = ?", row.key);
50
- const cb = this.callbacks.get(row.key);
51
- this.callbacks.delete(row.key);
52
- if (cb) await cb();
53
- }
54
- await this.armNext();
55
- }
56
-
57
- private async armNext(): Promise<void> {
58
- const [next] = [...this.storage.sql.exec(
59
- "SELECT deadline_ms FROM scheduled_tasks ORDER BY deadline_ms ASC LIMIT 1",
60
- )] as Array<{ deadline_ms: number }>;
61
- if (!next) {
62
- await this.storage.deleteAlarm();
63
- return;
64
- }
65
- await this.storage.setAlarm(next.deadline_ms);
66
- }
67
- }