@sentry/junior-memory 0.124.0 → 0.124.2
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/api.d.ts +33 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +312 -40
- package/dist/index.js.map +1 -1
- package/dist/personal-store.d.ts +56 -7
- package/dist/personal.d.ts +13 -3
- package/dist/user-pages.d.ts +2 -2
- package/package.json +2 -2
- package/src/api.ts +64 -6
- package/src/index.ts +2 -0
- package/src/personal-store.ts +276 -16
- package/src/personal.ts +52 -13
- package/src/user-pages.ts +69 -21
package/dist/api.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Authenticated REST resources for
|
|
2
|
+
* Authenticated REST resources for viewer-visible memories.
|
|
3
3
|
*
|
|
4
4
|
* HTTP identity is one verified viewer. Linked platform actors are resolved
|
|
5
|
-
* behind the route boundary and used only to authorize personal
|
|
5
|
+
* behind the route boundary and used only to authorize personal and public
|
|
6
|
+
* workspace scopes.
|
|
6
7
|
*/
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
import { type PluginRouteApp, type PluginUserPageActor } from "@sentry/junior-plugin-api";
|
|
@@ -18,6 +19,10 @@ export declare const memoryApiSchema: z.ZodObject<{
|
|
|
18
19
|
knowledge: "knowledge";
|
|
19
20
|
}>;
|
|
20
21
|
observedAt: z.ZodISODateTime;
|
|
22
|
+
visibility: z.ZodEnum<{
|
|
23
|
+
public: "public";
|
|
24
|
+
private: "private";
|
|
25
|
+
}>;
|
|
21
26
|
}, z.core.$strict>;
|
|
22
27
|
export declare const memoryListResponseSchema: z.ZodObject<{
|
|
23
28
|
memories: z.ZodArray<z.ZodObject<{
|
|
@@ -31,15 +36,40 @@ export declare const memoryListResponseSchema: z.ZodObject<{
|
|
|
31
36
|
knowledge: "knowledge";
|
|
32
37
|
}>;
|
|
33
38
|
observedAt: z.ZodISODateTime;
|
|
39
|
+
visibility: z.ZodEnum<{
|
|
40
|
+
public: "public";
|
|
41
|
+
private: "private";
|
|
42
|
+
}>;
|
|
34
43
|
}, z.core.$strict>>;
|
|
35
44
|
nextCursor: z.ZodOptional<z.ZodString>;
|
|
36
45
|
}, z.core.$strict>;
|
|
46
|
+
export declare const memoryDashboardResponseSchema: z.ZodObject<{
|
|
47
|
+
days: z.ZodArray<z.ZodObject<{
|
|
48
|
+
date: z.ZodISODate;
|
|
49
|
+
personal: z.ZodNumber;
|
|
50
|
+
public: z.ZodNumber;
|
|
51
|
+
}, z.core.$strict>>;
|
|
52
|
+
generatedAt: z.ZodISODateTime;
|
|
53
|
+
stats: z.ZodObject<{
|
|
54
|
+
active: z.ZodNumber;
|
|
55
|
+
automatic: z.ZodNumber;
|
|
56
|
+
createdThirtyDays: z.ZodNumber;
|
|
57
|
+
embedded: z.ZodNumber;
|
|
58
|
+
explicit: z.ZodNumber;
|
|
59
|
+
knowledge: z.ZodNumber;
|
|
60
|
+
personal: z.ZodNumber;
|
|
61
|
+
preference: z.ZodNumber;
|
|
62
|
+
procedure: z.ZodNumber;
|
|
63
|
+
public: z.ZodNumber;
|
|
64
|
+
}, z.core.$strict>;
|
|
65
|
+
}, z.core.$strict>;
|
|
37
66
|
export type MemoryApi = z.output<typeof memoryApiSchema>;
|
|
67
|
+
export type MemoryDashboardResponse = z.output<typeof memoryDashboardResponseSchema>;
|
|
38
68
|
export type MemoryListResponse = z.output<typeof memoryListResponseSchema>;
|
|
39
69
|
interface MemoryApiOptions {
|
|
40
70
|
actors(email: string): Promise<PluginUserPageActor[]>;
|
|
41
71
|
db: MemoryDb;
|
|
42
72
|
}
|
|
43
|
-
/** Create the authenticated
|
|
73
|
+
/** Create the authenticated viewer-memory REST app. */
|
|
44
74
|
export declare function createMemoryApi(options: MemoryApiOptions): PluginRouteApp;
|
|
45
75
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { memoryPlugin } from "./plugin";
|
|
2
|
-
export { memoryApiSchema, memoryListResponseSchema, type MemoryApi, type MemoryListResponse, } from "./api";
|
|
2
|
+
export { memoryApiSchema, memoryDashboardResponseSchema, memoryListResponseSchema, type MemoryApi, type MemoryDashboardResponse, type MemoryListResponse, } from "./api";
|
|
3
3
|
export type { MemoryPluginOptions } from "./plugin";
|
|
4
4
|
export { createMemoryStore } from "./store";
|
|
5
5
|
export type { ArchiveMemoryInput, CreateMemoryInput, CreateMemoryResult, ListMemoriesInput, MemoryDb, MemoryEmbeddingProvider, MemoryRecord, MemoryStore, MemoryStoreOptions, SearchMemoriesInput, } from "./store";
|
package/dist/index.js
CHANGED
|
@@ -496,12 +496,12 @@ function visibleScopePredicate(scopes) {
|
|
|
496
496
|
);
|
|
497
497
|
}
|
|
498
498
|
function activeVisiblePredicate(args) {
|
|
499
|
-
const
|
|
500
|
-
if (!
|
|
499
|
+
const scopePredicate2 = visibleScopePredicate(args.scopes);
|
|
500
|
+
if (!scopePredicate2) {
|
|
501
501
|
return void 0;
|
|
502
502
|
}
|
|
503
503
|
return and(
|
|
504
|
-
|
|
504
|
+
scopePredicate2,
|
|
505
505
|
isNull(juniorMemoryMemories.archivedAtMs),
|
|
506
506
|
isNull(juniorMemoryMemories.supersededAtMs),
|
|
507
507
|
isNull(juniorMemoryMemories.supersededById),
|
|
@@ -571,12 +571,12 @@ async function findByIdempotencyKey(args) {
|
|
|
571
571
|
return void 0;
|
|
572
572
|
}
|
|
573
573
|
async function archiveExpiredMemoryBatch(args) {
|
|
574
|
-
const
|
|
575
|
-
if (!
|
|
574
|
+
const scopePredicate2 = visibleScopePredicate(args.scopes);
|
|
575
|
+
if (!scopePredicate2) {
|
|
576
576
|
return { archivedCount: 0 };
|
|
577
577
|
}
|
|
578
578
|
const predicates = [
|
|
579
|
-
|
|
579
|
+
scopePredicate2,
|
|
580
580
|
isNull(juniorMemoryMemories.archivedAtMs),
|
|
581
581
|
isNull(juniorMemoryMemories.supersededAtMs),
|
|
582
582
|
isNull(juniorMemoryMemories.supersededById),
|
|
@@ -1762,18 +1762,26 @@ import {
|
|
|
1762
1762
|
import { z as z5 } from "zod";
|
|
1763
1763
|
|
|
1764
1764
|
// src/personal-store.ts
|
|
1765
|
-
import { and as and2, asc as asc2, desc as desc2, eq as eq2, gt as gt2, ilike, lt, or as or2, sql as sql3 } from "drizzle-orm";
|
|
1765
|
+
import { and as and2, asc as asc2, desc as desc2, eq as eq2, gt as gt2, ilike, like as like2, lt, or as or2, sql as sql3 } from "drizzle-orm";
|
|
1766
1766
|
import { z as z4 } from "zod";
|
|
1767
1767
|
var nonEmptyStringSchema3 = z4.string().min(1);
|
|
1768
|
+
var memoryVisibilitySchema = z4.enum(["private", "public"]);
|
|
1768
1769
|
var personalMemoryCursorSchema = z4.object({
|
|
1769
1770
|
createdAtMs: z4.number().finite(),
|
|
1770
1771
|
id: nonEmptyStringSchema3
|
|
1771
1772
|
}).strict();
|
|
1772
1773
|
var personalMemoryPageInputSchema = z4.object({
|
|
1773
1774
|
cursor: personalMemoryCursorSchema.optional(),
|
|
1775
|
+
kind: z4.enum(MEMORY_KINDS).optional(),
|
|
1774
1776
|
limit: z4.number().int().min(1).max(50),
|
|
1775
|
-
|
|
1777
|
+
origin: z4.enum(["automatic", "explicit"]).optional(),
|
|
1778
|
+
query: z4.string().max(200).optional(),
|
|
1779
|
+
visibility: memoryVisibilitySchema.optional()
|
|
1776
1780
|
}).strict();
|
|
1781
|
+
var personalMemoryTimelineInputSchema = z4.object({
|
|
1782
|
+
days: z4.number().int().min(1).max(365)
|
|
1783
|
+
}).strict();
|
|
1784
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
1777
1785
|
var PersonalMemoryNotFoundError = class extends Error {
|
|
1778
1786
|
constructor() {
|
|
1779
1787
|
super("Memory was not found for the authenticated viewer.");
|
|
@@ -1790,6 +1798,39 @@ function personalScopes(runtimeContexts) {
|
|
|
1790
1798
|
).values()
|
|
1791
1799
|
];
|
|
1792
1800
|
}
|
|
1801
|
+
function publicWorkspaceScopes(runtimeContexts) {
|
|
1802
|
+
return [
|
|
1803
|
+
...new Map(
|
|
1804
|
+
runtimeContexts.flatMap((context) => {
|
|
1805
|
+
if (context.source.platform !== "slack" || !context.actor) {
|
|
1806
|
+
return [];
|
|
1807
|
+
}
|
|
1808
|
+
if (context.actor.platform !== "slack") {
|
|
1809
|
+
return [];
|
|
1810
|
+
}
|
|
1811
|
+
const scope = {
|
|
1812
|
+
scope: "conversation",
|
|
1813
|
+
scopeKey: `slack:${context.actor.teamId}`
|
|
1814
|
+
};
|
|
1815
|
+
return [[`${scope.scope}:${scope.scopeKey}`, scope]];
|
|
1816
|
+
})
|
|
1817
|
+
).values()
|
|
1818
|
+
];
|
|
1819
|
+
}
|
|
1820
|
+
function scopePredicate(scopes) {
|
|
1821
|
+
if (scopes.length === 0) return void 0;
|
|
1822
|
+
return or2(
|
|
1823
|
+
...scopes.map(
|
|
1824
|
+
(scope) => and2(
|
|
1825
|
+
eq2(juniorMemoryMemories.scope, scope.scope),
|
|
1826
|
+
eq2(juniorMemoryMemories.scopeKey, scope.scopeKey)
|
|
1827
|
+
)
|
|
1828
|
+
)
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
function utcDate(ms) {
|
|
1832
|
+
return new Date(ms).toISOString().slice(0, 10);
|
|
1833
|
+
}
|
|
1793
1834
|
function searchTerms(query) {
|
|
1794
1835
|
return [
|
|
1795
1836
|
...new Set(
|
|
@@ -1797,14 +1838,55 @@ function searchTerms(query) {
|
|
|
1797
1838
|
)
|
|
1798
1839
|
];
|
|
1799
1840
|
}
|
|
1841
|
+
function memoryOrigin(idempotencyKey) {
|
|
1842
|
+
if (idempotencyKey?.startsWith("session:")) return "automatic";
|
|
1843
|
+
if (idempotencyKey?.startsWith("tool:")) return "explicit";
|
|
1844
|
+
return "other";
|
|
1845
|
+
}
|
|
1846
|
+
function memoryVisibility(scope) {
|
|
1847
|
+
return scope === "personal" ? "private" : "public";
|
|
1848
|
+
}
|
|
1849
|
+
function personalMemoryRecord(row) {
|
|
1850
|
+
const memory = parseMemoryRow(row);
|
|
1851
|
+
return {
|
|
1852
|
+
...memory,
|
|
1853
|
+
origin: memoryOrigin(row.idempotencyKey),
|
|
1854
|
+
sourcePlatform: row.sourcePlatform,
|
|
1855
|
+
visibility: memoryVisibility(memory.scope)
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
function emptyStats() {
|
|
1859
|
+
return {
|
|
1860
|
+
active: 0,
|
|
1861
|
+
automatic: 0,
|
|
1862
|
+
createdThirtyDays: 0,
|
|
1863
|
+
embedded: 0,
|
|
1864
|
+
explicit: 0,
|
|
1865
|
+
knowledge: 0,
|
|
1866
|
+
personal: 0,
|
|
1867
|
+
preference: 0,
|
|
1868
|
+
procedure: 0,
|
|
1869
|
+
public: 0
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1800
1872
|
function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
1801
|
-
const
|
|
1873
|
+
const privateScopes = personalScopes(runtimeContexts);
|
|
1874
|
+
const publicScopes = publicWorkspaceScopes(runtimeContexts);
|
|
1875
|
+
const allScopes = [...privateScopes, ...publicScopes];
|
|
1802
1876
|
const getNowMs = () => options.now?.() ?? Date.now();
|
|
1877
|
+
function scopesForVisibility(visibility) {
|
|
1878
|
+
if (visibility === "private") return privateScopes;
|
|
1879
|
+
if (visibility === "public") return publicScopes;
|
|
1880
|
+
return allScopes;
|
|
1881
|
+
}
|
|
1803
1882
|
return {
|
|
1804
1883
|
async archive(id) {
|
|
1805
1884
|
const memoryId = nonEmptyStringSchema3.parse(id);
|
|
1806
1885
|
const nowMs = getNowMs();
|
|
1807
|
-
const predicate = activeVisiblePredicate({
|
|
1886
|
+
const predicate = activeVisiblePredicate({
|
|
1887
|
+
nowMs,
|
|
1888
|
+
scopes: privateScopes
|
|
1889
|
+
});
|
|
1808
1890
|
if (!predicate) {
|
|
1809
1891
|
throw new PersonalMemoryNotFoundError();
|
|
1810
1892
|
}
|
|
@@ -1821,7 +1903,7 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
|
1821
1903
|
async get(id) {
|
|
1822
1904
|
const memoryId = nonEmptyStringSchema3.parse(id);
|
|
1823
1905
|
const nowMs = getNowMs();
|
|
1824
|
-
const predicate = activeVisiblePredicate({ nowMs, scopes });
|
|
1906
|
+
const predicate = activeVisiblePredicate({ nowMs, scopes: allScopes });
|
|
1825
1907
|
if (!predicate) {
|
|
1826
1908
|
throw new PersonalMemoryNotFoundError();
|
|
1827
1909
|
}
|
|
@@ -1829,11 +1911,12 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
|
1829
1911
|
if (!rows[0]) {
|
|
1830
1912
|
throw new PersonalMemoryNotFoundError();
|
|
1831
1913
|
}
|
|
1832
|
-
return
|
|
1914
|
+
return personalMemoryRecord(rows[0]);
|
|
1833
1915
|
},
|
|
1834
1916
|
async list(input) {
|
|
1835
1917
|
input = personalMemoryPageInputSchema.parse(input);
|
|
1836
1918
|
const nowMs = getNowMs();
|
|
1919
|
+
const scopes = scopesForVisibility(input.visibility);
|
|
1837
1920
|
await archiveExpiredMemoryBatch({ db, nowMs, scopes });
|
|
1838
1921
|
const active = activeVisiblePredicate({ nowMs, scopes });
|
|
1839
1922
|
if (!active) {
|
|
@@ -1852,12 +1935,14 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
|
1852
1935
|
(term) => ilike(juniorMemoryMemories.content, `%${term}%`)
|
|
1853
1936
|
)
|
|
1854
1937
|
);
|
|
1855
|
-
const
|
|
1938
|
+
const kind = input.kind ? eq2(juniorMemoryMemories.kind, input.kind) : void 0;
|
|
1939
|
+
const origin = input.origin === "automatic" ? like2(juniorMemoryMemories.idempotencyKey, "session:%") : input.origin === "explicit" ? like2(juniorMemoryMemories.idempotencyKey, "tool:%") : void 0;
|
|
1940
|
+
const rows = await db.select().from(juniorMemoryMemories).where(and2(active, cursor, search, kind, origin)).orderBy(
|
|
1856
1941
|
desc2(juniorMemoryMemories.createdAtMs),
|
|
1857
1942
|
asc2(juniorMemoryMemories.id)
|
|
1858
1943
|
).limit(input.limit + 1);
|
|
1859
1944
|
const hasNextPage = rows.length > input.limit;
|
|
1860
|
-
const memories = rows.slice(0, input.limit).map(
|
|
1945
|
+
const memories = rows.slice(0, input.limit).map(personalMemoryRecord);
|
|
1861
1946
|
const last = memories.at(-1);
|
|
1862
1947
|
return {
|
|
1863
1948
|
memories,
|
|
@@ -1868,6 +1953,97 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
|
1868
1953
|
}
|
|
1869
1954
|
} : {}
|
|
1870
1955
|
};
|
|
1956
|
+
},
|
|
1957
|
+
async stats() {
|
|
1958
|
+
const nowMs = getNowMs();
|
|
1959
|
+
await archiveExpiredMemoryBatch({ db, nowMs, scopes: allScopes });
|
|
1960
|
+
const active = activeVisiblePredicate({ nowMs, scopes: allScopes });
|
|
1961
|
+
if (!active) {
|
|
1962
|
+
return emptyStats();
|
|
1963
|
+
}
|
|
1964
|
+
const [counts] = await db.select({
|
|
1965
|
+
active: sql3`count(*)`.mapWith(Number),
|
|
1966
|
+
automatic: sql3`count(*) filter (where ${juniorMemoryMemories.idempotencyKey} like 'session:%')`.mapWith(
|
|
1967
|
+
Number
|
|
1968
|
+
),
|
|
1969
|
+
createdThirtyDays: sql3`count(*) filter (where ${juniorMemoryMemories.createdAtMs} >= ${nowMs - 30 * 24 * 60 * 60 * 1e3})`.mapWith(
|
|
1970
|
+
Number
|
|
1971
|
+
),
|
|
1972
|
+
embedded: sql3`count(${juniorMemoryEmbeddings.memoryId})`.mapWith(
|
|
1973
|
+
Number
|
|
1974
|
+
),
|
|
1975
|
+
explicit: sql3`count(*) filter (where ${juniorMemoryMemories.idempotencyKey} like 'tool:%')`.mapWith(
|
|
1976
|
+
Number
|
|
1977
|
+
),
|
|
1978
|
+
knowledge: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
|
|
1979
|
+
Number
|
|
1980
|
+
),
|
|
1981
|
+
personal: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
|
|
1982
|
+
Number
|
|
1983
|
+
),
|
|
1984
|
+
preference: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
|
|
1985
|
+
Number
|
|
1986
|
+
),
|
|
1987
|
+
procedure: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
|
|
1988
|
+
Number
|
|
1989
|
+
),
|
|
1990
|
+
public: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
|
|
1991
|
+
Number
|
|
1992
|
+
)
|
|
1993
|
+
}).from(juniorMemoryMemories).leftJoin(
|
|
1994
|
+
juniorMemoryEmbeddings,
|
|
1995
|
+
eq2(juniorMemoryEmbeddings.memoryId, juniorMemoryMemories.id)
|
|
1996
|
+
).where(active);
|
|
1997
|
+
return {
|
|
1998
|
+
active: counts?.active ?? 0,
|
|
1999
|
+
automatic: counts?.automatic ?? 0,
|
|
2000
|
+
createdThirtyDays: counts?.createdThirtyDays ?? 0,
|
|
2001
|
+
embedded: counts?.embedded ?? 0,
|
|
2002
|
+
explicit: counts?.explicit ?? 0,
|
|
2003
|
+
knowledge: counts?.knowledge ?? 0,
|
|
2004
|
+
personal: counts?.personal ?? 0,
|
|
2005
|
+
preference: counts?.preference ?? 0,
|
|
2006
|
+
procedure: counts?.procedure ?? 0,
|
|
2007
|
+
public: counts?.public ?? 0
|
|
2008
|
+
};
|
|
2009
|
+
},
|
|
2010
|
+
async timeline(input) {
|
|
2011
|
+
input = personalMemoryTimelineInputSchema.parse(input);
|
|
2012
|
+
const todayMs = Date.parse(`${utcDate(getNowMs())}T00:00:00.000Z`);
|
|
2013
|
+
const startMs = todayMs - (input.days - 1) * DAY_MS;
|
|
2014
|
+
const ownership = scopePredicate(allScopes);
|
|
2015
|
+
if (!ownership) {
|
|
2016
|
+
return Array.from({ length: input.days }, (_, index2) => ({
|
|
2017
|
+
date: utcDate(startMs + index2 * DAY_MS),
|
|
2018
|
+
personal: 0,
|
|
2019
|
+
public: 0
|
|
2020
|
+
}));
|
|
2021
|
+
}
|
|
2022
|
+
const rows = await db.select({
|
|
2023
|
+
date: sql3`to_char(to_timestamp(${juniorMemoryMemories.createdAtMs} / 1000.0) AT TIME ZONE 'UTC', 'YYYY-MM-DD')`.as(
|
|
2024
|
+
"date"
|
|
2025
|
+
),
|
|
2026
|
+
personal: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
|
|
2027
|
+
Number
|
|
2028
|
+
),
|
|
2029
|
+
public: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
|
|
2030
|
+
Number
|
|
2031
|
+
)
|
|
2032
|
+
}).from(juniorMemoryMemories).where(
|
|
2033
|
+
and2(ownership, gt2(juniorMemoryMemories.createdAtMs, startMs - 1))
|
|
2034
|
+
).groupBy(
|
|
2035
|
+
sql3`to_char(to_timestamp(${juniorMemoryMemories.createdAtMs} / 1000.0) AT TIME ZONE 'UTC', 'YYYY-MM-DD')`
|
|
2036
|
+
);
|
|
2037
|
+
const byDate = new Map(rows.map((row) => [row.date, row]));
|
|
2038
|
+
return Array.from({ length: input.days }, (_, index2) => {
|
|
2039
|
+
const date = utcDate(startMs + index2 * DAY_MS);
|
|
2040
|
+
const row = byDate.get(date);
|
|
2041
|
+
return {
|
|
2042
|
+
date,
|
|
2043
|
+
personal: row?.personal ?? 0,
|
|
2044
|
+
public: row?.public ?? 0
|
|
2045
|
+
};
|
|
2046
|
+
});
|
|
1871
2047
|
}
|
|
1872
2048
|
};
|
|
1873
2049
|
}
|
|
@@ -1876,8 +2052,11 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
|
1876
2052
|
var cursorSchema = z5.object({
|
|
1877
2053
|
createdAtMs: z5.number().finite(),
|
|
1878
2054
|
id: z5.string().min(1),
|
|
2055
|
+
kind: z5.enum(["preference", "procedure", "knowledge"]).optional(),
|
|
2056
|
+
origin: z5.enum(["automatic", "explicit"]).optional(),
|
|
1879
2057
|
query: z5.string().max(200).optional(),
|
|
1880
|
-
version: z5.literal(1)
|
|
2058
|
+
version: z5.literal(1),
|
|
2059
|
+
visibility: z5.enum(["private", "public"]).optional()
|
|
1881
2060
|
}).strict();
|
|
1882
2061
|
var InvalidMemoryCursorError = class extends Error {
|
|
1883
2062
|
constructor() {
|
|
@@ -1906,13 +2085,13 @@ function runtimeContext(actor) {
|
|
|
1906
2085
|
}
|
|
1907
2086
|
};
|
|
1908
2087
|
}
|
|
1909
|
-
function decodeCursor(value,
|
|
2088
|
+
function decodeCursor(value, input) {
|
|
1910
2089
|
if (!value) return void 0;
|
|
1911
2090
|
try {
|
|
1912
2091
|
const parsed = cursorSchema.parse(
|
|
1913
2092
|
JSON.parse(Buffer.from(value, "base64url").toString("utf8"))
|
|
1914
2093
|
);
|
|
1915
|
-
if (parsed.query !== query) {
|
|
2094
|
+
if (parsed.query !== input.query || parsed.kind !== input.kind || parsed.origin !== input.origin || parsed.visibility !== input.visibility) {
|
|
1916
2095
|
throw new InvalidMemoryCursorError();
|
|
1917
2096
|
}
|
|
1918
2097
|
return { createdAtMs: parsed.createdAtMs, id: parsed.id };
|
|
@@ -1920,9 +2099,16 @@ function decodeCursor(value, query) {
|
|
|
1920
2099
|
throw new InvalidMemoryCursorError();
|
|
1921
2100
|
}
|
|
1922
2101
|
}
|
|
1923
|
-
function encodeCursor(cursor,
|
|
2102
|
+
function encodeCursor(cursor, input) {
|
|
1924
2103
|
return Buffer.from(
|
|
1925
|
-
JSON.stringify({
|
|
2104
|
+
JSON.stringify({
|
|
2105
|
+
...cursor,
|
|
2106
|
+
...input.query ? { query: input.query } : {},
|
|
2107
|
+
...input.kind ? { kind: input.kind } : {},
|
|
2108
|
+
...input.origin ? { origin: input.origin } : {},
|
|
2109
|
+
...input.visibility ? { visibility: input.visibility } : {},
|
|
2110
|
+
version: 1
|
|
2111
|
+
}),
|
|
1926
2112
|
"utf8"
|
|
1927
2113
|
).toString("base64url");
|
|
1928
2114
|
}
|
|
@@ -1940,15 +2126,27 @@ function createViewerMemories(db, actors) {
|
|
|
1940
2126
|
},
|
|
1941
2127
|
async list(input) {
|
|
1942
2128
|
const query = input.query?.trim() || void 0;
|
|
2129
|
+
const filters = {
|
|
2130
|
+
...input.kind ? { kind: input.kind } : {},
|
|
2131
|
+
...input.origin ? { origin: input.origin } : {},
|
|
2132
|
+
...query ? { query } : {},
|
|
2133
|
+
...input.visibility ? { visibility: input.visibility } : {}
|
|
2134
|
+
};
|
|
1943
2135
|
const page = await collection.list({
|
|
1944
|
-
cursor: decodeCursor(input.cursor,
|
|
1945
|
-
|
|
1946
|
-
|
|
2136
|
+
cursor: decodeCursor(input.cursor, filters),
|
|
2137
|
+
...filters,
|
|
2138
|
+
limit: input.limit
|
|
1947
2139
|
});
|
|
1948
2140
|
return {
|
|
1949
2141
|
memories: page.memories,
|
|
1950
|
-
...page.nextCursor ? { nextCursor: encodeCursor(page.nextCursor,
|
|
2142
|
+
...page.nextCursor ? { nextCursor: encodeCursor(page.nextCursor, filters) } : {}
|
|
1951
2143
|
};
|
|
2144
|
+
},
|
|
2145
|
+
async stats() {
|
|
2146
|
+
return await collection.stats();
|
|
2147
|
+
},
|
|
2148
|
+
async timeline(input) {
|
|
2149
|
+
return await collection.timeline(input);
|
|
1952
2150
|
}
|
|
1953
2151
|
};
|
|
1954
2152
|
}
|
|
@@ -1960,12 +2158,34 @@ var memoryApiSchema = z6.object({
|
|
|
1960
2158
|
expiresAt: z6.iso.datetime().optional(),
|
|
1961
2159
|
id: z6.string().min(1),
|
|
1962
2160
|
kind: z6.enum(["preference", "procedure", "knowledge"]),
|
|
1963
|
-
observedAt: z6.iso.datetime()
|
|
2161
|
+
observedAt: z6.iso.datetime(),
|
|
2162
|
+
visibility: z6.enum(["private", "public"])
|
|
1964
2163
|
}).strict();
|
|
1965
2164
|
var memoryListResponseSchema = z6.object({
|
|
1966
2165
|
memories: z6.array(memoryApiSchema),
|
|
1967
2166
|
nextCursor: z6.string().min(1).optional()
|
|
1968
2167
|
}).strict();
|
|
2168
|
+
var memoryDashboardDaySchema = z6.object({
|
|
2169
|
+
date: z6.iso.date(),
|
|
2170
|
+
personal: z6.number().int().min(0),
|
|
2171
|
+
public: z6.number().int().min(0)
|
|
2172
|
+
}).strict();
|
|
2173
|
+
var memoryDashboardResponseSchema = z6.object({
|
|
2174
|
+
days: z6.array(memoryDashboardDaySchema).length(90),
|
|
2175
|
+
generatedAt: z6.iso.datetime(),
|
|
2176
|
+
stats: z6.object({
|
|
2177
|
+
active: z6.number().int().min(0),
|
|
2178
|
+
automatic: z6.number().int().min(0),
|
|
2179
|
+
createdThirtyDays: z6.number().int().min(0),
|
|
2180
|
+
embedded: z6.number().int().min(0),
|
|
2181
|
+
explicit: z6.number().int().min(0),
|
|
2182
|
+
knowledge: z6.number().int().min(0),
|
|
2183
|
+
personal: z6.number().int().min(0),
|
|
2184
|
+
preference: z6.number().int().min(0),
|
|
2185
|
+
procedure: z6.number().int().min(0),
|
|
2186
|
+
public: z6.number().int().min(0)
|
|
2187
|
+
}).strict()
|
|
2188
|
+
}).strict();
|
|
1969
2189
|
var memoryListQuerySchema = z6.object({
|
|
1970
2190
|
cursor: z6.string().min(1).max(1e3).optional(),
|
|
1971
2191
|
limit: z6.coerce.number().int().min(1).max(50).default(25),
|
|
@@ -1984,7 +2204,8 @@ function apiMemory(memory) {
|
|
|
1984
2204
|
...memory.expiresAtMs !== void 0 ? { expiresAt: new Date(memory.expiresAtMs).toISOString() } : {},
|
|
1985
2205
|
id: memory.id,
|
|
1986
2206
|
kind: memory.kind,
|
|
1987
|
-
observedAt: new Date(memory.observedAtMs).toISOString()
|
|
2207
|
+
observedAt: new Date(memory.observedAtMs).toISOString(),
|
|
2208
|
+
visibility: memory.visibility
|
|
1988
2209
|
};
|
|
1989
2210
|
}
|
|
1990
2211
|
function viewerEmail(context) {
|
|
@@ -2004,12 +2225,28 @@ function createMemoryApi(options) {
|
|
|
2004
2225
|
const url = new URL(request.url);
|
|
2005
2226
|
const memoryPath = /^\/memories\/([^/]+)$/.exec(url.pathname);
|
|
2006
2227
|
const isCollection = url.pathname === "/memories";
|
|
2007
|
-
|
|
2228
|
+
const isDashboard = url.pathname === "/dashboard";
|
|
2229
|
+
if (!isCollection && !isDashboard && !memoryPath) {
|
|
2008
2230
|
return json({ error: "Not found." }, 404);
|
|
2009
2231
|
}
|
|
2010
2232
|
const actors = await options.actors(email);
|
|
2011
2233
|
const memories = createViewerMemories(options.db, actors);
|
|
2012
2234
|
try {
|
|
2235
|
+
if (isDashboard && (request.method === "GET" || request.method === "HEAD")) {
|
|
2236
|
+
const [stats, days] = await Promise.all([
|
|
2237
|
+
memories.stats(),
|
|
2238
|
+
memories.timeline({ days: 90 })
|
|
2239
|
+
]);
|
|
2240
|
+
const body = memoryDashboardResponseSchema.parse({
|
|
2241
|
+
days,
|
|
2242
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2243
|
+
stats
|
|
2244
|
+
});
|
|
2245
|
+
return request.method === "HEAD" ? new Response(null, {
|
|
2246
|
+
headers: { "cache-control": "no-store" },
|
|
2247
|
+
status: 200
|
|
2248
|
+
}) : json(body);
|
|
2249
|
+
}
|
|
2013
2250
|
if (isCollection && (request.method === "GET" || request.method === "HEAD")) {
|
|
2014
2251
|
const query = memoryListQuerySchema.parse({
|
|
2015
2252
|
cursor: url.searchParams.get("cursor") ?? void 0,
|
|
@@ -2925,7 +3162,7 @@ async function createMemoryPromptContributions(context) {
|
|
|
2925
3162
|
// src/operational-report.ts
|
|
2926
3163
|
import { and as and4, eq as eq5, gt as gt4, isNull as isNull3, or as or4, sql as sql4 } from "drizzle-orm";
|
|
2927
3164
|
import { z as z11 } from "zod";
|
|
2928
|
-
var
|
|
3165
|
+
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
2929
3166
|
var WINDOWS = [7, 30, 90];
|
|
2930
3167
|
var memoryDaySchema = z11.object({
|
|
2931
3168
|
conversation: z11.number().int().nonnegative(),
|
|
@@ -2945,8 +3182,8 @@ function startOfUtcDay(value) {
|
|
|
2945
3182
|
}
|
|
2946
3183
|
async function aggregateMemoryDays(args) {
|
|
2947
3184
|
const end = startOfUtcDay(args.nowMs);
|
|
2948
|
-
const start = startOfUtcDay(args.nowMs - (WINDOWS.at(-1) - 1) *
|
|
2949
|
-
const endExclusiveMs = end.getTime() +
|
|
3185
|
+
const start = startOfUtcDay(args.nowMs - (WINDOWS.at(-1) - 1) * DAY_MS2);
|
|
3186
|
+
const endExclusiveMs = end.getTime() + DAY_MS2;
|
|
2950
3187
|
const table = juniorMemoryMemories;
|
|
2951
3188
|
const result = await args.db.execute(sql4`
|
|
2952
3189
|
WITH days AS (
|
|
@@ -3010,7 +3247,7 @@ async function buildMemoryOperationalReport(args) {
|
|
|
3010
3247
|
conversation: sql4`count(*) filter (where ${active} and ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
|
|
3011
3248
|
Number
|
|
3012
3249
|
),
|
|
3013
|
-
createdThirtyDays: sql4`count(*) filter (where ${juniorMemoryMemories.createdAtMs} >= ${args.nowMs - 30 *
|
|
3250
|
+
createdThirtyDays: sql4`count(*) filter (where ${juniorMemoryMemories.createdAtMs} >= ${args.nowMs - 30 * DAY_MS2})`.mapWith(
|
|
3014
3251
|
Number
|
|
3015
3252
|
),
|
|
3016
3253
|
embedded: sql4`count(${juniorMemoryEmbeddings.memoryId}) filter (where ${active})`.mapWith(
|
|
@@ -3080,36 +3317,59 @@ async function buildMemoryOperationalReport(args) {
|
|
|
3080
3317
|
}
|
|
3081
3318
|
|
|
3082
3319
|
// src/user-pages.ts
|
|
3083
|
-
function
|
|
3084
|
-
return
|
|
3320
|
+
function titleCase(value) {
|
|
3321
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
3085
3322
|
}
|
|
3086
3323
|
function rememberedDate(createdAtMs) {
|
|
3087
3324
|
return new Intl.DateTimeFormat("en-US", {
|
|
3088
3325
|
dateStyle: "medium",
|
|
3326
|
+
timeStyle: "short",
|
|
3089
3327
|
timeZone: "UTC"
|
|
3090
3328
|
}).format(new Date(createdAtMs));
|
|
3091
3329
|
}
|
|
3330
|
+
function originLabel(origin) {
|
|
3331
|
+
if (origin === "automatic") return "Automatic";
|
|
3332
|
+
if (origin === "explicit") return "Explicit";
|
|
3333
|
+
return "Other";
|
|
3334
|
+
}
|
|
3335
|
+
function visibilityLabel(visibility) {
|
|
3336
|
+
return visibility === "public" ? "Public" : "Private";
|
|
3337
|
+
}
|
|
3338
|
+
function pageFilter(filter) {
|
|
3339
|
+
if (filter === "private") return { visibility: "private" };
|
|
3340
|
+
if (filter === "public") return { visibility: "public" };
|
|
3341
|
+
return {};
|
|
3342
|
+
}
|
|
3343
|
+
function pageEmptyText(input) {
|
|
3344
|
+
if (input.query) return "No memories matched your search.";
|
|
3345
|
+
if (input.filter === "private") return "No private memories yet.";
|
|
3346
|
+
if (input.filter === "public") return "No public memories yet.";
|
|
3347
|
+
return "No memories yet.";
|
|
3348
|
+
}
|
|
3092
3349
|
function createMemoryUserPage() {
|
|
3093
3350
|
return {
|
|
3094
3351
|
id: "memories",
|
|
3095
3352
|
label: "Memories",
|
|
3096
|
-
|
|
3353
|
+
navigation: "primary",
|
|
3354
|
+
description: "Personal and public memories Junior can use across conversations.",
|
|
3097
3355
|
async read(ctx, input) {
|
|
3098
|
-
const
|
|
3356
|
+
const memories = createViewerMemories(
|
|
3099
3357
|
ctx.db,
|
|
3100
3358
|
ctx.viewer.actors
|
|
3101
|
-
)
|
|
3359
|
+
);
|
|
3360
|
+
const page = await memories.list({
|
|
3102
3361
|
cursor: input.cursor,
|
|
3362
|
+
...pageFilter(input.filter),
|
|
3103
3363
|
limit: input.limit,
|
|
3104
3364
|
...input.query ? { query: input.query } : {}
|
|
3105
3365
|
});
|
|
3106
3366
|
return {
|
|
3107
3367
|
type: "list",
|
|
3108
|
-
emptyText: input
|
|
3368
|
+
emptyText: pageEmptyText(input),
|
|
3109
3369
|
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
3110
3370
|
searchPlaceholder: "Search memories",
|
|
3111
3371
|
records: page.memories.map((memory) => ({
|
|
3112
|
-
actions: [
|
|
3372
|
+
actions: memory.visibility === "private" ? [
|
|
3113
3373
|
{
|
|
3114
3374
|
confirmation: "Forget this memory?",
|
|
3115
3375
|
href: `/api/plugins/memory/memories/${encodeURIComponent(memory.id)}`,
|
|
@@ -3117,12 +3377,23 @@ function createMemoryUserPage() {
|
|
|
3117
3377
|
method: "DELETE",
|
|
3118
3378
|
tone: "danger"
|
|
3119
3379
|
}
|
|
3120
|
-
],
|
|
3380
|
+
] : [],
|
|
3121
3381
|
id: memory.id,
|
|
3122
3382
|
title: memory.content,
|
|
3123
3383
|
metadata: [
|
|
3124
|
-
{ label: "Type", value:
|
|
3125
|
-
{ label: "
|
|
3384
|
+
{ label: "Type", value: titleCase(memory.kind) },
|
|
3385
|
+
{ label: "Learned", value: originLabel(memory.origin) },
|
|
3386
|
+
{ label: "Source", value: titleCase(memory.sourcePlatform) },
|
|
3387
|
+
{
|
|
3388
|
+
label: "Visibility",
|
|
3389
|
+
value: visibilityLabel(memory.visibility)
|
|
3390
|
+
},
|
|
3391
|
+
{ label: "Remembered", value: rememberedDate(memory.createdAtMs) },
|
|
3392
|
+
{ label: "Observed", value: rememberedDate(memory.observedAtMs) },
|
|
3393
|
+
{
|
|
3394
|
+
label: "Expires",
|
|
3395
|
+
value: memory.expiresAtMs ? rememberedDate(memory.expiresAtMs) : "Never"
|
|
3396
|
+
}
|
|
3126
3397
|
]
|
|
3127
3398
|
}))
|
|
3128
3399
|
};
|
|
@@ -3250,6 +3521,7 @@ export {
|
|
|
3250
3521
|
MEMORY_KINDS,
|
|
3251
3522
|
createMemoryStore,
|
|
3252
3523
|
memoryApiSchema,
|
|
3524
|
+
memoryDashboardResponseSchema,
|
|
3253
3525
|
memoryListResponseSchema,
|
|
3254
3526
|
memoryPlugin
|
|
3255
3527
|
};
|