@hexis-ai/engram-server 0.10.1 → 0.11.1
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/adapters/memory.d.ts +4 -0
- package/dist/adapters/memory.js +9 -0
- package/dist/adapters/postgres.d.ts +4 -0
- package/dist/adapters/postgres.js +8 -0
- package/dist/routes/sessions.js +8 -0
- package/dist/schemas.d.ts +6 -0
- package/dist/schemas.js +6 -0
- package/dist/storage.d.ts +17 -1
- package/openapi.json +46 -0
- package/package.json +2 -2
|
@@ -29,7 +29,11 @@ export declare class InMemoryAdapter implements StorageAdapter {
|
|
|
29
29
|
listSessions(opts: {
|
|
30
30
|
limit: number;
|
|
31
31
|
channel?: string;
|
|
32
|
+
channel_prefix?: string;
|
|
32
33
|
status?: "active" | "idle" | "completed";
|
|
34
|
+
has_trigger?: boolean;
|
|
35
|
+
no_summary?: boolean;
|
|
36
|
+
updated_before?: string;
|
|
33
37
|
}): Promise<Session[]>;
|
|
34
38
|
sessionsForPerson(personId: string, opts: {
|
|
35
39
|
limit: number;
|
package/dist/adapters/memory.js
CHANGED
|
@@ -147,8 +147,17 @@ export class InMemoryAdapter {
|
|
|
147
147
|
for (const stored of this.sessions.values()) {
|
|
148
148
|
if (opts.channel && stored.row.channel !== opts.channel)
|
|
149
149
|
continue;
|
|
150
|
+
if (opts.channel_prefix &&
|
|
151
|
+
!(stored.row.channel ?? "").startsWith(opts.channel_prefix))
|
|
152
|
+
continue;
|
|
150
153
|
if (opts.status && stored.row.status !== opts.status)
|
|
151
154
|
continue;
|
|
155
|
+
if (opts.has_trigger && stored.row.trigger_conversation_id == null)
|
|
156
|
+
continue;
|
|
157
|
+
if (opts.no_summary && stored.row.summary != null)
|
|
158
|
+
continue;
|
|
159
|
+
if (opts.updated_before && stored.row.updatedAt >= opts.updated_before)
|
|
160
|
+
continue;
|
|
152
161
|
all.push({
|
|
153
162
|
s: foldEvents(stored.row, [...stored.events.values()], now),
|
|
154
163
|
updatedAt: stored.row.updatedAt,
|
|
@@ -42,7 +42,11 @@ export declare class PostgresAdapter implements StorageAdapter {
|
|
|
42
42
|
listSessions(opts: {
|
|
43
43
|
limit: number;
|
|
44
44
|
channel?: string;
|
|
45
|
+
channel_prefix?: string;
|
|
45
46
|
status?: "active" | "idle" | "completed";
|
|
47
|
+
has_trigger?: boolean;
|
|
48
|
+
no_summary?: boolean;
|
|
49
|
+
updated_before?: string;
|
|
46
50
|
}): Promise<Session[]>;
|
|
47
51
|
sessionsForPerson(personId: string, opts: {
|
|
48
52
|
limit: number;
|
|
@@ -173,12 +173,20 @@ export class PostgresAdapter {
|
|
|
173
173
|
}
|
|
174
174
|
async listSessions(opts) {
|
|
175
175
|
const channelFilter = opts.channel ?? null;
|
|
176
|
+
const channelPrefix = opts.channel_prefix ?? null;
|
|
176
177
|
const statusFilter = opts.status ?? null;
|
|
178
|
+
const hasTrigger = opts.has_trigger === true;
|
|
179
|
+
const noSummary = opts.no_summary === true;
|
|
180
|
+
const updatedBefore = opts.updated_before ?? null;
|
|
177
181
|
const rows = await this.sql `
|
|
178
182
|
SELECT id FROM engram_sessions
|
|
179
183
|
WHERE workspace_id = ${this.workspaceId}
|
|
180
184
|
AND (${channelFilter}::text IS NULL OR channel = ${channelFilter}::text)
|
|
185
|
+
AND (${channelPrefix}::text IS NULL OR channel LIKE ${channelPrefix ? channelPrefix + "%" : null}::text)
|
|
181
186
|
AND (${statusFilter}::text IS NULL OR status = ${statusFilter}::text)
|
|
187
|
+
AND (${hasTrigger}::boolean = FALSE OR trigger_conversation_id IS NOT NULL)
|
|
188
|
+
AND (${noSummary}::boolean = FALSE OR summary IS NULL)
|
|
189
|
+
AND (${updatedBefore}::timestamptz IS NULL OR updated_at < ${updatedBefore}::timestamptz)
|
|
182
190
|
ORDER BY updated_at DESC
|
|
183
191
|
LIMIT ${opts.limit}
|
|
184
192
|
`;
|
package/dist/routes/sessions.js
CHANGED
|
@@ -63,14 +63,22 @@ export function sessionsRoutes(cfg) {
|
|
|
63
63
|
app.get("/sessions", async (c) => {
|
|
64
64
|
const limit = clampLimit(c, cfg.defaultListLimit, cfg.maxListLimit);
|
|
65
65
|
const channel = c.req.query("channel") || undefined;
|
|
66
|
+
const channel_prefix = c.req.query("channel_prefix") || undefined;
|
|
66
67
|
const rawStatus = c.req.query("status");
|
|
67
68
|
const status = rawStatus === "active" || rawStatus === "idle" || rawStatus === "completed"
|
|
68
69
|
? rawStatus
|
|
69
70
|
: undefined;
|
|
71
|
+
const has_trigger = c.req.query("has_trigger") === "true" || undefined;
|
|
72
|
+
const no_summary = c.req.query("no_summary") === "true" || undefined;
|
|
73
|
+
const updated_before = c.req.query("updated_before") || undefined;
|
|
70
74
|
const sessions = await c.var.ctx.storage.listSessions({
|
|
71
75
|
limit,
|
|
72
76
|
channel,
|
|
77
|
+
channel_prefix,
|
|
73
78
|
status,
|
|
79
|
+
has_trigger,
|
|
80
|
+
no_summary,
|
|
81
|
+
updated_before,
|
|
74
82
|
});
|
|
75
83
|
const persons = await resolvePersonMap(c.var.ctx.storage, sessions);
|
|
76
84
|
return c.json({ sessions, persons });
|
package/dist/schemas.d.ts
CHANGED
|
@@ -112,9 +112,15 @@ export declare const eventBatchSchema: z.ZodObject<{
|
|
|
112
112
|
}, z.core.$strip>;
|
|
113
113
|
export declare const personCreateSchema: z.ZodObject<{
|
|
114
114
|
display_name: z.ZodOptional<z.ZodString>;
|
|
115
|
+
role: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
116
|
+
team: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
117
|
+
source: z.ZodOptional<z.ZodString>;
|
|
115
118
|
}, z.core.$strip>;
|
|
116
119
|
export declare const personUpdateSchema: z.ZodObject<{
|
|
117
120
|
display_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
121
|
+
role: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
122
|
+
team: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
123
|
+
source: z.ZodOptional<z.ZodString>;
|
|
118
124
|
}, z.core.$strip>;
|
|
119
125
|
export declare const aliasUpsertSchema: z.ZodObject<{
|
|
120
126
|
caller: z.ZodString;
|
package/dist/schemas.js
CHANGED
|
@@ -90,9 +90,15 @@ export const eventBatchSchema = z.object({
|
|
|
90
90
|
// --- Persons ---------------------------------------------------------
|
|
91
91
|
export const personCreateSchema = z.object({
|
|
92
92
|
display_name: z.string().optional(),
|
|
93
|
+
role: z.string().nullable().optional(),
|
|
94
|
+
team: z.string().nullable().optional(),
|
|
95
|
+
source: z.string().optional(),
|
|
93
96
|
});
|
|
94
97
|
export const personUpdateSchema = z.object({
|
|
95
98
|
display_name: z.string().nullable().optional(),
|
|
99
|
+
role: z.string().nullable().optional(),
|
|
100
|
+
team: z.string().nullable().optional(),
|
|
101
|
+
source: z.string().optional(),
|
|
96
102
|
});
|
|
97
103
|
// --- Aliases ----------------------------------------------------------
|
|
98
104
|
export const aliasUpsertSchema = z.object({
|
package/dist/storage.d.ts
CHANGED
|
@@ -33,11 +33,27 @@ export interface StorageAdapter {
|
|
|
33
33
|
* events, which returns `[]`).
|
|
34
34
|
*/
|
|
35
35
|
getSessionEvents(sessionId: string): Promise<SessionEvent[] | null>;
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* List recent sessions, ordered by `updated_at` desc.
|
|
38
|
+
*
|
|
39
|
+
* Filter combinations are AND'd. Pass `channel_prefix` instead of
|
|
40
|
+
* `channel` to match channels by prefix (e.g. `slack_dm:C123/`) —
|
|
41
|
+
* this is the only way to express "any thread under DM Cxxx".
|
|
42
|
+
* `has_trigger=true` restricts to sessions whose
|
|
43
|
+
* `trigger_conversation_id` is set; `no_summary=true` restricts to
|
|
44
|
+
* sessions whose `summary` is null. `updated_before` restricts to
|
|
45
|
+
* sessions whose `updated_at` is strictly less than the ISO timestamp
|
|
46
|
+
* — combine with `status='idle' + no_summary=true` to find idle,
|
|
47
|
+
* unsummarized conversations older than N minutes.
|
|
48
|
+
*/
|
|
37
49
|
listSessions(opts: {
|
|
38
50
|
limit: number;
|
|
39
51
|
channel?: string;
|
|
52
|
+
channel_prefix?: string;
|
|
40
53
|
status?: "active" | "idle" | "completed";
|
|
54
|
+
has_trigger?: boolean;
|
|
55
|
+
no_summary?: boolean;
|
|
56
|
+
updated_before?: string;
|
|
41
57
|
}): Promise<Session[]>;
|
|
42
58
|
/**
|
|
43
59
|
* Create a person with a freshly allocated id. The host (e.g. monet)
|
package/openapi.json
CHANGED
|
@@ -340,6 +340,29 @@
|
|
|
340
340
|
"properties": {
|
|
341
341
|
"display_name": {
|
|
342
342
|
"type": "string"
|
|
343
|
+
},
|
|
344
|
+
"role": {
|
|
345
|
+
"anyOf": [
|
|
346
|
+
{
|
|
347
|
+
"type": "string"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"type": "null"
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
},
|
|
354
|
+
"team": {
|
|
355
|
+
"anyOf": [
|
|
356
|
+
{
|
|
357
|
+
"type": "string"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"type": "null"
|
|
361
|
+
}
|
|
362
|
+
]
|
|
363
|
+
},
|
|
364
|
+
"source": {
|
|
365
|
+
"type": "string"
|
|
343
366
|
}
|
|
344
367
|
},
|
|
345
368
|
"additionalProperties": false
|
|
@@ -356,6 +379,29 @@
|
|
|
356
379
|
"type": "null"
|
|
357
380
|
}
|
|
358
381
|
]
|
|
382
|
+
},
|
|
383
|
+
"role": {
|
|
384
|
+
"anyOf": [
|
|
385
|
+
{
|
|
386
|
+
"type": "string"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"type": "null"
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
},
|
|
393
|
+
"team": {
|
|
394
|
+
"anyOf": [
|
|
395
|
+
{
|
|
396
|
+
"type": "string"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"type": "null"
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
},
|
|
403
|
+
"source": {
|
|
404
|
+
"type": "string"
|
|
359
405
|
}
|
|
360
406
|
},
|
|
361
407
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hexis-ai/engram-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Engram server: ingest agent session events, persist via a pluggable adapter, expose search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"engram",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@hexis-ai/engram-core": "^0.2.0",
|
|
53
|
-
"@hexis-ai/engram-sdk": "^0.
|
|
53
|
+
"@hexis-ai/engram-sdk": "^0.10.0",
|
|
54
54
|
"hono": "^4.6.0",
|
|
55
55
|
"zod": "^4.0.0"
|
|
56
56
|
},
|