@kuralle-agents/redis-store 0.12.0 → 0.14.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 +16 -0
- package/dist/RedisSessionStore.d.ts +1 -1
- package/dist/RedisSessionStore.js +12 -0
- package/dist/RedisTraceStore.d.ts +21 -0
- package/dist/RedisTraceStore.js +53 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Three backend implementations — sessions, long-term memory, and vector search
|
|
|
17
17
|
**Key exports:**
|
|
18
18
|
|
|
19
19
|
- **`RedisSessionStore`** — `SessionStore` implementation for durable session persistence.
|
|
20
|
+
- **`RedisTraceStore`** — independent native trace persistence and read API.
|
|
20
21
|
- **`RedisMemoryService`** — `MemoryService` implementation for cross-session long-term memory.
|
|
21
22
|
- **`RedisPersistentMemoryStore`** — `PersistentMemoryStore` for durable USER/MEMORY markdown blocks.
|
|
22
23
|
- **`RedisVectorStore`** — `VectorStoreCore` implementation for vector similarity search.
|
|
@@ -38,6 +39,21 @@ const runtime = createRuntime({
|
|
|
38
39
|
});
|
|
39
40
|
```
|
|
40
41
|
|
|
42
|
+
## Trace store
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { RedisTraceStore } from '@kuralle-agents/redis-store';
|
|
46
|
+
|
|
47
|
+
const traceStore = new RedisTraceStore({ client, traceTtlSeconds: 604800 });
|
|
48
|
+
const runtime = createRuntime({
|
|
49
|
+
agents: [agent],
|
|
50
|
+
defaultAgentId: 'support',
|
|
51
|
+
tracing: { store: traceStore },
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Trace keys use a separate `trace`/`traces` namespace from sessions.
|
|
56
|
+
|
|
41
57
|
## Client adapters
|
|
42
58
|
|
|
43
59
|
**node-redis:**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AuditListOptions, type ConversationAuditEntry, type Session, type SessionStore } from '@kuralle-agents/core';
|
|
2
2
|
type RedisResult<T = unknown> = T | null;
|
|
3
3
|
type RedisCommand = (...args: any[]) => Promise<RedisResult>;
|
|
4
4
|
export type RedisClientLike = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { StaleWriteError, } from '@kuralle-agents/core';
|
|
2
3
|
import { callCommand, getMembers, addMembers, removeMembers, setExpiration, setScore, removeScore, rangeByScore, removeByScore, } from './redisHelpers.js';
|
|
3
4
|
const defaultPrefix = 'kuralle';
|
|
4
5
|
const reviveSession = (raw) => {
|
|
@@ -75,9 +76,20 @@ export class RedisSessionStore {
|
|
|
75
76
|
}
|
|
76
77
|
async save(session) {
|
|
77
78
|
const previous = await this.get(session.id);
|
|
79
|
+
const expectedVersion = session.version ?? 0;
|
|
80
|
+
if (previous !== null) {
|
|
81
|
+
const storedVersion = previous.version ?? 0;
|
|
82
|
+
if (storedVersion !== expectedVersion) {
|
|
83
|
+
throw new StaleWriteError(session.id, expectedVersion, storedVersion);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (expectedVersion !== 0) {
|
|
87
|
+
throw new StaleWriteError(session.id, expectedVersion, 0);
|
|
88
|
+
}
|
|
78
89
|
session.updatedAt = new Date();
|
|
79
90
|
session.conversationId = session.conversationId ?? session.id;
|
|
80
91
|
session.channelId = session.channelId ?? 'web';
|
|
92
|
+
session.version = expectedVersion + 1;
|
|
81
93
|
const key = this.sessionKey(session.id);
|
|
82
94
|
const payload = JSON.stringify(session);
|
|
83
95
|
await callCommand(this.client, ['set'], key, payload);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AgentSpan, AgentTrace, TraceListWindow, TraceStore } from '@kuralle-agents/core';
|
|
2
|
+
import type { RedisClientLike } from './RedisSessionStore.js';
|
|
3
|
+
export interface RedisTraceStoreOptions {
|
|
4
|
+
client: RedisClientLike;
|
|
5
|
+
prefix?: string;
|
|
6
|
+
traceTtlSeconds?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class RedisTraceStore implements TraceStore {
|
|
9
|
+
private readonly options;
|
|
10
|
+
private readonly prefix;
|
|
11
|
+
private queue;
|
|
12
|
+
constructor(options: RedisTraceStoreOptions);
|
|
13
|
+
write(span: AgentSpan): Promise<void>;
|
|
14
|
+
putSpan(span: AgentSpan): Promise<void>;
|
|
15
|
+
getTrace(traceId: string): Promise<AgentTrace | null>;
|
|
16
|
+
listTraces(sessionId: string, window?: TraceListWindow): Promise<AgentTrace[]>;
|
|
17
|
+
flush(): Promise<void>;
|
|
18
|
+
private putSpanDirect;
|
|
19
|
+
private traceKey;
|
|
20
|
+
private sessionIndexKey;
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { traceFromSpans } from '@kuralle-agents/core/tracing';
|
|
2
|
+
import { callCommand, rangeByScore, setExpiration, setScore } from './redisHelpers.js';
|
|
3
|
+
export class RedisTraceStore {
|
|
4
|
+
options;
|
|
5
|
+
prefix;
|
|
6
|
+
queue = Promise.resolve();
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
this.prefix = options.prefix ?? 'kuralle';
|
|
10
|
+
}
|
|
11
|
+
write(span) { return this.putSpan(span); }
|
|
12
|
+
putSpan(span) {
|
|
13
|
+
const operation = this.queue.then(() => this.putSpanDirect(span));
|
|
14
|
+
this.queue = operation.catch(() => { });
|
|
15
|
+
return operation;
|
|
16
|
+
}
|
|
17
|
+
async getTrace(traceId) {
|
|
18
|
+
await this.queue;
|
|
19
|
+
const raw = await callCommand(this.options.client, ['get'], this.traceKey(traceId));
|
|
20
|
+
if (!raw)
|
|
21
|
+
return null;
|
|
22
|
+
const spans = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
23
|
+
return traceFromSpans(spans);
|
|
24
|
+
}
|
|
25
|
+
async listTraces(sessionId, window) {
|
|
26
|
+
await this.queue;
|
|
27
|
+
const min = window?.from?.getTime() ?? '-inf';
|
|
28
|
+
const max = window?.to?.getTime() ?? '+inf';
|
|
29
|
+
const ids = (await rangeByScore(this.options.client, this.sessionIndexKey(sessionId), min, max)).reverse();
|
|
30
|
+
const selected = window?.limit === undefined ? ids : ids.slice(0, window.limit);
|
|
31
|
+
const traces = await Promise.all(selected.map((id) => this.getTrace(id)));
|
|
32
|
+
return traces.filter((trace) => trace !== null);
|
|
33
|
+
}
|
|
34
|
+
flush() { return this.queue; }
|
|
35
|
+
async putSpanDirect(span) {
|
|
36
|
+
const key = this.traceKey(span.traceId);
|
|
37
|
+
const raw = await callCommand(this.options.client, ['get'], key);
|
|
38
|
+
const spans = raw
|
|
39
|
+
? (typeof raw === 'string' ? JSON.parse(raw) : raw)
|
|
40
|
+
: [];
|
|
41
|
+
const index = spans.findIndex((entry) => entry.spanId === span.spanId);
|
|
42
|
+
if (index >= 0)
|
|
43
|
+
spans[index] = span;
|
|
44
|
+
else
|
|
45
|
+
spans.push(span);
|
|
46
|
+
await callCommand(this.options.client, ['set'], key, JSON.stringify(spans));
|
|
47
|
+
await setExpiration(this.options.client, key, this.options.traceTtlSeconds);
|
|
48
|
+
await setScore(this.options.client, this.sessionIndexKey(span.attributes.sessionId), Math.min(...spans.map((entry) => entry.startTime)), span.traceId);
|
|
49
|
+
await setExpiration(this.options.client, this.sessionIndexKey(span.attributes.sessionId), this.options.traceTtlSeconds);
|
|
50
|
+
}
|
|
51
|
+
traceKey(traceId) { return `${this.prefix}:trace:${traceId}`; }
|
|
52
|
+
sessionIndexKey(sessionId) { return `${this.prefix}:traces:${sessionId}`; }
|
|
53
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { RedisSessionStore } from './RedisSessionStore.js';
|
|
2
2
|
export type { RedisClientLike, RedisStoreOptions } from './RedisSessionStore.js';
|
|
3
|
+
export { RedisTraceStore } from './RedisTraceStore.js';
|
|
4
|
+
export type { RedisTraceStoreOptions } from './RedisTraceStore.js';
|
|
3
5
|
export { RedisMemoryService } from './RedisMemoryService.js';
|
|
4
6
|
export type { RedisMemoryStoreOptions } from './RedisMemoryService.js';
|
|
5
7
|
export { RedisPersistentMemoryStore } from './RedisPersistentMemoryStore.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { RedisSessionStore } from './RedisSessionStore.js';
|
|
2
|
+
export { RedisTraceStore } from './RedisTraceStore.js';
|
|
2
3
|
export { RedisMemoryService } from './RedisMemoryService.js';
|
|
3
4
|
export { RedisPersistentMemoryStore } from './RedisPersistentMemoryStore.js';
|
|
4
5
|
export { fromUpstash, fromNodeRedis, fromIORedis } from './adapters.js';
|
package/package.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/kuralle/kuralle-agents.git",
|
|
7
|
-
"directory": "packages/
|
|
7
|
+
"directory": "packages/redis-store"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.14.0",
|
|
10
10
|
"description": "Redis-backed SessionStore for Kuralle (supports Upstash and common Redis clients)",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"main": "dist/index.js",
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@kuralle-agents/core": "0.
|
|
21
|
+
"@kuralle-agents/core": "0.14.0"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@kuralle-agents/
|
|
25
|
-
"@kuralle-agents/
|
|
24
|
+
"@kuralle-agents/core": "0.14.0",
|
|
25
|
+
"@kuralle-agents/rag": "0.14.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@ai-sdk/openai": "^3.0.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"tsx": "^4.7.0",
|
|
34
34
|
"typescript": "^5.3.0",
|
|
35
35
|
"zod": "^4.0.0",
|
|
36
|
-
"@kuralle-agents/rag": "0.
|
|
36
|
+
"@kuralle-agents/rag": "0.14.0"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|