@kuralle-agents/cf-agent 0.5.0 → 0.6.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/README.md CHANGED
@@ -19,6 +19,7 @@ Peers: `agents` (Cloudflare Agents SDK), `zod`.
19
19
  - **`KuralleAgent`** (alias `CfChatAgent`) — abstract base class; extend and implement `getAgents()` and `getDefaultAgentId()`.
20
20
  - **`BridgeSessionStore`** — bridges Kuralle `SessionStore` interface to CF's SQLite storage.
21
21
  - **`OrchestrationStore`** — Durable Object KV for orchestration state.
22
+ - **`SqlPersistentMemoryStore`** — DO SQLite-backed `PersistentMemoryStore` for USER/MEMORY blocks.
22
23
  - **`createSSEResponse`** — helper for streaming SSE responses from Workers.
23
24
 
24
25
  ## Usage
@@ -64,6 +65,20 @@ tag = "v1"
64
65
  new_sqlite_classes = ["SupportAgent"]
65
66
  ```
66
67
 
68
+ ## Working memory blocks
69
+
70
+ `KuralleAgent` wires `SqlPersistentMemoryStore` into `defaultWorkingMemoryStore` automatically via DO SQLite. Override in `getRuntimeConfig()` or disable by overriding `getWorkingMemoryStore()` to return `undefined`.
71
+
72
+ ```ts
73
+ import { SqlPersistentMemoryStore } from '@kuralle-agents/cf-agent';
74
+
75
+ protected getRuntimeConfig() {
76
+ return {
77
+ defaultWorkingMemoryStore: new SqlPersistentMemoryStore(this.getSql()),
78
+ };
79
+ }
80
+ ```
81
+
67
82
  ## Flows and routing
68
83
 
69
84
  Attach `flows` for structured SOPs or `routes` + `routing: { mode: 'structured' }` for triage — same `defineAgent` primitive as Node/Bun. No runtime differences.
@@ -20,6 +20,7 @@
20
20
  */
21
21
  import { AIChatAgent } from '@cloudflare/ai-chat';
22
22
  import { type HarnessConfig } from '@kuralle-agents/core';
23
+ import type { PersistentMemoryStore } from '@kuralle-agents/core';
23
24
  import type { StreamTextOnFinishCallback, ToolSet } from 'ai';
24
25
  import type { OnChatMessageOptions } from '@cloudflare/ai-chat';
25
26
  import type { StreamAdapterConfig } from './types.js';
@@ -64,6 +65,11 @@ export declare abstract class KuralleAgent<Env = unknown, State = unknown> exten
64
65
  * Optional: Configure which Kuralle events become data parts in the stream.
65
66
  */
66
67
  protected getStreamConfig(): Partial<StreamAdapterConfig>;
68
+ /**
69
+ * Optional: durable working-memory blocks backed by DO SQLite.
70
+ * When returned, wired into `HarnessConfig.defaultWorkingMemoryStore`.
71
+ */
72
+ protected getWorkingMemoryStore(): PersistentMemoryStore | undefined;
67
73
  /**
68
74
  * Get the SQL executor for the Durable Object.
69
75
  * CF's AIChatAgent exposes this.sql as a tagged template function.
@@ -22,6 +22,7 @@ import { AIChatAgent } from '@cloudflare/ai-chat';
22
22
  import { createRuntime } from '@kuralle-agents/core';
23
23
  import { BridgeSessionStore } from './BridgeSessionStore.js';
24
24
  import { OrchestrationStore } from './OrchestrationStore.js';
25
+ import { SqlPersistentMemoryStore } from './SqlPersistentMemoryStore.js';
25
26
  import { createSSEResponse } from './StreamAdapter.js';
26
27
  import { DEFAULT_STREAM_CONFIG } from './types.js';
27
28
  import { durableAgentSurface } from './durable-agent-surface.js';
@@ -62,6 +63,13 @@ export class KuralleAgent extends AIChatAgent {
62
63
  getStreamConfig() {
63
64
  return {};
64
65
  }
66
+ /**
67
+ * Optional: durable working-memory blocks backed by DO SQLite.
68
+ * When returned, wired into `HarnessConfig.defaultWorkingMemoryStore`.
69
+ */
70
+ getWorkingMemoryStore() {
71
+ return new SqlPersistentMemoryStore(this.getSql());
72
+ }
65
73
  /**
66
74
  * Get the SQL executor for the Durable Object.
67
75
  * CF's AIChatAgent exposes this.sql as a tagged template function.
@@ -113,11 +121,15 @@ export class KuralleAgent extends AIChatAgent {
113
121
  });
114
122
  // Build runtime (fresh per request to pick up latest config)
115
123
  const extraConfig = this.getRuntimeConfig();
124
+ const workingMemoryStore = this.getWorkingMemoryStore();
116
125
  this.runtime = createRuntime({
117
126
  ...extraConfig,
118
127
  agents: this.getAgents(),
119
128
  defaultAgentId,
120
129
  sessionStore,
130
+ ...(workingMemoryStore && !extraConfig.defaultWorkingMemoryStore
131
+ ? { defaultWorkingMemoryStore: workingMemoryStore }
132
+ : {}),
121
133
  });
122
134
  const handle = this.runtime.run({
123
135
  input: lastUserMessage,
@@ -0,0 +1,12 @@
1
+ import type { MemoryBlockScope, PersistentMemoryBlock, PersistentMemoryStore } from '@kuralle-agents/core';
2
+ import type { SqlExecutor } from './types.js';
3
+ export declare class SqlPersistentMemoryStore implements PersistentMemoryStore {
4
+ private sql;
5
+ private initialized;
6
+ constructor(sql: SqlExecutor);
7
+ private ensureTable;
8
+ loadBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<PersistentMemoryBlock | null>;
9
+ saveBlock(block: PersistentMemoryBlock, owner: string): Promise<void>;
10
+ deleteBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<void>;
11
+ listBlocks(scope: MemoryBlockScope, owner: string): Promise<string[]>;
12
+ }
@@ -0,0 +1,71 @@
1
+ export class SqlPersistentMemoryStore {
2
+ sql;
3
+ initialized = false;
4
+ constructor(sql) {
5
+ this.sql = sql;
6
+ }
7
+ ensureTable() {
8
+ if (this.initialized) {
9
+ return;
10
+ }
11
+ this.sql `
12
+ CREATE TABLE IF NOT EXISTS working_memory_blocks (
13
+ scope TEXT NOT NULL,
14
+ owner TEXT NOT NULL,
15
+ key TEXT NOT NULL,
16
+ content TEXT NOT NULL,
17
+ char_limit INTEGER NOT NULL,
18
+ updated_at TEXT NOT NULL,
19
+ PRIMARY KEY (scope, owner, key)
20
+ )
21
+ `;
22
+ this.initialized = true;
23
+ }
24
+ async loadBlock(scope, owner, key) {
25
+ this.ensureTable();
26
+ const rows = this.sql `
27
+ SELECT content, char_limit, updated_at
28
+ FROM working_memory_blocks
29
+ WHERE scope = ${scope} AND owner = ${owner} AND key = ${key}
30
+ `;
31
+ if (!rows || rows.length === 0) {
32
+ return null;
33
+ }
34
+ const row = rows[0];
35
+ return {
36
+ key,
37
+ scope,
38
+ content: row.content,
39
+ charLimit: row.char_limit,
40
+ updatedAt: row.updated_at,
41
+ };
42
+ }
43
+ async saveBlock(block, owner) {
44
+ this.ensureTable();
45
+ const updatedAt = block.updatedAt ?? new Date().toISOString();
46
+ this.sql `
47
+ INSERT INTO working_memory_blocks (scope, owner, key, content, char_limit, updated_at)
48
+ VALUES (${block.scope}, ${owner}, ${block.key}, ${block.content}, ${block.charLimit}, ${updatedAt})
49
+ ON CONFLICT(scope, owner, key) DO UPDATE SET
50
+ content = excluded.content,
51
+ char_limit = excluded.char_limit,
52
+ updated_at = excluded.updated_at
53
+ `;
54
+ }
55
+ async deleteBlock(scope, owner, key) {
56
+ this.ensureTable();
57
+ this.sql `
58
+ DELETE FROM working_memory_blocks
59
+ WHERE scope = ${scope} AND owner = ${owner} AND key = ${key}
60
+ `;
61
+ }
62
+ async listBlocks(scope, owner) {
63
+ this.ensureTable();
64
+ const rows = this.sql `
65
+ SELECT key FROM working_memory_blocks
66
+ WHERE scope = ${scope} AND owner = ${owner}
67
+ ORDER BY key
68
+ `;
69
+ return (rows ?? []).map((row) => row.key);
70
+ }
71
+ }
package/dist/index.d.ts CHANGED
@@ -26,6 +26,8 @@
26
26
  export { KuralleAgent, KuralleAgent as CfChatAgent } from './KuralleAgent.js';
27
27
  export { BridgeSessionStore } from './BridgeSessionStore.js';
28
28
  export { OrchestrationStore } from './OrchestrationStore.js';
29
+ export { SqlPersistentMemoryStore } from './SqlPersistentMemoryStore.js';
30
+ export { createSqlExecutor } from './sqlExecutor.js';
29
31
  export { createSSEResponse } from './StreamAdapter.js';
30
32
  export type { StreamAdapterConfig, OrchestrationState, SqlExecutor, } from './types.js';
31
33
  export { DEFAULT_STREAM_CONFIG } from './types.js';
package/dist/index.js CHANGED
@@ -26,5 +26,7 @@
26
26
  export { KuralleAgent, KuralleAgent as CfChatAgent } from './KuralleAgent.js';
27
27
  export { BridgeSessionStore } from './BridgeSessionStore.js';
28
28
  export { OrchestrationStore } from './OrchestrationStore.js';
29
+ export { SqlPersistentMemoryStore } from './SqlPersistentMemoryStore.js';
30
+ export { createSqlExecutor } from './sqlExecutor.js';
29
31
  export { createSSEResponse } from './StreamAdapter.js';
30
32
  export { DEFAULT_STREAM_CONFIG } from './types.js';
@@ -0,0 +1,7 @@
1
+ import type { SqlExecutor } from './types.js';
2
+ type SqlStorageExec = {
3
+ exec: (query: string, ...params: unknown[]) => unknown;
4
+ };
5
+ /** Wrap DO `ctx.storage.sql.exec` as the tagged-template `SqlExecutor` shape. */
6
+ export declare function createSqlExecutor(storageSql: SqlStorageExec): SqlExecutor;
7
+ export {};
@@ -0,0 +1,19 @@
1
+ function rowsFromExecResult(result) {
2
+ if (result && typeof result === 'object') {
3
+ const cursor = result;
4
+ if (typeof cursor.toArray === 'function') {
5
+ return cursor.toArray();
6
+ }
7
+ if (Symbol.iterator in cursor) {
8
+ return [...result];
9
+ }
10
+ }
11
+ return [];
12
+ }
13
+ /** Wrap DO `ctx.storage.sql.exec` as the tagged-template `SqlExecutor` shape. */
14
+ export function createSqlExecutor(storageSql) {
15
+ return ((strings, ...values) => {
16
+ const query = strings.reduce((acc, part, index) => acc + part + (index < values.length ? '?' : ''), '');
17
+ return rowsFromExecResult(storageSql.exec(query, ...values));
18
+ });
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuralle-agents/cf-agent",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Kuralle agent integration for Cloudflare Workers with AIChatAgent",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,18 +22,20 @@
22
22
  "@cloudflare/ai-chat": "^0.1.8",
23
23
  "ai": "^6.0.90",
24
24
  "zod-to-json-schema": "^3.24.0",
25
- "@kuralle-agents/core": "0.5.0",
26
- "@kuralle-agents/realtime-audio": "0.5.0"
25
+ "@kuralle-agents/realtime-audio": "0.6.0",
26
+ "@kuralle-agents/core": "0.6.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "agents": "^0.11.5",
30
30
  "zod": "^3.0.0",
31
- "@kuralle-agents/voice-protocol": "0.5.0"
31
+ "@kuralle-agents/voice-protocol": "0.6.0"
32
32
  },
33
33
  "devDependencies": {
34
+ "@cloudflare/vitest-pool-workers": "^0.12.7",
34
35
  "agents": "^0.11.5",
35
36
  "typescript": "^5.7.0",
36
- "@kuralle-agents/voice-protocol": "0.5.0"
37
+ "vitest": "^3.2.4",
38
+ "@kuralle-agents/voice-protocol": "0.6.0"
37
39
  },
38
40
  "engines": {
39
41
  "node": ">=20"
@@ -57,7 +59,8 @@
57
59
  "prebuild": "rm -rf dist",
58
60
  "build": "tsc",
59
61
  "dev": "tsc --watch",
60
- "test": "bun test src/voice/__tests__ src/__tests__",
62
+ "test": "bun test src/voice/__tests__ src/__tests__ && vitest run --config vitest.config.ts",
63
+ "test:sql-memory-workers": "vitest run --config vitest.config.ts",
61
64
  "typecheck": "tsc --noEmit",
62
65
  "clean": "rm -rf dist"
63
66
  }