@hraness/oh 0.2.7 → 0.3.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 +116 -12
- package/dist/canonical.d.ts.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +91 -19
- package/dist/cloudflare-embedding.d.ts +104 -0
- package/dist/cloudflare-embedding.d.ts.map +1 -0
- package/dist/graph.d.ts.map +1 -1
- package/dist/index.js +90 -18
- package/dist/libsql-semantic.d.ts +111 -0
- package/dist/libsql-semantic.d.ts.map +1 -0
- package/dist/libsql.js +105 -18
- package/dist/memory-page.d.ts +2 -0
- package/dist/memory-page.d.ts.map +1 -0
- package/dist/memory-page.js +725 -0
- package/dist/memory-pages.d.ts +76 -0
- package/dist/memory-pages.d.ts.map +1 -0
- package/dist/memory.d.ts +1 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +478 -18
- package/dist/projection-public.js +105 -18
- package/dist/projection-suss.js +105 -18
- package/dist/sdk.js +90 -18
- package/dist/semantic-cloud.d.ts +3 -0
- package/dist/semantic-cloud.d.ts.map +1 -0
- package/dist/semantic-cloud.js +1843 -0
- package/dist/semantic.d.ts.map +1 -1
- package/dist/semantic.js +104 -21
- package/dist/sqlite/index.js +90 -18
- package/dist/store.js +105 -18
- package/dist/sync.js +90 -18
- package/package.json +10 -2
- package/skills/oh/SKILL.md +28 -2
- package/spec/README.md +11 -3
- package/spec/manifest.json +9 -1
- package/spec/v1/cloudflare-embedding-profile.json +13 -0
- package/spec/v1/cloudflare-embedding-renderer.json +8 -0
- package/spec/v1/memory-page.md +153 -0
- package/spec/v1/memory-page.schema.json +154 -0
- package/spec/v1/memory.md +18 -0
- package/spec/v1/migration.md +13 -0
- package/spec/v1/semantic-cloud.md +87 -0
- package/src/canonical.ts +28 -13
- package/src/cli.ts +1 -1
- package/src/cloudflare-embedding.test.ts +306 -0
- package/src/cloudflare-embedding.ts +385 -0
- package/src/contracts.test.ts +20 -0
- package/src/graph.ts +63 -6
- package/src/libsql-semantic.test.ts +478 -0
- package/src/libsql-semantic.ts +1117 -0
- package/src/memory-page.ts +1 -0
- package/src/memory-pages.test.ts +277 -0
- package/src/memory-pages.ts +440 -0
- package/src/memory.ts +2 -0
- package/src/semantic-cloud.ts +2 -0
- package/src/semantic.ts +14 -3
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type Sha256Hex } from "./canonical";
|
|
2
|
+
import { type OhCloudflareEmbeddingClientV1 } from "./cloudflare-embedding";
|
|
3
|
+
import type { OhLibSqlClientV1 } from "./libsql";
|
|
4
|
+
export declare const OH_LIBSQL_SEMANTIC_LIMITS_V1: Readonly<{
|
|
5
|
+
chunksPerDocument: 64;
|
|
6
|
+
chunksPerGeneration: 4096;
|
|
7
|
+
documentsPerGeneration: 512;
|
|
8
|
+
embeddingBatch: 16;
|
|
9
|
+
searchLimit: 100;
|
|
10
|
+
searchPage: 128;
|
|
11
|
+
}>;
|
|
12
|
+
export declare class OhLibSqlSemanticError extends Error {
|
|
13
|
+
readonly code: "conflict" | "integrity" | "invalid-input" | "purged" | "schema-unavailable";
|
|
14
|
+
constructor(code: OhLibSqlSemanticError["code"], message: string);
|
|
15
|
+
}
|
|
16
|
+
export type OhSemanticAuthorityRefV1 = Readonly<{
|
|
17
|
+
authorityId: string;
|
|
18
|
+
authoritySha256: Sha256Hex;
|
|
19
|
+
generation: number;
|
|
20
|
+
records: readonly Readonly<{
|
|
21
|
+
key: string;
|
|
22
|
+
recordSha256: Sha256Hex;
|
|
23
|
+
}>[];
|
|
24
|
+
v: 1;
|
|
25
|
+
}>;
|
|
26
|
+
export type OhSemanticDocumentV1 = Readonly<{
|
|
27
|
+
content: string;
|
|
28
|
+
key: string;
|
|
29
|
+
recordSha256: Sha256Hex;
|
|
30
|
+
title: string;
|
|
31
|
+
v: 1;
|
|
32
|
+
}>;
|
|
33
|
+
export type OhSemanticStageResultV1 = Readonly<{
|
|
34
|
+
authorityId: string;
|
|
35
|
+
chunks: number;
|
|
36
|
+
documents: number;
|
|
37
|
+
embedded: number;
|
|
38
|
+
generation: number;
|
|
39
|
+
generationSha256: Sha256Hex;
|
|
40
|
+
membershipSha256: Sha256Hex;
|
|
41
|
+
reused: number;
|
|
42
|
+
status: "staged";
|
|
43
|
+
v: 1;
|
|
44
|
+
}>;
|
|
45
|
+
export type OhSemanticPublishResultV1 = Readonly<{
|
|
46
|
+
authorityId: string;
|
|
47
|
+
generation: number;
|
|
48
|
+
generationSha256: Sha256Hex;
|
|
49
|
+
published: boolean;
|
|
50
|
+
v: 1;
|
|
51
|
+
}>;
|
|
52
|
+
export type OhSemanticSearchResultV1 = Readonly<{
|
|
53
|
+
chunkOrdinal: number;
|
|
54
|
+
key: string;
|
|
55
|
+
recordSha256: Sha256Hex;
|
|
56
|
+
score: number;
|
|
57
|
+
v: 1;
|
|
58
|
+
}>;
|
|
59
|
+
export type OhSemanticPurgeResultV1 = Readonly<{
|
|
60
|
+
authorityId: string;
|
|
61
|
+
generations: number;
|
|
62
|
+
memberships: number;
|
|
63
|
+
orphanVectors: number;
|
|
64
|
+
purgedAt: string;
|
|
65
|
+
v: 1;
|
|
66
|
+
}>;
|
|
67
|
+
export declare function bootstrapOhLibSqlSemanticCacheV1(client: OhLibSqlClientV1, options?: Readonly<{
|
|
68
|
+
appliedAt?: string;
|
|
69
|
+
}>): Promise<Readonly<{
|
|
70
|
+
schemaSha256: Sha256Hex;
|
|
71
|
+
schemaVersion: 1;
|
|
72
|
+
v: 1;
|
|
73
|
+
}>>;
|
|
74
|
+
export declare class OhLibSqlSemanticCacheV1 {
|
|
75
|
+
#private;
|
|
76
|
+
private constructor();
|
|
77
|
+
/** @internal Public callers should use `openOhLibSqlSemanticCacheV1`. */
|
|
78
|
+
static open(client: OhLibSqlClientV1, closeClient: boolean): Promise<OhLibSqlSemanticCacheV1>;
|
|
79
|
+
close(): Promise<void>;
|
|
80
|
+
stage(input: Readonly<{
|
|
81
|
+
authorityId: string;
|
|
82
|
+
authoritySha256: Sha256Hex;
|
|
83
|
+
createdAt?: string;
|
|
84
|
+
documents: readonly OhSemanticDocumentV1[];
|
|
85
|
+
embeddingClient: OhCloudflareEmbeddingClientV1;
|
|
86
|
+
generation: number;
|
|
87
|
+
maximumChunksPerDocument?: number;
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
}>): Promise<OhSemanticStageResultV1>;
|
|
90
|
+
publish(input: Readonly<{
|
|
91
|
+
authorityId: string;
|
|
92
|
+
expectedPublishedGeneration: number | null;
|
|
93
|
+
generation: number;
|
|
94
|
+
publishedAt?: string;
|
|
95
|
+
}>): Promise<OhSemanticPublishResultV1>;
|
|
96
|
+
search(input: Readonly<{
|
|
97
|
+
authority: OhSemanticAuthorityRefV1;
|
|
98
|
+
embeddingClient: OhCloudflareEmbeddingClientV1;
|
|
99
|
+
limit?: number;
|
|
100
|
+
query: string;
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
}>): Promise<readonly OhSemanticSearchResultV1[]>;
|
|
103
|
+
purgeAuthority(input: Readonly<{
|
|
104
|
+
authorityId: string;
|
|
105
|
+
purgedAt?: string;
|
|
106
|
+
}>): Promise<OhSemanticPurgeResultV1>;
|
|
107
|
+
}
|
|
108
|
+
export declare function openOhLibSqlSemanticCacheV1(client: OhLibSqlClientV1, options?: Readonly<{
|
|
109
|
+
closeClient?: boolean;
|
|
110
|
+
}>): Promise<OhLibSqlSemanticCacheV1>;
|
|
111
|
+
//# sourceMappingURL=libsql-semantic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"libsql-semantic.d.ts","sourceRoot":"","sources":["../src/libsql-semantic.ts"],"names":[],"mappings":"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"}
|
package/dist/libsql.js
CHANGED
|
@@ -60,17 +60,27 @@ function encodeCanonical(value, path, ancestors) {
|
|
|
60
60
|
ancestors.add(value);
|
|
61
61
|
try {
|
|
62
62
|
if (Array.isArray(value)) {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
encoded.push(encodeCanonical(value[index], `${path}[${index}]`, ancestors));
|
|
63
|
+
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
|
|
64
|
+
const length = lengthDescriptor?.value;
|
|
65
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0) {
|
|
66
|
+
throw new OhValidationError("non-json-property", path, "array has an invalid length descriptor");
|
|
69
67
|
}
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
68
|
+
const ownKeys2 = Reflect.ownKeys(value);
|
|
69
|
+
if (!ownKeys2.includes("length") || ownKeys2.some((key) => key !== "length" && (typeof key !== "string" || !/^(?:0|[1-9][0-9]*)$/u.test(key) || Number(key) >= length))) {
|
|
72
70
|
throw new OhValidationError("non-json-property", path, "array has non-index properties");
|
|
73
71
|
}
|
|
72
|
+
const elements = [];
|
|
73
|
+
for (let index = 0;index < length; index += 1) {
|
|
74
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
75
|
+
if (descriptor === undefined) {
|
|
76
|
+
throw new OhValidationError("sparse-array", `${path}[${index}]`, "must not contain holes");
|
|
77
|
+
}
|
|
78
|
+
if (!descriptor.enumerable || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
79
|
+
throw new OhValidationError("non-json-property", `${path}[${index}]`, "must be an enumerable data property");
|
|
80
|
+
}
|
|
81
|
+
elements.push(descriptor.value);
|
|
82
|
+
}
|
|
83
|
+
const encoded = elements.map((element, index) => encodeCanonical(element, `${path}[${index}]`, ancestors));
|
|
74
84
|
return `[${encoded.join(",")}]`;
|
|
75
85
|
}
|
|
76
86
|
if (!isPlainRecord(value)) {
|
|
@@ -80,19 +90,21 @@ function encodeCanonical(value, path, ancestors) {
|
|
|
80
90
|
if (ownKeys.some((key) => typeof key !== "string")) {
|
|
81
91
|
throw new OhValidationError("non-json-property", path, "object has a symbol property");
|
|
82
92
|
}
|
|
93
|
+
const entries = [];
|
|
83
94
|
const keys = ownKeys;
|
|
84
95
|
for (const key of keys) {
|
|
85
96
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
86
97
|
if (descriptor === undefined || !descriptor.enumerable || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
87
98
|
throw new OhValidationError("non-json-property", `${path}.${key}`, "must be an enumerable data property");
|
|
88
99
|
}
|
|
100
|
+
entries.push([key, descriptor.value]);
|
|
89
101
|
}
|
|
90
|
-
|
|
91
|
-
const
|
|
102
|
+
entries.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
103
|
+
const encodedEntries = entries.map(([key, entryValue]) => {
|
|
92
104
|
assertUnicodeScalarString(key, `${path}.<key>`);
|
|
93
|
-
return `${JSON.stringify(key)}:${encodeCanonical(
|
|
105
|
+
return `${JSON.stringify(key)}:${encodeCanonical(entryValue, `${path}.${key}`, ancestors)}`;
|
|
94
106
|
});
|
|
95
|
-
return `{${
|
|
107
|
+
return `{${encodedEntries.join(",")}}`;
|
|
96
108
|
} finally {
|
|
97
109
|
ancestors.delete(value);
|
|
98
110
|
}
|
|
@@ -140,6 +152,21 @@ function canonicalNow() {
|
|
|
140
152
|
function safeCode(value, maximumLength = 128) {
|
|
141
153
|
return typeof value === "string" && value.length <= maximumLength && /^[a-z][a-z0-9]*(?:[._:/-][a-z0-9]+)*$/u.test(value) ? value : null;
|
|
142
154
|
}
|
|
155
|
+
function boundedText(value, maximumBytes = 64 * 1024) {
|
|
156
|
+
if (typeof value !== "string" || value.length === 0 || value.normalize("NFC") !== value || utf8ByteLength(value) > maximumBytes)
|
|
157
|
+
return null;
|
|
158
|
+
try {
|
|
159
|
+
assertUnicodeScalarString(value, "$text");
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
for (const character of value) {
|
|
164
|
+
const code = character.codePointAt(0) ?? 0;
|
|
165
|
+
if (code <= 8 || code >= 11 && code <= 12 || code >= 14 && code <= 31 || code >= 127 && code <= 159)
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
143
170
|
function orderedUnique(values, key) {
|
|
144
171
|
return values.every((value, index) => index === 0 || key(values[index - 1]) < key(value));
|
|
145
172
|
}
|
|
@@ -183,17 +210,70 @@ var OH_KNOWLEDGE_GRAPH_RECORD_KINDS_V1 = [
|
|
|
183
210
|
"view",
|
|
184
211
|
"vocabulary"
|
|
185
212
|
];
|
|
213
|
+
var KNOWLEDGE_GRAPH_RECORD_KEYS_V1 = [
|
|
214
|
+
"dependencies",
|
|
215
|
+
"key",
|
|
216
|
+
"kind",
|
|
217
|
+
"recordSha256",
|
|
218
|
+
"v",
|
|
219
|
+
"value"
|
|
220
|
+
];
|
|
221
|
+
function exactKnowledgeGraphRecordEnvelopeV1(value) {
|
|
222
|
+
try {
|
|
223
|
+
if (!isPlainRecord(value))
|
|
224
|
+
return null;
|
|
225
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
226
|
+
if (ownKeys.length !== KNOWLEDGE_GRAPH_RECORD_KEYS_V1.length || ownKeys.some((key) => typeof key !== "string") || KNOWLEDGE_GRAPH_RECORD_KEYS_V1.some((key) => !ownKeys.includes(key)))
|
|
227
|
+
return null;
|
|
228
|
+
const detached = {};
|
|
229
|
+
for (const key of KNOWLEDGE_GRAPH_RECORD_KEYS_V1) {
|
|
230
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
231
|
+
if (descriptor === undefined || !descriptor.enumerable || descriptor.get !== undefined || descriptor.set !== undefined)
|
|
232
|
+
return null;
|
|
233
|
+
detached[key] = descriptor.value;
|
|
234
|
+
}
|
|
235
|
+
return detached;
|
|
236
|
+
} catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function exactGraphDependenciesV1(value) {
|
|
241
|
+
try {
|
|
242
|
+
if (!Array.isArray(value))
|
|
243
|
+
return null;
|
|
244
|
+
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
|
|
245
|
+
const length = lengthDescriptor?.value;
|
|
246
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || length > OH_GRAPH_LIMITS_V1.dependenciesPerRecord)
|
|
247
|
+
return null;
|
|
248
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
249
|
+
if (ownKeys.length !== length + 1 || !ownKeys.includes("length") || ownKeys.some((key) => key !== "length" && (typeof key !== "string" || !/^(?:0|[1-9][0-9]*)$/u.test(key) || Number(key) >= length)))
|
|
250
|
+
return null;
|
|
251
|
+
const detached = [];
|
|
252
|
+
for (let index = 0;index < length; index += 1) {
|
|
253
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
254
|
+
if (descriptor === undefined || !descriptor.enumerable || descriptor.get !== undefined || descriptor.set !== undefined)
|
|
255
|
+
return null;
|
|
256
|
+
detached.push(descriptor.value);
|
|
257
|
+
}
|
|
258
|
+
return detached;
|
|
259
|
+
} catch {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
186
263
|
function recordKey(value) {
|
|
187
264
|
return typeof value === "string" && value.length <= 512 && /^[a-z][a-z0-9]*(?:[._:/-][a-z0-9]+)*$/u.test(value) ? value : null;
|
|
188
265
|
}
|
|
189
266
|
function createKnowledgeGraphRecordV1(input) {
|
|
190
|
-
if (!isPlainRecord(input) || !hasExactKeys(input, ["dependencies", "key", "kind", "v", "value"]) || input.v !== 1
|
|
267
|
+
if (!isPlainRecord(input) || !hasExactKeys(input, ["dependencies", "key", "kind", "v", "value"]) || input.v !== 1)
|
|
191
268
|
throw new TypeError("Invalid graph record input.");
|
|
269
|
+
const dependencyInput = exactGraphDependenciesV1(input.dependencies);
|
|
270
|
+
if (dependencyInput === null)
|
|
271
|
+
throw new TypeError("Invalid graph record dependencies.");
|
|
192
272
|
const key = recordKey(input.key);
|
|
193
273
|
const kind = OH_KNOWLEDGE_GRAPH_RECORD_KINDS_V1.find((candidate) => candidate === input.kind);
|
|
194
|
-
if (key === null || kind === undefined
|
|
274
|
+
if (key === null || kind === undefined)
|
|
195
275
|
throw new TypeError("Invalid graph record identity.");
|
|
196
|
-
const dependencies =
|
|
276
|
+
const dependencies = dependencyInput.map(recordKey);
|
|
197
277
|
if (dependencies.some((dependency) => dependency === null) || !orderedUnique(dependencies, String) || dependencies.includes(key)) {
|
|
198
278
|
throw new TypeError("Graph dependencies must be ordered, unique, and non-reflexive.");
|
|
199
279
|
}
|
|
@@ -205,10 +285,17 @@ function createKnowledgeGraphRecordV1(input) {
|
|
|
205
285
|
return { ...payload, recordSha256: canonicalSha256(payload) };
|
|
206
286
|
}
|
|
207
287
|
function parseKnowledgeGraphRecordV1(value) {
|
|
208
|
-
|
|
288
|
+
const envelope = exactKnowledgeGraphRecordEnvelopeV1(value);
|
|
289
|
+
if (envelope === null)
|
|
209
290
|
return null;
|
|
210
|
-
const recordSha256 = parseSha256Hex(
|
|
211
|
-
const
|
|
291
|
+
const recordSha256 = parseSha256Hex(envelope.recordSha256);
|
|
292
|
+
const input = {
|
|
293
|
+
dependencies: envelope.dependencies,
|
|
294
|
+
key: envelope.key,
|
|
295
|
+
kind: envelope.kind,
|
|
296
|
+
v: envelope.v,
|
|
297
|
+
value: envelope.value
|
|
298
|
+
};
|
|
212
299
|
try {
|
|
213
300
|
const created = createKnowledgeGraphRecordV1(input);
|
|
214
301
|
return recordSha256 !== null && created.recordSha256 === recordSha256 ? { ...created, recordSha256 } : null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-page.d.ts","sourceRoot":"","sources":["../src/memory-page.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|